diff --git a/Core/Source/bee/Convert/SceneConverter.Material.cpp b/Core/Source/bee/Convert/SceneConverter.Material.cpp index 81b39c3..3165e33 100644 --- a/Core/Source/bee/Convert/SceneConverter.Material.cpp +++ b/Core/Source/bee/Convert/SceneConverter.Material.cpp @@ -28,14 +28,12 @@ void to_json(nlohmann::json &j_, const MaterialError &error_) { /// /// Material {} use texture for property \"{}\", which is not supported. /// -class ShallNotBeTextureError - : public MaterialError { +class ShallNotBeTextureError : public MaterialError { 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_) { } @@ -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 &>( - error_)); + static_cast &>(error_)); j_["property"] = forceTreatAsPlain(error_.property()); } @@ -60,23 +56,34 @@ template static T_ getMetalnessFromSpecular(const T_ *specular_) { } std::optional -SceneConverter::_convertMaterial(fbxsdk::FbxSurfaceMaterial &fbx_material_) { - if (fbx_material_.Is()) { - return _convertLambertMaterial( - static_cast(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 { + if (fbx_material_.Is()) { + return _convertLambertMaterial( + static_cast(fbx_material_), + material_usage_); + } else { + return {}; + } + }(); + r = _materialConvertCache.emplace(convertKey, glTFMaterialIndex).first; } + return r->second; } std::optional 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; @@ -180,6 +187,12 @@ std::optional SceneConverter::_convertLambertMaterial( getRoughness(static_cast(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; diff --git a/Core/Source/bee/Convert/SceneConverter.Mesh.cpp b/Core/Source/bee/Convert/SceneConverter.Mesh.cpp index b5fabd4..e5eb725 100644 --- a/Core/Source/bee/Convert/SceneConverter.Mesh.cpp +++ b/Core/Source/bee/Convert/SceneConverter.Mesh.cpp @@ -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; } } @@ -159,7 +161,8 @@ fx::gltf::Primitive SceneConverter::_convertMeshAsPrimitive( fbxsdk::FbxMatrix *vertex_transform_, fbxsdk::FbxMatrix *normal_transform_, std::span fbx_shapes_, - std::span skin_influence_channels_) { + std::span skin_influence_channels_, + MaterialUsage &material_usage_) { auto vertexLayout = _getFbxMeshVertexLayout(fbx_mesh_, fbx_shapes_, skin_influence_channels_); const auto vertexSize = vertexLayout.size; @@ -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_]; @@ -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( stagingVertexData + offset); FbxColorSpreader::spread(color, pColor); @@ -321,6 +328,8 @@ fx::gltf::Primitive SceneConverter::_convertMeshAsPrimitive( bulks, static_cast(fbx_shapes_.size()), nUniqueVertices, uniqueVerticesData.get(), vertexLayout.size, indices, mesh_name_); + material_usage_.hasTransparentVertex = hasTransparentVertex; + return glTFPrimitive; } diff --git a/Core/Source/bee/Convert/SceneConverter.h b/Core/Source/bee/Convert/SceneConverter.h index f5b52d0..88bf333 100644 --- a/Core/Source/bee/Convert/SceneConverter.h +++ b/Core/Source/bee/Convert/SceneConverter.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -176,6 +177,36 @@ class SceneConverter { std::vector 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{}(key_._material); + } + }; + + private: + fbxsdk::FbxUInt64 _material; + MaterialUsage _usage; + }; + GLTFBuilder &_glTFBuilder; fbxsdk::FbxManager &_fbxManager; fbxsdk::FbxGeometryConverter _fbxGeometryConverter; @@ -187,6 +218,10 @@ class SceneConverter { std::vector _anncouncedfbxNodes; std::unordered_map _uniqueSamplers; + std::unordered_map, + MaterialConvertKey::Hash> + _materialConvertCache; std::unordered_map> _textureMap; std::unordered_map _nodeDumpMetaMap; @@ -242,7 +277,8 @@ class SceneConverter { fbxsdk::FbxMatrix *vertex_transform_, fbxsdk::FbxMatrix *normal_transform_, std::span fbx_shapes_, - std::span skin_influence_channels_); + std::span skin_influence_channels_, + MaterialUsage &material_usage_); FbxMeshVertexLayout _getFbxMeshVertexLayout( fbxsdk::FbxMesh &fbx_mesh_, @@ -291,10 +327,12 @@ class SceneConverter { const std::vector &fbx_meshes_); std::optional - _convertMaterial(fbxsdk::FbxSurfaceMaterial &fbx_material_); + _convertMaterial(fbxsdk::FbxSurfaceMaterial &fbx_material_, + const MaterialUsage &material_usage_); std::optional - _convertLambertMaterial(fbxsdk::FbxSurfaceLambert &fbx_material_); + _convertLambertMaterial(fbxsdk::FbxSurfaceLambert &fbx_material_, + const MaterialUsage &material_usage_); std::optional _convertTextureProperty(fbxsdk::FbxProperty &fbx_property_); @@ -356,4 +394,4 @@ class SceneConverter { fbxsdk::FbxNode &fbx_node_, const AnimRange &anim_range_); }; -} // namespace bee \ No newline at end of file +} // namespace bee