瀏覽代碼

Merge pull request #1965 from loebl/bug/exception-on-empty-mesh-after-degenerate-removal

Bug/exception on empty mesh after degenerate removal
Kim Kulling 7 年之前
父節點
當前提交
f8c4891acf
共有 2 個文件被更改,包括 55 次插入12 次删除
  1. 53 11
      code/FindDegenerates.cpp
  2. 2 1
      code/FindDegenerates.h

+ 53 - 11
code/FindDegenerates.cpp

@@ -54,6 +54,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 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
 FindDegeneratesProcess::FindDegeneratesProcess()
@@ -87,11 +92,50 @@ void FindDegeneratesProcess::SetupProperties(const Importer* pImp) {
 void FindDegeneratesProcess::Execute( aiScene* pScene) {
     ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
     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");
 }
 
+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 ) {
     ai_real s = (a + b + c) / 2;
     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
-void FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
+bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
     mesh->mPrimitiveTypes = 0;
 
     std::vector<bool> remove_me;
@@ -227,30 +271,28 @@ evil_jump_outside:
                 if (&face_src != &face_dest) {
                     // clear source
                     face_src.mNumIndices = 0;
-                    face_src.mIndices = NULL;
+                    face_src.mIndices = nullptr;
                 }
             }
             else {
                 // Otherwise delete it if we don't need this face
                 delete[] face_src.mIndices;
-                face_src.mIndices = NULL;
+                face_src.mIndices = nullptr;
                 face_src.mNumIndices = 0;
             }
         }
         // Just leave the rest of the array unreferenced, we don't care for now
         mesh->mNumFaces = n;
         if (!mesh->mNumFaces) {
-            // WTF!?
-            // OK ... for completeness and because I'm not yet tired,
-            // let's write code that will hopefully never be called
-            // (famous last words)
-
-            // OK ... bad idea.
-            throw DeadlyImportError("Mesh is empty after removal of degenerated primitives ... WTF!?");
+            //The whole mesh consists of degenerated faces
+            //signal upward, that this mesh should be deleted.
+            ASSIMP_LOG_DEBUG("FindDegeneratesProcess removed a mesh full of degenerated primitives");
+            return true;
         }
     }
 
     if (deg && !DefaultLogger::isNullLogger()) {
         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
-    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