[Bf-blender-cvs] [ee8aad79c15] master: Fix T56408: Hair children recalc on every frame on Alembic mesh

Sybren A. Stüvel noreply at git.blender.org
Fri Aug 16 14:54:04 CEST 2019


Commit: ee8aad79c1590cd0e98ba67961909ebfa8f6a803
Author: Sybren A. Stüvel
Date:   Fri Aug 16 14:52:08 2019 +0200
Branches: master
https://developer.blender.org/rBee8aad79c1590cd0e98ba67961909ebfa8f6a803

Fix T56408: Hair children recalc on every frame on Alembic mesh

This fixes the glitching hairs described in T56408, T63534, and possibly
also T63534.

The fix consists of returning the original mesh (i.e. as visible in edit
mode) when constructing the ORCO mesh. This allows a static set of
coordinates to be used when computing the child hair positions.

The original mesh is only returned when it has the same topology (at
least same number of vertices, loops, and polys. It's up the author of
the Alembic file to ensure stable geometry when it's desired to be
compatible with Blender's hair system.

Reviewers: mont29, brecht

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

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

M	source/blender/alembic/ABC_alembic.h
M	source/blender/alembic/intern/abc_mesh.cc
M	source/blender/alembic/intern/abc_mesh.h
M	source/blender/alembic/intern/abc_object.cc
M	source/blender/alembic/intern/abc_object.h
M	source/blender/alembic/intern/alembic_capi.cc
M	source/blender/modifiers/intern/MOD_meshsequencecache.c

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

diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h
index 653382017d6..696e0ff1810 100644
--- a/source/blender/alembic/ABC_alembic.h
+++ b/source/blender/alembic/ABC_alembic.h
@@ -117,6 +117,12 @@ struct Mesh *ABC_read_mesh(struct CacheReader *reader,
                            const char **err_str,
                            int flags);
 
+bool ABC_mesh_topology_changed(struct CacheReader *reader,
+                               struct Object *ob,
+                               struct Mesh *existing_mesh,
+                               const float time,
+                               const char **err_str);
+
 void CacheReader_incref(struct CacheReader *reader);
 void CacheReader_free(struct CacheReader *reader);
 
diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc
index 6647ca83bd6..be2793e38f7 100644
--- a/source/blender/alembic/intern/abc_mesh.cc
+++ b/source/blender/alembic/intern/abc_mesh.cc
@@ -1131,6 +1131,31 @@ bool AbcMeshReader::accepts_object_type(
   return true;
 }
 
+bool AbcMeshReader::topology_changed(Mesh *existing_mesh, const ISampleSelector &sample_sel)
+{
+  IPolyMeshSchema::Sample sample;
+  try {
+    sample = m_schema.getValue(sample_sel);
+  }
+  catch (Alembic::Util::Exception &ex) {
+    printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n",
+           m_iobject.getFullName().c_str(),
+           m_schema.getName().c_str(),
+           sample_sel.getRequestedTime(),
+           ex.what());
+    // A similar error in read_mesh() would just return existing_mesh.
+    return false;
+  }
+
+  const P3fArraySamplePtr &positions = sample.getPositions();
+  const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
+  const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
+
+  return positions->size() != existing_mesh->totvert ||
+         face_counts->size() != existing_mesh->totpoly ||
+         face_indices->size() != existing_mesh->totloop;
+}
+
 Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
                                const ISampleSelector &sample_sel,
                                int read_flag,
@@ -1162,10 +1187,7 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
   ImportSettings settings;
   settings.read_flag |= read_flag;
 
