Skip to content

Commit

Permalink
Material convert cache (#19)
Browse files Browse the repository at this point in the history
* Material convert cache

* clang fix

* clang fix: defaulted <=> is broken on Appveyor macOS

* continue fix

* Update

* Update

* Fix
  • Loading branch information
shrinktofit authored Oct 19, 2020
1 parent 03d01ca commit d521acc
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 28 deletions.
49 changes: 31 additions & 18 deletions Core/Source/bee/Convert/SceneConverter.Material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,12 @@ void to_json(nlohmann::json &j_, const MaterialError<FinalError_> &error_) {
/// <summary>
/// Material {} use texture for property \"{}\", which is not supported.
/// </summary>
class ShallNotBeTextureError
: public MaterialError<ShallNotBeTextureError> {
class ShallNotBeTextureError : public MaterialError<ShallNotBeTextureError> {
public:
constexpr static inline std::u8string_view code =
u8"shall_not_be_texture";
constexpr static inline std::u8string_view code = u8"shall_not_be_texture";

ShallNotBeTextureError(std::u8string_view material_name_,
std::u8string_view property_name_)
std::u8string_view property_name_)
: MaterialError(material_name_), _propertyName(property_name_) {
}

Expand All @@ -47,11 +45,9 @@ class ShallNotBeTextureError
std::u8string _propertyName;
};

void to_json(nlohmann::json &j_,
const ShallNotBeTextureError &error_) {
void to_json(nlohmann::json &j_, const ShallNotBeTextureError &error_) {
to_json(j_,
static_cast<const MaterialError<ShallNotBeTextureError> &>(
error_));
static_cast<const MaterialError<ShallNotBeTextureError> &>(error_));
j_["property"] = forceTreatAsPlain(error_.property());
}

Expand All @@ -60,23 +56,34 @@ template <typename T_> static T_ getMetalnessFromSpecular(const T_ *specular_) {
}

std::optional<GLTFBuilder::XXIndex>
SceneConverter::_convertMaterial(fbxsdk::FbxSurfaceMaterial &fbx_material_) {
if (fbx_material_.Is<fbxsdk::FbxSurfaceLambert>()) {
return _convertLambertMaterial(
static_cast<fbxsdk::FbxSurfaceLambert &>(fbx_material_));
} else {
return {};
SceneConverter::_convertMaterial(fbxsdk::FbxSurfaceMaterial &fbx_material_,
const MaterialUsage &material_usage_) {
MaterialConvertKey convertKey{fbx_material_, material_usage_};
auto r = _materialConvertCache.find(convertKey);
if (r == _materialConvertCache.end()) {
const auto glTFMaterialIndex =
[&]() -> std::optional<GLTFBuilder::XXIndex> {
if (fbx_material_.Is<fbxsdk::FbxSurfaceLambert>()) {
return _convertLambertMaterial(
static_cast<fbxsdk::FbxSurfaceLambert &>(fbx_material_),
material_usage_);
} else {
return {};
}
}();
r = _materialConvertCache.emplace(convertKey, glTFMaterialIndex).first;
}
return r->second;
}

std::optional<GLTFBuilder::XXIndex> SceneConverter::_convertLambertMaterial(
fbxsdk::FbxSurfaceLambert &fbx_material_) {
fbxsdk::FbxSurfaceLambert &fbx_material_,
const MaterialUsage &material_usage_) {
const auto materialName = std::string{fbx_material_.GetName()};

auto forbidTextureProperty = [&](std::u8string_view property_name_) {
_log(Logger::Level::warning,
ShallNotBeTextureError{forceTreatAsU8(materialName),
property_name_});
ShallNotBeTextureError{forceTreatAsU8(materialName), property_name_});
};

fx::gltf::Material glTFMaterial;
Expand Down Expand Up @@ -180,6 +187,12 @@ std::optional<GLTFBuilder::XXIndex> SceneConverter::_convertLambertMaterial(
getRoughness(static_cast<float>(fbxPhong.Shininess.Get()));
}

// Alpha mode
if (glTFPbrMetallicRoughness.baseColorFactor[3] < 1.0f ||
material_usage_.hasTransparentVertex) {
glTFMaterial.alphaMode = fx::gltf::Material::AlphaMode::Blend;
}

auto glTFMaterailIndex =
_glTFBuilder.add(&fx::gltf::Document::materials, std::move(glTFMaterial));
return glTFMaterailIndex;
Expand Down
21 changes: 15 additions & 6 deletions Core/Source/bee/Convert/SceneConverter.Mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,16 @@ SceneConverter::_convertNodeMeshes(
skinInfluenceChannels = nodeMeshesSkinData->meshChannels[iFbxMesh];
}

MaterialUsage materialUsage;
auto glTFPrimitive = _convertMeshAsPrimitive(
*fbxMesh, meshName, vertexTransformX, normalTransformX, fbxShapes,
skinInfluenceChannels);
skinInfluenceChannels, materialUsage);

auto materialIndex = _getTheUniqueMaterialIndex(*fbxMesh);
if (materialIndex >= 0) {
const auto fbxMaterial = fbx_node_.GetMaterial(materialIndex);
if (auto glTFMaterialIndex = _convertMaterial(*fbxMaterial)) {
if (auto glTFMaterialIndex =
_convertMaterial(*fbxMaterial, materialUsage)) {
glTFPrimitive.material = *glTFMaterialIndex;
}
}
Expand Down Expand Up @@ -159,7 +161,8 @@ fx::gltf::Primitive SceneConverter::_convertMeshAsPrimitive(
fbxsdk::FbxMatrix *vertex_transform_,
fbxsdk::FbxMatrix *normal_transform_,
std::span<fbxsdk::FbxShape *> fbx_shapes_,
std::span<MeshSkinData::InfluenceChannel> skin_influence_channels_) {
std::span<MeshSkinData::InfluenceChannel> skin_influence_channels_,
MaterialUsage &material_usage_) {
auto vertexLayout =
_getFbxMeshVertexLayout(fbx_mesh_, fbx_shapes_, skin_influence_channels_);
const auto vertexSize = vertexLayout.size;
Expand All @@ -171,12 +174,13 @@ fx::gltf::Primitive SceneConverter::_convertMeshAsPrimitive(
UntypedVertexEqual>
uniqueVertices({}, 0, UntypedVertexHasher{},
UntypedVertexEqual{vertexSize});
bool hasTransparentVertex = false;

const auto nMeshPolygonVertices = fbx_mesh_.GetPolygonVertexCount();
auto meshPolygonVertices = fbx_mesh_.GetPolygonVertices();
auto controlPoints = fbx_mesh_.GetControlPoints();
const auto meshPolygonVertices = fbx_mesh_.GetPolygonVertices();
const auto controlPoints = fbx_mesh_.GetControlPoints();
auto stagingVertex = untypedVertexAllocator.allocate();
auto processPolygonVertex =
const auto processPolygonVertex =
[&](int polygon_vertex_index_) -> UniqueVertexIndex {
auto [stagingVertexData, stagingVertexIndex] = stagingVertex;
auto iControlPoint = meshPolygonVertices[polygon_vertex_index_];
Expand Down Expand Up @@ -223,6 +227,9 @@ fx::gltf::Primitive SceneConverter::_convertMeshAsPrimitive(
// Vertex color
for (auto [offset, element] : vertexLayout.colors) {
auto color = element(iControlPoint, polygon_vertex_index_);
if (!hasTransparentVertex && color.mAlpha != 1.0) {
hasTransparentVertex = true;
}
auto pColor = reinterpret_cast<NeutralVertexColorComponent *>(
stagingVertexData + offset);
FbxColorSpreader::spread(color, pColor);
Expand Down Expand Up @@ -321,6 +328,8 @@ fx::gltf::Primitive SceneConverter::_convertMeshAsPrimitive(
bulks, static_cast<std::uint32_t>(fbx_shapes_.size()), nUniqueVertices,
uniqueVerticesData.get(), vertexLayout.size, indices, mesh_name_);

material_usage_.hasTransparentVertex = hasTransparentVertex;

return glTFPrimitive;
}

Expand Down
46 changes: 42 additions & 4 deletions Core/Source/bee/Convert/SceneConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <bee/GLTFBuilder.h>
#include <bee/GLTFUtilities.h>
#include <bee/polyfills/filesystem.h>
#include <compare>
#include <fbxsdk.h>
#include <list>
#include <map>
Expand Down Expand Up @@ -176,6 +177,36 @@ class SceneConverter {
std::vector<double> values;
};

struct MaterialUsage {
bool hasTransparentVertex = false;

bool operator==(const MaterialUsage &that_) const {
return this->hasTransparentVertex == that_.hasTransparentVertex;
}
};

struct MaterialConvertKey {
public:
MaterialConvertKey(const fbxsdk::FbxSurfaceMaterial &material_,
const MaterialUsage &usage_)
: _material(material_.GetUniqueID()), _usage(usage_) {
}

bool operator==(const MaterialConvertKey &that_) const {
return this->_material == that_._material && this->_usage == that_._usage;
}

struct Hash {
std::size_t operator()(const MaterialConvertKey &key_) const noexcept {
return std::hash<fbxsdk::FbxUInt64>{}(key_._material);
}
};

private:
fbxsdk::FbxUInt64 _material;
MaterialUsage _usage;
};

GLTFBuilder &_glTFBuilder;
fbxsdk::FbxManager &_fbxManager;
fbxsdk::FbxGeometryConverter _fbxGeometryConverter;
Expand All @@ -187,6 +218,10 @@ class SceneConverter {
std::vector<fbxsdk::FbxNode *> _anncouncedfbxNodes;
std::unordered_map<GLTFSamplerKeys, GLTFBuilder::XXIndex, GLTFSamplerHash>
_uniqueSamplers;
std::unordered_map<MaterialConvertKey,
std::optional<GLTFBuilder::XXIndex>,
MaterialConvertKey::Hash>
_materialConvertCache;
std::unordered_map<fbxsdk::FbxUInt64, std::optional<GLTFBuilder::XXIndex>>
_textureMap;
std::unordered_map<const fbxsdk::FbxNode *, FbxNodeDumpMeta> _nodeDumpMetaMap;
Expand Down Expand Up @@ -242,7 +277,8 @@ class SceneConverter {
fbxsdk::FbxMatrix *vertex_transform_,
fbxsdk::FbxMatrix *normal_transform_,
std::span<fbxsdk::FbxShape *> fbx_shapes_,
std::span<MeshSkinData::InfluenceChannel> skin_influence_channels_);
std::span<MeshSkinData::InfluenceChannel> skin_influence_channels_,
MaterialUsage &material_usage_);

FbxMeshVertexLayout _getFbxMeshVertexLayout(
fbxsdk::FbxMesh &fbx_mesh_,
Expand Down Expand Up @@ -291,10 +327,12 @@ class SceneConverter {
const std::vector<fbxsdk::FbxMesh *> &fbx_meshes_);

std::optional<GLTFBuilder::XXIndex>
_convertMaterial(fbxsdk::FbxSurfaceMaterial &fbx_material_);
_convertMaterial(fbxsdk::FbxSurfaceMaterial &fbx_material_,
const MaterialUsage &material_usage_);

std::optional<GLTFBuilder::XXIndex>
_convertLambertMaterial(fbxsdk::FbxSurfaceLambert &fbx_material_);
_convertLambertMaterial(fbxsdk::FbxSurfaceLambert &fbx_material_,
const MaterialUsage &material_usage_);

std::optional<GLTFBuilder::XXIndex>
_convertTextureProperty(fbxsdk::FbxProperty &fbx_property_);
Expand Down Expand Up @@ -356,4 +394,4 @@ class SceneConverter {
fbxsdk::FbxNode &fbx_node_,
const AnimRange &anim_range_);
};
} // namespace bee
} // namespace bee

0 comments on commit d521acc

Please sign in to comment.