From f80535f543c99a5d3b5fe484a31c3bbfe722b781 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Fri, 3 Sep 2010 09:37:58 +0200 Subject: [PATCH] ignore duplicate geometry when importing --- src/converter/collada.cpp | 115 ++++++++++++++++++++++++++++++-------- 1 file changed, 91 insertions(+), 24 deletions(-) diff --git a/src/converter/collada.cpp b/src/converter/collada.cpp index a50533cf..39491aa7 100644 --- a/src/converter/collada.cpp +++ b/src/converter/collada.cpp @@ -203,34 +203,72 @@ VertexData *fetchVertexData(Transform transform, std::ostream &os, /// For using vertices as keys in an associative structure struct vertex_key_order : public std::binary_function { -public: + static int compare(const Vertex &v1, const Vertex &v2) { + if (v1.v.x < v2.v.x) return -1; + else if (v1.v.x > v2.v.x) return 1; + if (v1.v.y < v2.v.y) return -1; + else if (v1.v.y > v2.v.y) return 1; + if (v1.v.z < v2.v.z) return -1; + else if (v1.v.z > v2.v.z) return 1; + if (v1.n.x < v2.n.x) return -1; + else if (v1.n.x > v2.n.x) return 1; + if (v1.n.y < v2.n.y) return -1; + else if (v1.n.y > v2.n.y) return 1; + if (v1.n.z < v2.n.z) return -1; + else if (v1.n.z > v2.n.z) return 1; + if (v1.uv.x < v2.uv.x) return -1; + else if (v1.uv.x > v2.uv.x) return 1; + if (v1.uv.y < v2.uv.y) return -1; + else if (v1.uv.y > v2.uv.y) return 1; + return 0; + } + bool operator()(const Vertex &v1, const Vertex &v2) const { - if (v1.v.x < v2.v.x) return true; - else if (v1.v.x > v2.v.x) return false; - if (v1.v.y < v2.v.y) return true; - else if (v1.v.y > v2.v.y) return false; - if (v1.v.z < v2.v.z) return true; - else if (v1.v.z > v2.v.z) return false; - if (v1.n.x < v2.n.x) return true; - else if (v1.n.x > v2.n.x) return false; - if (v1.n.y < v2.n.y) return true; - else if (v1.n.y > v2.n.y) return false; - if (v1.n.z < v2.n.z) return true; - else if (v1.n.z > v2.n.z) return false; - if (v1.uv.x < v2.uv.x) return true; - else if (v1.uv.x > v2.uv.x) return false; - if (v1.uv.y < v2.uv.y) return true; - else if (v1.uv.y > v2.uv.y) return false; + return compare(v1, v2) < 0; + } +}; + +struct SimpleTriangle { + Point p0, p1, p2; + + inline SimpleTriangle() { } + inline SimpleTriangle(const Point &p0, const Point &p1, const Point &p2) + : p0(p0), p1(p1), p2(p2) { } +}; + +struct triangle_key_order : public std::binary_function { + static int compare(const Point &v1, const Point &v2) { + if (v1.x < v2.x) return -1; + else if (v1.x > v2.x) return 1; + if (v1.y < v2.y) return -1; + else if (v1.y > v2.y) return 1; + if (v1.z < v2.z) return -1; + else if (v1.z > v2.z) return 1; + return 0; + } + bool operator()(const SimpleTriangle &t1, const SimpleTriangle &t2) const { + int result; + result = compare(t1.p0, t2.p0); + if (result == -1) return true; + if (result == 1) return false; + result = compare(t1.p1, t2.p1); + if (result == -1) return true; + if (result == 1) return false; + result = compare(t1.p2, t2.p2); + if (result == -1) return true; + if (result == 1) return false; return false; } }; +typedef std::map TriangleMap; + void writeGeometry(std::string prefixName, std::string id, int geomIndex, std::string matID, Transform transform, - std::ostream &os, VertexData *vData, const std::string &meshesDirectory) { + std::ostream &os, VertexData *vData, TriangleMap &triMap, const std::string &meshesDirectory) { std::vector vertexBuffer; std::vector triangles; std::map vertexMap; - size_t numMerged = 0, triangleIdx = 0; + size_t numMerged = 0, triangleIdx = 0, duplicates = 0; Triangle triangle; if (tess_data.size() == 0) return; @@ -263,11 +301,38 @@ void writeGeometry(std::string prefixName, std::string id, int geomIndex, std::s } triangle.idx[triangleIdx++] = key; if (triangleIdx == 3) { - triangles.push_back(triangle); + Point p0 = vertexBuffer[triangle.idx[0]].v, + p1 = vertexBuffer[triangle.idx[1]].v, + p2 = vertexBuffer[triangle.idx[2]].v; + if (triMap.find(SimpleTriangle(p0, p1, p2)) != triMap.end() || + triMap.find(SimpleTriangle(p2, p0, p1)) != triMap.end() || + triMap.find(SimpleTriangle(p1, p2, p0)) != triMap.end() || + triMap.find(SimpleTriangle(p1, p0, p2)) != triMap.end() || + triMap.find(SimpleTriangle(p0, p2, p1)) != triMap.end() || + triMap.find(SimpleTriangle(p2, p1, p0)) != triMap.end()) { + /* This triangle is a duplicate from another one which exists + in the same geometry group -- we may be dealing with SketchUp, + which sometimes exports every face TWICE! */ + duplicates++; + } else { + triMap[SimpleTriangle(p0, p1, p2)] = true; + triangles.push_back(triangle); + } triangleIdx = 0; } } + if (duplicates > 0) { + if (triangles.size() == 0) { + SLog(EWarn, "%s: Only contains duplicates of already-existing geometry. Ignoring."); + os << "\t" << endl << endl; + return; + } else { + SLog(EWarn, "Geometry contains %i duplicate triangles!", duplicates); + } + } + SAssert(triangleIdx == 0); SLog(EInfo, "%s: Converted " SIZE_T_FMT " triangles, " SIZE_T_FMT " vertices (merged " SIZE_T_FMT " vertices).", id.c_str(), @@ -315,8 +380,10 @@ void loadGeometry(std::string prefixName, Transform transform, std::ostream &os, identifier = formatString("unnamedGeom_%i", unnamedCtr++); } } + TriangleMap triMap; - SLog(EInfo, "Converting geometry \"%s\" (instantiated by %s)..", identifier.c_str(), prefixName.c_str()); + SLog(EInfo, "Converting geometry \"%s\" (instantiated by %s)..", identifier.c_str(), + prefixName == "" ? "/" : prefixName.c_str()); domMesh *mesh = geom.getMesh().cast(); if (!mesh) SLog(EError, "Invalid geometry type encountered (must be a )!"); @@ -340,7 +407,7 @@ void loadGeometry(std::string prefixName, Transform transform, std::ostream &os, SLog(EWarn, "Referenced material could not be found, substituting a lambertian BRDF."); else matID = matLookupTable[triangles->getMaterial()]; - writeGeometry(prefixName, identifier, geomIndex, matID, transform, os, data, meshesDir); + writeGeometry(prefixName, identifier, geomIndex, matID, transform, os, data, triMap, meshesDir); delete data; ++geomIndex; } @@ -378,7 +445,7 @@ void loadGeometry(std::string prefixName, Transform transform, std::ostream &os, else matID = matLookupTable[polygons->getMaterial()]; - writeGeometry(prefixName, identifier, geomIndex, matID, transform, os, data, meshesDir); + writeGeometry(prefixName, identifier, geomIndex, matID, transform, os, data, triMap, meshesDir); delete data; ++geomIndex; } @@ -418,7 +485,7 @@ void loadGeometry(std::string prefixName, Transform transform, std::ostream &os, else matID = matLookupTable[polylist->getMaterial()]; - writeGeometry(prefixName, identifier, geomIndex, matID, transform, os, data, meshesDir); + writeGeometry(prefixName, identifier, geomIndex, matID, transform, os, data, triMap, meshesDir); delete data; ++geomIndex; }