Просмотр исходного кода

Do not throw exception on empty mesh after removal of degenerates

Remove mesh instead. This keeps one edge case open: nodes without mesh
references. They are kept as it is for now (they may stilol contain
transformations and child references).
Daniel Löber 7 лет назад
Родитель
Сommit
46ed73c768
2 измененных файлов с 54 добавлено и 5 удалено
  1. 52 4
      code/FindDegenerates.cpp
  2. 2 1
      code/FindDegenerates.h

+ 52 - 4
code/FindDegenerates.cpp

@@ -54,6 +54,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 using namespace Assimp;
 using namespace Assimp;
 
 
+//remove mesh at position 'index' from the scene
+static void removeMesh(aiScene* pScene, unsigned const index);
+//correct node indices to meshes and remove references to deleted mesh
+static void updateSceneGraph(aiNode* pNode, unsigned const index);
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
 FindDegeneratesProcess::FindDegeneratesProcess()
 FindDegeneratesProcess::FindDegeneratesProcess()
@@ -87,11 +92,50 @@ void FindDegeneratesProcess::SetupProperties(const Importer* pImp) {
 void FindDegeneratesProcess::Execute( aiScene* pScene) {
 void FindDegeneratesProcess::Execute( aiScene* pScene) {
     ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
     ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
     for (unsigned int i = 0; i < pScene->mNumMeshes;++i){
     for (unsigned int i = 0; i < pScene->mNumMeshes;++i){
-        ExecuteOnMesh( pScene->mMeshes[ i ] );
+        if (ExecuteOnMesh(pScene->mMeshes[i])) {
+            removeMesh(pScene, i);
+            --i; //the current i is removed, do not skip the next one
+        }
     }
     }
     ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished");
     ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished");
 }
 }
 
 
+static void removeMesh(aiScene* pScene, unsigned const index) {
+    //we start at index and copy the pointers one position forward
+    //save the mesh pointer to delete it later
+    auto delete_me = pScene->mMeshes[index];
+    for (unsigned i = index; i < pScene->mNumMeshes - 1; ++i) {
+        pScene->mMeshes[i] = pScene->mMeshes[i+1];
+    }
+    pScene->mMeshes[pScene->mNumMeshes - 1] = nullptr;
+    --(pScene->mNumMeshes);
+    delete delete_me;
+
+    //removing a mesh also requires updating all references to it in the scene graph
+    updateSceneGraph(pScene->mRootNode, index);
+}
+
+static void updateSceneGraph(aiNode* pNode, unsigned const index) {
+    for (unsigned i = 0; i < pNode->mNumMeshes; ++i) {
+        if (pNode->mMeshes[i] > index) {
+            --(pNode->mMeshes[i]);
+            continue;
+        }
+        if (pNode->mMeshes[i] == index) {
+            for (unsigned j = i; j < pNode->mNumMeshes -1; ++j) {
+                pNode->mMeshes[j] = pNode->mMeshes[j+1];
+            }
+            --(pNode->mNumMeshes);
+            --i;
+            continue;
+        }
+    }
+    //recurse to all children
+    for (unsigned i = 0; i < pNode->mNumChildren; ++i) {
+        updateSceneGraph(pNode->mChildren[i], index);
+    }
+}
+
 static ai_real heron( ai_real a, ai_real b, ai_real c ) {
 static ai_real heron( ai_real a, ai_real b, ai_real c ) {
     ai_real s = (a + b + c) / 2;
     ai_real s = (a + b + c) / 2;
     ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), (ai_real)0.5 );
     ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), (ai_real)0.5 );
@@ -125,7 +169,7 @@ static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported mesh
 // Executes the post processing step on the given imported mesh
-void FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
+bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
     mesh->mPrimitiveTypes = 0;
     mesh->mPrimitiveTypes = 0;
 
 
     std::vector<bool> remove_me;
     std::vector<bool> remove_me;
@@ -227,19 +271,22 @@ evil_jump_outside:
                 if (&face_src != &face_dest) {
                 if (&face_src != &face_dest) {
                     // clear source
                     // clear source
                     face_src.mNumIndices = 0;
                     face_src.mNumIndices = 0;
-                    face_src.mIndices = NULL;
+                    face_src.mIndices = nullptr;
                 }
                 }
             }
             }
             else {
             else {
                 // Otherwise delete it if we don't need this face
                 // Otherwise delete it if we don't need this face
                 delete[] face_src.mIndices;
                 delete[] face_src.mIndices;
-                face_src.mIndices = NULL;
+                face_src.mIndices = nullptr;
                 face_src.mNumIndices = 0;
                 face_src.mNumIndices = 0;
             }
             }
         }
         }
         // Just leave the rest of the array unreferenced, we don't care for now
         // Just leave the rest of the array unreferenced, we don't care for now
         mesh->mNumFaces = n;
         mesh->mNumFaces = n;
         if (!mesh->mNumFaces) {
         if (!mesh->mNumFaces) {
+            //The whole mesh consists of degenerated faces
+            //signal upward, that this mesh should be deleted.
+            return true;
             // WTF!?
             // WTF!?
             // OK ... for completeness and because I'm not yet tired,
             // OK ... for completeness and because I'm not yet tired,
             // let's write code that will hopefully never be called
             // let's write code that will hopefully never be called
@@ -253,4 +300,5 @@ evil_jump_outside:
     if (deg && !DefaultLogger::isNullLogger()) {
     if (deg && !DefaultLogger::isNullLogger()) {
         ASSIMP_LOG_WARN_F( "Found ", deg, " degenerated primitives");
         ASSIMP_LOG_WARN_F( "Found ", deg, " degenerated primitives");
     }
     }
+    return false;
 }
 }

+ 2 - 1
code/FindDegenerates.h

@@ -74,7 +74,8 @@ public:
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     // Execute step on a given mesh
     // Execute step on a given mesh
-    void ExecuteOnMesh( aiMesh* mesh);
+    ///@returns true if the current mesh should be deleted, false otherwise
+    bool ExecuteOnMesh( aiMesh* mesh);
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /// @brief Enable the instant removal of degenerated primitives
     /// @brief Enable the instant removal of degenerated primitives