浏览代码

Initial version for FBX layered textures.
Fixed assert during parsing UDP3DSMAX.

attila-barsi 11 年之前
父节点
当前提交
ed9204ab1b
共有 4 个文件被更改,包括 250 次插入11 次删除
  1. 110 1
      code/FBXConverter.cpp
  2. 4 1
      code/FBXDocument.cpp
  3. 70 2
      code/FBXDocument.h
  4. 66 7
      code/FBXMaterial.cpp

+ 110 - 1
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<std::string>(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<unsigned int>(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<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 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);
+	}
 
 
 	// ------------------------------------------------------------------------------------------------

+ 4 - 1
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));
 		}

+ 70 - 2
code/FBXDocument.h

@@ -516,8 +516,6 @@ private:
 	boost::shared_ptr<const PropertyTable> 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<std::string, const Texture*> TextureMap;
+typedef std::fbx_unordered_map<std::string, const LayeredTexture*> 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<const PropertyTable> props;
 
 	TextureMap textures;
+	LayeredTextureMap layeredTextures;
 };
 
 

+ 66 - 7
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<const Texture*>(ob);
 		if(!tex) {
-			DOMWarning("source object for texture link is not a texture, ignoring",&element);
-			continue;
+			const LayeredTexture* const layeredTexture = dynamic_cast<const LayeredTexture*>(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);
 		}
-
-		const std::string& prop = con->PropertyName();
-		if (textures.find(prop) != textures.end()) {
-			DOMWarning("duplicate texture link: " + prop,&element);
+		else
+		{
+			const std::string& prop = con->PropertyName();
+			if (textures.find(prop) != textures.end()) {
+				DOMWarning("duplicate texture link: " + prop,&element);
+			}
+
+			textures[prop] = tex;
 		}
 
-		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
 } //!Assimp