diff --git a/src/fbx/materials/3dsMaxPhysicalMaterial.cpp b/src/fbx/materials/3dsMaxPhysicalMaterial.cpp index 86b0913..5f52239 100644 --- a/src/fbx/materials/3dsMaxPhysicalMaterial.cpp +++ b/src/fbx/materials/3dsMaxPhysicalMaterial.cpp @@ -10,11 +10,14 @@ #include "RoughnessMetallicMaterials.hpp" std::unique_ptr Fbx3dsMaxPhysicalMaterialResolver::resolve() const { - const FbxProperty topProp = fbxMaterial->FindProperty("3dsMax"); + const FbxProperty topProp = fbxMaterial->FindProperty("3dsMax", false); if (topProp.GetPropertyDataType() != FbxCompoundDT) { return nullptr; } - const FbxProperty props = fbxMaterial->FindProperty("Parameters"); + const FbxProperty props = topProp.Find("Parameters", false); + if (!props.IsValid()) { + return nullptr; + } FbxString shadingModel = fbxMaterial->ShadingModel.Get(); if (!shadingModel.IsEmpty() && shadingModel != "unknown") { @@ -26,29 +29,21 @@ std::unique_ptr Fbx3dsMaxPhysicalMaterialResolver::reso auto getTex = [&](std::string propName) -> const FbxFileTexture* { const FbxFileTexture* ptr = nullptr; - - const FbxProperty useProp = props.FindHierarchical((propName + "_map_on").c_str()); - if (useProp.IsValid() && useProp.Get()) { - const FbxProperty texProp = useProp.FindHierarchical((propName + "_map").c_str()); - if (texProp.IsValid()) { - ptr = texProp.GetSrcObject(); - if (ptr != nullptr && textureLocations.find(ptr) == textureLocations.end()) { - ptr = nullptr; - } + const FbxProperty texProp = props.Find((propName + "_map").c_str(), false); + if (texProp.IsValid()) { + const FbxProperty useProp = props.Find((propName + "_map_on").c_str(), false); + if (useProp.IsValid() && !useProp.Get()) { + // skip this texture if the _on property exists *and* is explicitly false + return nullptr; + } + ptr = texProp.GetSrcObject(); + if (ptr != nullptr && textureLocations.find(ptr) == textureLocations.end()) { + ptr = nullptr; } - } else if (verboseOutput && useProp.IsValid()) { - fmt::printf( - "Note: property '%s' of 3dsMax Physical material '%s' exists, but is flagged as 'off'.\n", - propName, - fbxMaterial->GetName()); } return ptr; }; - int materialMode = getValue(props, "material_mode", 0); - fmt::printf("Note: 3dsMax Physical material has material_mode = %d.\n", materialMode); - - // baseWeight && baseColor FbxDouble baseWeight = getValue(props, "base_weight", 1.0); const auto* baseWeightMap = getTex("base_weight"); FbxDouble4 baseCol = getValue(props, "base_color", FbxDouble4(0.5, 0.5, 0.5, 1.0)); @@ -58,49 +53,97 @@ std::unique_ptr Fbx3dsMaxPhysicalMaterialResolver::reso const auto* emissiveWeightMap = getTex("emission"); FbxDouble4 emissiveColor = getValue(props, "emit_color", FbxDouble4(1, 1, 1, 1)); const auto* emissiveColorMap = getTex("emit_color"); - // TODO: emit_luminance, emit_kelvin? - // roughness & metalness: supported double roughness = getValue(props, "roughness", 0.0); const auto* roughnessMap = getTex("roughness"); double metalness = getValue(props, "metalness", 0.0); const auto* metalnessMap = getTex("metalness"); - // TODO: does invertRoughness affect roughness_map too? + // TODO: we need this to affect roughness map, too. bool invertRoughness = getValue(props, "inv_roughness", false); if (invertRoughness) { roughness = 1.0f - roughness; } - // TODO: attempt to bake transparency > 0.0f into the alpha of baseColour? - // double transparency = getValue(props, "transparency", 0.0); - // const auto* transparencyMap = getTex("transparency"); - - // SSS: not supported - // double scattering = getValue(props, "scattering", 0.0); - // const auto* scatteringMap = getTex("scattering"); - - // reflectivity: not supported - // double reflectivityWeight = getValue(props, "reflectivity", 1.); - // const auto* reflectivityWeightMap = getTex("reflectivity"); - // FbxDouble4 reflectivityColor = getValue(props, "refl_color", FbxDouble4(1, 1, 1, 1)); - // const auto* reflectivityColorMap = getTex("refl_color"); - - // coatings: not supported - // double coating = getValue(props, "coating", 0.0); - - // diffuse roughness: not supported - // double diffuseRoughness = getValue(props, "diff_roughness", 0.); - - // explicit brdf curve control: not supported - // bool isBrdfMode = getValue(props, "brdf_mode", false); - - // anisotrophy: not supported - // double anisotropy = getValue(props, "anisotropy", 1.0); - - // TODO: how the heck do we combine these to generate a normal map? + // TODO: turn this into a normal map through simple numerial differentiation const auto* bumpMap = getTex("bump"); - // const auto* displacementMap = getTex("displacement"); + + std::string unsupported; + const auto addUnsupported = [&](const std::string bit) { + if (!unsupported.empty()) { + unsupported += ", "; + } + unsupported += bit; + }; + + // TODO: bake transparency > 0.0f into the alpha of baseColor? + double transparency = getValue(props, "transparency", 0.0); + const auto* transparencyMap = getTex("transparency"); + if (transparency != 0.0 || transparencyMap != nullptr) { + addUnsupported("transparency"); + } + + // TODO: if/when we bake transparency, we'll need this + // double transparencyDepth = getValue(props, "trans_depth", 0.0); + // if (transparencyDepth != 0.0) { + // addUnsupported("transparency depth"); + // } + // double transparencyColor = getValue(props, "trans_color", 0.0); + // const auto* transparencyColorMap = getTex("trans_color"); + // if (transparencyColor != 0.0 || transparencyColorMap != nullptr) { + // addUnsupported("transparency color"); + // } + // double thinWalledTransparency = getValue(props, "thin_walled", false); + // if (thinWalledTransparency) { + // addUnsupported("thin-walled transparency"); + // } + + const auto* displacementMap = getTex("displacement"); + if (displacementMap != nullptr) { + addUnsupported("displacement"); + } + + double reflectivityWeight = getValue(props, "reflectivity", 1.0); + const auto* reflectivityWeightMap = getTex("reflectivity"); + FbxDouble4 reflectivityColor = getValue(props, "refl_color", FbxDouble4(1, 1, 1, 1)); + const auto* reflectivityColorMap = getTex("refl_color"); + if (reflectivityWeight != 1.0 || reflectivityWeightMap != nullptr || + reflectivityColor != FbxDouble4(1, 1, 1, 1) || reflectivityColorMap != nullptr) { + addUnsupported("reflectivity"); + } + + double scattering = getValue(props, "scattering", 0.0); + const auto* scatteringMap = getTex("scattering"); + if (scattering != 0.0 || scatteringMap != nullptr) { + addUnsupported("sub-surface scattering"); + } + + double coating = getValue(props, "coating", 0.0); + if (coating != 0.0) { + addUnsupported("coating"); + } + + double diffuseRoughness = getValue(props, "diff_roughness", 0.0); + if (diffuseRoughness != 0.0) { + addUnsupported("diffuse roughness"); + } + + bool isBrdfMode = getValue(props, "brdf_mode", false); + if (isBrdfMode) { + addUnsupported("advanced reflectance custom curve"); + } + + double anisotropy = getValue(props, "anisotropy", 1.0); + if (anisotropy != 1.0) { + addUnsupported("anisotropy"); + } + + if (verboseOutput && !unsupported.empty()) { + fmt::printf( + "Warning: 3dsMax Physical Material %s uses features glTF cannot express:\n %s\n", + fbxMaterial->GetName(), + unsupported); + } std::unique_ptr res(new FbxRoughMetMaterialInfo( fbxMaterial->GetName(), @@ -115,8 +158,6 @@ std::unique_ptr Fbx3dsMaxPhysicalMaterialResolver::reso res->texMetallic = metalnessMap; res->texRoughness = roughnessMap; - res->texNormal = bumpMap; // TODO LOL NO NONO - res->emissive = emissiveColor; res->emissiveIntensity = emissiveWeight; res->texEmissive = emissiveColorMap;