Browse Source

- fbx: work on resolving material links.

Alexander Gessler 13 years ago
parent
commit
17629f1ff1
7 changed files with 120 additions and 18 deletions
  1. 64 10
      code/FBXConverter.cpp
  2. 1 1
      code/FBXDocument.cpp
  3. 9 1
      code/FBXDocument.h
  4. 7 0
      code/FBXImportSettings.h
  5. 1 1
      code/FBXMaterial.cpp
  6. 35 2
      code/FBXMeshGeometry.cpp
  7. 3 3
      code/FBXUtil.cpp

+ 64 - 10
code/FBXConverter.cpp

@@ -85,17 +85,22 @@ public:
 			}
 		}
 
-		// hack to process all materials
-		BOOST_FOREACH(const ObjectMap::value_type& v,doc.Objects()) {
+		if(doc.Settings().readAllMaterials) {
+			// unfortunately this means we have to evaluate all objects
+			BOOST_FOREACH(const ObjectMap::value_type& v,doc.Objects()) {
 
-			const Object* ob = v.second->Get();
-			if(!ob) {
-				continue;
-			}
+				const Object* ob = v.second->Get();
+				if(!ob) {
+					continue;
+				}
+
+				const Material* mat = dynamic_cast<const Material*>(ob);
+				if(mat) {
 
-			const Material* mat = dynamic_cast<const Material*>(ob);
-			if(mat) {
-				ConvertMaterial(*mat);
+					if (materials_converted.find(mat) == materials_converted.end()) {
+						ConvertMaterial(*mat);
+					}
+				}
 			}
 		}
 
@@ -244,18 +249,60 @@ private:
 			out_mesh->mColors[i] = new aiColor4D[vertices.size()];
 			std::copy(colors.begin(),colors.end(),out_mesh->mColors[i]);
 		}
+
+		const std::vector<unsigned int>& mindices = mesh.GetMaterialIndices();
+		ConvertMaterialForMesh(out_mesh,mesh,mindices.size() ? mindices[0] : 9);
+	}
+
+
+	// ------------------------------------------------------------------------------------------------
+	void ConvertMaterialForMesh(aiMesh* out, const MeshGeometry& geo, unsigned int materialIndex)
+	{
+		// locate source materials for this mesh
+		const std::vector<const Material*>& mats = geo.GetMaterials();
+		if (materialIndex >= mats.size()) {
+			FBXImporter::LogError("material index out of bounds, ignoring");
+			out->mMaterialIndex = GetDefaultMaterial();
+			return;
+		}
+
+		out->mMaterialIndex = ConvertMaterial(*mats[materialIndex]);		
+	}
+
+
+	// ------------------------------------------------------------------------------------------------
+	unsigned int GetDefaultMaterial()
+	{
+		if (defaultMaterialIndex) {
+			return defaultMaterialIndex - 1; 
+		}
+
+		aiMaterial* out_mat = new aiMaterial();
+		materials.push_back(out_mat);
+
+		const aiColor3D diffuse = aiColor3D(0.8f,0.8f,0.8f);
+		out_mat->AddProperty(&diffuse,1,AI_MATKEY_COLOR_DIFFUSE);
+
+		aiString s;
+		s.Set(AI_DEFAULT_MATERIAL_NAME);
+
+		out_mat->AddProperty(&s,AI_MATKEY_NAME);
+
+		defaultMaterialIndex = static_cast<unsigned int>(materials.size());
+		return defaultMaterialIndex - 1;
 	}
 
 
 	// ------------------------------------------------------------------------------------------------
 	// Material -> aiMaterial
-	void ConvertMaterial(const Material& material)
+	unsigned int ConvertMaterial(const Material& material)
 	{
 		const PropertyTable& props = material.Props();
 
 		// generate empty output material
 		aiMaterial* out_mat = new aiMaterial();
 		materials.push_back(out_mat);
+		materials_converted.insert(&material);
 
 		aiString str;
 
@@ -268,6 +315,8 @@ private:
 	
 		// texture assignments
 		SetTextureProperties(out_mat,material.Textures());
+
+		return static_cast<unsigned int>(materials.size() - 1);
 	}
 
 
@@ -475,9 +524,14 @@ private:
 
 private:
 
+	// 0: not assigned yet, others: index is value - 1
+	unsigned int defaultMaterialIndex;
+
 	std::vector<aiMesh*> meshes;
 	std::vector<aiMaterial*> materials;
 
+	std::set<const Material*> materials_converted;
+
 	std::vector<const MeshGeometry*> sourceMeshes;
 
 	aiScene* const out;

+ 1 - 1
code/FBXDocument.cpp

@@ -410,7 +410,7 @@ const Object* LazyObject::Get()
 	const size_t length = static_cast<size_t>(key.end()-key.begin());
 	if (!strncmp(obtype,"Geometry",length)) {
 		if (!strcmp(classtag.c_str(),"Mesh")) {
-			object.reset(new MeshGeometry(id,element,name,doc.Settings()));
+			object.reset(new MeshGeometry(id,element,name,doc));
 		}
 	}
 	else if (!strncmp(obtype,"Material",length)) {

+ 9 - 1
code/FBXDocument.h

@@ -240,7 +240,7 @@ class MeshGeometry : public Geometry
 
 public:
 
-	MeshGeometry(uint64_t id, const Element& element, const std::string& name, const ImportSettings& settings);
+	MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc);
 	~MeshGeometry();
 
 public:
