From 8f34c24ae0fd9c49eb90d8f1c1cc2b3c85fd3e30 Mon Sep 17 00:00:00 2001 From: Marshall Hahn Date: Mon, 30 Sep 2013 14:07:53 -0400 Subject: [PATCH 1/7] 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); } From 66fd9bb8a28ea170522d1d50fc3c3c51bdfbbefb Mon Sep 17 00:00:00 2001 From: Marshall Hahn Date: Mon, 30 Sep 2013 14:11:37 -0400 Subject: [PATCH 2/7] fixed bad merge --- code/ObjExporter.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/code/ObjExporter.cpp b/code/ObjExporter.cpp index 6cc1063d2..bbf26ce56 100644 --- a/code/ObjExporter.cpp +++ b/code/ObjExporter.cpp @@ -59,10 +59,16 @@ 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); } } From b72b16c90b025486a756caad68838cbd7b77f887 Mon Sep 17 00:00:00 2001 From: Marshall Hahn Date: Mon, 30 Sep 2013 14:12:38 -0400 Subject: [PATCH 3/7] whitespace fix --- code/ObjExporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/ObjExporter.cpp b/code/ObjExporter.cpp index bbf26ce56..dce217d12 100644 --- a/code/ObjExporter.cpp +++ b/code/ObjExporter.cpp @@ -60,7 +60,7 @@ void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene { boost::scoped_ptr outfile (pIOSystem->Open(pFile,"wt")); if(outfile == NULL) { - throw DeadlyExportError("could not open output .obj file: " + std::string(pFile)); + throw DeadlyExportError("could not open output .obj file: " + std::string(pFile)); } outfile->Write( exporter.mOutput.str().c_str(), static_cast(exporter.mOutput.tellp()),1); } From c29109d1a4ee237d60d4334acfbceb95b2e5cf3a Mon Sep 17 00:00:00 2001 From: Calvin Hsu Date: Mon, 30 Sep 2013 15:12:56 -0700 Subject: [PATCH 4/7] obj: Fix tabs causing vertices to be skipped If an obj vertex definition 'v' is followed by a tab instead of a space, the vertex definition is skipped. --- code/ObjFileParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index ab8fdd124..3d81ab925 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -112,7 +112,7 @@ void ObjFileParser::parseFile() case 'v': // Parse a vertex texture coordinate { ++m_DataIt; - if (*m_DataIt == ' ') + if (*m_DataIt == ' ' || *m_DataIt == '\t') { // Read in vertex definition getVector3(m_pModel->m_Vertices); From 32a10ec0a040aad78e3d9e5cbdac336a76af2903 Mon Sep 17 00:00:00 2001 From: Calvin Hsu Date: Mon, 30 Sep 2013 15:13:11 -0700 Subject: [PATCH 5/7] obj: Add support for relative vertex indexing obj files allow faces to specify indices relatively by using negative integers. See vertex refering in http://www.martinreddy.net/gfx/3d/OBJ.spec --- code/ObjFileParser.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index 3d81ab925..e701ddc62 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -290,6 +290,10 @@ void ObjFileParser::getFace(aiPrimitiveType type) std::vector *pNormalID = new std::vector; bool hasNormal = false; + const int vSize = m_pModel->m_Vertices.size(); + const int vtSize = m_pModel->m_TextureCoord.size(); + const int vnSize = m_pModel->m_Normals.size(); + const bool vt = (!m_pModel->m_TextureCoord.empty()); const bool vn = (!m_pModel->m_Normals.empty()); int iStep = 0, iPos = 0; @@ -323,7 +327,11 @@ void ObjFileParser::getFace(aiPrimitiveType type) { //OBJ USES 1 Base ARRAYS!!!! const int iVal = atoi( pPtr ); + + // increment iStep position based off of the sign and # of digits int tmp = iVal; + if (iVal < 0) + ++iStep; while ( ( tmp = tmp / 10 )!=0 ) ++iStep; @@ -348,6 +356,27 @@ void ObjFileParser::getFace(aiPrimitiveType type) reportErrorTokenInFace(); } } + else if ( iVal < 0 ) + { + // Store relatively index + if ( 0 == iPos ) + { + pIndices->push_back( vSize + iVal ); + } + else if ( 1 == iPos ) + { + pTexID->push_back( vtSize + iVal ); + } + else if ( 2 == iPos ) + { + pNormalID->push_back( vnSize + iVal ); + hasNormal = true; + } + else + { + reportErrorTokenInFace(); + } + } } pPtr += iStep; } From c5921540064ee19cabd0707422274b9c3262f9b9 Mon Sep 17 00:00:00 2001 From: Marshall Hahn Date: Tue, 1 Oct 2013 11:21:36 -0400 Subject: [PATCH 6/7] using a custom compare function instead of a global aiVector3t less than operator --- code/ObjExporter.cpp | 4 ++-- code/ObjExporter.h | 17 ++++++++++++++++- include/assimp/vector3.h | 1 - include/assimp/vector3.inl | 10 ---------- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/code/ObjExporter.cpp b/code/ObjExporter.cpp index dce217d12..b680abb74 100644 --- a/code/ObjExporter.cpp +++ b/code/ObjExporter.cpp @@ -261,7 +261,7 @@ void ObjExporter :: WriteGeometryFile() int ObjExporter::vecIndexMap::getIndex(const aiVector3D& vec) { - std::map::iterator vertIt = vecMap.find(vec); + vecIndexMap::dataType::iterator vertIt = vecMap.find(vec); if(vertIt != vecMap.end()){// vertex already exists, so reference it return vertIt->second; } @@ -274,7 +274,7 @@ int ObjExporter::vecIndexMap::getIndex(const aiVector3D& vec) void ObjExporter::vecIndexMap::getVectors( std::vector& vecs ) { vecs.resize(vecMap.size()); - for(std::map::iterator it = vecMap.begin(); it != vecMap.end(); it++){ + for(vecIndexMap::dataType::iterator it = vecMap.begin(); it != vecMap.end(); it++){ vecs[it->second-1] = it->first; } } diff --git a/code/ObjExporter.h b/code/ObjExporter.h index 4f2f83240..4f6555aa5 100644 --- a/code/ObjExporter.h +++ b/code/ObjExporter.h @@ -113,10 +113,25 @@ private: std::vector vp, vn, vt; + + struct aiVectorCompare + { + bool operator() (const aiVector3D& a, const aiVector3D& b) const + { + if(a.x < b.x) return true; + if(a.x > b.x) return false; + if(a.y < b.y) return true; + if(a.y > b.y) return false; + if(a.z < b.z) return true; + return false; + } + }; + class vecIndexMap { int mNextIndex; - std::map vecMap; + typedef std::map dataType; + dataType vecMap; public: vecIndexMap():mNextIndex(1) diff --git a/include/assimp/vector3.h b/include/assimp/vector3.h index 5b3da297d..cbdee264d 100644 --- a/include/assimp/vector3.h +++ b/include/assimp/vector3.h @@ -85,7 +85,6 @@ 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 90370fa07..c03437980 100644 --- a/include/assimp/vector3.inl +++ b/include/assimp/vector3.inl @@ -149,16 +149,6 @@ 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); } From 325ef632cfad8efb3ece5f62121e0f6457bdc735 Mon Sep 17 00:00:00 2001 From: acgessler Date: Tue, 1 Oct 2013 17:56:00 +0200 Subject: [PATCH 7/7] PlyExporter: fix export format for compatibility with Blender and MeshLab (and the PLY spec). Fixes #122 --- code/PlyExporter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/PlyExporter.cpp b/code/PlyExporter.cpp index 257e6f1f7..e78cfd964 100644 --- a/code/PlyExporter.cpp +++ b/code/PlyExporter.cpp @@ -103,7 +103,7 @@ PlyExporter :: PlyExporter(const char* _filename, const aiScene* pScene) mOutput << "ply" << endl; mOutput << "format ascii 1.0" << endl; - mOutput << "Created by Open Asset Import Library - http://assimp.sf.net (v" + mOutput << "comment Created by Open Asset Import Library - http://assimp.sf.net (v" << aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.' << aiGetVersionRevision() << ")" << endl; @@ -159,7 +159,7 @@ PlyExporter :: PlyExporter(const char* _filename, const aiScene* pScene) } mOutput << "element face " << faces << endl; - mOutput << "property list uint uint vertex_indices" << endl; + mOutput << "property list uint uint vertex_index" << endl; mOutput << "end_header" << endl; for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {