[Bf-blender-cvs] [e9c149d911c] master: Alembic import: load face-varying normals

Sybren A. Stüvel noreply at git.blender.org
Tue Jul 30 17:07:13 CEST 2019


Commit: e9c149d911c2ec52e02e266767797f09ba088f91
Author: Sybren A. Stüvel
Date:   Fri Jul 5 12:36:30 2019 +0200
Branches: master
https://developer.blender.org/rBe9c149d911c2ec52e02e266767797f09ba088f91

Alembic import: load face-varying normals

Loop normals are called 'Face-varying normals' in Alembic. Before this
commit, the existence of such normals was used to enable smooth shading.
This is incorrect, as the normals could encode flat faces just as well.

This commit adds the loading of these normals as custom loop normals. It
then also enables Auto-Smoothing on the mesh (which is a bit of a
misnomer and indicates to Blender that the custom normals should be
used).

Fixes the glitching described in T65959.

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

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

M	source/blender/alembic/intern/abc_mesh.cc

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

diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc
index e4431bde2f6..1b5ae0b7adc 100644
--- a/source/blender/alembic/intern/abc_mesh.cc
+++ b/source/blender/alembic/intern/abc_mesh.cc
@@ -46,6 +46,8 @@ extern "C" {
 #include "BKE_modifier.h"
 #include "BKE_object.h"
 
+#include "MEM_guardedalloc.h"
+
 #include "WM_api.h"
 #include "WM_types.h"
 
@@ -758,7 +760,8 @@ struct AbcMeshData {
   P3fArraySamplePtr ceil_positions;
 
   N3fArraySamplePtr vertex_normals;
-  N3fArraySamplePtr face_normals;
+  N3fArraySamplePtr loop_normals;
+  bool poly_flag_smooth;
 
   V2fArraySamplePtr uvs;
   UInt32ArraySamplePtr uvs_indices;
@@ -832,7 +835,6 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
   const size_t uvs_size = uvs == nullptr ? 0 : uvs->size();
 
   const UInt32ArraySamplePtr &uvs_indices = mesh_data.uvs_indices;
-  const N3fArraySamplePtr &normals = mesh_data.face_normals;
 
   const bool do_uvs = (mloopuvs && uvs && uvs_indices) &&
                       (uvs_indices->size() == face_indices->size());
@@ -847,9 +849,12 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
     poly.loopstart = loop_index;
     poly.totloop = face_size;
 
-    if (normals != NULL) {
+    if (mesh_data.poly_flag_smooth) {
       poly.flag |= ME_SMOOTH;
     }
+    else {
+      poly.flag &= ~ME_SMOOTH;
+    }
 
     /* NOTE: Alembic data is stored in the reverse order. */
     rev_loop_index = loop_index + (face_size - 1);
@@ -873,6 +878,40 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
       }
     }
   }
+
+  BKE_mesh_calc_edges(config.mesh, false, false);
+}
+
+static void process_normals(CDStreamConfig &config, const AbcMeshData &mesh_data)
+{
+  Mesh *mesh = config.mesh;
+
+  if (!mesh_data.loop_normals) {
+    BKE_mesh_calc_normals(config.mesh);
+    config.mesh->flag &= ~ME_AUTOSMOOTH;
+    return;
+  }
+
+  config.mesh->flag |= ME_AUTOSMOOTH;
+
+  const Alembic::AbcGeom::N3fArraySample &loop_normals = *mesh_data.loop_normals;
+  long int loop_count = loop_normals.size();
+
+  float(*lnors)[3] = static_cast<float(*)[3]>(
+      MEM_malloc_arrayN(loop_count, sizeof(float[3]), "ABC::FaceNormals"));
+
+  MPoly *mpoly = mesh->mpoly;
+  int abc_index = 0;
+  for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mpoly) {
+    /* As usual, ABC orders the loops in reverse. */
+    for (int j = mpoly->totloop - 1; j >= 0; --j, ++abc_index) {
+      int blender_index = mpoly->loopstart + j;
+      copy_zup_from_yup(lnors[blender_index], loop_normals[abc_index].getValue());
+    }
+  }
+  BKE_mesh_set_custom_normals(config.mesh, lnors);
+
+  MEM_freeN(lnors);
 }
 
 ABC_INLINE void read_uvs_params(CDStreamConfig &config,
@@ -905,10 +944,6 @@ ABC_INLINE void read_uvs_params(CDStreamConfig &config,
   }
 }
 
