From ed9204ab1b754d3ff7a786bfdb8e4007166c0afa Mon Sep 17 00:00:00 2001 From: attila-barsi Date: Mon, 24 Mar 2014 11:46:36 +0100 Subject: [PATCH 1/2] Initial version for FBX layered textures. Fixed assert during parsing UDP3DSMAX. --- code/FBXConverter.cpp | 111 +++++++++++++++++++++++++++++++++++++++++- code/FBXDocument.cpp | 5 +- code/FBXDocument.h | 72 ++++++++++++++++++++++++++- code/FBXMaterial.cpp | 75 +++++++++++++++++++++++++--- 4 files changed, 251 insertions(+), 12 deletions(-) diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index d08dc3dce..9f2b70b7f 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -23,7 +23,7 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT @@ -766,6 +766,7 @@ private: // find user defined properties (3ds Max) data->Set(index++, "UserProperties", aiString(PropertyGet(props, "UDP3DSMAX", ""))); + unparsedProperties.erase("UDP3DSMAX"); // preserve the info that a node was marked as Null node in the original file. data->Set(index++, "IsNull", model.IsNull() ? true : false); @@ -1439,6 +1440,7 @@ private: // texture assignments SetTextureProperties(out_mat,material.Textures()); + SetTextureProperties(out_mat,material.LayeredTextures()); return static_cast(materials.size() - 1); } @@ -1538,6 +1540,99 @@ private: out_mat->AddProperty(&uvIndex,1,_AI_MATKEY_UVWSRC_BASE,target,0); } + // ------------------------------------------------------------------------------------------------ + void TrySetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, + const std::string& propName, + aiTextureType target) + { + LayeredTextureMap::const_iterator it = layeredTextures.find(propName); + if(it == layeredTextures.end()) { + return; + } + + const Texture* const tex = (*it).second->getTexture(); + + aiString path; + path.Set(tex->RelativeFilename()); + + out_mat->AddProperty(&path,_AI_MATKEY_TEXTURE_BASE,target,0); + + aiUVTransform uvTrafo; + // XXX handle all kinds of UV transformations + uvTrafo.mScaling = tex->UVScaling(); + uvTrafo.mTranslation = tex->UVTranslation(); + out_mat->AddProperty(&uvTrafo,1,_AI_MATKEY_UVTRANSFORM_BASE,target,0); + + const PropertyTable& props = tex->Props(); + + int uvIndex = 0; + + bool ok; + const std::string& uvSet = PropertyGet(props,"UVSet",ok); + if(ok) { + // "default" is the name which usually appears in the FbxFileTexture template + if(uvSet != "default" && uvSet.length()) { + // this is a bit awkward - we need to find a mesh that uses this + // material and scan its UV channels for the given UV name because + // assimp references UV channels by index, not by name. + + // XXX: the case that UV channels may appear in different orders + // in meshes is unhandled. A possible solution would be to sort + // the UV channels alphabetically, but this would have the side + // effect that the primary (first) UV channel would sometimes + // be moved, causing trouble when users read only the first + // UV channel and ignore UV channel assignments altogether. + + const unsigned int matIndex = static_cast(std::distance(materials.begin(), + std::find(materials.begin(),materials.end(),out_mat) + )); + + uvIndex = -1; + BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) { + const MeshGeometry* const mesh = dynamic_cast (v.first); + if(!mesh) { + continue; + } + + const MatIndexArray& mats = mesh->GetMaterialIndices(); + if(std::find(mats.begin(),mats.end(),matIndex) == mats.end()) { + continue; + } + + int index = -1; + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + if(mesh->GetTextureCoords(i).empty()) { + break; + } + const std::string& name = mesh->GetTextureCoordChannelName(i); + if(name == uvSet) { + index = static_cast(i); + break; + } + } + if(index == -1) { + FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); + continue; + } + + if(uvIndex == -1) { + uvIndex = index; + } + else { + FBXImporter::LogWarn("the UV channel named " + uvSet + + " appears at different positions in meshes, results will be wrong"); + } + } + + if(uvIndex == -1) { + FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); + uvIndex = 0; + } + } + } + + out_mat->AddProperty(&uvIndex,1,_AI_MATKEY_UVWSRC_BASE,target,0); + } // ------------------------------------------------------------------------------------------------ void SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures) @@ -1554,6 +1649,20 @@ private: TrySetTextureProperties(out_mat, textures, "ShininessExponent", aiTextureType_SHININESS); } + // ------------------------------------------------------------------------------------------------ + void SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures) + { + TrySetTextureProperties(out_mat, layeredTextures, "DiffuseColor", aiTextureType_DIFFUSE); + TrySetTextureProperties(out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT); + TrySetTextureProperties(out_mat, layeredTextures, "EmissiveColor", aiTextureType_EMISSIVE); + TrySetTextureProperties(out_mat, layeredTextures, "SpecularColor", aiTextureType_SPECULAR); + TrySetTextureProperties(out_mat, layeredTextures, "TransparentColor", aiTextureType_OPACITY); + TrySetTextureProperties(out_mat, layeredTextures, "ReflectionColor", aiTextureType_REFLECTION); + TrySetTextureProperties(out_mat, layeredTextures, "DisplacementColor", aiTextureType_DISPLACEMENT); + TrySetTextureProperties(out_mat, layeredTextures, "NormalMap", aiTextureType_NORMALS); + TrySetTextureProperties(out_mat, layeredTextures, "Bump", aiTextureType_HEIGHT); + TrySetTextureProperties(out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS); + } // ------------------------------------------------------------------------------------------------ diff --git a/code/FBXDocument.cpp b/code/FBXDocument.cpp index cff52e542..404a8d6e2 100644 --- a/code/FBXDocument.cpp +++ b/code/FBXDocument.cpp @@ -14,7 +14,7 @@ following conditions are met: following disclaimer. * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the + copyright notice, this list of conditions and the* following disclaimer in the documentation and/or other materials provided with the distribution. @@ -176,6 +176,9 @@ const Object* LazyObject::Get(bool dieOnError) else if (!strncmp(obtype,"Texture",length)) { object.reset(new Texture(id,element,doc,name)); } + else if (!strncmp(obtype,"LayeredTexture",length)) { + object.reset(new LayeredTexture(id,element,doc,name)); + } else if (!strncmp(obtype,"AnimationStack",length)) { object.reset(new AnimationStack(id,element,name,doc)); } diff --git a/code/FBXDocument.h b/code/FBXDocument.h index 9b7d5e3ec..9dd5c79dd 100644 --- a/code/FBXDocument.h +++ b/code/FBXDocument.h @@ -516,8 +516,6 @@ private: boost::shared_ptr props; }; - - /** DOM class for generic FBX textures */ class Texture : public Object { @@ -576,8 +574,73 @@ private: unsigned int crop[4]; }; +/** DOM class for layered FBX textures */ +class LayeredTexture : public Object +{ +public: + + LayeredTexture(uint64_t id, const Element& element, const Document& doc, const std::string& name); + ~LayeredTexture(); + + //Can only be called after construction of the layered texture object due to construction flag. + void fillTexture(const Document& doc); + + enum BlendMode + { + BlendMode_Translucent, + BlendMode_Additive, + BlendMode_Modulate, + BlendMode_Modulate2, + BlendMode_Over, + BlendMode_Normal, + BlendMode_Dissolve, + BlendMode_Darken, + BlendMode_ColorBurn, + BlendMode_LinearBurn, + BlendMode_DarkerColor, + BlendMode_Lighten, + BlendMode_Screen, + BlendMode_ColorDodge, + BlendMode_LinearDodge, + BlendMode_LighterColor, + BlendMode_SoftLight, + BlendMode_HardLight, + BlendMode_VividLight, + BlendMode_LinearLight, + BlendMode_PinLight, + BlendMode_HardMix, + BlendMode_Difference, + BlendMode_Exclusion, + BlendMode_Subtract, + BlendMode_Divide, + BlendMode_Hue, + BlendMode_Saturation, + BlendMode_Color, + BlendMode_Luminosity, + BlendMode_Overlay, + BlendMode_BlendModeCount + }; + + const Texture* getTexture() const + { + return texture; + } + BlendMode GetBlendMode() + { + return blendMode; + } + float Alpha() + { + return alpha; + } +private: + const Texture* texture; + BlendMode blendMode; + float alpha; +}; typedef std::fbx_unordered_map TextureMap; +typedef std::fbx_unordered_map LayeredTextureMap; /** DOM class for generic FBX materials */ @@ -607,6 +670,10 @@ public: return textures; } + const LayeredTextureMap& LayeredTextures() const { + return layeredTextures; + } + private: std::string shading; @@ -614,6 +681,7 @@ private: boost::shared_ptr props; TextureMap textures; + LayeredTextureMap layeredTextures; }; diff --git a/code/FBXMaterial.cpp b/code/FBXMaterial.cpp index 1a5d7d443..a5e2a1169 100644 --- a/code/FBXMaterial.cpp +++ b/code/FBXMaterial.cpp @@ -110,16 +110,29 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con const Texture* const tex = dynamic_cast(ob); if(!tex) { - DOMWarning("source object for texture link is not a texture, ignoring",&element); - continue; + const LayeredTexture* const layeredTexture = dynamic_cast(ob); + if(!layeredTexture) { + DOMWarning("source object for texture link is not a texture or layered texture, ignoring",&element); + continue; + } + const std::string& prop = con->PropertyName(); + if (layeredTextures.find(prop) != layeredTextures.end()) { + DOMWarning("duplicate layered texture link: " + prop,&element); + } + + layeredTextures[prop] = layeredTexture; + ((LayeredTexture*)layeredTexture)->fillTexture(doc); + } + else + { + const std::string& prop = con->PropertyName(); + if (textures.find(prop) != textures.end()) { + DOMWarning("duplicate texture link: " + prop,&element); + } + + textures[prop] = tex; } - const std::string& prop = con->PropertyName(); - if (textures.find(prop) != textures.end()) { - DOMWarning("duplicate texture link: " + prop,&element); - } - - textures[prop] = tex; } } @@ -194,6 +207,52 @@ Texture::~Texture() } +LayeredTexture::LayeredTexture(uint64_t id, const Element& element, const Document& doc, const std::string& name) +: Object(id,element,name) +,texture(0) +,blendMode(BlendMode_Modulate) +,alpha(1) +{ + const Scope& sc = GetRequiredScope(element); + + const Element* const BlendModes = sc["BlendModes"]; + const Element* const Alphas = sc["Alphas"]; + + + if(BlendModes!=0) + { + blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(*BlendModes,0)); + } + if(Alphas!=0) + { + alpha = ParseTokenAsFloat(GetRequiredToken(*Alphas,0)); + } +} + +LayeredTexture::~LayeredTexture() +{ + +} + +void LayeredTexture::fillTexture(const Document& doc) +{ + const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID()); + for(size_t i = 0; i < conns.size();++i) + { + const Connection* con = conns.at(i); + + const Object* const ob = con->SourceObject(); + if(!ob) { + DOMWarning("failed to read source object for texture link, ignoring",&element); + continue; + } + + const Texture* const tex = dynamic_cast(ob); + + texture = tex; + } +} + } //!FBX } //!Assimp From 4f36e85bd89f3ab769614125523447e18839b5d3 Mon Sep 17 00:00:00 2001 From: attila-barsi Date: Mon, 31 Mar 2014 10:30:04 +0200 Subject: [PATCH 2/2] Added required changes to doc and protection from nullptr. --- code/FBXConverter.cpp | 132 +++++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 65 deletions(-) diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index 9f2b70b7f..a68be8ac5 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -23,7 +23,7 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT @@ -1457,87 +1457,89 @@ private: } const Texture* const tex = (*it).second; - - aiString path; - path.Set(tex->RelativeFilename()); + if(tex !=0 ) + { + aiString path; + path.Set(tex->RelativeFilename()); - out_mat->AddProperty(&path,_AI_MATKEY_TEXTURE_BASE,target,0); + out_mat->AddProperty(&path,_AI_MATKEY_TEXTURE_BASE,target,0); - aiUVTransform uvTrafo; - // XXX handle all kinds of UV transformations - uvTrafo.mScaling = tex->UVScaling(); - uvTrafo.mTranslation = tex->UVTranslation(); - out_mat->AddProperty(&uvTrafo,1,_AI_MATKEY_UVTRANSFORM_BASE,target,0); + aiUVTransform uvTrafo; + // XXX handle all kinds of UV transformations + uvTrafo.mScaling = tex->UVScaling(); + uvTrafo.mTranslation = tex->UVTranslation(); + out_mat->AddProperty(&uvTrafo,1,_AI_MATKEY_UVTRANSFORM_BASE,target,0); - const PropertyTable& props = tex->Props(); + const PropertyTable& props = tex->Props(); - int uvIndex = 0; + int uvIndex = 0; - bool ok; - const std::string& uvSet = PropertyGet(props,"UVSet",ok); - if(ok) { - // "default" is the name which usually appears in the FbxFileTexture template - if(uvSet != "default" && uvSet.length()) { - // this is a bit awkward - we need to find a mesh that uses this - // material and scan its UV channels for the given UV name because - // assimp references UV channels by index, not by name. + bool ok; + const std::string& uvSet = PropertyGet(props,"UVSet",ok); + if(ok) { + // "default" is the name which usually appears in the FbxFileTexture template + if(uvSet != "default" && uvSet.length()) { + // this is a bit awkward - we need to find a mesh that uses this + // material and scan its UV channels for the given UV name because + // assimp references UV channels by index, not by name. - // XXX: the case that UV channels may appear in different orders - // in meshes is unhandled. A possible solution would be to sort - // the UV channels alphabetically, but this would have the side - // effect that the primary (first) UV channel would sometimes - // be moved, causing trouble when users read only the first - // UV channel and ignore UV channel assignments altogether. + // XXX: the case that UV channels may appear in different orders + // in meshes is unhandled. A possible solution would be to sort + // the UV channels alphabetically, but this would have the side + // effect that the primary (first) UV channel would sometimes + // be moved, causing trouble when users read only the first + // UV channel and ignore UV channel assignments altogether. - const unsigned int matIndex = static_cast(std::distance(materials.begin(), - std::find(materials.begin(),materials.end(),out_mat) - )); + const unsigned int matIndex = static_cast(std::distance(materials.begin(), + std::find(materials.begin(),materials.end(),out_mat) + )); - uvIndex = -1; - BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) { - const MeshGeometry* const mesh = dynamic_cast (v.first); - if(!mesh) { - continue; - } - - const MatIndexArray& mats = mesh->GetMaterialIndices(); - if(std::find(mats.begin(),mats.end(),matIndex) == mats.end()) { - continue; - } - - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if(mesh->GetTextureCoords(i).empty()) { - break; + uvIndex = -1; + BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) { + const MeshGeometry* const mesh = dynamic_cast (v.first); + if(!mesh) { + continue; } - const std::string& name = mesh->GetTextureCoordChannelName(i); - if(name == uvSet) { - index = static_cast(i); - break; + + const MatIndexArray& mats = mesh->GetMaterialIndices(); + if(std::find(mats.begin(),mats.end(),matIndex) == mats.end()) { + continue; + } + + int index = -1; + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + if(mesh->GetTextureCoords(i).empty()) { + break; + } + const std::string& name = mesh->GetTextureCoordChannelName(i); + if(name == uvSet) { + index = static_cast(i); + break; + } + } + if(index == -1) { + FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); + continue; + } + + if(uvIndex == -1) { + uvIndex = index; + } + else { + FBXImporter::LogWarn("the UV channel named " + uvSet + + " appears at different positions in meshes, results will be wrong"); } - } - if(index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - continue; } if(uvIndex == -1) { - uvIndex = index; + FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); + uvIndex = 0; } - else { - FBXImporter::LogWarn("the UV channel named " + uvSet + - " appears at different positions in meshes, results will be wrong"); - } - } - - if(uvIndex == -1) { - FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); - uvIndex = 0; } } - } - out_mat->AddProperty(&uvIndex,1,_AI_MATKEY_UVWSRC_BASE,target,0); + out_mat->AddProperty(&uvIndex,1,_AI_MATKEY_UVWSRC_BASE,target,0); + } } // ------------------------------------------------------------------------------------------------