[Bf-blender-cvs] [75ad8da1ea6] master: Refactor: Replace old Mesh edge split implementation

Hans Goudey noreply at git.blender.org
Wed Dec 14 01:41:53 CET 2022


Commit: 75ad8da1ea6799e3983e4146f4b20dc4bfbb8415
Author: Hans Goudey
Date:   Tue Dec 13 18:39:36 2022 -0600
Branches: master
https://developer.blender.org/rB75ad8da1ea6799e3983e4146f4b20dc4bfbb8415

Refactor: Replace old Mesh edge split implementation

Recently a new geometry node for splitting edges was added in D16399.
However, there was already a similar implementation in mesh.cc that was
mainly used to fake auto smooth support in Cycles by splitting sharp
edges and edges around sharp faces.

While there are still possibilities for optimization in the new code,
the implementation is safer and simpler, multi-threaded, and aligns
better with development plans for caching topology on Mesh and other
recent developments with attributes.

This patch removes the old code and moves the node implementation to
the geometry module so it can be used in editors and RNA. The "free
loop normals" argument is deprecated now, since it was only an internal
optimization exposed for Cycles.

The new mesh `editors` function creates an `IndexMask` of edges to
split by reusing some of the code from the corner normal calculation.

This change will help to simplify the changes in D16530 and T102858.

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

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

M	intern/cycles/blender/util.h
M	source/blender/blenkernel/BKE_mesh.h
M	source/blender/blenkernel/intern/mesh.cc
M	source/blender/editors/include/ED_mesh.h
M	source/blender/editors/mesh/CMakeLists.txt
M	source/blender/editors/mesh/mesh_data.cc
M	source/blender/editors/object/object_bake_api.c
M	source/blender/geometry/CMakeLists.txt
A	source/blender/geometry/GEO_mesh_split_edges.hh
A	source/blender/geometry/intern/mesh_split_edges.cc
M	source/blender/makesrna/intern/rna_mesh_api.c
M	source/blender/nodes/geometry/nodes/node_geo_edge_split.cc

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