@@ -302,10 +302,16 @@ public:
 		return materials;
 	}
 
+	/** Get per-face-vertex material assignments */
+	const std::vector<const Material*>& GetMaterials() const {
+		return materials_resolved;
+	}
+
 public:
 
 private:
 
+	void ResolveMaterialLinks(const Element& element, const Document& doc);
 	void ReadLayer(const Scope& layer);
 	void ReadLayerElement(const Scope& layerElement);
 	void ReadVertexData(const std::string& type, int index, const Scope& source);
@@ -336,6 +342,8 @@ private:
 
 private:
 
+	std::vector<const Material*> materials_resolved;
+
 	// cached data arrays
 	std::vector<unsigned int> materials;
 	std::vector<aiVector3D> vertices;

+ 7 - 0
code/FBXImportSettings.h

@@ -52,6 +52,7 @@ struct ImportSettings
 {
 	ImportSettings()
 		: readAllLayers(true)
+		, readAllMaterials()
 	{}
 
 	/** specifies whether all geometry layers are read and scanned for
@@ -61,6 +62,12 @@ struct ImportSettings
 	  * vertex data is spread among multiple layers. The default
 	  * value for this option is true.*/
 	bool readAllLayers;
+
+	/** specifies whether all materials are read, or only those that
+	 *  are referenced by at least one mesh. Reading all materials
+	 *  may make FBX reading a lot slower since all objects
+	 *  need to be processed .*/
+	bool readAllMaterials;
 };
 
 

+ 1 - 1
code/FBXMaterial.cpp

@@ -94,7 +94,7 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con
 	props = GetPropertyTable(doc,templateName,element,sc);
 
 	// resolve texture links
-	const std::vector<const Connection*> conns = doc.GetConnectionsByDestinationSequenced(ID());
+	const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
 	BOOST_FOREACH(const Connection* con, conns) {
 
 		// texture link to properties, not objects

+ 35 - 2
code/FBXMeshGeometry.cpp

@@ -58,7 +58,7 @@ namespace FBX {
 	using namespace Util;
 
 // ------------------------------------------------------------------------------------------------
-MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const ImportSettings& settings)
+MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
 : Geometry(id, element,name)
 {
 	const Scope* sc = element.Compound();
@@ -148,7 +148,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
 			DOMError(err,&element);
 		}
 
-		if(settings.readAllLayers || index == 0) {
+		if(doc.Settings().readAllLayers || index == 0) {
 			const Scope& layer = GetRequiredScope(*(*it).second);
 			ReadLayer(layer);
 		}
@@ -156,6 +156,8 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
 			FBXImporter::LogWarn("ignoring additional geometry layers");
 		}
 	}
+
+	ResolveMaterialLinks(element,doc);
 }
 
 
@@ -166,6 +168,37 @@ MeshGeometry::~MeshGeometry()
 }
 
 
+// ------------------------------------------------------------------------------------------------
+void MeshGeometry::ResolveMaterialLinks(const Element& element, const Document& doc)
+{
+	// resolve material
+	const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
+
+	materials_resolved.reserve(conns.size());
+	BOOST_FOREACH(const Connection* con, conns) {
+
+		// material links should be Object-Object connections
+		if (con->PropertyName().length()) {
+			continue;
+		}
+
+		const Object* const ob = con->SourceObject();
+		if(!ob) {
+			DOMWarning("failed to read source object for material link, ignoring",&element);
+			continue;
+		}
+
+		const Material* const mat = dynamic_cast<const Material*>(ob);
+		if(!mat) {
+			DOMWarning("source object for material link is not a material, ignoring",&element);
+			continue;
+		}
+
+		materials_resolved.push_back(mat);
+	}
+}
+
+
 // ------------------------------------------------------------------------------------------------
 void MeshGeometry::ReadLayer(const Scope& layer)
 {

+ 3 - 3
code/FBXUtil.cpp

@@ -82,15 +82,15 @@ const char* TokenTypeString(TokenType t)
 // ------------------------------------------------------------------------------------------------
 std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column)
 {
-	return static_cast<std::string>( (Formatter::format(),prefix,"(line ",line,", col ",column,") ",text) );
+	return static_cast<std::string>( (Formatter::format(),prefix," (line ",line,", col ",column,") ",text) );
 }
 
 // ------------------------------------------------------------------------------------------------
 std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok)
 {
 	return static_cast<std::string>( (Formatter::format(),prefix,
-		"(",TokenTypeString(tok->Type()),
-		"line ",tok->Line(),
+		" (",TokenTypeString(tok->Type()),
+		", line ",tok->Line(),
 		", col ",tok->Column(),") ",
 		text) );
 }