Bladeren bron

Simplify JoinVerticesProcess (#5895)

Previously JoinVertices had a lot of extra complexity, simplify it greatly.

Co-authored-by: Julian Knodt <[email protected]>
Co-authored-by: Kim Kulling <[email protected]>
Julian Knodt 9 maanden geleden
bovenliggende
commit
12f3309996
2 gewijzigde bestanden met toevoegingen van 29 en 117 verwijderingen
  1. 5 117
      code/PostProcessing/JoinVerticesProcess.cpp
  2. 24 0
      include/assimp/Vertex.h

+ 5 - 117
code/PostProcessing/JoinVerticesProcess.cpp

@@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <unordered_set>
 #include <unordered_set>
 #include <unordered_map>
 #include <unordered_map>
 #include <memory>
 #include <memory>
+#include <map>
 
 
 using namespace Assimp;
 using namespace Assimp;
 
 
@@ -99,52 +100,6 @@ void JoinVerticesProcess::Execute( aiScene* pScene) {
 
 
 namespace {
 namespace {
 
 
-bool areVerticesEqual(
-    const Vertex &lhs,
-    const Vertex &rhs,
-    unsigned numUVChannels,
-    unsigned numColorChannels) {
-    // A little helper to find locally close vertices faster.
-    // Try to reuse the lookup table from the last step.
-    const static float epsilon = 1e-5f;
-    // Squared because we check against squared length of the vector difference
-    static const float squareEpsilon = epsilon * epsilon;
-
-    // Square compare is useful for animeshes vertices compare
-    if ((lhs.position - rhs.position).SquareLength() > squareEpsilon) {
-        return false;
-    }
-
-    // We just test the other attributes even if they're not present in the mesh.
-    // In this case they're initialized to 0 so the comparison succeeds.
-    // By this method the non-present attributes are effectively ignored in the comparison.
-    if ((lhs.normal - rhs.normal).SquareLength() > squareEpsilon) {
-        return false;
-    }
-
-    if ((lhs.tangent - rhs.tangent).SquareLength() > squareEpsilon) {
-        return false;
-    }
-
-    if ((lhs.bitangent - rhs.bitangent).SquareLength() > squareEpsilon) {
-        return false;
-    }
-
-    for (unsigned i = 0; i < numUVChannels; i++) {
-        if ((lhs.texcoords[i] - rhs.texcoords[i]).SquareLength() > squareEpsilon) {
-            return false;
-        }
-    }
-
-    for (unsigned i = 0; i < numColorChannels; i++) {
-        if (GetColorDifference(lhs.colors[i], rhs.colors[i]) > squareEpsilon) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
 template<class XMesh>
 template<class XMesh>
 void updateXMeshVertices(XMesh *pMesh, std::vector<int> &uniqueVertices) {
 void updateXMeshVertices(XMesh *pMesh, std::vector<int> &uniqueVertices) {
     // replace vertex data with the unique data sets
     // replace vertex data with the unique data sets
@@ -157,7 +112,7 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<int> &uniqueVertices) {
     // ----------------------------------------------------------------------------
     // ----------------------------------------------------------------------------
 
 
     // Position, if present (check made for aiAnimMesh)
     // Position, if present (check made for aiAnimMesh)
-    if (pMesh->mVertices) {  
+    if (pMesh->mVertices) {
         std::unique_ptr<aiVector3D[]> oldVertices(pMesh->mVertices);
         std::unique_ptr<aiVector3D[]> oldVertices(pMesh->mVertices);
         pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
         pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
         for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
         for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
@@ -204,41 +159,6 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<int> &uniqueVertices) {
 } // namespace
 } // namespace
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-// Unites identical vertices in the given mesh
-// combine hashes
-inline void hash_combine(std::size_t &) {
-    // empty
-}
-
-template <typename T, typename... Rest>
-inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
-    std::hash<T> hasher;
-    seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
-    hash_combine(seed, rest...);
-}
-//template specialization for std::hash for Vertex
-template<>
-struct std::hash<Vertex> {
-    std::size_t operator()(Vertex const& v) const noexcept {
-        size_t seed = 0;
-        hash_combine(seed, v.position.x ,v.position.y,v.position.z);
-        return seed;
-    }
-};
-//template specialization for std::equal_to for Vertex
-template<>
-struct std::equal_to<Vertex> {
-    equal_to(unsigned numUVChannels, unsigned numColorChannels) :
-            mNumUVChannels(numUVChannels),
-            mNumColorChannels(numColorChannels) {}
-    bool operator()(const Vertex &lhs, const Vertex &rhs) const {
-        return areVerticesEqual(lhs, rhs, mNumUVChannels, mNumColorChannels);
-    }
-
-private:
-    unsigned mNumUVChannels;
-    unsigned mNumColorChannels;
-};
 
 
 static constexpr size_t JOINED_VERTICES_MARK = 0x80000000u;
 static constexpr size_t JOINED_VERTICES_MARK = 0x80000000u;
 
 
@@ -266,7 +186,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) {
 
 
     // We'll never have more vertices afterwards.
     // We'll never have more vertices afterwards.
     std::vector<int> uniqueVertices;
     std::vector<int> uniqueVertices;
-    uniqueVertices.reserve( pMesh->mNumVertices);
 
 
     // For each vertex the index of the vertex it was replaced by.
     // For each vertex the index of the vertex it was replaced by.
     // Since the maximal number of vertices is 2^31-1, the most significand bit can be used to mark
     // Since the maximal number of vertices is 2^31-1, the most significand bit can be used to mark
@@ -276,31 +195,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) {
     static_assert(AI_MAX_VERTICES == 0x7fffffff, "AI_MAX_VERTICES == 0x7fffffff");
     static_assert(AI_MAX_VERTICES == 0x7fffffff, "AI_MAX_VERTICES == 0x7fffffff");
     std::vector<unsigned int> replaceIndex( pMesh->mNumVertices, 0xffffffff);
     std::vector<unsigned int> replaceIndex( pMesh->mNumVertices, 0xffffffff);
 
 
-    // float posEpsilonSqr;
-    SpatialSort *vertexFinder = nullptr;
-    SpatialSort _vertexFinder;
-
-    typedef std::pair<SpatialSort,float> SpatPair;
-    if (shared) {
-        std::vector<SpatPair >* avf;
-        shared->GetProperty(AI_SPP_SPATIAL_SORT,avf);
-        if (avf)    {
-            SpatPair& blubb = (*avf)[meshIndex];
-            vertexFinder  = &blubb.first;
-            // posEpsilonSqr = blubb.second;
-        }
-    }
-    if (!vertexFinder)  {
-        // bad, need to compute it.
-        _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
-        vertexFinder = &_vertexFinder;
-        // posEpsilonSqr = ComputePositionEpsilon(pMesh);
-    }
-
-    // Again, better waste some bytes than a realloc ...
-    std::vector<unsigned int> verticesFound;
-    verticesFound.reserve(10);
-
     // Run an optimized code path if we don't have multiple UVs or vertex colors.
     // Run an optimized code path if we don't have multiple UVs or vertex colors.
     // This should yield false in more than 99% of all imports ...
     // This should yield false in more than 99% of all imports ...
     const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0;
     const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0;
@@ -314,14 +208,8 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) {
         }
         }
     }
     }
     // a map that maps a vertex to its new index
     // a map that maps a vertex to its new index
-    const auto numBuckets = pMesh->mNumVertices;
-    const auto hasher = std::hash<Vertex>();
-    const auto comparator = std::equal_to<Vertex>(
-            pMesh->GetNumUVChannels(),
-            pMesh->GetNumColorChannels());
-    std::unordered_map<Vertex, int> vertex2Index(numBuckets, hasher, comparator);
+    std::map<Vertex, int> vertex2Index = {};
     // we can not end up with more vertices than we started with
     // we can not end up with more vertices than we started with
-    vertex2Index.reserve(pMesh->mNumVertices);
     // Now check each vertex if it brings something new to the table
     // Now check each vertex if it brings something new to the table
     int newIndex = 0;
     int newIndex = 0;
     for( unsigned int a = 0; a < pMesh->mNumVertices; a++)  {
     for( unsigned int a = 0; a < pMesh->mNumVertices; a++)  {
@@ -336,8 +224,8 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) {
         // if the vertex is not in the map then it is a new vertex add it.
         // if the vertex is not in the map then it is a new vertex add it.
         if (it == vertex2Index.end()) {
         if (it == vertex2Index.end()) {
             // this is a new vertex give it a new index
             // this is a new vertex give it a new index
-            vertex2Index[v] = newIndex;
-            //keep track of its index and increment 1
+            vertex2Index.emplace(v, newIndex);
+            // keep track of its index and increment 1
             replaceIndex[a] = newIndex++;
             replaceIndex[a] = newIndex++;
             // add the vertex to the unique vertices
             // add the vertex to the unique vertices
             uniqueVertices.push_back(a);
             uniqueVertices.push_back(a);

+ 24 - 0
include/assimp/Vertex.h

@@ -111,6 +111,7 @@ struct Vertex {
     aiColor4D colors[AI_MAX_NUMBER_OF_COLOR_SETS];
     aiColor4D colors[AI_MAX_NUMBER_OF_COLOR_SETS];
 
 
     Vertex() = default;
     Vertex() = default;
+    ~Vertex() = default;
 
 
     // ----------------------------------------------------------------------------
     // ----------------------------------------------------------------------------
     /** Extract a particular vertex from a mesh and interleave all components */
     /** Extract a particular vertex from a mesh and interleave all components */
@@ -182,6 +183,29 @@ struct Vertex {
         return *this;
         return *this;
     }
     }
 
 
+    bool operator < (const Vertex & o) const {
+        if (position < o.position) return true;
+        if (position != o.position) return false;
+
+        if (normal < o.normal) return true;
+        if (normal != o.normal) return false;
+
+        for (uint32_t i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i ++) {
+          if (texcoords[i] < o.texcoords[i]) return true;
+          if (texcoords[i] != o.texcoords[i]) return false;
+        }
+
+        // note that tangent/bitangent are not checked since they are optional
+
+        for (uint32_t i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; i ++) {
+          if (colors[i] < o.colors[i]) return true;
+          if (colors[i] != o.colors[i]) return false;
+        }
+
+        // if reached this point, they are equal
+        return false;
+    }
+
     // ----------------------------------------------------------------------------
     // ----------------------------------------------------------------------------
     /// Convert back to non-interleaved storage
     /// Convert back to non-interleaved storage
     void SortBack(aiMesh* out, unsigned int idx) const {
     void SortBack(aiMesh* out, unsigned int idx) const {