From 39ce0c0456b2cb4453dd69edd7d76274795e7287 Mon Sep 17 00:00:00 2001 From: Julian Knodt Date: Tue, 2 Apr 2024 09:31:19 -0700 Subject: [PATCH] Respect merge identical vertices in ObjExporter (#5521) Co-authored-by: Kim Kulling --- code/AssetLib/Obj/ObjExporter.cpp | 34 +++++++++++++++++-------------- code/AssetLib/Obj/ObjExporter.h | 13 +++++++----- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/code/AssetLib/Obj/ObjExporter.cpp b/code/AssetLib/Obj/ObjExporter.cpp index a5d8325fc..7c5c051f3 100644 --- a/code/AssetLib/Obj/ObjExporter.cpp +++ b/code/AssetLib/Obj/ObjExporter.cpp @@ -59,9 +59,9 @@ namespace Assimp { // ------------------------------------------------------------------------------------------------ // Worker function for exporting a scene to Wavefront OBJ. Prototyped and registered in Exporter.cpp -void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) { +void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* props) { // invoke the exporter - ObjExporter exporter(pFile, pScene); + ObjExporter exporter(pFile, pScene, false, props); if (exporter.mOutput.fail() || exporter.mOutputMat.fail()) { throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile)); @@ -86,9 +86,9 @@ void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene // ------------------------------------------------------------------------------------------------ // Worker function for exporting a scene to Wavefront OBJ without the material file. Prototyped and registered in Exporter.cpp -void ExportSceneObjNoMtl(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* ) { +void ExportSceneObjNoMtl(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* props) { // invoke the exporter - ObjExporter exporter(pFile, pScene, true); + ObjExporter exporter(pFile, pScene, true, props); if (exporter.mOutput.fail() || exporter.mOutputMat.fail()) { throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile)); @@ -111,7 +111,7 @@ void ExportSceneObjNoMtl(const char* pFile,IOSystem* pIOSystem, const aiScene* p static const std::string MaterialExt = ".mtl"; // ------------------------------------------------------------------------------------------------ -ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene, bool noMtl) +ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene, bool noMtl, const ExportProperties* props) : filename(_filename) , pScene(pScene) , vn() @@ -130,7 +130,10 @@ ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene, bool noMt mOutputMat.imbue(l); mOutputMat.precision(ASSIMP_AI_REAL_TEXT_PRECISION); - WriteGeometryFile(noMtl); + WriteGeometryFile( + noMtl, + props == nullptr ? true : props->GetPropertyBool("bJoinIdenticalVertices", true) + ); if ( !noMtl ) { WriteMaterialFile(); } @@ -255,14 +258,14 @@ void ObjExporter::WriteMaterialFile() { } } -void ObjExporter::WriteGeometryFile(bool noMtl) { +void ObjExporter::WriteGeometryFile(bool noMtl, bool merge_identical_vertices) { WriteHeader(mOutput); if (!noMtl) mOutput << "mtllib " << GetMaterialLibName() << endl << endl; // collect mesh geometry aiMatrix4x4 mBase; - AddNode(pScene->mRootNode, mBase); + AddNode(pScene->mRootNode, mBase, merge_identical_vertices); // write vertex positions with colors, if any mVpMap.getKeys( vp ); @@ -330,7 +333,7 @@ void ObjExporter::WriteGeometryFile(bool noMtl) { } // ------------------------------------------------------------------------------------------------ -void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) { +void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat, bool merge_identical_vertices) { mMeshes.emplace_back(); MeshInstance& mesh = mMeshes.back(); @@ -362,13 +365,14 @@ void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4 for(unsigned int a = 0; a < f.mNumIndices; ++a) { const unsigned int idx = f.mIndices[a]; + const unsigned int fi = merge_identical_vertices ? 0 : idx; aiVector3D vert = mat * m->mVertices[idx]; if ( nullptr != m->mColors[ 0 ] ) { aiColor4D col4 = m->mColors[ 0 ][ idx ]; - face.indices[a].vp = mVpMap.getIndex({vert, aiColor3D(col4.r, col4.g, col4.b)}); + face.indices[a].vp = mVpMap.getIndex({vert, aiColor3D(col4.r, col4.g, col4.b), fi}); } else { - face.indices[a].vp = mVpMap.getIndex({vert, aiColor3D(0,0,0)}); + face.indices[a].vp = mVpMap.getIndex({vert, aiColor3D(0,0,0), fi}); } if (m->mNormals) { @@ -388,21 +392,21 @@ void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4 } // ------------------------------------------------------------------------------------------------ -void ObjExporter::AddNode(const aiNode* nd, const aiMatrix4x4& mParent) { +void ObjExporter::AddNode(const aiNode* nd, const aiMatrix4x4& mParent, bool merge_identical_vertices) { const aiMatrix4x4& mAbs = mParent * nd->mTransformation; aiMesh *cm( nullptr ); for(unsigned int i = 0; i < nd->mNumMeshes; ++i) { cm = pScene->mMeshes[nd->mMeshes[i]]; if (nullptr != cm) { - AddMesh(cm->mName, pScene->mMeshes[nd->mMeshes[i]], mAbs); + AddMesh(cm->mName, pScene->mMeshes[nd->mMeshes[i]], mAbs, merge_identical_vertices); } else { - AddMesh(nd->mName, pScene->mMeshes[nd->mMeshes[i]], mAbs); + AddMesh(nd->mName, pScene->mMeshes[nd->mMeshes[i]], mAbs, merge_identical_vertices); } } for(unsigned int i = 0; i < nd->mNumChildren; ++i) { - AddNode(nd->mChildren[i], mAbs); + AddNode(nd->mChildren[i], mAbs, merge_identical_vertices); } } diff --git a/code/AssetLib/Obj/ObjExporter.h b/code/AssetLib/Obj/ObjExporter.h index a64f38f74..4c92aa16f 100644 --- a/code/AssetLib/Obj/ObjExporter.h +++ b/code/AssetLib/Obj/ObjExporter.h @@ -51,6 +51,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include + struct aiScene; struct aiNode; struct aiMesh; @@ -63,7 +65,7 @@ namespace Assimp { class ObjExporter { public: /// Constructor for a specific scene to export - ObjExporter(const char* filename, const aiScene* pScene, bool noMtl=false); + ObjExporter(const char* filename, const aiScene* pScene, bool noMtl=false, const ExportProperties* props = nullptr); ~ObjExporter(); std::string GetMaterialLibName(); std::string GetMaterialLibFileName(); @@ -97,10 +99,10 @@ private: void WriteHeader(std::ostringstream& out); void WriteMaterialFile(); - void WriteGeometryFile(bool noMtl=false); + void WriteGeometryFile(bool noMtl=false, bool merge_identical_vertices = false); std::string GetMaterialName(unsigned int index); - void AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat); - void AddNode(const aiNode* nd, const aiMatrix4x4& mParent); + void AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat, bool merge_identical_vertices); + void AddNode(const aiNode* nd, const aiMatrix4x4& mParent, bool merge_identical_vertices); private: std::string filename; @@ -109,6 +111,7 @@ private: struct vertexData { aiVector3D vp; aiColor3D vc; // OBJ does not support 4D color + uint32_t index = 0; }; std::vector vn, vt; @@ -133,7 +136,7 @@ private: if (a.vc.g > b.vc.g) return false; if (a.vc.b < b.vc.b) return true; if (a.vc.b > b.vc.b) return false; - return false; + return a.index < b.index; } };