summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKim Kulling <kimkulling@users.noreply.github.com>2022-05-14 11:54:06 +0200
committerGitHub <noreply@github.com>2022-05-14 11:54:06 +0200
commitc8dafe0d2887242285c0080c6cbbea8c1f1c8094 (patch)
tree41cc52263a42215ba49a822a63bc8a7aaa830749
parentf44a94e11857b644fdc46d111a6b6fd3b5ac99a6 (diff)
parent58af6ba9db9cccdd6a0acd2a57d35c531472fc3e (diff)
Merge pull request #4527 from motazmuhammad/masterv5.2.4
Accelerate the Merge vertex post processing step
-rw-r--r--code/PostProcessing/JoinVerticesProcess.cpp168
1 files changed, 75 insertions, 93 deletions
diff --git a/code/PostProcessing/JoinVerticesProcess.cpp b/code/PostProcessing/JoinVerticesProcess.cpp
index 184e8d745..745ce1a5e 100644
--- a/code/PostProcessing/JoinVerticesProcess.cpp
+++ b/code/PostProcessing/JoinVerticesProcess.cpp
@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team
-
-
All rights reserved.
Redistribution and use of this software in source and binary forms,
@@ -45,41 +43,38 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* for all imported meshes
*/
-
#ifndef ASSIMP_BUILD_NO_JOINVERTICES_PROCESS
#include "JoinVerticesProcess.h"
#include "ProcessHelper.h"
#include <assimp/Vertex.h>
#include <assimp/TinyFormatter.h>
+
#include <stdio.h>
#include <unordered_set>
+#include <unordered_map>
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
-JoinVerticesProcess::JoinVerticesProcess()
-{
+JoinVerticesProcess::JoinVerticesProcess() {
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
-JoinVerticesProcess::~JoinVerticesProcess()
-{
+JoinVerticesProcess::~JoinVerticesProcess() {
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
-bool JoinVerticesProcess::IsActive( unsigned int pFlags) const
-{
+bool JoinVerticesProcess::IsActive( unsigned int pFlags) const {
return (pFlags & aiProcess_JoinIdenticalVertices) != 0;
}
// ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data.
-void JoinVerticesProcess::Execute( aiScene* pScene)
-{
+void JoinVerticesProcess::Execute( aiScene* pScene) {
ASSIMP_LOG_DEBUG("JoinVerticesProcess begin");
// get the total number of vertices BEFORE the step is executed
@@ -92,27 +87,29 @@ void JoinVerticesProcess::Execute( aiScene* pScene)
// execute the step
int iNumVertices = 0;
- for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
+ for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
iNumVertices += ProcessMesh( pScene->mMeshes[a],a);
+ }
+
+ pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
// if logging is active, print detailed statistics
if (!DefaultLogger::isNullLogger()) {
if (iNumOldVertices == iNumVertices) {
ASSIMP_LOG_DEBUG("JoinVerticesProcess finished ");
- } else {
- ASSIMP_LOG_INFO("JoinVerticesProcess finished | Verts in: ", iNumOldVertices,
- " out: ", iNumVertices, " | ~",
- ((iNumOldVertices - iNumVertices) / (float)iNumOldVertices) * 100.f );
+ return;
}
+
+ // Show statistics
+ ASSIMP_LOG_INFO("JoinVerticesProcess finished | Verts in: ", iNumOldVertices,
+ " out: ", iNumVertices, " | ~",
+ ((iNumOldVertices - iNumVertices) / (float)iNumOldVertices) * 100.f );
}
-
- pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
}
namespace {
-bool areVerticesEqual(const Vertex &lhs, const Vertex &rhs, bool complex)
-{
+bool areVerticesEqual(const Vertex &lhs, const Vertex &rhs, bool complex) {
// 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;
@@ -171,8 +168,7 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<Vertex> &uniqueVertices) {
// ----------------------------------------------------------------------------
// Position, if present (check made for aiAnimMesh)
- if (pMesh->mVertices)
- {
+ if (pMesh->mVertices) {
delete [] pMesh->mVertices;
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
@@ -181,8 +177,7 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<Vertex> &uniqueVertices) {
}
// Normals, if present
- if (pMesh->mNormals)
- {
+ if (pMesh->mNormals) {
delete [] pMesh->mNormals;
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
@@ -190,8 +185,7 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<Vertex> &uniqueVertices) {
}
}
// Tangents, if present
- if (pMesh->mTangents)
- {
+ if (pMesh->mTangents) {
delete [] pMesh->mTangents;
pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
@@ -199,8 +193,7 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<Vertex> &uniqueVertices) {
}
}
// Bitangents as well
- if (pMesh->mBitangents)
- {
+ if (pMesh->mBitangents) {
delete [] pMesh->mBitangents;
pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
@@ -208,8 +201,7 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<Vertex> &uniqueVertices) {
}
}
// Vertex colors
- for (unsigned int a = 0; pMesh->HasVertexColors(a); a++)
- {
+ for (unsigned int a = 0; pMesh->HasVertexColors(a); a++) {
delete [] pMesh->mColors[a];
pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices];
for( unsigned int b = 0; b < pMesh->mNumVertices; b++) {
@@ -217,8 +209,7 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<Vertex> &uniqueVertices) {
}
}
// Texture coords
- for (unsigned int a = 0; pMesh->HasTextureCoords(a); a++)
- {
+ for (unsigned int a = 0; pMesh->HasTextureCoords(a); a++) {
delete [] pMesh->mTextureCoords[a];
pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices];
for (unsigned int b = 0; b < pMesh->mNumVertices; b++) {
@@ -226,12 +217,40 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<Vertex> &uniqueVertices) {
}
}
}
+
} // namespace
// ------------------------------------------------------------------------------------------------
// Unites identical vertices in the given mesh
-int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
-{
+// 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> {
+ bool operator()(const Vertex &lhs, const Vertex &rhs) const {
+ return areVerticesEqual(lhs, rhs, false);
+ }
+};
+// now start the JoinVerticesProcess
+int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) {
static_assert( AI_MAX_NUMBER_OF_COLOR_SETS == 8, "AI_MAX_NUMBER_OF_COLOR_SETS == 8");
static_assert( AI_MAX_NUMBER_OF_TEXTURECOORDS == 8, "AI_MAX_NUMBER_OF_TEXTURECOORDS == 8");
@@ -245,8 +264,7 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
// multiple meshes)
std::unordered_set<unsigned int> usedVertexIndices;
usedVertexIndices.reserve(pMesh->mNumVertices);
- for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
- {
+ for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
aiFace& face = pMesh->mFaces[a];
for( unsigned int b = 0; b < face.mNumIndices; b++) {
usedVertexIndices.insert(face.mIndices[b]);
@@ -292,7 +310,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
// 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 complex = ( pMesh->GetNumColorChannels() > 0 || pMesh->GetNumUVChannels() > 1);
const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0;
// We'll never have more vertices afterwards.
@@ -303,72 +320,38 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
uniqueAnimatedVertices[animMeshIndex].reserve(pMesh->mNumVertices);
}
}
-
+ // a map that maps a vertix to its new index
+ std::unordered_map<Vertex,int> 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++) {
+ // if the vertex is unused Do nothing
if (usedVertexIndices.find(a) == usedVertexIndices.end()) {
continue;
}
-
// collect the vertex data
Vertex v(pMesh,a);
-
- // collect all vertices that are close enough to the given position
- vertexFinder->FindIdenticalPositions( v.position, verticesFound);
- unsigned int matchIndex = 0xffffffff;
-
- // check all unique vertices close to the position if this vertex is already present among them
- for( unsigned int b = 0; b < verticesFound.size(); b++) {
- const unsigned int vidx = verticesFound[b];
- const unsigned int uidx = replaceIndex[ vidx];
- if( uidx & 0x80000000)
- continue;
-
- const Vertex& uv = uniqueVertices[ uidx];
-
- if (!areVerticesEqual(v, uv, complex)) {
- continue;
- }
-
- if (hasAnimMeshes) {
- // If given vertex is animated, then it has to be preserver 1 to 1 (base mesh and animated mesh require same topology)
- // NOTE: not doing this totaly breaks anim meshes as they don't have their own faces (they use pMesh->mFaces)
- bool breaksAnimMesh = false;
- for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) {
- const Vertex& animatedUV = uniqueAnimatedVertices[animMeshIndex][ uidx];
- Vertex aniMeshVertex(pMesh->mAnimMeshes[animMeshIndex], a);
- if (!areVerticesEqual(aniMeshVertex, animatedUV, complex)) {
- breaksAnimMesh = true;
- break;
- }
- }
- if (breaksAnimMesh) {
- continue;
- }
- }
-
- // we're still here -> this vertex perfectly matches our given vertex
- matchIndex = uidx;
- break;
- }
-
- // found a replacement vertex among the uniques?
- if( matchIndex != 0xffffffff)
- {
- // store where to found the matching unique vertex
- replaceIndex[a] = matchIndex | 0x80000000;
- }
- else
- {
- // no unique vertex matches it up to now -> so add it
- replaceIndex[a] = (unsigned int)uniqueVertices.size();
- uniqueVertices.push_back( v);
+ // is the vertex already in the map?
+ auto it = vertex2Index.find(v);
+ // 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
+ replaceIndex[a] = newIndex++;
+ // add the vertex to the unique vertices
+ uniqueVertices.push_back(v);
if (hasAnimMeshes) {
for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) {
Vertex aniMeshVertex(pMesh->mAnimMeshes[animMeshIndex], a);
- uniqueAnimatedVertices[animMeshIndex].push_back(aniMeshVertex);
+ uniqueAnimatedVertices[animMeshIndex].push_back(v);
}
}
+ } else{
+ // if the vertex is already there just find the replace index that is appropriate to it
+ replaceIndex[a] = it->second;
}
}
@@ -394,8 +377,7 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
}
// adjust the indices in all faces
- for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
- {
+ for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
aiFace& face = pMesh->mFaces[a];
for( unsigned int b = 0; b < face.mNumIndices; b++) {
face.mIndices[b] = replaceIndex[face.mIndices[b]] & ~0x80000000;