diff --git a/intern/cycles/blender/util.h b/intern/cycles/blender/util.h
index dbdfbaddaf1..9a4b8c5cc64 100644
--- a/intern/cycles/blender/util.h
+++ b/intern/cycles/blender/util.h
@@ -113,6 +113,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
 
   if ((bool)mesh && subdivision_type == Mesh::SUBDIVISION_NONE) {
     if (mesh.use_auto_smooth()) {
+      mesh.calc_normals_split();
       mesh.split_faces(false);
     }
 
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index a2067169506..6a55fe00bf6 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -254,14 +254,6 @@ void BKE_mesh_texspace_get_reference(struct Mesh *me,
                                      float **r_size);
 void BKE_mesh_texspace_copy_from_object(struct Mesh *me, struct Object *ob);
 
-/**
- * Split faces based on the edge angle and loop normals.
- * Matches behavior of face splitting in render engines.
- *
- * \note Will leave #CD_NORMAL loop data layer which is used by render engines to set shading up.
- */
-void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals);
-
 /**
  * Create new mesh from the given object at its current state.
  * The owner of this mesh is unknown, it is up to the caller to decide.
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 1fd2a72f311..77ef4674596 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -1836,267 +1836,6 @@ void BKE_mesh_calc_normals_split(Mesh *mesh)
   BKE_mesh_calc_normals_split_ex(mesh, nullptr, ensure_corner_normal_layer(*mesh));
 }
 
-/* Split faces helper functions. */
-
-struct SplitFaceNewVert {
-  struct SplitFaceNewVert *next;
-  int new_index;
-  int orig_index;
-  const float *vnor;
-};
-
-struct SplitFaceNewEdge {
-  struct SplitFaceNewEdge *next;
-  int new_index;
-  int orig_index;
-  int v1;
-  int v2;
-};
-
-/**
- * Detect necessary new vertices, and update loop vertex indices accordingly.
- * \warning Leaves mesh in invalid state.
- * \param lnors_spacearr: Mandatory because trying to do the job in simple way without that data is
- * doomed to fail, even when only dealing with smooth/flat faces one can find cases that no simple
- * algorithm can handle properly.
- */
-static int split_faces_prepare_new_verts(Mesh &mesh,
-                                         const MLoopNorSpaceArray &lnors_spacearr,
-                                         SplitFaceNewVert **new_verts,
-                                         MemArena &memarena)
-{
-  const int loops_len = mesh.totloop;
-  int verts_len = mesh.totvert;
-  MutableSpan<MLoop> loops = mesh.loops_for_write();
-  BKE_mesh_vertex_normals_ensure(&mesh);
-  float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(&mesh);
-
-  BitVector<> verts_used(verts_len, false);
-  BitVector<> done_loops(loops_len, false);
-
-  BLI_assert(lnors_spacearr.data_type == MLNOR_SPACEARR_LOOP_INDEX);
-
-  for (int loop_idx = 0; loop_idx < loops_len; loop_idx++) {
-    if (done_loops[loop_idx]) {
-      continue;
-    }
-    const MLoopNorSpace &lnor_space = *lnors_spacearr.lspacearr[loop_idx];
-    const int vert_idx = loops[loop_idx].v;
-    const bool vert_used = verts_used[vert_idx];
-    /* If vert is already used by another smooth fan, we need a new vert for this one. */
-    const int new_vert_idx = vert_used ? verts_len++ : vert_idx;
-
-    if (lnor_space.flags & MLNOR_SPACE_IS_SINGLE) {
-      /* Single loop in this fan... */
-      BLI_assert(POINTER_AS_INT(lnor_space.loops) == loop_idx);
-      done_loops[loop_idx].set();
-      if (vert_used) {
-        loops[loop_idx].v = new_vert_idx;
-      }
-    }
-    else {
-      for (const LinkNode *lnode = lnor_space.loops; lnode; lnode = lnode->next) {
-        const int ml_fan_idx = POINTER_AS_INT(lnode->link);
-        done_loops[ml_fan_idx].set();
-        if (vert_used) {
-          loops[ml_fan_idx].v = new_vert_idx;
-        }
-      }
-    }
-
-    if (!vert_used) {
-      verts_used[vert_idx].set();
-      /* We need to update that vertex's normal here, we won't go over it again. */
-      /* This is important! *DO NOT* set vnor to final computed lnor,
-       * vnor should always be defined to 'automatic normal' value computed from its polys,
-       * not some custom normal.
-       * Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */
-      copy_v3_v3(vert_normals[vert_idx], lnor_space.vec_lnor);
-    }
-    else {
-      /* Add new vert to list. */
-      SplitFaceNewVert *new_vert = static_cast<SplitFaceNewVert *>(
-          BLI_memarena_alloc(&memarena, sizeof(*new_vert)));
-      new_vert->orig_index = vert_idx;
-      new_vert->new_index = new_vert_idx;
-      new_vert->vnor = lnor_space.vec_lnor; /* See note above. */
-      new_vert->next = *new_verts;
-      *new_verts = new_vert;
-    }
-  }
-
-  return verts_len - mesh.totvert;
-}
-
-/* Detect needed new edges, and update accordingly loops' edge indices.
- * WARNING! Leaves mesh in invalid state. */
-static int split_faces_prepare_new_edges(Mesh *mesh,
-                                         SplitFaceNewEdge **new_edges,
-                                         MemArena *memarena)
-{
-  const int num_polys = mesh->totpoly;
-  int num_edges = mesh->totedge;
-  MutableSpan<MEdge> edges = mesh->edges_for_write();
-  MutableSpan<MLoop> loops = mesh->loops_for_write();
-  const Span<MPoly> polys = mesh->polys();
-
-  BitVector<> edges_used(num_edges, false);
-  EdgeHash *edges_hash = BLI_edgehash_new_ex(__func__, num_edges);
-
-  const MPoly *mp = polys.data();
-  for (int poly_idx = 0; poly_idx < num_polys; poly_idx++, mp++) {
-    MLoop *ml_prev = &loops[mp->loopstart + mp->totloop - 1];
-    MLoop *ml = &loops[mp->loopstart];
-    for (int loop_idx = 0; loop_idx < mp->totloop; loop_idx++, ml++) {
-      void **eval;
-      if (!BLI_edgehash_ensure_p(edges_hash, ml_prev->v, ml->v, &eval)) {
-        const int edge_idx = ml_prev->e;
-
-        /* That edge has not been encountered yet, define it. */
-        if (edges_used[edge_idx]) {
-          /* Original edge has already been used, we need to define a new one. */
-          const int new_edge_idx = num_edges++;
-          *eval = POINTER_FROM_INT(new_edge_idx);
-          ml_prev->e = new_edge_idx;
-
-          SplitFaceNewEdge *new_edge = (SplitFaceNewEdge *)BLI_memarena_alloc(memarena,
-                                                                              sizeof(*new_edge));
-          new_edge->orig_index = edge_idx;
-          new_edge->new_index = new_edge_idx;
-          new_edge->v1 = ml_prev->v;
-          new_edge->v2 = ml->v;
-          new_edge->next = *new_edges;
-          *new_edges = new_edge;
-        }
-        else {
-          /* We can re-use original edge. */
-          edges[edge_idx].v1 = ml_prev->v;
-          edges[edge_idx].v2 = ml->v;
-          *eval = POINTER_FROM_INT(edge_idx);
-          edges_used[edge_idx].set();
-        }
-      }
-      else {
-        /* Edge already known, just update loop's edge index. */
-        ml_prev->e = POINTER_AS_INT(*eval);
-      }
-
-      ml_prev = ml;
-    }
-  }
-
-  BLI_edgehash_free(edges_hash, nullptr);
-
-  return num_edges - mesh->totedge;
-}
-
-/* Perform actual split of vertices. */
-static void split_faces_split_new_verts(Mesh *mesh,
-                                        SplitFaceNewVert *new_verts,
-                                        const int num_new_verts)
-{
-  const int verts_len = mesh->totvert - num_new_verts;
-  float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh);
-
-  /* Normals were already calculated at the beginning of this operation, we rely on that to update
-   * them partially here. */
-  BLI_assert(!BKE_mesh_vertex_normals_are_dirty(mesh));
-
-  /* Remember new_verts is a single linklist, so its items are in reversed order... */
-  for (int i = mesh->totvert - 1; i >= verts_len; i--, new_verts = new_verts->next) {
-    BLI_assert(new_verts->new_index == i);
-    BLI_assert(new_verts->new_index != new_verts->orig_index);
-    CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1);
-    if (new_verts->vnor) {
-      copy_v3_v3(vert_normals[i], new_verts->vnor);
-    }
-  }
-}
-
-/* Perform actual split of edges. */
-static void split_faces_split_new_edges(Mesh *mesh,
-                                        SplitFaceNewEdge *new_edges,
-                                        const int num_new_edges)
-{
-  const int num_edges = mesh->totedge - num_new_edges;
-  MutableSpan<MEdge> edges = mesh->edges_for_write();
-
-  /* Remember new_edges is a single linklist, so its items are in reversed order... */
-  MEdge *new_med = &edges[mesh->totedge - 1];
-  for (int i = mesh->totedge - 1; i >= num_edges; i--, new_med--, new_edges = new_edges->next) {
-    BLI_assert(new_edges->new_index == i);
-    BLI_assert(new_edges->new_index != new_edges->orig_index);
-    CustomData_copy_data(&mesh->edata, &mesh->edata, new_edges->orig_index, i, 1);
-    new_med->v1 = new_edges->v1;
-    new_med->v2 = new_edges->v2;
-  }
-}
-
-void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
-{
-  const int num_polys = mesh->totpoly;
-
-  if (num_polys == 0) {
-    return;
-  }
-  BKE_mesh_tessface_clear(mesh);
-
-  MLoopNorSpaceArray lnors_spacearr = {nullptr};
-  /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */
-  BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr, ensure_corner_normal_layer(*mesh));
-  /* Stealing memarena from loop normals space array. */
-  MemArena *memarena = lnors_spacearr.mem;
-
-  SplitFaceNewVert *new_verts = nullptr;
-  SplitFaceNewEdge *new_edges = nullptr;
-
-  /* Detect loop normal spaces (a.k.a. smooth fans) that will need a new vert. */
-  const int num_new_verts = split_faces_prepare_new_verts(
-      *mesh, lnors_spacearr, &new_verts, *memarena);
-
-  if (num_new_verts > 0) {
-    /* Reminder: beyond this point, there is no way out, mesh is in invalid state
-     * (due to early-reassignment of loops' vertex and edge indices to new,
-     * to-be-created s

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list