Browse Source

remove duplicate vectors when export obj format

Marshall Hahn 12 years ago
parent
commit
8f34c24ae0
4 changed files with 65 additions and 15 deletions
  1. 39 15
      code/ObjExporter.cpp
  2. 15 0
      code/ObjExporter.h
  3. 1 0
      include/assimp/vector3.h
  4. 10 0
      include/assimp/vector3.inl

+ 39 - 15
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<IOStream> 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<size_t>(exporter.mOutput.tellp()),1);
 	}
 	{
 		boost::scoped_ptr<IOStream> 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<size_t>(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<aiVector3D, int>::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<aiVector3D>& vecs )
+{
+	vecs.resize(vecMap.size());
+	for(std::map<aiVector3D, int>::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();
 		}
 	}
 }

+ 15 - 0
code/ObjExporter.h

@@ -112,6 +112,21 @@ private:
 	const aiScene* const pScene;
 
 	std::vector<aiVector3D> vp, vn, vt;
+
+	class vecIndexMap
+	{
+		int mNextIndex;
+		std::map<aiVector3D, int> vecMap;
+	public:
+
+		vecIndexMap():mNextIndex(1)
+		{}
+
+		int getIndex(const aiVector3D& vec);
+		void getVectors( std::vector<aiVector3D>& vecs );
+	};
+
+	vecIndexMap vpMap, vnMap, vtMap;
 	std::vector<MeshInstance> meshes;
 
 	// this endl() doesn't flush() the stream

+ 1 - 0
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 <typename TOther>
 	operator aiVector3t<TOther> () const;

+ 10 - 0
include/assimp/vector3.inl

@@ -149,6 +149,16 @@ AI_FORCE_INLINE bool aiVector3t<TReal>::operator!= (const aiVector3t<TReal>& oth
 }
 // ------------------------------------------------------------------------------------------------
 template <typename TReal>
+AI_FORCE_INLINE bool aiVector3t<TReal>::operator< (const aiVector3t<TReal>& 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 <typename TReal>
 AI_FORCE_INLINE const aiVector3t<TReal> aiVector3t<TReal>::SymMul(const aiVector3t<TReal>& o) {
 	return aiVector3t<TReal>(x*o.x,y*o.y,z*o.z);
 }