Merge pull request #249 from attila-barsi/master

Initial version for FBX layered textures.
pull/251/head
Kim Kulling 2014-04-01 16:02:16 +02:00
commit a6044e125e
4 changed files with 256 additions and 15 deletions

View File

@ -23,7 +23,7 @@ following conditions are met:
derived from this software without specific prior derived from this software without specific prior
written permission of the assimp team. 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 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
@ -767,6 +767,7 @@ private:
// find user defined properties (3ds Max) // find user defined properties (3ds Max)
data->Set(index++, "UserProperties", aiString(PropertyGet<std::string>(props, "UDP3DSMAX", ""))); data->Set(index++, "UserProperties", aiString(PropertyGet<std::string>(props, "UDP3DSMAX", "")));
unparsedProperties.erase("UDP3DSMAX");
// preserve the info that a node was marked as Null node in the original file. // preserve the info that a node was marked as Null node in the original file.
data->Set(index++, "IsNull", model.IsNull() ? true : false); data->Set(index++, "IsNull", model.IsNull() ? true : false);
@ -1440,6 +1441,7 @@ private:
// texture assignments // texture assignments
SetTextureProperties(out_mat,material.Textures()); SetTextureProperties(out_mat,material.Textures());
SetTextureProperties(out_mat,material.LayeredTextures());
return static_cast<unsigned int>(materials.size() - 1); return static_cast<unsigned int>(materials.size() - 1);
} }
@ -1456,7 +1458,103 @@ private:
} }
const Texture* const tex = (*it).second; const Texture* const tex = (*it).second;
if(tex !=0 )
{
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<std::string>(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<unsigned int>(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<const MeshGeometry*> (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<int>(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 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; aiString path;
path.Set(tex->RelativeFilename()); path.Set(tex->RelativeFilename());
@ -1490,7 +1588,7 @@ private:
const unsigned int matIndex = static_cast<unsigned int>(std::distance(materials.begin(), const unsigned int matIndex = static_cast<unsigned int>(std::distance(materials.begin(),
std::find(materials.begin(),materials.end(),out_mat) std::find(materials.begin(),materials.end(),out_mat)
)); ));
uvIndex = -1; uvIndex = -1;
BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) { BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) {
@ -1539,7 +1637,6 @@ private:
out_mat->AddProperty(&uvIndex,1,_AI_MATKEY_UVWSRC_BASE,target,0); out_mat->AddProperty(&uvIndex,1,_AI_MATKEY_UVWSRC_BASE,target,0);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures) void SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures)
{ {
@ -1555,6 +1652,20 @@ private:
TrySetTextureProperties(out_mat, textures, "ShininessExponent", aiTextureType_SHININESS); 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);
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -14,7 +14,7 @@ following conditions are met:
following disclaimer. following disclaimer.
* Redistributions in binary form must reproduce the above * 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 following disclaimer in the documentation and/or other
materials provided with the distribution. materials provided with the distribution.
@ -176,6 +176,9 @@ const Object* LazyObject::Get(bool dieOnError)
else if (!strncmp(obtype,"Texture",length)) { else if (!strncmp(obtype,"Texture",length)) {
object.reset(new Texture(id,element,doc,name)); 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)) { else if (!strncmp(obtype,"AnimationStack",length)) {
object.reset(new AnimationStack(id,element,name,doc)); object.reset(new AnimationStack(id,element,name,doc));
} }

View File

@ -516,8 +516,6 @@ private:
boost::shared_ptr<const PropertyTable> props; boost::shared_ptr<const PropertyTable> props;
}; };
/** DOM class for generic FBX textures */ /** DOM class for generic FBX textures */
class Texture : public Object class Texture : public Object
{ {
@ -576,8 +574,73 @@ private:
unsigned int crop[4]; 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<std::string, const Texture*> TextureMap; typedef std::fbx_unordered_map<std::string, const Texture*> TextureMap;
typedef std::fbx_unordered_map<std::string, const LayeredTexture*> LayeredTextureMap;
/** DOM class for generic FBX materials */ /** DOM class for generic FBX materials */
@ -607,6 +670,10 @@ public:
return textures; return textures;
} }
const LayeredTextureMap& LayeredTextures() const {
return layeredTextures;
}
private: private:
std::string shading; std::string shading;
@ -614,6 +681,7 @@ private:
boost::shared_ptr<const PropertyTable> props; boost::shared_ptr<const PropertyTable> props;
TextureMap textures; TextureMap textures;
LayeredTextureMap layeredTextures;
}; };

View File

@ -110,16 +110,29 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con
const Texture* const tex = dynamic_cast<const Texture*>(ob); const Texture* const tex = dynamic_cast<const Texture*>(ob);
if(!tex) { if(!tex) {
DOMWarning("source object for texture link is not a texture, ignoring",&element); const LayeredTexture* const layeredTexture = dynamic_cast<const LayeredTexture*>(ob);
continue; 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<const Connection*>& 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<const Texture*>(ob);
texture = tex;
}
}
} //!FBX } //!FBX
} //!Assimp } //!Assimp