Merge remote-tracking branch 'upstream/master' into feat/mocha-tests

This commit is contained in:
Par Winzell 2019-01-25 14:42:08 -08:00
commit d686d8eca7
17 changed files with 182 additions and 542 deletions

View File

@ -154,20 +154,20 @@ endif()
set(LIB_SOURCE_FILES
src/FBX2glTF.h
src/fbx/materials/3dsMaxPhysicalMaterial.cpp
src/fbx/materials/FbxMaterials.cpp
src/fbx/materials/FbxMaterials.hpp
src/fbx/materials/RoughnessMetallicMaterials.hpp
src/fbx/materials/StingrayPBSMaterial.cpp
src/fbx/materials/TraditionalMaterials.cpp
src/fbx/materials/TraditionalMaterials.hpp
src/fbx/Fbx2Raw.cpp
src/fbx/Fbx2Raw.hpp
src/fbx/FbxBlendShapesAccess.cpp
src/fbx/FbxBlendShapesAccess.hpp
src/fbx/FbxLayerElementAccess.hpp
src/fbx/FbxMaterialInfo.hpp
src/fbx/FbxMaterialsAccess.cpp
src/fbx/FbxMaterialsAccess.hpp
src/fbx/FbxRoughMetMaterialInfo.cpp
src/fbx/FbxRoughMetMaterialInfo.hpp
src/fbx/FbxSkinningAccess.cpp
src/fbx/FbxSkinningAccess.hpp
src/fbx/FbxTraditionalMaterialInfo.cpp
src/fbx/FbxTraditionalMaterialInfo.hpp
src/gltf/Raw2Gltf.cpp
src/gltf/Raw2Gltf.hpp
src/gltf/GltfModel.cpp

View File

@ -103,33 +103,10 @@ int main(int argc, char* argv[]) {
"When to compute vertex normals from mesh geometry.")
->type_name("(never|broken|missing|always)");
std::vector<std::function<Vec2f(Vec2f)>> texturesTransforms;
app.add_flag_function(
"--flip-u",
[&](size_t count) {
if (count > 0) {
texturesTransforms.emplace_back([](Vec2f uv) { return Vec2f(1.0f - uv[0], uv[1]); });
if (verboseOutput) {
fmt::printf("Flipping texture coordinates in the 'U' dimension.\n");
}
}
},
"Flip all U texture coordinates.");
app.add_flag("--no-flip-u", "Don't flip U texture coordinates.")->excludes("--flip-u");
app.add_flag_function(
"--no-flip-v",
[&](size_t count) {
if (count > 0) {
texturesTransforms.emplace_back([](Vec2f uv) { return Vec2f(uv[0], 1.0f - uv[1]); });
if (verboseOutput) {
fmt::printf("NOT flipping texture coordinates in the 'V' dimension.\n");
}
}
},
"Flip all V texture coordinates.");
app.add_flag("--flip-v", "Don't flip U texture coordinates.")->excludes("--no-flip-v");
const auto opt_flip_u = app.add_flag("--flip-u", "Flip all U texture coordinates.");
const auto opt_no_flip_u = app.add_flag("--no-flip-u", "Don't flip U texture coordinates.");
const auto opt_flip_v = app.add_flag("--flip-v", "Flip all V texture coordinates.");
const auto opt_no_flip_v = app.add_flag("--no-flip-v", "Don't flip V texture coordinates.");
app.add_flag(
"--pbr-metallic-rougnness",
@ -250,6 +227,32 @@ int main(int argc, char* argv[]) {
CLI11_PARSE(app, argc, argv);
bool do_flip_u = false;
bool do_flip_v = true;
// somewhat tedious way to resolve --flag vs --no-flag in order provided
for (const auto opt : app.parse_order()) {
do_flip_u = (do_flip_u || (opt == opt_flip_u)) && (opt != opt_no_flip_u);
do_flip_v = (do_flip_v || (opt == opt_flip_v)) && (opt != opt_no_flip_v);
}
std::vector<std::function<Vec2f(Vec2f)>> texturesTransforms;
if (do_flip_u || do_flip_v) {
if (do_flip_u && do_flip_v) {
texturesTransforms.emplace_back([](Vec2f uv) { return Vec2f(1.0 - uv[0], 1.0 - uv[1]); });
} else if (do_flip_u) {
texturesTransforms.emplace_back([](Vec2f uv) { return Vec2f(1.0 - uv[0], uv[1]); });
} else {
texturesTransforms.emplace_back([](Vec2f uv) { return Vec2f(uv[0], 1.0 - uv[1]); });
}
}
if (verboseOutput) {
if (do_flip_u) {
fmt::printf("Flipping texture coordinates in the 'U' dimension.\n");
}
if (!do_flip_v) {
fmt::printf("NOT flipping texture coordinates in the 'V' dimension.\n");
}
}
if (inputPath.empty()) {
fmt::printf("You must supply a FBX file to convert.\n");
exit(1);

View File

@ -29,8 +29,9 @@
#include "FbxBlendShapesAccess.hpp"
#include "FbxLayerElementAccess.hpp"
#include "FbxMaterialsAccess.hpp"
#include "FbxSkinningAccess.hpp"
#include "materials/RoughnessMetallicMaterials.hpp"
#include "materials/TraditionalMaterials.hpp"
float scaleFactor;
@ -236,7 +237,7 @@ static void ReadMesh(
FbxRoughMetMaterialInfo* fbxMatInfo =
static_cast<FbxRoughMetMaterialInfo*>(fbxMaterial.get());
maybeAddTexture(fbxMatInfo->texColor, RAW_TEXTURE_USAGE_ALBEDO);
maybeAddTexture(fbxMatInfo->texBaseColor, RAW_TEXTURE_USAGE_ALBEDO);
maybeAddTexture(fbxMatInfo->texNormal, RAW_TEXTURE_USAGE_NORMAL);
maybeAddTexture(fbxMatInfo->texEmissive, RAW_TEXTURE_USAGE_EMISSIVE);
maybeAddTexture(fbxMatInfo->texRoughness, RAW_TEXTURE_USAGE_ROUGHNESS);
@ -244,11 +245,12 @@ static void ReadMesh(
maybeAddTexture(fbxMatInfo->texAmbientOcclusion, RAW_TEXTURE_USAGE_OCCLUSION);
rawMatProps.reset(new RawMetRoughMatProps(
RAW_SHADING_MODEL_PBR_MET_ROUGH,
toVec4f(fbxMatInfo->colBase),
toVec3f(fbxMatInfo->colEmissive),
toVec4f(fbxMatInfo->baseColor),
toVec3f(fbxMatInfo->emissive),
fbxMatInfo->emissiveIntensity,
fbxMatInfo->metallic,
fbxMatInfo->roughness));
fbxMatInfo->roughness,
fbxMatInfo->invertRoughnessMap));
} else {
FbxTraditionalMaterialInfo* fbxMatInfo =
static_cast<FbxTraditionalMaterialInfo*>(fbxMaterial.get());

View File

@ -1,21 +0,0 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#pragma once
#include "FBX2glTF.h"
class FbxMaterialInfo {
public:
FbxMaterialInfo(const FbxString& name, const FbxString& shadingModel)
: name(name), shadingModel(shadingModel) {}
const FbxString name;
const FbxString shadingModel;
};

View File

@ -1,104 +0,0 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#include "FbxMaterialsAccess.hpp"
#include "Fbx2Raw.hpp"
FbxMaterialsAccess::FbxMaterialsAccess(
const FbxMesh* pMesh,
const std::map<const FbxTexture*, FbxString>& textureLocations)
: mappingMode(FbxGeometryElement::eNone), mesh(nullptr), indices(nullptr) {
if (pMesh->GetElementMaterialCount() <= 0) {
return;
}
const FbxGeometryElement::EMappingMode materialMappingMode =
pMesh->GetElementMaterial()->GetMappingMode();
if (materialMappingMode != FbxGeometryElement::eByPolygon &&
materialMappingMode != FbxGeometryElement::eAllSame) {
return;
}
const FbxGeometryElement::EReferenceMode materialReferenceMode =
pMesh->GetElementMaterial()->GetReferenceMode();
if (materialReferenceMode != FbxGeometryElement::eIndexToDirect) {
return;
}
mappingMode = materialMappingMode;
mesh = pMesh;
indices = &pMesh->GetElementMaterial()->GetIndexArray();
for (int ii = 0; ii < indices->GetCount(); ii++) {
int materialNum = indices->GetAt(ii);
if (materialNum < 0) {
continue;
}
FbxSurfaceMaterial* surfaceMaterial =
mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum);
if (materialNum >= summaries.size()) {
summaries.resize(materialNum + 1);
}
auto summary = summaries[materialNum];
if (summary == nullptr) {
summary = summaries[materialNum] = GetMaterialInfo(surfaceMaterial, textureLocations);
}
if (materialNum >= userProperties.size()) {
userProperties.resize(materialNum + 1);
}
if (userProperties[materialNum].empty()) {
FbxProperty objectProperty = surfaceMaterial->GetFirstProperty();
while (objectProperty.IsValid()) {
if (objectProperty.GetFlag(FbxPropertyFlags::eUserDefined)) {
userProperties[materialNum].push_back(TranscribeProperty(objectProperty).dump());
}
objectProperty = surfaceMaterial->GetNextProperty(objectProperty);
}
}
}
}
const std::shared_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterial(
const int polygonIndex) const {
if (mappingMode != FbxGeometryElement::eNone) {
const int materialNum =
indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
if (materialNum < 0) {
return nullptr;
}
return summaries.at((unsigned long)materialNum);
}
return nullptr;
}
const std::vector<std::string> FbxMaterialsAccess::GetUserProperties(const int polygonIndex) const {
if (mappingMode != FbxGeometryElement::eNone) {
const int materialNum =
indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
if (materialNum < 0) {
return std::vector<std::string>();
}
return userProperties.at((unsigned long)materialNum);
}
return std::vector<std::string>();
}
std::unique_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterialInfo(
FbxSurfaceMaterial* material,
const std::map<const FbxTexture*, FbxString>& textureLocations) {
std::unique_ptr<FbxMaterialInfo> res;
res = FbxRoughMetMaterialInfo::From(material, textureLocations);
if (!res) {
res = FbxTraditionalMaterialInfo::From(material, textureLocations);
}
return res;
}

View File

@ -1,37 +0,0 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#pragma once
#include "Fbx2Raw.hpp"
#include "FbxMaterialInfo.hpp"
#include "FbxRoughMetMaterialInfo.hpp"
#include "FbxTraditionalMaterialInfo.hpp"
class FbxMaterialsAccess {
public:
FbxMaterialsAccess(
const FbxMesh* pMesh,
const std::map<const FbxTexture*, FbxString>& textureLocations);
const std::shared_ptr<FbxMaterialInfo> GetMaterial(const int polygonIndex) const;
const std::vector<std::string> GetUserProperties(const int polygonIndex) const;
std::unique_ptr<FbxMaterialInfo> GetMaterialInfo(
FbxSurfaceMaterial* material,
const std::map<const FbxTexture*, FbxString>& textureLocations);
private:
FbxGeometryElement::EMappingMode mappingMode;
std::vector<std::shared_ptr<FbxMaterialInfo>> summaries{};
std::vector<std::vector<std::string>> userProperties;
const FbxMesh* mesh;
const FbxLayerElementArrayTemplate<int>* indices;
};

View File

@ -1,73 +0,0 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#include "FbxRoughMetMaterialInfo.hpp"
std::unique_ptr<FbxRoughMetMaterialInfo> FbxRoughMetMaterialInfo::From(
FbxSurfaceMaterial* fbxMaterial,
const std::map<const FbxTexture*, FbxString>& textureLocations) {
std::unique_ptr<FbxRoughMetMaterialInfo> res(
new FbxRoughMetMaterialInfo(fbxMaterial->GetName(), FBX_SHADER_METROUGH));
const FbxProperty mayaProp = fbxMaterial->FindProperty("Maya");
if (mayaProp.GetPropertyDataType() != FbxCompoundDT) {
return nullptr;
}
if (!fbxMaterial->ShadingModel.Get().IsEmpty()) {
::fmt::printf(
"Warning: Material %s has surprising shading model: %s\n",
fbxMaterial->GetName(),
fbxMaterial->ShadingModel.Get());
}
auto getTex = [&](std::string propName) {
const FbxFileTexture* ptr = nullptr;
const FbxProperty useProp = mayaProp.FindHierarchical(("use_" + propName + "_map").c_str());
if (useProp.IsValid() && useProp.Get<bool>()) {
const FbxProperty texProp = mayaProp.FindHierarchical(("TEX_" + propName + "_map").c_str());
if (texProp.IsValid()) {
ptr = texProp.GetSrcObject<FbxFileTexture>();
if (ptr != nullptr && textureLocations.find(ptr) == textureLocations.end()) {
ptr = nullptr;
}
}
} else if (verboseOutput && useProp.IsValid()) {
fmt::printf(
"Note: Property '%s' of material '%s' exists, but is flagged as 'do not use'.\n",
propName,
fbxMaterial->GetName());
}
return ptr;
};
auto getVec = [&](std::string propName) -> FbxDouble3 {
const FbxProperty vecProp = mayaProp.FindHierarchical(propName.c_str());
return vecProp.IsValid() ? vecProp.Get<FbxDouble3>() : FbxDouble3(1, 1, 1);
};
auto getVal = [&](std::string propName) -> FbxDouble {
const FbxProperty vecProp = mayaProp.FindHierarchical(propName.c_str());
return vecProp.IsValid() ? vecProp.Get<FbxDouble>() : 0;
};
res->texNormal = getTex("normal");
res->texColor = getTex("color");
res->colBase = getVec("base_color");
res->texAmbientOcclusion = getTex("ao");
res->texEmissive = getTex("emissive");
res->colEmissive = getVec("emissive");
res->emissiveIntensity = getVal("emissive_intensity");
res->texMetallic = getTex("metallic");
res->metallic = getVal("metallic");
res->texRoughness = getTex("roughness");
res->roughness = getVal("roughness");
return res;
}

View File

@ -1,41 +0,0 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#include <algorithm>
#include <fstream>
#include <map>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
#include "FbxMaterialInfo.hpp"
struct FbxRoughMetMaterialInfo : FbxMaterialInfo {
static constexpr const char* FBX_SHADER_METROUGH = "MetallicRoughness";
static std::unique_ptr<FbxRoughMetMaterialInfo> From(
FbxSurfaceMaterial* fbxMaterial,
const std::map<const FbxTexture*, FbxString>& textureLocations);
FbxRoughMetMaterialInfo(const FbxString& name, const FbxString& shadingModel)
: FbxMaterialInfo(name, shadingModel) {}
const FbxFileTexture* texColor{};
FbxVector4 colBase{};
const FbxFileTexture* texNormal{};
const FbxFileTexture* texMetallic{};
FbxDouble metallic{};
const FbxFileTexture* texRoughness{};
FbxDouble roughness{};
const FbxFileTexture* texEmissive{};
FbxVector4 colEmissive{};
FbxDouble emissiveIntensity{};
const FbxFileTexture* texAmbientOcclusion{};
};

View File

@ -1,137 +0,0 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#include "FbxTraditionalMaterialInfo.hpp"
std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialInfo::From(
FbxSurfaceMaterial* fbxMaterial,
const std::map<const FbxTexture*, FbxString>& textureLocations) {
auto getSurfaceScalar = [&](const char* propName) -> std::tuple<FbxDouble, FbxFileTexture*> {
const FbxProperty prop = fbxMaterial->FindProperty(propName);
FbxDouble val(0);
FbxFileTexture* tex = prop.GetSrcObject<FbxFileTexture>();
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
tex = nullptr;
}
if (tex == nullptr && prop.IsValid()) {
val = prop.Get<FbxDouble>();
}
return std::make_tuple(val, tex);
};
auto getSurfaceVector = [&](const char* propName) -> std::tuple<FbxDouble3, FbxFileTexture*> {
const FbxProperty prop = fbxMaterial->FindProperty(propName);
FbxDouble3 val(1, 1, 1);
FbxFileTexture* tex = prop.GetSrcObject<FbxFileTexture>();
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
tex = nullptr;
}
if (tex == nullptr && prop.IsValid()) {
val = prop.Get<FbxDouble3>();
}
return std::make_tuple(val, tex);
};
auto getSurfaceValues =
[&](const char* colName,
const char* facName) -> std::tuple<FbxVector4, FbxFileTexture*, FbxFileTexture*> {
const FbxProperty colProp = fbxMaterial->FindProperty(colName);
const FbxProperty facProp = fbxMaterial->FindProperty(facName);
FbxDouble3 colorVal(1, 1, 1);
FbxDouble factorVal(1);
FbxFileTexture* colTex = colProp.GetSrcObject<FbxFileTexture>();
if (colTex != nullptr && textureLocations.find(colTex) == textureLocations.end()) {
colTex = nullptr;
}
if (colTex == nullptr && colProp.IsValid()) {
colorVal = colProp.Get<FbxDouble3>();
}
FbxFileTexture* facTex = facProp.GetSrcObject<FbxFileTexture>();
if (facTex != nullptr && textureLocations.find(facTex) == textureLocations.end()) {
facTex = nullptr;
}
if (facTex == nullptr && facProp.IsValid()) {
factorVal = facProp.Get<FbxDouble>();
}
auto val = FbxVector4(
colorVal[0] * factorVal, colorVal[1] * factorVal, colorVal[2] * factorVal, factorVal);
return std::make_tuple(val, colTex, facTex);
};
std::string name = fbxMaterial->GetName();
std::unique_ptr<FbxTraditionalMaterialInfo> res(
new FbxTraditionalMaterialInfo(name.c_str(), fbxMaterial->ShadingModel.Get()));
// four properties are on the same structure and follow the same rules
auto handleBasicProperty = [&](const char* colName,
const char* facName) -> std::tuple<FbxVector4, FbxFileTexture*> {
FbxFileTexture *colTex, *facTex;
FbxVector4 vec;
std::tie(vec, colTex, facTex) = getSurfaceValues(colName, facName);
if (colTex) {
if (facTex) {
fmt::printf(
"Warning: Mat [%s]: Can't handle both %s and %s textures; discarding %s.\n",
name,
colName,
facName,
facName);
}
return std::make_tuple(vec, colTex);
}
return std::make_tuple(vec, facTex);
};
std::tie(res->colAmbient, res->texAmbient) =
handleBasicProperty(FbxSurfaceMaterial::sAmbient, FbxSurfaceMaterial::sAmbientFactor);
std::tie(res->colSpecular, res->texSpecular) =
handleBasicProperty(FbxSurfaceMaterial::sSpecular, FbxSurfaceMaterial::sSpecularFactor);
std::tie(res->colDiffuse, res->texDiffuse) =
handleBasicProperty(FbxSurfaceMaterial::sDiffuse, FbxSurfaceMaterial::sDiffuseFactor);
std::tie(res->colEmissive, res->texEmissive) =
handleBasicProperty(FbxSurfaceMaterial::sEmissive, FbxSurfaceMaterial::sEmissiveFactor);
// the normal map can only ever be a map, ignore everything else
tie(std::ignore, res->texNormal) = getSurfaceVector(FbxSurfaceMaterial::sNormalMap);
// shininess can be a map or a factor; afaict the map is always 'ShininessExponent' and the
// value is always found in 'Shininess' but only sometimes in 'ShininessExponent'.
tie(std::ignore, res->texShininess) = getSurfaceScalar("ShininessExponent");
tie(res->shininess, std::ignore) = getSurfaceScalar("Shininess");
// for transparency we just want a constant vector value;
FbxVector4 transparency;
// extract any existing textures only so we can warn that we're throwing them away
FbxFileTexture *colTex, *facTex;
std::tie(transparency, colTex, facTex) = getSurfaceValues(
FbxSurfaceMaterial::sTransparentColor, FbxSurfaceMaterial::sTransparencyFactor);
if (colTex) {
fmt::printf(
"Warning: Mat [%s]: Can't handle texture for %s; discarding.\n",
name,
FbxSurfaceMaterial::sTransparentColor);
}
if (facTex) {
fmt::printf(
"Warning: Mat [%s]: Can't handle texture for %s; discarding.\n",
name,
FbxSurfaceMaterial::sTransparencyFactor);
}
// FBX color is RGB, so we calculate the A channel as the average of the FBX transparency color
// vector
res->colDiffuse[3] = 1.0 - (transparency[0] + transparency[1] + transparency[2]) / 3.0;
return res;
}

View File

@ -1,43 +0,0 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#include <algorithm>
#include <fstream>
#include <map>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
#include "FbxMaterialInfo.hpp"
struct FbxTraditionalMaterialInfo : FbxMaterialInfo {
static constexpr const char* FBX_SHADER_LAMBERT = "Lambert";
static constexpr const char* FBX_SHADER_BLINN = "Blinn";
static constexpr const char* FBX_SHADER_PHONG = "Phong";
FbxTraditionalMaterialInfo(const FbxString& name, const FbxString& shadingModel)
: FbxMaterialInfo(name, shadingModel) {}
FbxFileTexture* texAmbient{};
FbxVector4 colAmbient{};
FbxFileTexture* texSpecular{};
FbxVector4 colSpecular{};
FbxFileTexture* texDiffuse{};
FbxVector4 colDiffuse{};
FbxFileTexture* texEmissive{};
FbxVector4 colEmissive{};
FbxFileTexture* texNormal{};
FbxFileTexture* texShininess{};
FbxDouble shininess{};
static std::unique_ptr<FbxTraditionalMaterialInfo> From(
FbxSurfaceMaterial* fbxMaterial,
const std::map<const FbxTexture*, FbxString>& textureLocations);
};

View File

@ -10,11 +10,14 @@
#include "RoughnessMetallicMaterials.hpp"
std::unique_ptr<FbxRoughMetMaterialInfo> 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<FbxRoughMetMaterialInfo> 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<bool>()) {
const FbxProperty texProp = useProp.FindHierarchical((propName + "_map").c_str());
if (texProp.IsValid()) {
ptr = texProp.GetSrcObject<FbxFileTexture>();
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<FbxBool>()) {
// skip this texture if the _on property exists *and* is explicitly false
return nullptr;
}
ptr = texProp.GetSrcObject<FbxFileTexture>();
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,100 @@ std::unique_ptr<FbxRoughMetMaterialInfo> 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?
std::string unsupported;
const auto addUnsupported = [&](const std::string bit) {
if (!unsupported.empty()) {
unsupported += ", ";
}
unsupported += bit;
};
// TODO: turn this into a normal map through simple numerial differentiation
const auto* bumpMap = getTex("bump");
if (bumpMap != nullptr) {
addUnsupported("bump map");
}
// 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");
}
// SSS: not supported
double scattering = getValue(props, "scattering", 0.0);
const auto* scatteringMap = getTex("scattering");
// 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");
// }
// reflectivity: not supported
double reflectivityWeight = getValue(props, "reflectivity", 1.);
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");
}
// coatings: not supported
double coating = getValue(props, "coating", 0.0);
if (coating != 0.0) {
addUnsupported("coating");
}
// diffuse roughness: not supported
double diffuseRoughness = getValue(props, "diff_roughness", 0.);
double diffuseRoughness = getValue(props, "diff_roughness", 0.0);
if (diffuseRoughness != 0.0) {
addUnsupported("diffuse roughness");
}
// explicit brdf curve control: not supported
bool isBrdfMode = getValue(props, "brdf_mode", false);
if (isBrdfMode) {
addUnsupported("advanced reflectance custom curve");
}
// anisotrophy: not supported
double anisotropy = getValue(props, "anisotropy", 1.0);
if (anisotropy != 1.0) {
addUnsupported("anisotropy");
}
// TODO: how the heck do we combine these to generate a normal map?
const auto* bumpMap = getTex("bump");
const auto* displacementMap = getTex("displacement");
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<FbxRoughMetMaterialInfo> res(new FbxRoughMetMaterialInfo(
fbxMaterial->GetName(),
@ -114,8 +160,7 @@ std::unique_ptr<FbxRoughMetMaterialInfo> Fbx3dsMaxPhysicalMaterialResolver::reso
res->texMetallic = metalnessMap;
res->texRoughness = roughnessMap;
res->texNormal = bumpMap; // TODO LOL NO NONO
res->invertRoughnessMap = invertRoughness;
res->emissive = emissiveColor;
res->emissiveIntensity = emissiveWeight;

View File

@ -7,6 +7,8 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/
#include "fbx/Fbx2Raw.hpp"
#include "FbxMaterials.hpp"
#include "RoughnessMetallicMaterials.hpp"
#include "TraditionalMaterials.hpp"
@ -41,13 +43,29 @@ FbxMaterialsAccess::FbxMaterialsAccess(
if (materialNum < 0) {
continue;
}
FbxSurfaceMaterial* surfaceMaterial =
mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum);
if (materialNum >= summaries.size()) {
summaries.resize(materialNum + 1);
}
auto summary = summaries[materialNum];
if (summary == nullptr) {
summary = summaries[materialNum] = GetMaterialInfo(
mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum), textureLocations);
summary = summaries[materialNum] = GetMaterialInfo(surfaceMaterial, textureLocations);
}
if (materialNum >= userProperties.size()) {
userProperties.resize(materialNum + 1);
}
if (userProperties[materialNum].empty()) {
FbxProperty objectProperty = surfaceMaterial->GetFirstProperty();
while (objectProperty.IsValid()) {
if (objectProperty.GetFlag(FbxPropertyFlags::eUserDefined)) {
userProperties[materialNum].push_back(TranscribeProperty(objectProperty).dump());
}
objectProperty = surfaceMaterial->GetNextProperty(objectProperty);
}
}
}
}
@ -65,6 +83,18 @@ const std::shared_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterial(
return nullptr;
}
const std::vector<std::string> FbxMaterialsAccess::GetUserProperties(const int polygonIndex) const {
if (mappingMode != FbxGeometryElement::eNone) {
const int materialNum =
indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
if (materialNum < 0) {
return std::vector<std::string>();
}
return userProperties.at((unsigned long)materialNum);
}
return std::vector<std::string>();
}
std::unique_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterialInfo(
FbxSurfaceMaterial* material,
const std::map<const FbxTexture*, FbxString>& textureLocations) {

View File

@ -45,6 +45,8 @@ class FbxMaterialsAccess {
const std::shared_ptr<FbxMaterialInfo> GetMaterial(const int polygonIndex) const;
const std::vector<std::string> GetUserProperties(const int polygonIndex) const;
std::unique_ptr<FbxMaterialInfo> GetMaterialInfo(
FbxSurfaceMaterial* material,
const std::map<const FbxTexture*, FbxString>& textureLocations);
@ -52,6 +54,7 @@ class FbxMaterialsAccess {
private:
FbxGeometryElement::EMappingMode mappingMode;
std::vector<std::shared_ptr<FbxMaterialInfo>> summaries{};
std::vector<std::vector<std::string>> userProperties;
const FbxMesh* mesh;
const FbxLayerElementArrayTemplate<int>* indices;
};

View File

@ -35,6 +35,7 @@ struct FbxRoughMetMaterialInfo : FbxMaterialInfo {
const FbxDouble metallic;
const FbxDouble roughness;
FbxBool invertRoughnessMap = false;
FbxDouble baseWeight = 1;
FbxVector4 emissive = FbxVector4(0, 0, 0, 1);
FbxDouble emissiveIntensity = 1;
@ -70,8 +71,8 @@ class Fbx3dsMaxPhysicalMaterialResolver : FbxMaterialResolver<FbxRoughMetMateria
private:
template <typename T>
T getValue(const FbxProperty& props, std::string propName, const T& default) const {
T getValue(const FbxProperty& props, std::string propName, const T& def) const {
const FbxProperty prop = props.FindHierarchical(propName.c_str());
return prop.IsValid() ? prop.Get<T>() : default;
return prop.IsValid() ? prop.Get<T>() : def;
}
};

View File

@ -276,7 +276,13 @@ ModelData* Raw2Gltf(
},
"ao_met_rough",
[&](const std::vector<const TextureBuilder::pixel*> pixels) -> TextureBuilder::pixel {
return {{(*pixels[0])[0], (*pixels[2])[0], (*pixels[1])[0], 1}};
const float occlusion = (*pixels[0])[0];
const float metallic = (*pixels[1])[0];
const float roughness = (*pixels[2])[0];
return {{occlusion,
props->invertRoughnessMap ? 1.0f - roughness : roughness,
metallic,
1}};
},
false);

View File

@ -100,7 +100,10 @@ int RawModel::AddTexture(
return -1;
}
for (size_t i = 0; i < textures.size(); i++) {
if (StringUtils::CompareNoCase(textures[i].name, name) == 0 && textures[i].usage == usage) {
// we allocate the struct even if the implementing image file is missing
if (textures[i].usage == usage &&
StringUtils::CompareNoCase(textures[i].fileLocation, fileLocation) == 0 &&
StringUtils::CompareNoCase(textures[i].name, name) == 0) {
return (int)i;
}
}

View File

@ -234,18 +234,21 @@ struct RawMetRoughMatProps : RawMatProps {
const Vec3f&& emissiveFactor,
float emissiveIntensity,
float metallic,
float roughness)
float roughness,
bool invertRoughnessMap)
: RawMatProps(shadingModel),
diffuseFactor(diffuseFactor),
emissiveFactor(emissiveFactor),
emissiveIntensity(emissiveIntensity),
metallic(metallic),
roughness(roughness) {}
roughness(roughness),
invertRoughnessMap(invertRoughnessMap) {}
const Vec4f diffuseFactor;
const Vec3f emissiveFactor;
const float emissiveIntensity;
const float metallic;
const float roughness;
const bool invertRoughnessMap;
bool operator==(const RawMatProps& other) const override {
if (RawMatProps::operator==(other)) {