From 12f33099964c50877ff9bc29957212e020deb6be Mon Sep 17 00:00:00 2001 From: Julian Knodt Date: Wed, 27 Nov 2024 13:53:27 -0800 Subject: [PATCH] Simplify JoinVerticesProcess (#5895) Previously JoinVertices had a lot of extra complexity, simplify it greatly. Co-authored-by: Julian Knodt Co-authored-by: Kim Kulling --- code/PostProcessing/JoinVerticesProcess.cpp | 122 +------------------- include/assimp/Vertex.h | 24 ++++ 2 files changed, 29 insertions(+), 117 deletions(-) diff --git a/code/PostProcessing/JoinVerticesProcess.cpp b/code/PostProcessing/JoinVerticesProcess.cpp index f4c623c98..7d36fbf89 100644 --- a/code/PostProcessing/JoinVerticesProcess.cpp +++ b/code/PostProcessing/JoinVerticesProcess.cpp @@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include using namespace Assimp; @@ -99,52 +100,6 @@ void JoinVerticesProcess::Execute( aiScene* pScene) { 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 void updateXMeshVertices(XMesh *pMesh, std::vector &uniqueVertices) { // replace vertex data with the unique data sets @@ -157,7 +112,7 @@ void updateXMeshVertices(XMesh *pMesh, std::vector &uniqueVertices) { // ---------------------------------------------------------------------------- // Position, if present (check made for aiAnimMesh) - if (pMesh->mVertices) { + if (pMesh->mVertices) { std::unique_ptr oldVertices(pMesh->mVertices); pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; for (unsigned int a = 0; a < pMesh->mNumVertices; a++) @@ -204,41 +159,6 @@ void updateXMeshVertices(XMesh *pMesh, std::vector &uniqueVertices) { } // namespace // ------------------------------------------------------------------------------------------------ -// Unites identical vertices in the given mesh -// combine hashes -inline void hash_combine(std::size_t &) { - // empty -} - -template -inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) { - std::hash hasher; - seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); - hash_combine(seed, rest...); -} -//template specialization for std::hash for Vertex -template<> -struct std::hash { - 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 { - 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; @@ -266,7 +186,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) { // We'll never have more vertices afterwards. std::vector uniqueVertices; - uniqueVertices.reserve( pMesh->mNumVertices); // 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 @@ -276,31 +195,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) { static_assert(AI_MAX_VERTICES == 0x7fffffff, "AI_MAX_VERTICES == 0x7fffffff"); std::vector replaceIndex( pMesh->mNumVertices, 0xffffffff); - // float posEpsilonSqr; - SpatialSort *vertexFinder = nullptr; - SpatialSort _vertexFinder; - - typedef std::pair SpatPair; - if (shared) { - std::vector* 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 verticesFound; - verticesFound.reserve(10); - // 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 ... 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 - const auto numBuckets = pMesh->mNumVertices; - const auto hasher = std::hash(); - const auto comparator = std::equal_to( - pMesh->GetNumUVChannels(), - pMesh->GetNumColorChannels()); - std::unordered_map vertex2Index(numBuckets, hasher, comparator); + std::map vertex2Index = {}; // 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 int newIndex = 0; 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 (it == vertex2Index.end()) { // 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++; // add the vertex to the unique vertices uniqueVertices.push_back(a); diff --git a/include/assimp/Vertex.h b/include/assimp/Vertex.h index c0a6a836a..1f6782966 100644 --- a/include/assimp/Vertex.h +++ b/include/assimp/Vertex.h @@ -111,6 +111,7 @@ struct Vertex { aiColor4D colors[AI_MAX_NUMBER_OF_COLOR_SETS]; Vertex() = default; + ~Vertex() = default; // ---------------------------------------------------------------------------- /** Extract a particular vertex from a mesh and interleave all components */ @@ -182,6 +183,29 @@ struct Vertex { 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 void SortBack(aiMesh* out, unsigned int idx) const {