diff --git a/CMakeLists.txt b/CMakeLists.txt index 102783ba3..b739674af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -249,9 +249,15 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW) SET(CMAKE_POSITION_INDEPENDENT_CODE ON) ENDIF() # hide all not-exported symbols - SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}") - SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}") - SET(LIBSTDC++_LIBRARIES -lstdc++) + IF(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "mips64" ) + SET(CMAKE_CXX_FLAGS "-mxgot -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}") + SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}") + SET(LIBSTDC++_LIBRARIES -lstdc++) + ELSE() + SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}") + SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}") + SET(LIBSTDC++_LIBRARIES -lstdc++) + ENDIF() ELSEIF(MSVC) # enable multi-core compilation with MSVC IF( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) # clang-cl diff --git a/Readme.md b/Readme.md index 87d5b40d8..c6212bcc0 100644 --- a/Readme.md +++ b/Readme.md @@ -16,13 +16,16 @@ A library to import and export various 3d-model-formats including scene-post-pro
APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS. - -[Check the latest doc](https://assimp-docs.readthedocs.io/en/latest/). - Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more. -This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases). +### Latest Doc's ### +Please check the latest documents at [Asset-Importer-Lib-Doc](https://assimp-docs.readthedocs.io/en/latest/). +### Get involved ### +This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases). +
+You find a bug in the docs? Use [Doc-Repo](https://github.com/assimp/assimp-docs). +
Please check our Wiki as well: https://github.com/assimp/assimp/wiki If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb diff --git a/code/AssetLib/Assjson/cencode.c b/code/AssetLib/Assjson/cencode.c index 0ed979b01..614a2671f 100644 --- a/code/AssetLib/Assjson/cencode.c +++ b/code/AssetLib/Assjson/cencode.c @@ -9,8 +9,10 @@ For details, see http://sourceforge.net/projects/libb64 const int CHARS_PER_LINE = 72; +#ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4244) +#endif // _MSC_VER void base64_init_encodestate(base64_encodestate* state_in) { @@ -33,9 +35,9 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, char* codechar = code_out; char result; char fragment; - + result = state_in->result; - + switch (state_in->step) { while (1) @@ -74,7 +76,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, *codechar++ = base64_encode_value(result); result = (fragment & 0x03f) >> 0; *codechar++ = base64_encode_value(result); - + ++(state_in->stepcount); if (state_in->stepcount == CHARS_PER_LINE/4) { @@ -90,7 +92,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, int base64_encode_blockend(char* code_out, base64_encodestate* state_in) { char* codechar = code_out; - + switch (state_in->step) { case step_B: @@ -106,8 +108,10 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in) break; } *codechar++ = '\n'; - + return (int)(codechar - code_out); } +#ifdef _MSC_VER #pragma warning(pop) +#endif // _MSC_VER diff --git a/code/AssetLib/FBX/FBXConverter.cpp b/code/AssetLib/FBX/FBXConverter.cpp index efecf450f..1a484a38a 100644 --- a/code/AssetLib/FBX/FBXConverter.cpp +++ b/code/AssetLib/FBX/FBXConverter.cpp @@ -185,6 +185,17 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN return unique_name; } +/// This struct manages nodes which may or may not end up in the node hierarchy. +/// When a node becomes a child of another node, that node becomes its owner and mOwnership should be released. +struct FBXConverter::PotentialNode +{ + PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {} + PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {} + aiNode* operator->() { return mNode; } + std::unique_ptr mOwnership; + aiNode* mNode; +}; + /// todo: pre-build node hierarchy /// todo: get bone from stack /// todo: make map of aiBone* to aiNode* @@ -192,137 +203,129 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) { const std::vector &conns = doc.GetConnectionsByDestinationSequenced(id, "Model"); - std::vector nodes; + std::vector nodes; nodes.reserve(conns.size()); - std::vector nodes_chain; - std::vector post_nodes_chain; + std::vector nodes_chain; + std::vector post_nodes_chain; - try { - for (const Connection *con : conns) { - // ignore object-property links - if (con->PropertyName().length()) { - // really important we document why this is ignored. - FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored"); - continue; //? + for (const Connection *con : conns) { + // ignore object-property links + if (con->PropertyName().length()) { + // really important we document why this is ignored. + FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored"); + continue; //? + } + + // convert connection source object into Object base class + const Object *const object = con->SourceObject(); + if (nullptr == object) { + FBXImporter::LogError("failed to convert source object for Model link"); + continue; + } + + // FBX Model::Cube, Model::Bone001, etc elements + // This detects if we can cast the object into this model structure. + const Model *const model = dynamic_cast(object); + + if (nullptr != model) { + nodes_chain.clear(); + post_nodes_chain.clear(); + + aiMatrix4x4 new_abs_transform = parent->mTransformation; + std::string node_name = FixNodeName(model->Name()); + // even though there is only a single input node, the design of + // assimp (or rather: the complicated transformation chain that + // is employed by fbx) means that we may need multiple aiNode's + // to represent a fbx node's transformation. + + // generate node transforms - this includes pivot data + // if need_additional_node is true then you t + const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain); + + // assert that for the current node we must have at least a single transform + ai_assert(nodes_chain.size()); + + if (need_additional_node) { + nodes_chain.emplace_back(PotentialNode(node_name)); } - // convert connection source object into Object base class - const Object *const object = con->SourceObject(); - if (nullptr == object) { - FBXImporter::LogError("failed to convert source object for Model link"); - continue; - } + //setup metadata on newest node + SetupNodeMetadata(*model, *nodes_chain.back().mNode); - // FBX Model::Cube, Model::Bone001, etc elements - // This detects if we can cast the object into this model structure. - const Model *const model = dynamic_cast(object); + // link all nodes in a row + aiNode *last_parent = parent; + for (PotentialNode& child : nodes_chain) { + ai_assert(child.mNode); - if (nullptr != model) { - nodes_chain.clear(); - post_nodes_chain.clear(); - - aiMatrix4x4 new_abs_transform = parent->mTransformation; - std::string node_name = FixNodeName(model->Name()); - // even though there is only a single input node, the design of - // assimp (or rather: the complicated transformation chain that - // is employed by fbx) means that we may need multiple aiNode's - // to represent a fbx node's transformation. - - // generate node transforms - this includes pivot data - // if need_additional_node is true then you t - const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain); - - // assert that for the current node we must have at least a single transform - ai_assert(nodes_chain.size()); - - if (need_additional_node) { - nodes_chain.push_back(new aiNode(node_name)); + if (last_parent != parent) { + last_parent->mNumChildren = 1; + last_parent->mChildren = new aiNode *[1]; + last_parent->mChildren[0] = child.mOwnership.release(); } - //setup metadata on newest node - SetupNodeMetadata(*model, *nodes_chain.back()); + child->mParent = last_parent; + last_parent = child.mNode; - // link all nodes in a row - aiNode *last_parent = parent; - for (aiNode *child : nodes_chain) { - ai_assert(child); + new_abs_transform *= child->mTransformation; + } + + // attach geometry + ConvertModel(*model, nodes_chain.back().mNode, root_node, new_abs_transform); + + // check if there will be any child nodes + const std::vector &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model"); + + // if so, link the geometric transform inverse nodes + // before we attach any child nodes + if (child_conns.size()) { + for (PotentialNode& postnode : post_nodes_chain) { + ai_assert(postnode.mNode); if (last_parent != parent) { last_parent->mNumChildren = 1; last_parent->mChildren = new aiNode *[1]; - last_parent->mChildren[0] = child; + last_parent->mChildren[0] = postnode.mOwnership.release(); } - child->mParent = last_parent; - last_parent = child; + postnode->mParent = last_parent; + last_parent = postnode.mNode; - new_abs_transform *= child->mTransformation; + new_abs_transform *= postnode->mTransformation; } - - // attach geometry - ConvertModel(*model, nodes_chain.back(), root_node, new_abs_transform); - - // check if there will be any child nodes - const std::vector &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model"); - - // if so, link the geometric transform inverse nodes - // before we attach any child nodes - if (child_conns.size()) { - for (aiNode *postnode : post_nodes_chain) { - ai_assert(postnode); - - if (last_parent != parent) { - last_parent->mNumChildren = 1; - last_parent->mChildren = new aiNode *[1]; - last_parent->mChildren[0] = postnode; - } - - postnode->mParent = last_parent; - last_parent = postnode; - - new_abs_transform *= postnode->mTransformation; - } - } else { - // free the nodes we allocated as we don't need them - Util::delete_fun deleter; - std::for_each( - post_nodes_chain.begin(), - post_nodes_chain.end(), - deleter); - } - - // recursion call - child nodes - ConvertNodes(model->ID(), last_parent, root_node); - - if (doc.Settings().readLights) { - ConvertLights(*model, node_name); - } - - if (doc.Settings().readCameras) { - ConvertCameras(*model, node_name); - } - - nodes.push_back(nodes_chain.front()); - nodes_chain.clear(); + } else { + // free the nodes we allocated as we don't need them + post_nodes_chain.clear(); } + + // recursion call - child nodes + ConvertNodes(model->ID(), last_parent, root_node); + + if (doc.Settings().readLights) { + ConvertLights(*model, node_name); + } + + if (doc.Settings().readCameras) { + ConvertCameras(*model, node_name); + } + + nodes.push_back(std::move(nodes_chain.front())); + nodes_chain.clear(); } + } - if (nodes.size()) { - parent->mChildren = new aiNode *[nodes.size()](); - parent->mNumChildren = static_cast(nodes.size()); + if (nodes.size()) { + parent->mChildren = new aiNode *[nodes.size()](); + parent->mNumChildren = static_cast(nodes.size()); - std::swap_ranges(nodes.begin(), nodes.end(), parent->mChildren); - } else { - parent->mNumChildren = 0; - parent->mChildren = nullptr; + for (unsigned int i = 0; i < nodes.size(); ++i) + { + parent->mChildren[i] = nodes[i].mOwnership.release(); } - - } catch (std::exception &) { - Util::delete_fun deleter; - std::for_each(nodes.begin(), nodes.end(), deleter); - std::for_each(nodes_chain.begin(), nodes_chain.end(), deleter); - std::for_each(post_nodes_chain.begin(), post_nodes_chain.end(), deleter); + nodes.clear(); + } else { + parent->mNumChildren = 0; + parent->mChildren = nullptr; } } @@ -681,8 +684,8 @@ std::string FBXConverter::NameTransformationChainNode(const std::string &name, T return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp); } -bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std::string &name, std::vector &output_nodes, - std::vector &post_output_nodes) { +bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std::string &name, std::vector &output_nodes, + std::vector &post_output_nodes) { const PropertyTable &props = model.Props(); const Model::RotOrder rot = model.RotationOrder(); @@ -828,7 +831,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std chain[i] = chain[i].Inverse(); } - aiNode *nd = new aiNode(); + PotentialNode nd; nd->mName.Set(NameTransformationChainNode(name, comp)); nd->mTransformation = chain[i]; @@ -836,9 +839,9 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std if (comp == TransformationComp_GeometricScalingInverse || comp == TransformationComp_GeometricRotationInverse || comp == TransformationComp_GeometricTranslationInverse) { - post_output_nodes.push_back(nd); + post_output_nodes.emplace_back(std::move(nd)); } else { - output_nodes.push_back(nd); + output_nodes.emplace_back(std::move(nd)); } } @@ -847,8 +850,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std } // else, we can just multiply the matrices together - aiNode *nd = new aiNode(); - output_nodes.push_back(nd); + PotentialNode nd; // name passed to the method is already unique nd->mName.Set(name); @@ -857,6 +859,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std for (unsigned int i = TransformationComp_Translation; i < TransformationComp_MAXIMUM; i++) { nd->mTransformation = nd->mTransformation * chain[i]; } + output_nodes.push_back(std::move(nd)); return false; } @@ -2011,12 +2014,40 @@ void FBXConverter::SetTextureProperties(aiMaterial *out_mat, const TextureMap &_ TrySetTextureProperties(out_mat, _textures, "Maya|TEX_roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh); TrySetTextureProperties(out_mat, _textures, "Maya|TEX_ao_map", aiTextureType_AMBIENT_OCCLUSION, mesh); - // 3DSMax PBR + // 3DSMax Physical material TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|base_color_map", aiTextureType_BASE_COLOR, mesh); TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|bump_map", aiTextureType_NORMAL_CAMERA, mesh); TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|emission_map", aiTextureType_EMISSION_COLOR, mesh); TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|metalness_map", aiTextureType_METALNESS, mesh); TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh); + + // 3DSMax PBR materials + TrySetTextureProperties(out_mat, _textures, "3dsMax|main|base_color_map", aiTextureType_BASE_COLOR, mesh); + TrySetTextureProperties(out_mat, _textures, "3dsMax|main|norm_map", aiTextureType_NORMAL_CAMERA, mesh); + TrySetTextureProperties(out_mat, _textures, "3dsMax|main|emit_color_map", aiTextureType_EMISSION_COLOR, mesh); + TrySetTextureProperties(out_mat, _textures, "3dsMax|main|ao_map", aiTextureType_AMBIENT_OCCLUSION, mesh); + TrySetTextureProperties(out_mat, _textures, "3dsMax|main|opacity_map", aiTextureType_OPACITY, mesh); + // Metalness/Roughness material type + TrySetTextureProperties(out_mat, _textures, "3dsMax|main|metalness_map", aiTextureType_METALNESS, mesh); + // Specular/Gloss material type + TrySetTextureProperties(out_mat, _textures, "3dsMax|main|specular_map", aiTextureType_SPECULAR, mesh); + + // Glossiness vs roughness in 3ds Max Pbr Materials + int useGlossiness; + if (out_mat->Get("$raw.3dsMax|main|useGlossiness", aiTextureType_NONE, 0, useGlossiness) == aiReturn_SUCCESS) { + // These textures swap meaning if ((useGlossiness == 1) != (material type is Specular/Gloss)) + if (useGlossiness == 1) { + TrySetTextureProperties(out_mat, _textures, "3dsMax|main|roughness_map", aiTextureType_SHININESS, mesh); + TrySetTextureProperties(out_mat, _textures, "3dsMax|main|glossiness_map", aiTextureType_SHININESS, mesh); + } + else if (useGlossiness == 2) { + TrySetTextureProperties(out_mat, _textures, "3dsMax|main|roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh); + TrySetTextureProperties(out_mat, _textures, "3dsMax|main|glossiness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh); + } + else { + FBXImporter::LogWarn("A 3dsMax Pbr Material must have a useGlossiness value to correctly interpret roughness and glossiness textures."); + } + } } void FBXConverter::SetTextureProperties(aiMaterial *out_mat, const LayeredTextureMap &layeredTextures, const MeshGeometry *const mesh) { diff --git a/code/AssetLib/FBX/FBXConverter.h b/code/AssetLib/FBX/FBXConverter.h index 0ae0da662..52f978a7b 100644 --- a/code/AssetLib/FBX/FBXConverter.h +++ b/code/AssetLib/FBX/FBXConverter.h @@ -171,9 +171,10 @@ private: // ------------------------------------------------------------------------------------------------ /** - * note: memory for output_nodes will be managed by the caller + * note: memory for output_nodes is managed by the caller, via the PotentialNode struct. */ - bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector& output_nodes, std::vector& post_output_nodes); + struct PotentialNode; + bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector& output_nodes, std::vector& post_output_nodes); // ------------------------------------------------------------------------------------------------ void SetupNodeMetadata(const Model& model, aiNode& nd); diff --git a/code/AssetLib/FBX/FBXProperties.cpp b/code/AssetLib/FBX/FBXProperties.cpp index a3a95228e..84098cf10 100644 --- a/code/AssetLib/FBX/FBXProperties.cpp +++ b/code/AssetLib/FBX/FBXProperties.cpp @@ -69,6 +69,20 @@ Property::~Property() namespace { +void checkTokenCount(const TokenList& tok, unsigned int expectedCount) +{ + ai_assert(expectedCount >= 2); + if (tok.size() < expectedCount) { + const std::string& s = ParseTokenAsString(*tok[1]); + if (tok[1]->IsBinary()) { + throw DeadlyImportError("Not enough tokens for property of type ", s, " at offset ", tok[1]->Offset()); + } + else { + throw DeadlyImportError("Not enough tokens for property of type ", s, " at line ", tok[1]->Line()); + } + } +} + // ------------------------------------------------------------------------------------------------ // read a typed property out of a FBX element. The return value is nullptr if the property cannot be read. Property* ReadTypedProperty(const Element& element) @@ -83,23 +97,23 @@ Property* ReadTypedProperty(const Element& element) const std::string& s = ParseTokenAsString(*tok[1]); const char* const cs = s.c_str(); if (!strcmp(cs,"KString")) { - ai_assert(tok.size() >= 5); + checkTokenCount(tok, 5); return new TypedProperty(ParseTokenAsString(*tok[4])); } else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) { - ai_assert(tok.size() >= 5); + checkTokenCount(tok, 5); return new TypedProperty(ParseTokenAsInt(*tok[4]) != 0); } - else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) { - ai_assert(tok.size() >= 5); + else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum") || !strcmp(cs, "Integer")) { + checkTokenCount(tok, 5); return new TypedProperty(ParseTokenAsInt(*tok[4])); } else if (!strcmp(cs, "ULongLong")) { - ai_assert(tok.size() >= 5); + checkTokenCount(tok, 5); return new TypedProperty(ParseTokenAsID(*tok[4])); } else if (!strcmp(cs, "KTime")) { - ai_assert(tok.size() >= 5); + checkTokenCount(tok, 5); return new TypedProperty(ParseTokenAsInt64(*tok[4])); } else if (!strcmp(cs,"Vector3D") || @@ -110,7 +124,7 @@ Property* ReadTypedProperty(const Element& element) !strcmp(cs,"Lcl Rotation") || !strcmp(cs,"Lcl Scaling") ) { - ai_assert(tok.size() >= 7); + checkTokenCount(tok, 7); return new TypedProperty(aiVector3D( ParseTokenAsFloat(*tok[4]), ParseTokenAsFloat(*tok[5]), @@ -118,9 +132,18 @@ Property* ReadTypedProperty(const Element& element) ); } else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView") || !strcmp( cs, "UnitScaleFactor" ) ) { - ai_assert(tok.size() >= 5); + checkTokenCount(tok, 5); return new TypedProperty(ParseTokenAsFloat(*tok[4])); } + else if (!strcmp(cs, "ColorAndAlpha")) { + checkTokenCount(tok, 8); + return new TypedProperty(aiColor4D( + ParseTokenAsFloat(*tok[4]), + ParseTokenAsFloat(*tok[5]), + ParseTokenAsFloat(*tok[6]), + ParseTokenAsFloat(*tok[7])) + ); + } return nullptr; } diff --git a/code/AssetLib/glTF/glTFCommon.cpp b/code/AssetLib/glTF/glTFCommon.cpp index 6bea18a0a..01ba31209 100644 --- a/code/AssetLib/glTF/glTFCommon.cpp +++ b/code/AssetLib/glTF/glTFCommon.cpp @@ -49,7 +49,9 @@ using namespace glTFCommon::Util; namespace Util { size_t DecodeBase64(const char *in, size_t inLength, uint8_t *&out) { - ai_assert(inLength % 4 == 0); + if (inLength % 4 != 0) { + throw DeadlyImportError("Invalid base64 encoded data: \"", std::string(in, std::min(size_t(32), inLength)), "\", length:", inLength); + } if (inLength < 4) { out = 0; diff --git a/code/AssetLib/glTF/glTFCommon.h b/code/AssetLib/glTF/glTFCommon.h index 977fc0da4..6d402b0e3 100644 --- a/code/AssetLib/glTF/glTFCommon.h +++ b/code/AssetLib/glTF/glTFCommon.h @@ -249,7 +249,10 @@ inline char EncodeCharBase64(uint8_t b) { } inline uint8_t DecodeCharBase64(char c) { - return DATA::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs? + if (c & 0x80) { + throw DeadlyImportError("Invalid base64 char value: ", size_t(c)); + } + return DATA::tableDecodeBase64[size_t(c & 0x7F)]; // TODO faster with lookup table or ifs? } size_t DecodeBase64(const char *in, size_t inLength, uint8_t *&out); diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 23c19cc58..be149f86e 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -1124,6 +1124,14 @@ private: IOStream *OpenFile(std::string path, const char *mode, bool absolute = false); }; +inline std::string getContextForErrorMessages(const std::string &id, const std::string &name) { + std::string context = id; + if (!name.empty()) { + context += " (\"" + name + "\")"; + } + return context; +} + } // namespace glTF2 // Include the implementation of the methods diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index c892e6697..8fc8bf24e 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -273,17 +273,21 @@ Ref LazyDict::Retrieve(unsigned int i) { } if (!mDict->IsArray()) { - throw DeadlyImportError("GLTF: Field is not an array \"", mDictId, "\""); + throw DeadlyImportError("GLTF: Field \"", mDictId, "\" is not an array"); + } + + if (i >= mDict->Size()) { + throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\""); } Value &obj = (*mDict)[i]; if (!obj.IsObject()) { - throw DeadlyImportError("GLTF: Object at index \"", to_string(i), "\" is not a JSON object"); + throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object"); } if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) { - throw DeadlyImportError("GLTF: Object at index \"", to_string(i), "\" has recursive reference to itself"); + throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself"); } mRecursiveReferenceCheck.insert(i); @@ -741,14 +745,6 @@ inline void CopyData(size_t count, } } -inline std::string getContextForErrorMessages(const std::string& id, const std::string& name) { - std::string context = id; - if (!name.empty()) { - context += " (\"" + name + "\")"; - } - return context; -} - } // namespace template @@ -766,11 +762,12 @@ void Accessor::ExtractData(T *&outData) { const size_t targetElemSize = sizeof(T); if (elemSize > targetElemSize) { - throw DeadlyImportError("GLTF: elemSize > targetElemSize"); + throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name)); } - if (count*stride > (bufferView ? bufferView->byteLength : sparse->data.size())) { - throw DeadlyImportError("GLTF: count*stride out of range"); + const size_t maxSize = (bufferView ? bufferView->byteLength : sparse->data.size()); + if (count*stride > maxSize) { + throw DeadlyImportError("GLTF: count*stride ", (count * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name)); } outData = new T[count]; diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index 872543ef2..637808877 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -1126,7 +1126,7 @@ void glTF2Exporter::MergeMeshes() unsigned int meshIndex = meshRef.GetIndex(); if (meshIndex == removedIndex) { - node->meshes.erase(curNode->meshes.begin() + mm); + curNode->meshes.erase(curNode->meshes.begin() + mm); } else if (meshIndex > removedIndex) { Ref newMeshRef = mAsset->meshes.Get(meshIndex - 1); diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 3fb7889af..672bac52d 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -918,7 +918,10 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector & if (!node.meshes.empty()) { // GLTF files contain at most 1 mesh per node. - assert(node.meshes.size() == 1); + if (node.meshes.size() > 1) + { + throw DeadlyImportError("GLTF: Invalid input, found ", node.meshes.size(), " meshes in ", getContextForErrorMessages(node.id, node.name), ", but only 1 mesh per node allowed."); + } int mesh_idx = node.meshes[0].GetIndex(); int count = meshOffsets[mesh_idx + 1] - meshOffsets[mesh_idx]; diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index a0bad4e10..bb83a5f97 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1033,7 +1033,10 @@ ELSE() INCLUDE_DIRECTORIES( "../contrib" ) INCLUDE_DIRECTORIES( "../contrib/pugixml/src" ) ADD_DEFINITIONS( -DRAPIDJSON_HAS_STDSTRING=1 ) - ADD_DEFINITIONS( -DRAPIDJSON_NOMEMBERITERATORCLASS ) + option( ASSIMP_RAPIDJSON_NO_MEMBER_ITERATOR "Suppress rapidjson warning on MSVC (NOTE: breaks android build)" ON ) + if(ASSIMP_RAPIDJSON_NO_MEMBER_ITERATOR) + ADD_DEFINITIONS( -DRAPIDJSON_NOMEMBERITERATORCLASS ) + endif() ENDIF() # VC2010 fixes diff --git a/code/Common/ScenePreprocessor.cpp b/code/Common/ScenePreprocessor.cpp index 55aa04ad2..2b73d9452 100644 --- a/code/Common/ScenePreprocessor.cpp +++ b/code/Common/ScenePreprocessor.cpp @@ -96,8 +96,9 @@ void ScenePreprocessor::ProcessMesh(aiMesh *mesh) { if (!mesh->mTextureCoords[i]) { mesh->mNumUVComponents[i] = 0; } else { - if (!mesh->mNumUVComponents[i]) + if (!mesh->mNumUVComponents[i]) { mesh->mNumUVComponents[i] = 2; + } aiVector3D *p = mesh->mTextureCoords[i], *end = p + mesh->mNumVertices; @@ -105,16 +106,19 @@ void ScenePreprocessor::ProcessMesh(aiMesh *mesh) { // as if they were 2D channels .. just in case an application doesn't handle // this case if (2 == mesh->mNumUVComponents[i]) { - for (; p != end; ++p) + for (; p != end; ++p) { p->z = 0.f; + } } else if (1 == mesh->mNumUVComponents[i]) { - for (; p != end; ++p) + for (; p != end; ++p) { p->z = p->y = 0.f; + } } else if (3 == mesh->mNumUVComponents[i]) { // Really 3D coordinates? Check whether the third coordinate is != 0 for at least one element for (; p != end; ++p) { - if (p->z != 0) + if (p->z != 0) { break; + } } if (p == end) { ASSIMP_LOG_WARN("ScenePreprocessor: UVs are declared to be 3D but they're obviously not. Reverting to 2D."); @@ -151,7 +155,6 @@ void ScenePreprocessor::ProcessMesh(aiMesh *mesh) { // If tangents and normals are given but no bitangents compute them if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) { - mesh->mBitangents = new aiVector3D[mesh->mNumVertices]; for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { mesh->mBitangents[i] = mesh->mNormals[i] ^ mesh->mTangents[i]; @@ -165,11 +168,9 @@ void ScenePreprocessor::ProcessAnimation(aiAnimation *anim) { for (unsigned int i = 0; i < anim->mNumChannels; ++i) { aiNodeAnim *channel = anim->mChannels[i]; - /* If the exact duration of the animation is not given - * compute it now. - */ + // If the exact duration of the animation is not given + // compute it now. if (anim->mDuration == -1.) { - // Position keys for (unsigned int j = 0; j < channel->mNumPositionKeys; ++j) { aiVectorKey &key = channel->mPositionKeys[j]; @@ -192,11 +193,10 @@ void ScenePreprocessor::ProcessAnimation(aiAnimation *anim) { } } - /* Check whether the animation channel has no rotation - * or position tracks. In this case we generate a dummy - * track from the information we have in the transformation - * matrix of the corresponding node. - */ + // Check whether the animation channel has no rotation + // or position tracks. In this case we generate a dummy + // track from the information we have in the transformation + // matrix of the corresponding node. if (!channel->mNumRotationKeys || !channel->mNumPositionKeys || !channel->mNumScalingKeys) { // Find the node that belongs to this animation aiNode *node = scene->mRootNode->FindNode(channel->mNodeName); @@ -210,6 +210,10 @@ void ScenePreprocessor::ProcessAnimation(aiAnimation *anim) { // No rotation keys? Generate a dummy track if (!channel->mNumRotationKeys) { + if (channel->mRotationKeys) { + delete[] channel->mRotationKeys; + channel->mRotationKeys = nullptr; + } ai_assert(!channel->mRotationKeys); channel->mNumRotationKeys = 1; channel->mRotationKeys = new aiQuatKey[1]; @@ -225,6 +229,10 @@ void ScenePreprocessor::ProcessAnimation(aiAnimation *anim) { // No scaling keys? Generate a dummy track if (!channel->mNumScalingKeys) { + if (channel->mScalingKeys) { + delete[] channel->mScalingKeys; + channel->mScalingKeys = nullptr; + } ai_assert(!channel->mScalingKeys); channel->mNumScalingKeys = 1; channel->mScalingKeys = new aiVectorKey[1]; @@ -240,6 +248,10 @@ void ScenePreprocessor::ProcessAnimation(aiAnimation *anim) { // No position keys? Generate a dummy track if (!channel->mNumPositionKeys) { + if (channel->mPositionKeys) { + delete[] channel->mPositionKeys; + channel->mPositionKeys = nullptr; + } ai_assert(!channel->mPositionKeys); channel->mNumPositionKeys = 1; channel->mPositionKeys = new aiVectorKey[1]; diff --git a/code/PostProcessing/SplitByBoneCountProcess.cpp b/code/PostProcessing/SplitByBoneCountProcess.cpp index 1fd26c757..b39444859 100644 --- a/code/PostProcessing/SplitByBoneCountProcess.cpp +++ b/code/PostProcessing/SplitByBoneCountProcess.cpp @@ -408,6 +408,45 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vectormNumAnimMeshes > 0) { + newMesh->mNumAnimMeshes = pMesh->mNumAnimMeshes; + newMesh->mAnimMeshes = new aiAnimMesh*[newMesh->mNumAnimMeshes]; + + for (unsigned int morphIdx = 0; morphIdx < newMesh->mNumAnimMeshes; ++morphIdx) { + aiAnimMesh* origTarget = pMesh->mAnimMeshes[morphIdx]; + aiAnimMesh* newTarget = new aiAnimMesh; + newTarget->mName = origTarget->mName; + newTarget->mWeight = origTarget->mWeight; + newTarget->mNumVertices = numSubMeshVertices; + newTarget->mVertices = new aiVector3D[numSubMeshVertices]; + newMesh->mAnimMeshes[morphIdx] = newTarget; + + if (origTarget->HasNormals()) { + newTarget->mNormals = new aiVector3D[numSubMeshVertices]; + } + + if (origTarget->HasTangentsAndBitangents()) { + newTarget->mTangents = new aiVector3D[numSubMeshVertices]; + newTarget->mBitangents = new aiVector3D[numSubMeshVertices]; + } + + for( unsigned int vi = 0; vi < numSubMeshVertices; ++vi) { + // find the source vertex for it in the source mesh + unsigned int previousIndex = previousVertexIndices[vi]; + newTarget->mVertices[vi] = origTarget->mVertices[previousIndex]; + + if (newTarget->HasNormals()) { + newTarget->mNormals[vi] = origTarget->mNormals[previousIndex]; + } + if (newTarget->HasTangentsAndBitangents()) { + newTarget->mTangents[vi] = origTarget->mTangents[previousIndex]; + newTarget->mBitangents[vi] = origTarget->mBitangents[previousIndex]; + } + } + } + } + // I have the strange feeling that this will break apart at some point in time... } } diff --git a/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl b/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl index c965fcd50..8bd85f27b 100644 --- a/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl +++ b/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl @@ -27,10 +27,10 @@ THE SOFTWARE. #include "o3dgcArithmeticCodec.h" #include "o3dgcTimer.h" -#ifdef _WIN32 +#ifdef _MSC_VER # pragma warning(push) # pragma warning( disable : 4456) -#endif // _WIN32 +#endif // _MSC_VER //#define DEBUG_VERBOSE @@ -852,9 +852,9 @@ namespace o3dgc } } // namespace o3dgc -#ifdef _WIN32 +#ifdef _MSC_VER # pragma warning( pop ) -#endif // _WIN32 +#endif // _MSC_VER #endif // O3DGC_SC3DMC_DECODER_INL diff --git a/contrib/Open3DGC/o3dgcSC3DMCEncoder.inl b/contrib/Open3DGC/o3dgcSC3DMCEncoder.inl index 78d4b3e78..ca1e0ea76 100644 --- a/contrib/Open3DGC/o3dgcSC3DMCEncoder.inl +++ b/contrib/Open3DGC/o3dgcSC3DMCEncoder.inl @@ -32,10 +32,10 @@ THE SOFTWARE. //#define DEBUG_VERBOSE -#ifdef _WIN32 +#ifdef _MSC_VER # pragma warning(push) # pragma warning(disable : 4456) -#endif // _WIN32 +#endif // _MSC_VER namespace o3dgc { @@ -927,9 +927,9 @@ namespace o3dgc } } // namespace o3dgc -#ifdef _WIN32 +#ifdef _MSC_VER # pragma warning(pop) -#endif // _WIN32 +#endif // _MSC_VER #endif // O3DGC_SC3DMC_ENCODER_INL diff --git a/contrib/Open3DGC/o3dgcTimer.h b/contrib/Open3DGC/o3dgcTimer.h index d9a285968..f5ed0c83f 100644 --- a/contrib/Open3DGC/o3dgcTimer.h +++ b/contrib/Open3DGC/o3dgcTimer.h @@ -28,7 +28,9 @@ THE SOFTWARE. #ifdef _WIN32 /* Thank you, Microsoft, for file WinDef.h with min/max redefinition. */ +#ifndef NOMINMAX #define NOMINMAX +#endif #include #elif __APPLE__ #include diff --git a/contrib/zip/src/zip.c b/contrib/zip/src/zip.c index 0020df0ed..83e8e2a41 100644 --- a/contrib/zip/src/zip.c +++ b/contrib/zip/src/zip.c @@ -18,8 +18,10 @@ /* Win32, DOS, MSVC, MSVS */ #include +#ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4706) +#endif // _MSC_VER #define MKDIR(DIRNAME) _mkdir(DIRNAME) #define STRCLONE(STR) ((STR) ? _strdup(STR) : NULL) @@ -968,4 +970,6 @@ out: return status; } +#ifdef _MSC_VER #pragma warning(pop) +#endif // _MSC_VER diff --git a/include/assimp/mesh.h b/include/assimp/mesh.h index 4b5af97ce..ec1062837 100644 --- a/include/assimp/mesh.h +++ b/include/assimp/mesh.h @@ -52,9 +52,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma GCC system_header #endif -#ifdef _WIN32 +#ifdef _MSC_VER #pragma warning(disable : 4351) -#endif // _WIN32 +#endif // _MSC_VER #include #include @@ -458,8 +458,8 @@ struct aiAnimMesh { */ unsigned int mNumVertices; - /** - * Weight of the AnimMesh. + /** + * Weight of the AnimMesh. */ float mWeight; @@ -713,8 +713,8 @@ struct aiMesh { * Note! Currently only works with Collada loader.*/ C_STRUCT aiAnimMesh **mAnimMeshes; - /** - * Method of morphing when animeshes are specified. + /** + * Method of morphing when animeshes are specified. */ unsigned int mMethod; diff --git a/port/AndroidJNI/README.md b/port/AndroidJNI/README.md index 0b95efd04..003b1da1a 100644 --- a/port/AndroidJNI/README.md +++ b/port/AndroidJNI/README.md @@ -14,6 +14,11 @@ To use this module please provide following cmake defines: "SOME_PATH" is a path to your cmake android toolchain script. + +The build script for this port is based on [android-cmake](https://github.com/taka-no-me/android-cmake). +See its documentation for more Android-specific cmake options (e.g. -DANDROID_ABI for the target ABI). +Check [Asset-Importer-Docs](https://assimp-docs.readthedocs.io/en/latest/) for more information. + ### Code ### A small example how to wrap assimp for Android: ```cpp diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp index c3269d290..01ba343e8 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp @@ -31,10 +31,16 @@ #include #include +#ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4005) +#endif // _MSC_VER + #include + +#ifdef _MSC_VER #pragma warning(pop) +#endif // _MSC_VER #include diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h index c2e0b5214..5448daf2a 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h @@ -31,10 +31,16 @@ #include +#ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4005) +#endif // _MSC_VER + #include + +#ifdef _MSC_VER #pragma warning(pop) +#endif // _MSC_VER HRESULT CreateWICTextureFromMemory(_In_ ID3D11Device* d3dDevice, _In_opt_ ID3D11DeviceContext* d3dContext, diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp index 5cce7c376..02e2b6088 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp @@ -25,10 +25,12 @@ #include "UTFConverter.h" #include "SafeRelease.hpp" +#ifdef _MSC_VER #pragma comment (lib, "d3d11.lib") #pragma comment (lib, "Dxgi.lib") #pragma comment(lib,"d3dcompiler.lib") #pragma comment (lib, "dxguid.lib") +#endif // _MSC_VER using namespace DirectX; using namespace AssimpSamples::SharedCode; diff --git a/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp b/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp index 806da8f8a..a36c792d4 100644 --- a/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp +++ b/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp @@ -18,10 +18,16 @@ #include #include +#ifdef _MSC_VER #pragma warning(disable: 4100) // Disable warning 'unreferenced formal parameter' +#endif // _MSC_VER + #define STB_IMAGE_IMPLEMENTATION #include "contrib/stb_image/stb_image.h" + +#ifdef _MSC_VER #pragma warning(default: 4100) // Enable warning 'unreferenced formal parameter' +#endif // _MSC_VER #include diff --git a/test/models/FBX/maxPbrMaterial_metalRough.fbx b/test/models/FBX/maxPbrMaterial_metalRough.fbx new file mode 100644 index 000000000..a66275269 --- /dev/null +++ b/test/models/FBX/maxPbrMaterial_metalRough.fbx @@ -0,0 +1,618 @@ +; FBX 7.7.0 project file +; ---------------------------------------------------- + +FBXHeaderExtension: { + FBXHeaderVersion: 1004 + FBXVersion: 7700 + CreationTimeStamp: { + Version: 1000 + Year: 2020 + Month: 12 + Day: 1 + Hour: 9 + Minute: 35 + Second: 57 + Millisecond: 532 + } + Creator: "FBX SDK/FBX Plugins version 2020.0.1" + OtherFlags: { + TCDefinition: 127 + } + SceneInfo: "SceneInfo::GlobalInfo", "UserData" { + Type: "UserData" + Version: 100 + MetaData: { + Version: 100 + Title: "" + Subject: "" + Author: "" + Keywords: "" + Revision: "" + Comment: "" + } + Properties70: { + P: "DocumentUrl", "KString", "Url", "", "G:\Temp\Max2021PbrMaterials\MaxPbrMaterial.fbx" + P: "SrcDocumentUrl", "KString", "Url", "", "G:\Temp\Max2021PbrMaterials\MaxPbrMaterial.fbx" + P: "Original", "Compound", "", "" + P: "Original|ApplicationVendor", "KString", "", "", "Autodesk" + P: "Original|ApplicationName", "KString", "", "", "3ds Max" + P: "Original|ApplicationVersion", "KString", "", "", "2021" + P: "Original|DateTime_GMT", "DateTime", "", "", "01/12/2020 09:35:57.532" + P: "Original|FileName", "KString", "", "", "G:\Temp\Max2021PbrMaterials\MaxPbrMaterial.fbx" + P: "LastSaved", "Compound", "", "" + P: "LastSaved|ApplicationVendor", "KString", "", "", "Autodesk" + P: "LastSaved|ApplicationName", "KString", "", "", "3ds Max" + P: "LastSaved|ApplicationVersion", "KString", "", "", "2021" + P: "LastSaved|DateTime_GMT", "DateTime", "", "", "01/12/2020 09:35:57.532" + P: "Original|ApplicationActiveProject", "KString", "", "", "C:\3ds Max 2021" + P: "Original|ApplicationNativeFile", "KString", "", "", "C;\3ds Max 2021\MaxPbrMaterial.max" + } + } +} +GlobalSettings: { + Version: 1000 + Properties70: { + P: "UpAxis", "int", "Integer", "",1 + P: "UpAxisSign", "int", "Integer", "",1 + P: "FrontAxis", "int", "Integer", "",2 + P: "FrontAxisSign", "int", "Integer", "",1 + P: "CoordAxis", "int", "Integer", "",0 + P: "CoordAxisSign", "int", "Integer", "",1 + P: "OriginalUpAxis", "int", "Integer", "",2 + P: "OriginalUpAxisSign", "int", "Integer", "",1 + P: "UnitScaleFactor", "double", "Number", "",100 + P: "OriginalUnitScaleFactor", "double", "Number", "",100.00000066 + P: "AmbientColor", "ColorRGB", "Color", "",0,0,0 + P: "DefaultCamera", "KString", "", "", "Producer Perspective" + P: "TimeMode", "enum", "", "",6 + P: "TimeProtocol", "enum", "", "",2 + P: "SnapOnFrameMode", "enum", "", "",0 + P: "TimeSpanStart", "KTime", "Time", "",0 + P: "TimeSpanStop", "KTime", "Time", "",153953860000 + P: "CustomFrameRate", "double", "Number", "",-1 + P: "TimeMarker", "Compound", "", "" + P: "CurrentTimeMarker", "int", "Integer", "",-1 + } +} + +; Documents Description +;------------------------------------------------------------------ + +Documents: { + Count: 1 + Document: 2188301813872, "", "Scene" { + Properties70: { + P: "SourceObject", "object", "", "" + P: "ActiveAnimStackName", "KString", "", "", "" + } + RootNode: 0 + } +} + +; Document References +;------------------------------------------------------------------ + +References: { +} + +; Object definitions +;------------------------------------------------------------------ + +Definitions: { + Version: 100 + Count: 18 + ObjectType: "GlobalSettings" { + Count: 1 + } + ObjectType: "Model" { + Count: 1 + PropertyTemplate: "FbxNode" { + Properties70: { + P: "QuaternionInterpolate", "enum", "", "",0 + P: "RotationOffset", "Vector3D", "Vector", "",0,0,0 + P: "RotationPivot", "Vector3D", "Vector", "",0,0,0 + P: "ScalingOffset", "Vector3D", "Vector", "",0,0,0 + P: "ScalingPivot", "Vector3D", "Vector", "",0,0,0 + P: "TranslationActive", "bool", "", "",0 + P: "TranslationMin", "Vector3D", "Vector", "",0,0,0 + P: "TranslationMax", "Vector3D", "Vector", "",0,0,0 + P: "TranslationMinX", "bool", "", "",0 + P: "TranslationMinY", "bool", "", "",0 + P: "TranslationMinZ", "bool", "", "",0 + P: "TranslationMaxX", "bool", "", "",0 + P: "TranslationMaxY", "bool", "", "",0 + P: "TranslationMaxZ", "bool", "", "",0 + P: "RotationOrder", "enum", "", "",0 + P: "RotationSpaceForLimitOnly", "bool", "", "",0 + P: "RotationStiffnessX", "double", "Number", "",0 + P: "RotationStiffnessY", "double", "Number", "",0 + P: "RotationStiffnessZ", "double", "Number", "",0 + P: "AxisLen", "double", "Number", "",10 + P: "PreRotation", "Vector3D", "Vector", "",0,0,0 + P: "PostRotation", "Vector3D", "Vector", "",0,0,0 + P: "RotationActive", "bool", "", "",0 + P: "RotationMin", "Vector3D", "Vector", "",0,0,0 + P: "RotationMax", "Vector3D", "Vector", "",0,0,0 + P: "RotationMinX", "bool", "", "",0 + P: "RotationMinY", "bool", "", "",0 + P: "RotationMinZ", "bool", "", "",0 + P: "RotationMaxX", "bool", "", "",0 + P: "RotationMaxY", "bool", "", "",0 + P: "RotationMaxZ", "bool", "", "",0 + P: "InheritType", "enum", "", "",0 + P: "ScalingActive", "bool", "", "",0 + P: "ScalingMin", "Vector3D", "Vector", "",0,0,0 + P: "ScalingMax", "Vector3D", "Vector", "",1,1,1 + P: "ScalingMinX", "bool", "", "",0 + P: "ScalingMinY", "bool", "", "",0 + P: "ScalingMinZ", "bool", "", "",0 + P: "ScalingMaxX", "bool", "", "",0 + P: "ScalingMaxY", "bool", "", "",0 + P: "ScalingMaxZ", "bool", "", "",0 + P: "GeometricTranslation", "Vector3D", "Vector", "",0,0,0 + P: "GeometricRotation", "Vector3D", "Vector", "",0,0,0 + P: "GeometricScaling", "Vector3D", "Vector", "",1,1,1 + P: "MinDampRangeX", "double", "Number", "",0 + P: "MinDampRangeY", "double", "Number", "",0 + P: "MinDampRangeZ", "double", "Number", "",0 + P: "MaxDampRangeX", "double", "Number", "",0 + P: "MaxDampRangeY", "double", "Number", "",0 + P: "MaxDampRangeZ", "double", "Number", "",0 + P: "MinDampStrengthX", "double", "Number", "",0 + P: "MinDampStrengthY", "double", "Number", "",0 + P: "MinDampStrengthZ", "double", "Number", "",0 + P: "MaxDampStrengthX", "double", "Number", "",0 + P: "MaxDampStrengthY", "double", "Number", "",0 + P: "MaxDampStrengthZ", "double", "Number", "",0 + P: "PreferedAngleX", "double", "Number", "",0 + P: "PreferedAngleY", "double", "Number", "",0 + P: "PreferedAngleZ", "double", "Number", "",0 + P: "LookAtProperty", "object", "", "" + P: "UpVectorProperty", "object", "", "" + P: "Show", "bool", "", "",1 + P: "NegativePercentShapeSupport", "bool", "", "",1 + P: "DefaultAttributeIndex", "int", "Integer", "",-1 + P: "Freeze", "bool", "", "",0 + P: "LODBox", "bool", "", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",0,0,0 + P: "Lcl Rotation", "Lcl Rotation", "", "A",0,0,0 + P: "Lcl Scaling", "Lcl Scaling", "", "A",1,1,1 + P: "Visibility", "Visibility", "", "A",1 + P: "Visibility Inheritance", "Visibility Inheritance", "", "",1 + } + } + } + ObjectType: "Geometry" { + Count: 1 + PropertyTemplate: "FbxMesh" { + Properties70: { + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "BBoxMin", "Vector3D", "Vector", "",0,0,0 + P: "BBoxMax", "Vector3D", "Vector", "",0,0,0 + P: "Primary Visibility", "bool", "", "",1 + P: "Casts Shadows", "bool", "", "",1 + P: "Receive Shadows", "bool", "", "",1 + } + } + } + ObjectType: "Material" { + Count: 1 + PropertyTemplate: "FbxSurfaceMaterial" { + Properties70: { + P: "ShadingModel", "KString", "", "", "Unknown" + P: "MultiLayer", "bool", "", "",0 + } + } + } + ObjectType: "Texture" { + Count: 7 + PropertyTemplate: "FbxFileTexture" { + Properties70: { + P: "TextureTypeUse", "enum", "", "",0 + P: "Texture alpha", "Number", "", "A",1 + P: "CurrentMappingType", "enum", "", "",0 + P: "WrapModeU", "enum", "", "",0 + P: "WrapModeV", "enum", "", "",0 + P: "UVSwap", "bool", "", "",0 + P: "PremultiplyAlpha", "bool", "", "",1 + P: "Translation", "Vector", "", "A",0,0,0 + P: "Rotation", "Vector", "", "A",0,0,0 + P: "Scaling", "Vector", "", "A",1,1,1 + P: "TextureRotationPivot", "Vector3D", "Vector", "",0,0,0 + P: "TextureScalingPivot", "Vector3D", "Vector", "",0,0,0 + P: "CurrentTextureBlendMode", "enum", "", "",1 + P: "UVSet", "KString", "", "", "default" + P: "UseMaterial", "bool", "", "",0 + P: "UseMipMap", "bool", "", "",0 + } + } + } + ObjectType: "Video" { + Count: 7 + PropertyTemplate: "FbxVideo" { + Properties70: { + P: "Path", "KString", "XRefUrl", "", "" + P: "RelPath", "KString", "XRefUrl", "", "" + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "ClipIn", "KTime", "Time", "",0 + P: "ClipOut", "KTime", "Time", "",0 + P: "Offset", "KTime", "Time", "",0 + P: "PlaySpeed", "double", "Number", "",0 + P: "FreeRunning", "bool", "", "",0 + P: "Loop", "bool", "", "",0 + P: "Mute", "bool", "", "",0 + P: "AccessMode", "enum", "", "",0 + P: "ImageSequence", "bool", "", "",0 + P: "ImageSequenceOffset", "int", "Integer", "",0 + P: "FrameRate", "double", "Number", "",0 + P: "LastFrame", "int", "Integer", "",0 + P: "Width", "int", "Integer", "",0 + P: "Height", "int", "Integer", "",0 + P: "StartFrame", "int", "Integer", "",0 + P: "StopFrame", "int", "Integer", "",0 + P: "InterlaceMode", "enum", "", "",0 + } + } + } +} + +; Object properties +;------------------------------------------------------------------ + +Objects: { + Geometry: 2188426094640, "Geometry::", "Mesh" { + Properties70: { + P: "Color", "ColorRGB", "Color", "",0.341176470588235,0.882352941176471,0.776470588235294 + } + Vertices: *24 { + a: -8.91135215759277,-10.98219871521,0,8.91135215759277,-10.98219871521,0,-8.91135215759277,10.98219871521,0,8.91135215759277,10.98219871521,0,-8.91135215759277,-10.98219871521,16.787576675415,8.91135215759277,-10.98219871521,16.787576675415,-8.91135215759277,10.98219871521,16.787576675415,8.91135215759277,10.98219871521,16.787576675415 + } + PolygonVertexIndex: *24 { + a: 0,2,3,-2,4,5,7,-7,0,1,5,-5,1,3,7,-6,3,2,6,-8,2,0,4,-7 + } + Edges: *12 { + a: 0,1,2,3,4,5,6,7,9,11,13,17 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *72 { + a: 0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 + } + NormalsW: *24 { + a: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "UVChannel_1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *48 { + a: 1,0,0,0,1,1,0,1,0,0,1,0,0,1,1,1,0,0,1,0,0,1,1,1,0,0,1,0,0,1,1,1,0,0,1,0,0,1,1,1,0,0,1,0,0,1,1,1 + } + UVIndex: *24 { + a: 0,2,3,1,4,5,7,6,8,9,11,10,12,13,15,14,16,17,19,18,20,21,23,22 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Model: 2187845653184, "Model::Box001", "Mesh" { + Version: 232 + Properties70: { + P: "PreRotation", "Vector3D", "Vector", "",-90,-0,0 + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",0.570660591125488,0,-0.671265125274658 + P: "MaxHandle", "int", "Integer", "UH",2 + } + Shading: T + Culling: "CullingOff" + } + Material: 2188102329504, "Material::PBR Material", "" { + Version: 102 + ShadingModel: "unknown" + MultiLayer: 0 + Properties70: { + P: "ShadingModel", "KString", "", "", "unknown" + P: "AmbientColor", "ColorRGB", "Color", "",0,1,1 + P: "DiffuseColor", "ColorRGB", "Color", "",0,1,1 + P: "SpecularColor", "ColorRGB", "Color", "",0.75,1,1 + P: "SpecularFactor", "double", "Number", "",2.25 + P: "ShininessExponent", "double", "Number", "",32 + P: "TransparencyFactor", "double", "Number", "",0 + P: "EmissiveColor", "ColorRGB", "Color", "",3.14159274101257,3.14159250259399,0 + P: "EmissiveFactor", "double", "Number", "",1 + P: "3dsMax", "Compound", "", "" + P: "3dsMax|ClassIDa", "int", "Integer", "",-804315648 + P: "3dsMax|ClassIDb", "int", "Integer", "",-1099438848 + P: "3dsMax|SuperClassID", "int", "Integer", "",3072 + P: "3dsMax|settings", "Compound", "", "" + P: "3dsMax|settings|ao_affects_diffuse", "Bool", "", "A",1 + P: "3dsMax|settings|ao_affects_reflection", "Bool", "", "A",1 + P: "3dsMax|settings|normal_flip_red", "Bool", "", "A",0 + P: "3dsMax|settings|normal_flip_green", "Bool", "", "A",0 + P: "3dsMax|main", "Compound", "", "" + P: "3dsMax|main|basecolor", "ColorAndAlpha", "", "A",0,1,1,1 + P: "3dsMax|main|base_color_map", "Reference", "", "A" + P: "3dsMax|main|metalness", "Float", "", "A",0.25 + P: "3dsMax|main|metalness_map", "Reference", "", "A" + P: "3dsMax|main|roughness", "Float", "", "A",0.5 + P: "3dsMax|main|roughness_map", "Reference", "", "A" + P: "3dsMax|main|useGlossiness", "Integer", "", "A",2 + P: "3dsMax|main|ao_map", "Reference", "", "A" + P: "3dsMax|main|bump_map_amt", "Float", "", "A",0.75 + P: "3dsMax|main|norm_map", "Reference", "", "A" + P: "3dsMax|main|emit_color", "ColorAndAlpha", "", "A",1,1,0,1 + P: "3dsMax|main|emit_color_map", "Reference", "", "A" + P: "3dsMax|main|opacity_map", "Reference", "", "A" + } + } + Video: 2188262711712, "Video::Albedo", "Clip" { + Type: "Clip" + Properties70: { + P: "Path", "KString", "XRefUrl", "", "Textures\albedo.png" + P: "RelPath", "KString", "XRefUrl", "", "Textures\albedo.png" + } + UseMipMap: 0 + Filename: "Textures\albedo.png" + RelativeFilename: "Textures\albedo.png" + } + Video: 2188262695872, "Video::Metalness", "Clip" { + Type: "Clip" + Properties70: { + P: "Path", "KString", "XRefUrl", "", "Textures\metalness.png" + P: "RelPath", "KString", "XRefUrl", "", "Textures\metalness.png" + } + UseMipMap: 0 + Filename: "Textures\metalness.png" + RelativeFilename: "Textures\metalness.png" + } + Video: 2188262686752, "Video::Roughness", "Clip" { + Type: "Clip" + Properties70: { + P: "Path", "KString", "XRefUrl", "", "Textures\roughness.png" + P: "RelPath", "KString", "XRefUrl", "", "Textures\roughness.png" + } + UseMipMap: 0 + Filename: "Textures\roughness.png" + RelativeFilename: "Textures\roughness.png" + } + Video: 2188262700672, "Video::Occlusion", "Clip" { + Type: "Clip" + Properties70: { + P: "Path", "KString", "XRefUrl", "", "Textures\occlusion.png" + P: "RelPath", "KString", "XRefUrl", "", "Textures\occlusion.png" + } + UseMipMap: 0 + Filename: "Textures\occlusion.png" + RelativeFilename: "Textures\occlusion.png" + } + Video: 2188262708832, "Video::Normal", "Clip" { + Type: "Clip" + Properties70: { + P: "Path", "KString", "XRefUrl", "", "Textures\normal.png" + P: "RelPath", "KString", "XRefUrl", "", "Textures\normal.png" + } + UseMipMap: 0 + Filename: "Textures\normal.png" + RelativeFilename: "Textures\normal.png" + } + Video: 2188262712672, "Video::Emission", "Clip" { + Type: "Clip" + Properties70: { + P: "Path", "KString", "XRefUrl", "", "Textures\emission.png" + P: "RelPath", "KString", "XRefUrl", "", "Textures\emission.png" + } + UseMipMap: 0 + Filename: "Textures\emission.png" + RelativeFilename: "Textures\emission.png" + } + Video: 2188262696352, "Video::Opacity", "Clip" { + Type: "Clip" + Properties70: { + P: "Path", "KString", "XRefUrl", "", "Textures\opacity.png" + P: "RelPath", "KString", "XRefUrl", "", "Textures\opacity.png" + } + UseMipMap: 0 + Filename: "Textures\opacity.png" + RelativeFilename: "Textures\opacity.png" + } + Texture: 2188262656992, "Texture::Albedo", "" { + Type: "TextureVideoClip" + Version: 202 + TextureName: "Texture::Albedo" + Properties70: { + P: "UVSet", "KString", "", "", "UVChannel_1" + P: "UseMaterial", "bool", "", "",1 + } + Media: "Video::Albedo" + FileName: "Textures\albedo.png" + RelativeFilename: "Textures\albedo.png" + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + } + Texture: 2188262678592, "Texture::Metalness", "" { + Type: "TextureVideoClip" + Version: 202 + TextureName: "Texture::Metalness" + Properties70: { + P: "UVSet", "KString", "", "", "UVChannel_1" + P: "UseMaterial", "bool", "", "",1 + } + Media: "Video::Metalness" + FileName: "Textures\metalness.png" + RelativeFilename: "Textures\metalness.png" + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + } + Texture: 2188262682432, "Texture::Roughness", "" { + Type: "TextureVideoClip" + Version: 202 + TextureName: "Texture::Roughness" + Properties70: { + P: "UVSet", "KString", "", "", "UVChannel_1" + P: "UseMaterial", "bool", "", "",1 + } + Media: "Video::Roughness" + FileName: "Textures\roughness.png" + RelativeFilename: "Textures\roughness.png" + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + } + Texture: 2188262656032, "Texture::Occlusion", "" { + Type: "TextureVideoClip" + Version: 202 + TextureName: "Texture::Occlusion" + Properties70: { + P: "UVSet", "KString", "", "", "UVChannel_1" + P: "UseMaterial", "bool", "", "",1 + } + Media: "Video::Occlusion" + FileName: "Textures\occlusion.png" + RelativeFilename: "Textures\occlusion.png" + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + } + Texture: 2188262659392, "Texture::Normal", "" { + Type: "TextureVideoClip" + Version: 202 + TextureName: "Texture::Normal" + Properties70: { + P: "UVSet", "KString", "", "", "UVChannel_1" + P: "UseMaterial", "bool", "", "",1 + } + Media: "Video::Normal" + FileName: "Textures\normal.png" + RelativeFilename: "Textures\normal.png" + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + } + Texture: 2188262700192, "Texture::Emission", "" { + Type: "TextureVideoClip" + Version: 202 + TextureName: "Texture::Emission" + Properties70: { + P: "UVSet", "KString", "", "", "UVChannel_1" + P: "UseMaterial", "bool", "", "",1 + } + Media: "Video::Emission" + FileName: "Textures\emission.png" + RelativeFilename: "Textures\emission.png" + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + } + Texture: 2188262684832, "Texture::Opacity", "" { + Type: "TextureVideoClip" + Version: 202 + TextureName: "Texture::Opacity" + Properties70: { + P: "UVSet", "KString", "", "", "UVChannel_1" + P: "UseMaterial", "bool", "", "",1 + } + Media: "Video::Opacity" + FileName: "Textures\opacity.png" + RelativeFilename: "Textures\opacity.png" + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + } +} + +; Object connections +;------------------------------------------------------------------ + +Connections: { + + ;Model::Box001, Model::RootNode + C: "OO",2187845653184,0 + + ;Geometry::, Model::Box001 + C: "OO",2188426094640,2187845653184 + + ;Material::PBR Material, Model::Box001 + C: "OO",2188102329504,2187845653184 + + ;Texture::Albedo, Material::PBR Material + C: "OP",2188262656992,2188102329504, "3dsMax|main|base_color_map" + + ;Texture::Metalness, Material::PBR Material + C: "OP",2188262678592,2188102329504, "3dsMax|main|metalness_map" + + ;Texture::Roughness, Material::PBR Material + C: "OP",2188262682432,2188102329504, "3dsMax|main|roughness_map" + + ;Texture::Occlusion, Material::PBR Material + C: "OP",2188262656032,2188102329504, "3dsMax|main|ao_map" + + ;Texture::Normal, Material::PBR Material + C: "OP",2188262659392,2188102329504, "3dsMax|main|norm_map" + + ;Texture::Emission, Material::PBR Material + C: "OP",2188262700192,2188102329504, "3dsMax|main|emit_color_map" + + ;Texture::Opacity, Material::PBR Material + C: "OP",2188262684832,2188102329504, "3dsMax|main|opacity_map" + + ;Video::Albedo, Texture::Albedo + C: "OO",2188262711712,2188262656992 + + ;Video::Metalness, Texture::Metalness + C: "OO",2188262695872,2188262678592 + + ;Video::Roughness, Texture::Roughness + C: "OO",2188262686752,2188262682432 + + ;Video::Occlusion, Texture::Occlusion + C: "OO",2188262700672,2188262656032 + + ;Video::Normal, Texture::Normal + C: "OO",2188262708832,2188262659392 + + ;Video::Emission, Texture::Emission + C: "OO",2188262712672,2188262700192 + + ;Video::Opacity, Texture::Opacity + C: "OO",2188262696352,2188262684832 +} diff --git a/test/models/FBX/maxPbrMaterial_specGloss.fbx b/test/models/FBX/maxPbrMaterial_specGloss.fbx new file mode 100644 index 000000000..83a4432c9 --- /dev/null +++ b/test/models/FBX/maxPbrMaterial_specGloss.fbx @@ -0,0 +1,618 @@ +; FBX 7.7.0 project file +; ---------------------------------------------------- + +FBXHeaderExtension: { + FBXHeaderVersion: 1004 + FBXVersion: 7700 + CreationTimeStamp: { + Version: 1000 + Year: 2020 + Month: 12 + Day: 1 + Hour: 11 + Minute: 50 + Second: 44 + Millisecond: 89 + } + Creator: "FBX SDK/FBX Plugins version 2020.0.1" + OtherFlags: { + TCDefinition: 127 + } + SceneInfo: "SceneInfo::GlobalInfo", "UserData" { + Type: "UserData" + Version: 100 + MetaData: { + Version: 100 + Title: "" + Subject: "" + Author: "" + Keywords: "" + Revision: "" + Comment: "" + } + Properties70: { + P: "DocumentUrl", "KString", "Url", "", "C:\3ds Max 2021\maxPbrMaterial_specGloss.fbx" + P: "SrcDocumentUrl", "KString", "Url", "", "C:\3ds Max 2021\maxPbrMaterial_specGloss.fbx" + P: "Original", "Compound", "", "" + P: "Original|ApplicationVendor", "KString", "", "", "Autodesk" + P: "Original|ApplicationName", "KString", "", "", "3ds Max" + P: "Original|ApplicationVersion", "KString", "", "", "2021" + P: "Original|DateTime_GMT", "DateTime", "", "", "01/12/2020 11:50:44.088" + P: "Original|FileName", "KString", "", "", "C:\3ds Max 2021\maxPbrMaterial_specGloss.fbx" + P: "LastSaved", "Compound", "", "" + P: "LastSaved|ApplicationVendor", "KString", "", "", "Autodesk" + P: "LastSaved|ApplicationName", "KString", "", "", "3ds Max" + P: "LastSaved|ApplicationVersion", "KString", "", "", "2021" + P: "LastSaved|DateTime_GMT", "DateTime", "", "", "01/12/2020 11:50:44.088" + P: "Original|ApplicationActiveProject", "KString", "", "", "C:\3ds Max 2021" + P: "Original|ApplicationNativeFile", "KString", "", "", "C:\3ds Max 2021\MaxPbrMaterial2.max" + } + } +} +GlobalSettings: { + Version: 1000 + Properties70: { + P: "UpAxis", "int", "Integer", "",1 + P: "UpAxisSign", "int", "Integer", "",1 + P: "FrontAxis", "int", "Integer", "",2 + P: "FrontAxisSign", "int", "Integer", "",1 + P: "CoordAxis", "int", "Integer", "",0 + P: "CoordAxisSign", "int", "Integer", "",1 + P: "OriginalUpAxis", "int", "Integer", "",2 + P: "OriginalUpAxisSign", "int", "Integer", "",1 + P: "UnitScaleFactor", "double", "Number", "",100 + P: "OriginalUnitScaleFactor", "double", "Number", "",100.00000066 + P: "AmbientColor", "ColorRGB", "Color", "",0,0,0 + P: "DefaultCamera", "KString", "", "", "Producer Perspective" + P: "TimeMode", "enum", "", "",6 + P: "TimeProtocol", "enum", "", "",2 + P: "SnapOnFrameMode", "enum", "", "",0 + P: "TimeSpanStart", "KTime", "Time", "",0 + P: "TimeSpanStop", "KTime", "Time", "",153953860000 + P: "CustomFrameRate", "double", "Number", "",-1 + P: "TimeMarker", "Compound", "", "" + P: "CurrentTimeMarker", "int", "Integer", "",-1 + } +} + +; Documents Description +;------------------------------------------------------------------ + +Documents: { + Count: 1 + Document: 2188636931248, "", "Scene" { + Properties70: { + P: "SourceObject", "object", "", "" + P: "ActiveAnimStackName", "KString", "", "", "" + } + RootNode: 0 + } +} + +; Document References +;------------------------------------------------------------------ + +References: { +} + +; Object definitions +;------------------------------------------------------------------ + +Definitions: { + Version: 100 + Count: 18 + ObjectType: "GlobalSettings" { + Count: 1 + } + ObjectType: "Model" { + Count: 1 + PropertyTemplate: "FbxNode" { + Properties70: { + P: "QuaternionInterpolate", "enum", "", "",0 + P: "RotationOffset", "Vector3D", "Vector", "",0,0,0 + P: "RotationPivot", "Vector3D", "Vector", "",0,0,0 + P: "ScalingOffset", "Vector3D", "Vector", "",0,0,0 + P: "ScalingPivot", "Vector3D", "Vector", "",0,0,0 + P: "TranslationActive", "bool", "", "",0 + P: "TranslationMin", "Vector3D", "Vector", "",0,0,0 + P: "TranslationMax", "Vector3D", "Vector", "",0,0,0 + P: "TranslationMinX", "bool", "", "",0 + P: "TranslationMinY", "bool", "", "",0 + P: "TranslationMinZ", "bool", "", "",0 + P: "TranslationMaxX", "bool", "", "",0 + P: "TranslationMaxY", "bool", "", "",0 + P: "TranslationMaxZ", "bool", "", "",0 + P: "RotationOrder", "enum", "", "",0 + P: "RotationSpaceForLimitOnly", "bool", "", "",0 + P: "RotationStiffnessX", "double", "Number", "",0 + P: "RotationStiffnessY", "double", "Number", "",0 + P: "RotationStiffnessZ", "double", "Number", "",0 + P: "AxisLen", "double", "Number", "",10 + P: "PreRotation", "Vector3D", "Vector", "",0,0,0 + P: "PostRotation", "Vector3D", "Vector", "",0,0,0 + P: "RotationActive", "bool", "", "",0 + P: "RotationMin", "Vector3D", "Vector", "",0,0,0 + P: "RotationMax", "Vector3D", "Vector", "",0,0,0 + P: "RotationMinX", "bool", "", "",0 + P: "RotationMinY", "bool", "", "",0 + P: "RotationMinZ", "bool", "", "",0 + P: "RotationMaxX", "bool", "", "",0 + P: "RotationMaxY", "bool", "", "",0 + P: "RotationMaxZ", "bool", "", "",0 + P: "InheritType", "enum", "", "",0 + P: "ScalingActive", "bool", "", "",0 + P: "ScalingMin", "Vector3D", "Vector", "",0,0,0 + P: "ScalingMax", "Vector3D", "Vector", "",1,1,1 + P: "ScalingMinX", "bool", "", "",0 + P: "ScalingMinY", "bool", "", "",0 + P: "ScalingMinZ", "bool", "", "",0 + P: "ScalingMaxX", "bool", "", "",0 + P: "ScalingMaxY", "bool", "", "",0 + P: "ScalingMaxZ", "bool", "", "",0 + P: "GeometricTranslation", "Vector3D", "Vector", "",0,0,0 + P: "GeometricRotation", "Vector3D", "Vector", "",0,0,0 + P: "GeometricScaling", "Vector3D", "Vector", "",1,1,1 + P: "MinDampRangeX", "double", "Number", "",0 + P: "MinDampRangeY", "double", "Number", "",0 + P: "MinDampRangeZ", "double", "Number", "",0 + P: "MaxDampRangeX", "double", "Number", "",0 + P: "MaxDampRangeY", "double", "Number", "",0 + P: "MaxDampRangeZ", "double", "Number", "",0 + P: "MinDampStrengthX", "double", "Number", "",0 + P: "MinDampStrengthY", "double", "Number", "",0 + P: "MinDampStrengthZ", "double", "Number", "",0 + P: "MaxDampStrengthX", "double", "Number", "",0 + P: "MaxDampStrengthY", "double", "Number", "",0 + P: "MaxDampStrengthZ", "double", "Number", "",0 + P: "PreferedAngleX", "double", "Number", "",0 + P: "PreferedAngleY", "double", "Number", "",0 + P: "PreferedAngleZ", "double", "Number", "",0 + P: "LookAtProperty", "object", "", "" + P: "UpVectorProperty", "object", "", "" + P: "Show", "bool", "", "",1 + P: "NegativePercentShapeSupport", "bool", "", "",1 + P: "DefaultAttributeIndex", "int", "Integer", "",-1 + P: "Freeze", "bool", "", "",0 + P: "LODBox", "bool", "", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",0,0,0 + P: "Lcl Rotation", "Lcl Rotation", "", "A",0,0,0 + P: "Lcl Scaling", "Lcl Scaling", "", "A",1,1,1 + P: "Visibility", "Visibility", "", "A",1 + P: "Visibility Inheritance", "Visibility Inheritance", "", "",1 + } + } + } + ObjectType: "Geometry" { + Count: 1 + PropertyTemplate: "FbxMesh" { + Properties70: { + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "BBoxMin", "Vector3D", "Vector", "",0,0,0 + P: "BBoxMax", "Vector3D", "Vector", "",0,0,0 + P: "Primary Visibility", "bool", "", "",1 + P: "Casts Shadows", "bool", "", "",1 + P: "Receive Shadows", "bool", "", "",1 + } + } + } + ObjectType: "Material" { + Count: 1 + PropertyTemplate: "FbxSurfaceMaterial" { + Properties70: { + P: "ShadingModel", "KString", "", "", "Unknown" + P: "MultiLayer", "bool", "", "",0 + } + } + } + ObjectType: "Texture" { + Count: 7 + PropertyTemplate: "FbxFileTexture" { + Properties70: { + P: "TextureTypeUse", "enum", "", "",0 + P: "Texture alpha", "Number", "", "A",1 + P: "CurrentMappingType", "enum", "", "",0 + P: "WrapModeU", "enum", "", "",0 + P: "WrapModeV", "enum", "", "",0 + P: "UVSwap", "bool", "", "",0 + P: "PremultiplyAlpha", "bool", "", "",1 + P: "Translation", "Vector", "", "A",0,0,0 + P: "Rotation", "Vector", "", "A",0,0,0 + P: "Scaling", "Vector", "", "A",1,1,1 + P: "TextureRotationPivot", "Vector3D", "Vector", "",0,0,0 + P: "TextureScalingPivot", "Vector3D", "Vector", "",0,0,0 + P: "CurrentTextureBlendMode", "enum", "", "",1 + P: "UVSet", "KString", "", "", "default" + P: "UseMaterial", "bool", "", "",0 + P: "UseMipMap", "bool", "", "",0 + } + } + } + ObjectType: "Video" { + Count: 7 + PropertyTemplate: "FbxVideo" { + Properties70: { + P: "Path", "KString", "XRefUrl", "", "" + P: "RelPath", "KString", "XRefUrl", "", "" + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "ClipIn", "KTime", "Time", "",0 + P: "ClipOut", "KTime", "Time", "",0 + P: "Offset", "KTime", "Time", "",0 + P: "PlaySpeed", "double", "Number", "",0 + P: "FreeRunning", "bool", "", "",0 + P: "Loop", "bool", "", "",0 + P: "Mute", "bool", "", "",0 + P: "AccessMode", "enum", "", "",0 + P: "ImageSequence", "bool", "", "",0 + P: "ImageSequenceOffset", "int", "Integer", "",0 + P: "FrameRate", "double", "Number", "",0 + P: "LastFrame", "int", "Integer", "",0 + P: "Width", "int", "Integer", "",0 + P: "Height", "int", "Integer", "",0 + P: "StartFrame", "int", "Integer", "",0 + P: "StopFrame", "int", "Integer", "",0 + P: "InterlaceMode", "enum", "", "",0 + } + } + } +} + +; Object properties +;------------------------------------------------------------------ + +Objects: { + Geometry: 2188631051296, "Geometry::", "Mesh" { + Properties70: { + P: "Color", "ColorRGB", "Color", "",0.341176470588235,0.882352941176471,0.776470588235294 + } + Vertices: *24 { + a: -8.91135215759277,-10.98219871521,0,8.91135215759277,-10.98219871521,0,-8.91135215759277,10.98219871521,0,8.91135215759277,10.98219871521,0,-8.91135215759277,-10.98219871521,16.787576675415,8.91135215759277,-10.98219871521,16.787576675415,-8.91135215759277,10.98219871521,16.787576675415,8.91135215759277,10.98219871521,16.787576675415 + } + PolygonVertexIndex: *24 { + a: 0,2,3,-2,4,5,7,-7,0,1,5,-5,1,3,7,-6,3,2,6,-8,2,0,4,-7 + } + Edges: *12 { + a: 0,1,2,3,4,5,6,7,9,11,13,17 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *72 { + a: 0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 + } + NormalsW: *24 { + a: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "UVChannel_1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *48 { + a: 1,0,0,0,1,1,0,1,0,0,1,0,0,1,1,1,0,0,1,0,0,1,1,1,0,0,1,0,0,1,1,1,0,0,1,0,0,1,1,1,0,0,1,0,0,1,1,1 + } + UVIndex: *24 { + a: 0,2,3,1,4,5,7,6,8,9,11,10,12,13,15,14,16,17,19,18,20,21,23,22 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Model: 2188763600256, "Model::Box001", "Mesh" { + Version: 232 + Properties70: { + P: "PreRotation", "Vector3D", "Vector", "",-90,-0,0 + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",0.570660591125488,0,-0.671265125274658 + P: "MaxHandle", "int", "Integer", "UH",2 + } + Shading: T + Culling: "CullingOff" + } + Material: 2188661245104, "Material::02 - Default", "" { + Version: 102 + ShadingModel: "unknown" + MultiLayer: 0 + Properties70: { + P: "ShadingModel", "KString", "", "", "unknown" + P: "AmbientColor", "ColorRGB", "Color", "",0,1,1 + P: "DiffuseColor", "ColorRGB", "Color", "",0,1,1 + P: "SpecularColor", "ColorRGB", "Color", "",1,1,1 + P: "SpecularFactor", "double", "Number", "",2 + P: "ShininessExponent", "double", "Number", "",1024 + P: "TransparencyFactor", "double", "Number", "",0 + P: "EmissiveColor", "ColorRGB", "Color", "",3.14159274101257,0,3.14159321784973 + P: "EmissiveFactor", "double", "Number", "",1 + P: "3dsMax", "Compound", "", "" + P: "3dsMax|ClassIDa", "int", "Integer", "",-804315648 + P: "3dsMax|ClassIDb", "int", "Integer", "",31173939 + P: "3dsMax|SuperClassID", "int", "Integer", "",3072 + P: "3dsMax|settings", "Compound", "", "" + P: "3dsMax|settings|ao_affects_diffuse", "Bool", "", "A",1 + P: "3dsMax|settings|ao_affects_reflection", "Bool", "", "A",1 + P: "3dsMax|settings|normal_flip_red", "Bool", "", "A",0 + P: "3dsMax|settings|normal_flip_green", "Bool", "", "A",0 + P: "3dsMax|main", "Compound", "", "" + P: "3dsMax|main|basecolor", "ColorAndAlpha", "", "A",0,1,1,1 + P: "3dsMax|main|base_color_map", "Reference", "", "A" + P: "3dsMax|main|Specular", "ColorAndAlpha", "", "A",1,1,0,1 + P: "3dsMax|main|specular_map", "Reference", "", "A" + P: "3dsMax|main|glossiness", "Float", "", "A",0.33 + P: "3dsMax|main|glossiness_map", "Reference", "", "A" + P: "3dsMax|main|useGlossiness", "Integer", "", "A",1 + P: "3dsMax|main|ao_map", "Reference", "", "A" + P: "3dsMax|main|bump_map_amt", "Float", "", "A",0.66 + P: "3dsMax|main|norm_map", "Reference", "", "A" + P: "3dsMax|main|emit_color", "ColorAndAlpha", "", "A",1,0,1,1 + P: "3dsMax|main|emit_color_map", "Reference", "", "A" + P: "3dsMax|main|opacity_map", "Reference", "", "A" + } + } + Video: 2188262470272, "Video::Albedo", "Clip" { + Type: "Clip" + Properties70: { + P: "Path", "KString", "XRefUrl", "", "Textures\albedo.png" + P: "RelPath", "KString", "XRefUrl", "", "Textures\albedo.png" + } + UseMipMap: 0 + Filename: "Textures\albedo.png" + RelativeFilename: "Textures\albedo.png" + } + Video: 2188262470752, "Video::Specular", "Clip" { + Type: "Clip" + Properties70: { + P: "Path", "KString", "XRefUrl", "", "Textures\specular.png" + P: "RelPath", "KString", "XRefUrl", "", "Textures\specular.png" + } + UseMipMap: 0 + Filename: "Textures\specular.png" + RelativeFilename: "Textures\specular.png" + } + Video: 2188262476032, "Video::Glossiness", "Clip" { + Type: "Clip" + Properties70: { + P: "Path", "KString", "XRefUrl", "", "Textures\glossiness.png" + P: "RelPath", "KString", "XRefUrl", "", "Textures\glossiness.png" + } + UseMipMap: 0 + Filename: "Textures\glossiness.png" + RelativeFilename: "Textures\glossiness.png" + } + Video: 2188262483232, "Video::Occlusion", "Clip" { + Type: "Clip" + Properties70: { + P: "Path", "KString", "XRefUrl", "", "Textures\occlusion.png" + P: "RelPath", "KString", "XRefUrl", "", "Textures\occlusion.png" + } + UseMipMap: 0 + Filename: "Textures\occlusion.png" + RelativeFilename: "Textures\occlusion.png" + } + Video: 2188262486112, "Video::Normal", "Clip" { + Type: "Clip" + Properties70: { + P: "Path", "KString", "XRefUrl", "", "Textures\normal.png" + P: "RelPath", "KString", "XRefUrl", "", "Textures\normal.png" + } + UseMipMap: 0 + Filename: "Textures\normal.png" + RelativeFilename: "Textures\normal.png" + } + Video: 2188262486592, "Video::Emission", "Clip" { + Type: "Clip" + Properties70: { + P: "Path", "KString", "XRefUrl", "", "Textures\emission.png" + P: "RelPath", "KString", "XRefUrl", "", "Textures\emission.png" + } + UseMipMap: 0 + Filename: "Textures\emission.png" + RelativeFilename: "Textures\emission.png" + } + Video: 2188262687712, "Video::Opacity", "Clip" { + Type: "Clip" + Properties70: { + P: "Path", "KString", "XRefUrl", "", "Textures\opacity.png" + P: "RelPath", "KString", "XRefUrl", "", "Textures\opacity.png" + } + UseMipMap: 0 + Filename: "Textures\opacity.png" + RelativeFilename: "Textures\opacity.png" + } + Texture: 2188262484672, "Texture::Albedo", "" { + Type: "TextureVideoClip" + Version: 202 + TextureName: "Texture::Albedo" + Properties70: { + P: "UVSet", "KString", "", "", "UVChannel_1" + P: "UseMaterial", "bool", "", "",1 + } + Media: "Video::Albedo" + FileName: "Textures\albedo.png" + RelativeFilename: "Textures\albedo.png" + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + } + Texture: 2188262499552, "Texture::Specular", "" { + Type: "TextureVideoClip" + Version: 202 + TextureName: "Texture::Specular" + Properties70: { + P: "UVSet", "KString", "", "", "UVChannel_1" + P: "UseMaterial", "bool", "", "",1 + } + Media: "Video::Specular" + FileName: "Textures\specular.png" + RelativeFilename: "Textures\specular.png" + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + } + Texture: 2188262475552, "Texture::Glossiness", "" { + Type: "TextureVideoClip" + Version: 202 + TextureName: "Texture::Glossiness" + Properties70: { + P: "UVSet", "KString", "", "", "UVChannel_1" + P: "UseMaterial", "bool", "", "",1 + } + Media: "Video::Glossiness" + FileName: "Textures\glossiness.png" + RelativeFilename: "Textures\glossiness.png" + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + } + Texture: 2188262480352, "Texture::Occlusion", "" { + Type: "TextureVideoClip" + Version: 202 + TextureName: "Texture::Occlusion" + Properties70: { + P: "UVSet", "KString", "", "", "UVChannel_1" + P: "UseMaterial", "bool", "", "",1 + } + Media: "Video::Occlusion" + FileName: "Textures\occlusion.png" + RelativeFilename: "Textures\occlusion.png" + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + } + Texture: 2188262482752, "Texture::Normal", "" { + Type: "TextureVideoClip" + Version: 202 + TextureName: "Texture::Normal" + Properties70: { + P: "UVSet", "KString", "", "", "UVChannel_1" + P: "UseMaterial", "bool", "", "",1 + } + Media: "Video::Normal" + FileName: "Textures\normal.png" + RelativeFilename: "Textures\normal.png" + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + } + Texture: 2188262481312, "Texture::Emission", "" { + Type: "TextureVideoClip" + Version: 202 + TextureName: "Texture::Emission" + Properties70: { + P: "UVSet", "KString", "", "", "UVChannel_1" + P: "UseMaterial", "bool", "", "",1 + } + Media: "Video::Emission" + FileName: "Textures\emission.png" + RelativeFilename: "Textures\emission.png" + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + } + Texture: 2188262469792, "Texture::Opacity", "" { + Type: "TextureVideoClip" + Version: 202 + TextureName: "Texture::Opacity" + Properties70: { + P: "UVSet", "KString", "", "", "UVChannel_1" + P: "UseMaterial", "bool", "", "",1 + } + Media: "Video::Opacity" + FileName: "Textures\opacity.png" + RelativeFilename: "Textures\opacity.png" + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + } +} + +; Object connections +;------------------------------------------------------------------ + +Connections: { + + ;Model::Box001, Model::RootNode + C: "OO",2188763600256,0 + + ;Geometry::, Model::Box001 + C: "OO",2188631051296,2188763600256 + + ;Material::02 - Default, Model::Box001 + C: "OO",2188661245104,2188763600256 + + ;Texture::Albedo, Material::02 - Default + C: "OP",2188262484672,2188661245104, "3dsMax|main|base_color_map" + + ;Texture::Specular, Material::02 - Default + C: "OP",2188262499552,2188661245104, "3dsMax|main|specular_map" + + ;Texture::Glossiness, Material::02 - Default + C: "OP",2188262475552,2188661245104, "3dsMax|main|glossiness_map" + + ;Texture::Occlusion, Material::02 - Default + C: "OP",2188262480352,2188661245104, "3dsMax|main|ao_map" + + ;Texture::Normal, Material::02 - Default + C: "OP",2188262482752,2188661245104, "3dsMax|main|norm_map" + + ;Texture::Emission, Material::02 - Default + C: "OP",2188262481312,2188661245104, "3dsMax|main|emit_color_map" + + ;Texture::Opacity, Material::02 - Default + C: "OP",2188262469792,2188661245104, "3dsMax|main|opacity_map" + + ;Video::Albedo, Texture::Albedo + C: "OO",2188262470272,2188262484672 + + ;Video::Specular, Texture::Specular + C: "OO",2188262470752,2188262499552 + + ;Video::Glossiness, Texture::Glossiness + C: "OO",2188262476032,2188262475552 + + ;Video::Occlusion, Texture::Occlusion + C: "OO",2188262483232,2188262480352 + + ;Video::Normal, Texture::Normal + C: "OO",2188262486112,2188262482752 + + ;Video::Emission, Texture::Emission + C: "OO",2188262486592,2188262481312 + + ;Video::Opacity, Texture::Opacity + C: "OO",2188262687712,2188262469792 +} diff --git a/test/unit/utFBXImporterExporter.cpp b/test/unit/utFBXImporterExporter.cpp index 2f1ea79e8..332bfc1ec 100644 --- a/test/unit/utFBXImporterExporter.cpp +++ b/test/unit/utFBXImporterExporter.cpp @@ -317,3 +317,109 @@ TEST_F(utFBXImporterExporter, importCubesWithOutOfRangeFloat) { ASSERT_NE(nullptr, scene); ASSERT_TRUE(scene->mRootNode); } + +TEST_F(utFBXImporterExporter, importMaxPbrMaterialsMetalRoughness) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/maxPbrMaterial_metalRough.fbx", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); + ASSERT_TRUE(scene->mRootNode); + + ASSERT_EQ(scene->mNumMaterials, 1); + const aiMaterial* mat = scene->mMaterials[0]; + aiString texture; + ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_BASE_COLOR, 0), texture), AI_SUCCESS); + EXPECT_EQ(texture, aiString("Textures\\albedo.png")); + ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_METALNESS, 0), texture), AI_SUCCESS); + EXPECT_EQ(texture, aiString("Textures\\metalness.png")); + ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_EMISSION_COLOR, 0), texture), AI_SUCCESS); + EXPECT_EQ(texture, aiString("Textures\\emission.png")); + ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_NORMAL_CAMERA, 0), texture), AI_SUCCESS); + EXPECT_EQ(texture, aiString("Textures\\normal.png")); + ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE_ROUGHNESS, 0), texture), AI_SUCCESS); + EXPECT_EQ(texture, aiString("Textures\\roughness.png")); + ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_AMBIENT_OCCLUSION, 0), texture), AI_SUCCESS); + EXPECT_EQ(texture, aiString("Textures\\occlusion.png")); + ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_OPACITY, 0), texture), AI_SUCCESS); + EXPECT_EQ(texture, aiString("Textures\\opacity.png")); + + // The material contains values for standard properties (e.g. SpecularColor), where 3ds Max has presumably + // used formulas to map the Pbr values into the standard material model. However, the pbr values themselves + // are available in the material as untyped "raw" properties. We check that these are correctly parsed: + + aiColor4D baseColor; + ASSERT_EQ(mat->Get("$raw.3dsMax|main|basecolor", aiTextureType_NONE, 0, baseColor), aiReturn_SUCCESS); + EXPECT_EQ(baseColor, aiColor4D(0, 1, 1, 1)); + + float metalness; + ASSERT_EQ(mat->Get("$raw.3dsMax|main|metalness", aiTextureType_NONE, 0, metalness), aiReturn_SUCCESS); + EXPECT_EQ(metalness, 0.25f); + + float roughness; + ASSERT_EQ(mat->Get("$raw.3dsMax|main|roughness", aiTextureType_NONE, 0, roughness), aiReturn_SUCCESS); + EXPECT_EQ(roughness, 0.5f); + + int useGlossiness; + ASSERT_EQ(mat->Get("$raw.3dsMax|main|useGlossiness", aiTextureType_NONE, 0, useGlossiness), aiReturn_SUCCESS); + EXPECT_EQ(useGlossiness, 2); // 1 = Roughness map is glossiness, 2 = Roughness map is roughness. + + float bumpMapAmt; // Presumably amount. + ASSERT_EQ(mat->Get("$raw.3dsMax|main|bump_map_amt", aiTextureType_NONE, 0, bumpMapAmt), aiReturn_SUCCESS); + EXPECT_EQ(bumpMapAmt, 0.75f); + + aiColor4D emitColor; + ASSERT_EQ(mat->Get("$raw.3dsMax|main|emit_color", aiTextureType_NONE, 0, emitColor), aiReturn_SUCCESS); + EXPECT_EQ(emitColor, aiColor4D(1, 1, 0, 1)); +} + +TEST_F(utFBXImporterExporter, importMaxPbrMaterialsSpecularGloss) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/maxPbrMaterial_specGloss.fbx", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); + ASSERT_TRUE(scene->mRootNode); + + ASSERT_EQ(scene->mNumMaterials, 1); + const aiMaterial* mat = scene->mMaterials[0]; + aiString texture; + ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_BASE_COLOR, 0), texture), AI_SUCCESS); + EXPECT_EQ(texture, aiString("Textures\\albedo.png")); + ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_SPECULAR, 0), texture), AI_SUCCESS); + EXPECT_EQ(texture, aiString("Textures\\specular.png")); + ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_EMISSION_COLOR, 0), texture), AI_SUCCESS); + EXPECT_EQ(texture, aiString("Textures\\emission.png")); + ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_NORMAL_CAMERA, 0), texture), AI_SUCCESS); + EXPECT_EQ(texture, aiString("Textures\\normal.png")); + ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_SHININESS, 0), texture), AI_SUCCESS); + EXPECT_EQ(texture, aiString("Textures\\glossiness.png")); + ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_AMBIENT_OCCLUSION, 0), texture), AI_SUCCESS); + EXPECT_EQ(texture, aiString("Textures\\occlusion.png")); + ASSERT_EQ(mat->Get(AI_MATKEY_TEXTURE(aiTextureType_OPACITY, 0), texture), AI_SUCCESS); + EXPECT_EQ(texture, aiString("Textures\\opacity.png")); + + // The material contains values for standard properties (e.g. SpecularColor), where 3ds Max has presumably + // used formulas to map the Pbr values into the standard material model. However, the pbr values themselves + // are available in the material as untyped "raw" properties. We check that these are correctly parsed: + + aiColor4D baseColor; + ASSERT_EQ(mat->Get("$raw.3dsMax|main|basecolor", aiTextureType_NONE, 0, baseColor), aiReturn_SUCCESS); + EXPECT_EQ(baseColor, aiColor4D(0, 1, 1, 1)); + + aiColor4D specular; + ASSERT_EQ(mat->Get("$raw.3dsMax|main|Specular", aiTextureType_NONE, 0, specular), aiReturn_SUCCESS); + EXPECT_EQ(specular, aiColor4D(1, 1, 0, 1)); + + float glossiness; + ASSERT_EQ(mat->Get("$raw.3dsMax|main|glossiness", aiTextureType_NONE, 0, glossiness), aiReturn_SUCCESS); + EXPECT_EQ(glossiness, 0.33f); + + int useGlossiness; + ASSERT_EQ(mat->Get("$raw.3dsMax|main|useGlossiness", aiTextureType_NONE, 0, useGlossiness), aiReturn_SUCCESS); + EXPECT_EQ(useGlossiness, 1); // 1 = Glossiness map is glossiness, 2 = Glossiness map is roughness. + + float bumpMapAmt; // Presumably amount. + ASSERT_EQ(mat->Get("$raw.3dsMax|main|bump_map_amt", aiTextureType_NONE, 0, bumpMapAmt), aiReturn_SUCCESS); + EXPECT_EQ(bumpMapAmt, 0.66f); + + aiColor4D emitColor; + ASSERT_EQ(mat->Get("$raw.3dsMax|main|emit_color", aiTextureType_NONE, 0, emitColor), aiReturn_SUCCESS); + EXPECT_EQ(emitColor, aiColor4D(1, 0, 1, 1)); +}