-/* TODO(kevin): normals from Alembic files are not read in anymore, this is due
- * to the fact that there are many issues that are not so easy to solve, mainly
- * regarding the way normals are handled in Blender (MPoly.flag vs loop normals).
- */
 ABC_INLINE void read_normals_params(AbcMeshData &abc_data,
                                     const IN3fGeomParam &normals,
                                     const ISampleSelector &selector)
@@ -922,10 +957,12 @@ ABC_INLINE void read_normals_params(AbcMeshData &abc_data,
   Alembic::AbcGeom::GeometryScope scope = normals.getScope();
   switch (scope) {
     case Alembic::AbcGeom::kFacevaryingScope:
-      abc_data.face_normals = normsamp.getVals();
+      abc_data.loop_normals = normsamp.getVals();
       break;
     case Alembic::AbcGeom::kVertexScope:
     case Alembic::AbcGeom::kVaryingScope:
+      /* Vertex normals from ABC aren't handled for now. */
+      abc_data.poly_flag_smooth = true;
       abc_data.vertex_normals = N3fArraySamplePtr();
       break;
     case Alembic::AbcGeom::kConstantScope:
@@ -935,31 +972,6 @@ ABC_INLINE void read_normals_params(AbcMeshData &abc_data,
   }
 }
 
-static bool check_smooth_poly_flag(Mesh *mesh)
-{
-  MPoly *mpolys = mesh->mpoly;
-
-  for (int i = 0, e = mesh->totpoly; i < e; ++i) {
-    MPoly &poly = mpolys[i];
-
-    if ((poly.flag & ME_SMOOTH) != 0) {
-      return true;
-    }
-  }
-
-  return false;
-}
-
-static void set_smooth_poly_flag(Mesh *mesh)
-{
-  MPoly *mpolys = mesh->mpoly;
-
-  for (int i = 0, e = mesh->totpoly; i < e; ++i) {
-    MPoly &poly = mpolys[i];
-    poly.flag |= ME_SMOOTH;
-  }
-}
-
 static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type)
 {
   CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
@@ -1001,8 +1013,7 @@ static void read_mesh_sample(const std::string &iobject_full_name,
                              ImportSettings *settings,
                              const IPolyMeshSchema &schema,
                              const ISampleSelector &selector,
-                             CDStreamConfig &config,
-                             bool &r_do_normals)
+                             CDStreamConfig &config)
 {
   const IPolyMeshSchema::Sample sample = schema.getValue(selector);
 
@@ -1010,11 +1021,10 @@ static void read_mesh_sample(const std::string &iobject_full_name,
   abc_mesh_data.face_counts = sample.getFaceCounts();
   abc_mesh_data.face_indices = sample.getFaceIndices();
   abc_mesh_data.positions = sample.getPositions();
+  abc_mesh_data.poly_flag_smooth = false;
 
   read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector);
 
-  r_do_normals = (abc_mesh_data.face_normals != NULL);
-
   get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
 
   if (config.weight != 0.0f) {
@@ -1033,6 +1043,7 @@ static void read_mesh_sample(const std::string &iobject_full_name,
 
   if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
     read_mpolys(config, abc_mesh_data);
+    process_normals(config, abc_mesh_data);
   }
 
   if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
@@ -1086,6 +1097,9 @@ void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
   Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, NULL);
   if (read_mesh != mesh) {
     BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true);
+
+    /* XXX fixme after 2.80; mesh->flag isn't copied by BKE_mesh_nomain_to_mesh() */
+    mesh->flag |= (read_mesh->flag & ME_AUTOSMOOTH);
   }
 
   if (m_settings->validate_meshes) {
@@ -1158,6 +1172,8 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
         existing_mesh, positions->size(), 0, 0, face_indices->size(), face_counts->size());
 
     settings.read_flag |= MOD_MESHSEQ_READ_ALL;
