From 17629f1ff12a87de351e827004c05896961fbbfa Mon Sep 17 00:00:00 2001 From: Alexander Gessler Date: Wed, 4 Jul 2012 15:07:57 +0200 Subject: [PATCH] - fbx: work on resolving material links. --- code/FBXConverter.cpp | 74 ++++++++++++++++++++++++++++++++++------ code/FBXDocument.cpp | 2 +- code/FBXDocument.h | 10 +++++- code/FBXImportSettings.h | 7 ++++ code/FBXMaterial.cpp | 2 +- code/FBXMeshGeometry.cpp | 37 ++++++++++++++++++-- code/FBXUtil.cpp | 6 ++-- 7 files changed, 120 insertions(+), 18 deletions(-) diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index 2ee76a134..0d288a8d4 100644 --- a/code/FBXConverter.cpp +++ b/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(ob); - if(mat) { - ConvertMaterial(*mat); + const Material* mat = dynamic_cast(ob); + if(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& 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& 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(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(materials.size() - 1); } @@ -475,9 +524,14 @@ private: private: + // 0: not assigned yet, others: index is value - 1 + unsigned int defaultMaterialIndex; + std::vector meshes; std::vector materials; + std::set materials_converted; + std::vector sourceMeshes; aiScene* const out; diff --git a/code/FBXDocument.cpp b/code/FBXDocument.cpp index 76d01b099..9a07e1865 100644 --- a/code/FBXDocument.cpp +++ b/code/FBXDocument.cpp @@ -410,7 +410,7 @@ const Object* LazyObject::Get() const size_t length = static_cast(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)) { diff --git a/code/FBXDocument.h b/code/FBXDocument.h index 4bbde76a9..38e3a85c9 100644 --- a/code/FBXDocument.h +++ b/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& 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 materials_resolved; + // cached data arrays std::vector materials; std::vector vertices; diff --git a/code/FBXImportSettings.h b/code/FBXImportSettings.h index f2a567916..020ba9820 100644 --- a/code/FBXImportSettings.h +++ b/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; }; diff --git a/code/FBXMaterial.cpp b/code/FBXMaterial.cpp index eb14bb3af..1a5d7d443 100644 --- a/code/FBXMaterial.cpp +++ b/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 conns = doc.GetConnectionsByDestinationSequenced(ID()); + const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID()); BOOST_FOREACH(const Connection* con, conns) { // texture link to properties, not objects diff --git a/code/FBXMeshGeometry.cpp b/code/FBXMeshGeometry.cpp index cbfe9442a..2b35ef137 100644 --- a/code/FBXMeshGeometry.cpp +++ b/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& 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(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) { diff --git a/code/FBXUtil.cpp b/code/FBXUtil.cpp index 57e8fc256..1c2d39f03 100644 --- a/code/FBXUtil.cpp +++ b/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( (Formatter::format(),prefix,"(line ",line,", col ",column,") ",text) ); + return static_cast( (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( (Formatter::format(),prefix, - "(",TokenTypeString(tok->Type()), - "line ",tok->Line(), + " (",TokenTypeString(tok->Type()), + ", line ",tok->Line(), ", col ",tok->Column(),") ", text) ); }