[Bf-blender-cvs] [973ab436f07] blender-v2.83-release: Fix T76514: Invalid geometry in Alembic crashes Blender

Sybren A. Stüvel noreply at git.blender.org
Tue May 12 13:59:02 CEST 2020


Commit: 973ab436f07c652cb6aa13bedc351df06bce6561
Author: Sybren A. Stüvel
Date:   Tue May 12 13:21:17 2020 +0200
Branches: blender-v2.83-release
https://developer.blender.org/rB973ab436f07c652cb6aa13bedc351df06bce6561

Fix T76514: Invalid geometry in Alembic crashes Blender

Even though {T76514} is caused by invalid geometry, and thus technically
constitutes a bug in the software that created the Alembic file, I would
like Blender not to crash on importing such a file.

The error in the Alembic file consists of invalid mesh loops, where
consecutive loops refer to the same vertex. The `BKE_mesh_validate()`
can actually correct these errors, so this commit focuses on two things:

- Letting Blender survive the situation until the mesh is loaded, and
- Detecting the error so that `BKE_mesh_validate()` can be called only
  when necessary. This ensures there is only a minimal impact on
  performance when loading actually valid data.

Differential Revision: https://developer.blender.org/D7703

Reviewed By: JacquesLucke

===================================================================

M	source/blender/blenkernel/intern/mesh_validate.c
M	source/blender/io/alembic/intern/abc_customdata.h
M	source/blender/io/alembic/intern/abc_reader_mesh.cc

===================================================================

diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 3343d41b13c..f64ed609d18 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -1593,8 +1593,15 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool update, const bool select)
       MLoop *l_prev = (l + (mp->totloop - 1));
       int j;
       for (j = 0; j < mp->totloop; j++, l++) {
-        /* lookup hashed edge index */
-        med_index = POINTER_AS_INT(BLI_edgehash_lookup(eh, l_prev->v, l->v));
+        /* Lookup hashed edge index, if it's valid. */
+        if (l_prev->v != l->v) {
+          med_index = POINTER_AS_INT(BLI_edgehash_lookup(eh, l_prev->v, l->v));
+        }
+        else {
+          /* This is an invalid edge; normally this does not happen in Blender, but it can be part
+           * of an imported mesh with invalid geometry. See T76514. */
+          med_index = 0;
+        }
         l_prev->e = med_index;
         l_prev = l;
       }
diff --git a/source/blender/io/alembic/intern/abc_customdata.h b/source/blender/io/alembic/intern/abc_customdata.h
index 6107e230627..11b005eb66a 100644
--- a/source/blender/io/alembic/intern/abc_customdata.h
+++ b/source/blender/io/alembic/intern/abc_customdata.h
@@ -68,6 +68,8 @@ struct CDStreamConfig {
   Alembic::AbcGeom::index_t index;
   Alembic::AbcGeom::index_t ceil_index;
 
+  const char **modifier_error_message;
+
   CDStreamConfig()
       : mloop(NULL),
         totloop(0),
@@ -80,7 +82,8 @@ struct CDStreamConfig {
         weight(0.0f),
         time(0.0f),
         index(0),
-        ceil_index(0)
+        ceil_index(0),
+        modifier_error_message(NULL)
   {
   }
 };
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index ec74fb2137e..b85bce3e10a 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -201,6 +201,7 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
   unsigned int loop_index = 0;
   unsigned int rev_loop_index = 0;
   unsigned int uv_index = 0;
+  bool seen_invalid_geometry = false;
 
   for (int i = 0; i < face_counts->size(); i++) {
     const int face_size = (*face_counts)[i];
@@ -216,10 +217,18 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
     /* NOTE: Alembic data is stored in the reverse order. */
     rev_loop_index = loop_index + (face_size - 1);
 
+    uint last_vertex_index = 0;
     for (int f = 0; f < face_size; f++, loop_index++, rev_loop_index--) {
       MLoop &loop = mloops[rev_loop_index];
       loop.v = (*face_indices)[loop_index];
 
+      if (f > 0 && loop.v == last_vertex_index) {
+        /* This face is invalid, as it has consecutive loops from the same vertex. This is caused
+         * by invalid geometry in the Alembic file, such as in T76514. */
+        seen_invalid_geometry = true;
+      }
+      last_vertex_index = loop.v;
+
       if (do_uvs) {
         MLoopUV &loopuv = mloopuvs[rev_loop_index];
 
@@ -237,6 +246,12 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
   }
 
   BKE_mesh_calc_edges(config.mesh, false, false);
+  if (seen_invalid_geometry) {
+    if (config.modifier_error_message) {
+      *config.modifier_error_message = "Mesh hash invalid geometry; more details on the console";
+    }
+    BKE_mesh_validate(config.mesh, true, true);
+  }
 }
 
 static void process_no_normals(CDStreamConfig &config)
@@ -609,6 +624,7 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
 
   CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh);
   config.time = sample_sel.getRequestedTime();
+  config.modifier_error_message = err_str;
 
   read_mesh_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config);



More information about the Bf-blender-cvs mailing list