+    /* XXX fixme after 2.80; mesh->flag isn't copied by BKE_mesh_new_nomain_from_template() */
+    new_mesh->flag |= (existing_mesh->flag & ME_AUTOSMOOTH);
   }
   else {
     /* If the face count changed (e.g. by triangulation), only read points.
@@ -1178,18 +1194,9 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
   CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh);
   config.time = sample_sel.getRequestedTime();
 
-  bool do_normals = false;
-  read_mesh_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config, do_normals);
+  read_mesh_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config);
 
   if (new_mesh) {
-    /* Check if we had ME_SMOOTH flag set to restore it. */
-    if (!do_normals && check_smooth_poly_flag(existing_mesh)) {
-      set_smooth_poly_flag(new_mesh);
-    }
-
-    BKE_mesh_calc_normals(new_mesh);
-    BKE_mesh_calc_edges(new_mesh, false, false);
-
     /* Here we assume that the number of materials doesn't change, i.e. that
      * the material slots that were created when the object was loaded from
      * Alembic are still valid now. */
@@ -1202,10 +1209,6 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
     return new_mesh;
   }
 
-  if (do_normals) {
-    BKE_mesh_calc_normals(existing_mesh);
-  }
-
   return existing_mesh;
 }
 
@@ -1292,7 +1295,7 @@ static void read_subd_sample(const std::string &iobject_full_name,
   abc_mesh_data.face_counts = sample.getFaceCounts();
   abc_mesh_data.face_indices = sample.getFaceIndices();
   abc_mesh_data.vertex_normals = N3fArraySamplePtr();
-  abc_mesh_data.face_normals = N3fArraySamplePtr();
+  abc_mesh_data.loop_normals = N3fArraySamplePtr();
   abc_mesh_data.positions = sample.getPositions();
 
   get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
@@ -1312,7 +1315,14 @@ static void read_subd_sample(const std::string &iobject_full_name,
   }
 
   if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
+    /* Alembic's 'SubD' scheme is used to store subdivision surfaces, i.e. the pre-subdivision
+     * mesh. Currently we don't add a subdivison modifier when we load such data. This code is
+     * assuming that the subdivided surface should be smooth, and sets a flag that will eventually
+     * mark all polygons as such. */
+    abc_mesh_data.poly_flag_smooth = true;
+
     read_mpolys(config, abc_mesh_data);
+    process_normals(config, abc_mesh_data);
   }
 
   if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
@@ -1400,9 +1410,6 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
     mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
   }
 
-  BKE_mesh_calc_normals(mesh);
-  BKE_mesh_calc_edges(mesh, false, false);
-
   if (m_settings->validate_meshes) {
     BKE_mesh_validate(mesh, false, false);
   }
@@ -1469,17 +1476,5 @@ Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh,
   config.time = sample_sel.getRequestedTime();
   read_subd_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config);
 
-  if (new_mesh) {
-    /* Check if we had ME_SMOOTH flag set to restore it. */
-    if (check_smooth_poly_flag(existing_mesh)) {
-      set_smooth_poly_flag(new_mesh);
-    }
-
-    BKE_mesh_calc_normals(new_mesh);
-    BKE_mesh_calc_edges(new_mesh, false, false);
-
-    return new_mesh;
-  }
-
-  return existing_mesh;
+  return config.mesh;
 }



More information about the Bf-blender-cvs mailing list