From 8f34c24ae0fd9c49eb90d8f1c1cc2b3c85fd3e30 Mon Sep 17 00:00:00 2001 From: Marshall Hahn Date: Mon, 30 Sep 2013 14:07:53 -0400 Subject: [PATCH] remove duplicate vectors when export obj format --- code/ObjExporter.cpp | 54 +++++++++++++++++++++++++++----------- code/ObjExporter.h | 15 +++++++++++ include/assimp/vector3.h | 1 + include/assimp/vector3.inl | 10 +++++++ 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/code/ObjExporter.cpp b/code/ObjExporter.cpp index 9ac902ee3..6cc1063d2 100644 --- a/code/ObjExporter.cpp +++ b/code/ObjExporter.cpp @@ -59,16 +59,10 @@ void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene // we're still here - export successfully completed. Write both the main OBJ file and the material script { boost::scoped_ptr outfile (pIOSystem->Open(pFile,"wt")); - if(outfile == NULL) { - throw DeadlyExportError("could not open output .obj file: " + std::string(pFile)); - } outfile->Write( exporter.mOutput.str().c_str(), static_cast(exporter.mOutput.tellp()),1); } { boost::scoped_ptr outfile (pIOSystem->Open(exporter.GetMaterialLibFileName(),"wt")); - if(outfile == NULL) { - throw DeadlyExportError("could not open output .mtl file: " + std::string(exporter.GetMaterialLibFileName())); - } outfile->Write( exporter.mOutputMat.str().c_str(), static_cast(exporter.mOutputMat.tellp()),1); } } @@ -199,6 +193,7 @@ void ObjExporter :: WriteGeometryFile() AddNode(pScene->mRootNode,mBase); // write vertex positions + vpMap.getVectors(vp); mOutput << "# " << vp.size() << " vertex positions" << endl; BOOST_FOREACH(const aiVector3D& v, vp) { mOutput << "v " << v.x << " " << v.y << " " << v.z << endl; @@ -206,6 +201,7 @@ void ObjExporter :: WriteGeometryFile() mOutput << endl; // write uv coordinates + vtMap.getVectors(vt); mOutput << "# " << vt.size() << " UV coordinates" << endl; BOOST_FOREACH(const aiVector3D& v, vt) { mOutput << "vt " << v.x << " " << v.y << " " << v.z << endl; @@ -213,6 +209,7 @@ void ObjExporter :: WriteGeometryFile() mOutput << endl; // write vertex normals + vnMap.getVectors(vn); mOutput << "# " << vn.size() << " vertex normals" << endl; BOOST_FOREACH(const aiVector3D& v, vn) { mOutput << "vn " << v.x << " " << v.y << " " << v.z << endl; @@ -252,6 +249,31 @@ void ObjExporter :: WriteGeometryFile() } } + + + + +int ObjExporter::vecIndexMap::getIndex(const aiVector3D& vec) +{ + std::map::iterator vertIt = vecMap.find(vec); + if(vertIt != vecMap.end()){// vertex already exists, so reference it + return vertIt->second; + } + vecMap[vec] = mNextIndex; + int ret = mNextIndex; + mNextIndex++; + return ret; +} + +void ObjExporter::vecIndexMap::getVectors( std::vector& vecs ) +{ + vecs.resize(vecMap.size()); + for(std::map::iterator it = vecMap.begin(); it != vecMap.end(); it++){ + vecs[it->second-1] = it->first; + } +} + + // ------------------------------------------------------------------------------------------------ void ObjExporter :: AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) { @@ -262,6 +284,7 @@ void ObjExporter :: AddMesh(const aiString& name, const aiMesh* m, const aiMatri mesh.matname = GetMaterialName(m->mMaterialIndex); mesh.faces.resize(m->mNumFaces); + for(unsigned int i = 0; i < m->mNumFaces; ++i) { const aiFace& f = m->mFaces[i]; @@ -281,21 +304,22 @@ void ObjExporter :: AddMesh(const aiString& name, const aiMesh* m, const aiMatri for(unsigned int a = 0; a < f.mNumIndices; ++a) { const unsigned int idx = f.mIndices[a]; - // XXX need a way to check if this is an unique vertex or if we had it already, - // in which case we should instead reference the previous occurrence. - ai_assert(m->mVertices); - vp.push_back( mat * m->mVertices[idx] ); - face.indices[a].vp = vp.size(); + aiVector3D vert = mat * m->mVertices[idx]; + face.indices[a].vp = vpMap.getIndex(vert); if (m->mNormals) { - vn.push_back( m->mNormals[idx] ); + face.indices[a].vn = vnMap.getIndex(m->mNormals[idx]); + } + else{ + face.indices[a].vn = 0; } - face.indices[a].vn = vn.size(); if (m->mTextureCoords[0]) { - vt.push_back( m->mTextureCoords[0][idx] ); + face.indices[a].vt = vtMap.getIndex(m->mTextureCoords[0][idx]); + } + else{ + face.indices[a].vt = 0; } - face.indices[a].vt = vt.size(); } } } diff --git a/code/ObjExporter.h b/code/ObjExporter.h index f857f5879..4f2f83240 100644 --- a/code/ObjExporter.h +++ b/code/ObjExporter.h @@ -112,6 +112,21 @@ private: const aiScene* const pScene; std::vector vp, vn, vt; + + class vecIndexMap + { + int mNextIndex; + std::map vecMap; + public: + + vecIndexMap():mNextIndex(1) + {} + + int getIndex(const aiVector3D& vec); + void getVectors( std::vector& vecs ); + }; + + vecIndexMap vpMap, vnMap, vtMap; std::vector meshes; // this endl() doesn't flush() the stream diff --git a/include/assimp/vector3.h b/include/assimp/vector3.h index cbdee264d..5b3da297d 100644 --- a/include/assimp/vector3.h +++ b/include/assimp/vector3.h @@ -85,6 +85,7 @@ public: // comparison bool operator== (const aiVector3t& other) const; bool operator!= (const aiVector3t& other) const; + bool operator< (const aiVector3t& other) const; template operator aiVector3t () const; diff --git a/include/assimp/vector3.inl b/include/assimp/vector3.inl index c03437980..90370fa07 100644 --- a/include/assimp/vector3.inl +++ b/include/assimp/vector3.inl @@ -149,6 +149,16 @@ AI_FORCE_INLINE bool aiVector3t::operator!= (const aiVector3t& oth } // ------------------------------------------------------------------------------------------------ template +AI_FORCE_INLINE bool aiVector3t::operator< (const aiVector3t& other) const { + if(x < other.x) return true; + if(x > other.x) return false; + if(y < other.y) return true; + if(y > other.y) return false; + if(z < other.z) return true; + return false; +} +// ------------------------------------------------------------------------------------------------ +template AI_FORCE_INLINE const aiVector3t aiVector3t::SymMul(const aiVector3t& o) { return aiVector3t(x*o.x,y*o.y,z*o.z); }