-  bool topology_changed = positions->size() != existing_mesh->totvert ||
-                          face_counts->size() != existing_mesh->totpoly ||
-                          face_indices->size() != existing_mesh->totloop;
-  if (topology_changed) {
+  if (topology_changed(existing_mesh, sample_sel)) {
     new_mesh = BKE_mesh_new_nomain_from_template(
         existing_mesh, positions->size(), 0, 0, face_indices->size(), face_counts->size());
 
diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h
index 859ab121eb6..77686a0204e 100644
--- a/source/blender/alembic/intern/abc_mesh.h
+++ b/source/blender/alembic/intern/abc_mesh.h
@@ -110,6 +110,8 @@ class AbcMeshReader : public AbcObjectReader {
                          const Alembic::Abc::ISampleSelector &sample_sel,
                          int read_flag,
                          const char **err_str);
+  bool topology_changed(Mesh *existing_mesh,
+                        const Alembic::Abc::ISampleSelector &sample_sel) override;
 
  private:
   void readFaceSetsSample(Main *bmain,
diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc
index f863fe4fee7..ebebbc0da1e 100644
--- a/source/blender/alembic/intern/abc_object.cc
+++ b/source/blender/alembic/intern/abc_object.cc
@@ -246,6 +246,14 @@ struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh,
   return existing_mesh;
 }
 
+bool AbcObjectReader::topology_changed(Mesh * /*existing_mesh*/,
+                                       const Alembic::Abc::ISampleSelector & /*sample_sel*/)
+{
+  /* The default implementation of read_mesh() just returns the original mesh, so never changes the
+   * topology. */
+  return false;
+}
+
 void AbcObjectReader::setupObjectTransform(const float time)
 {
   bool is_constant = false;
diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h
index 537f24ab7d6..efe78b9017c 100644
--- a/source/blender/alembic/intern/abc_object.h
+++ b/source/blender/alembic/intern/abc_object.h
@@ -190,6 +190,8 @@ class AbcObjectReader {
                                  const Alembic::Abc::ISampleSelector &sample_sel,
                                  int read_flag,
                                  const char **err_str);
+  virtual bool topology_changed(Mesh *existing_mesh,
+                                const Alembic::Abc::ISampleSelector &sample_sel);
 
   /** Reads the object matrix and sets up an object transform if animated. */
   void setupObjectTransform(const float time);
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
index d63b310fef7..f7ba925530b 100644
--- a/source/blender/alembic/intern/alembic_capi.cc
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -937,12 +937,7 @@ void ABC_get_transform(CacheReader *reader, float r_mat[4][4], float time, float
 
 /* ************************************************************************** */
 
-Mesh *ABC_read_mesh(CacheReader *reader,
-                    Object *ob,
-                    Mesh *existing_mesh,
-                    const float time,
-                    const char **err_str,
-                    int read_flag)
+static AbcObjectReader *get_abc_reader(CacheReader *reader, Object *ob, const char **err_str)
 {
   AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
   IObject iobject = abc_reader->iobject();
@@ -958,12 +953,44 @@ Mesh *ABC_read_mesh(CacheReader *reader,
     return NULL;
   }
 
+  return abc_reader;
+}
+
+static ISampleSelector sample_selector_for_time(float time)
+{
   /* kFloorIndex is used to be compatible with non-interpolating
    * properties; they use the floor. */
-  ISampleSelector sample_sel(time, ISampleSelector::kFloorIndex);
+  return ISampleSelector(time, ISampleSelector::kFloorIndex);
+}
+
+Mesh *ABC_read_mesh(CacheReader *reader,
+                    Object *ob,
+                    Mesh *existing_mesh,
+                    const float time,
+                    const char **err_str,
+                    int read_flag)
+{
+  AbcObjectReader *abc_reader = get_abc_reader(reader, ob, err_str);
+  if (abc_reader == NULL) {
+    return NULL;
+  }
+
+  ISampleSelector sample_sel = sample_selector_for_time(time);
   return abc_reader->read_mesh(existing_mesh, sample_sel, read_flag, err_str);
 }
 
+bool ABC_mesh_topology_changed(
+    CacheReader *reader, Object *ob, Mesh *existing_mesh, const float time, const char **err_str)
+{
+  AbcObjectReader *abc_reader = get_abc_reader(reader, ob, err_str);
+  if (abc_reader == NULL) {
+    return NULL;
+  }
+
+  ISampleSelector sample_sel = sample_selector_for_time(time);
+  return abc_reader->topology_changed(existing_mesh, sample_sel);
+}
+
 /* ************************************************************************** */
 
 void CacheReader_free(CacheReader *reader)
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
index 760830ffb24..0f57b759e38 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -114,10 +114,20 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
     }
   }
 
+  /* If this invocation is for the ORCO mesh, and the mesh in Alembic hasn't changed topology, we
+   * must return the mesh as-is instead of deforming it. */
+  if (ctx->flag & MOD_APPLY_ORCO &&
+      !ABC_mesh_topology_changed(mcmd->reader, ctx->object, mesh, time, &err_str)) {
+    return mesh;
+  }
+
   if (me != NULL) {
     MVert *mvert = mesh->mvert;
     MEdge *medge = mesh->medge;
     MPoly *mpoly = mesh->mpoly;
+
+    /* TODO(sybren+bastien): possibly check relevant custom data layers (UV/color depending on
+     * flags) and duplicate those too. */
     if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) {
       /* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */
       BKE_id_copy_ex(NULL,



More information about the Bf-blender-cvs mailing list