[Bf-blender-cvs] [9e1fcf9a239] temp-vert-normals-cleanup: Simplify normal node based on changes to normal storage

Hans Goudey noreply at git.blender.org
Sun Sep 12 18:31:42 CEST 2021


Commit: 9e1fcf9a239f532463302c31c1d676af76400557
Author: Hans Goudey
Date:   Sun Sep 12 11:31:34 2021 -0500
Branches: temp-vert-normals-cleanup
https://developer.blender.org/rB9e1fcf9a239f532463302c31c1d676af76400557

Simplify normal node based on changes to normal storage

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

M	source/blender/nodes/geometry/nodes/node_geo_input_normal.cc

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

diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
index b8f126ef1db..4a8adf6070b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
@@ -28,67 +28,16 @@ static void geo_node_input_normal_declare(NodeDeclarationBuilder &b)
   b.add_output<decl::Vector>("Normal");
 }
 
-static GVArrayPtr mesh_face_normals(const Mesh &mesh,
-                                    const Span<MVert> verts,
-                                    const Span<MPoly> polys,
-                                    const Span<MLoop> loops,
-                                    const IndexMask mask)
+static GVArrayPtr mesh_face_normals_gvarray(const Mesh &mesh)
 {
-  /* Use existing normals to avoid unnecessarily recalculating them, if possible. */
-  if (!(mesh.runtime.cd_dirty_poly & CD_MASK_NORMAL) &&
-      CustomData_has_layer(&mesh.pdata, CD_NORMAL)) {
-    const void *data = CustomData_get_layer(&mesh.pdata, CD_NORMAL);
-
-    return std::make_unique<fn::GVArray_For_Span<float3>>(
-        Span<float3>((const float3 *)data, polys.size()));
-  }
-
-  auto normal_fn = [verts, polys, loops](const int i) -> float3 {
-    float3 normal;
-    const MPoly &poly = polys[i];
-    BKE_mesh_calc_poly_normal(&poly, &loops[poly.loopstart], verts.data(), normal);
-    return normal;
-  };
-
-  return std::make_unique<
-      fn::GVArray_For_EmbeddedVArray<float3, VArray_For_Func<float3, decltype(normal_fn)>>>(
-      mask.min_array_size(), mask.min_array_size(), normal_fn);
+  Span<float3> face_normals{(float3 *)BKE_mesh_ensure_face_normals(&mesh), mesh.totpoly};
+  return std::make_unique<fn::GVArray_For_GSpan>(face_normals);
 }
 
-static GVArrayPtr mesh_vertex_normals(const Mesh &mesh,
-                                      const Span<MVert> verts,
-                                      const Span<MPoly> polys,
-                                      const Span<MLoop> loops,
-                                      const IndexMask mask)
+static GVArrayPtr mesh_face_normals_gvarray(const Mesh &mesh)
 {
-  /* Use existing normals to avoid unnecessarily recalculating them, if possible. */
-  if (!(mesh.runtime.cd_dirty_vert & CD_MASK_NORMAL) &&
-      CustomData_has_layer(&mesh.vdata, CD_NORMAL)) {
-    const void *data = CustomData_get_layer(&mesh.pdata, CD_NORMAL);
-
-    return std::make_unique<fn::GVArray_For_Span<float3>>(
-        Span<float3>((const float3 *)data, mesh.totvert));
-  }
-
-  /* If the normals are dirty, they must be recalculated for the output of this node's field
-   * source. Ideally vertex normals could be calculated lazily on a const mesh, but that's not
-   * possible at the moment, so we take ownership of the results. Sadly we must also create a copy
-   * of MVert to use the mesh normals API. This can be improved by adding mutex-protected lazy
-   * calculation of normals on meshes.
-   *
-   * Use mask.min_array_size() to avoid calculating a final chunk of data if possible. */
-  Array<MVert> temp_verts(verts);
-  Array<float3> normals(verts.size()); /* Use full size for accumulation from faces. */
-  BKE_mesh_calc_normals_poly_and_vertex(temp_verts.data(),
-                                        mask.min_array_size(),
-                                        loops.data(),
-                                        loops.size(),
-                                        polys.data(),
-                                        polys.size(),
-                                        nullptr,
-                                        (float(*)[3])normals.data());
-
-  return std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals));
+  Span<float3> vert_normals{(float3 *)BKE_mesh_ensure_vertex_normals(&mesh), mesh.totvert};
+  return std::make_unique<fn::GVArray_For_GSpan>(vert_normals);
 }
 
 static const GVArray *construct_mesh_normals_gvarray(const MeshComponent &mesh_component,
@@ -97,34 +46,25 @@ static const GVArray *construct_mesh_normals_gvarray(const MeshComponent &mesh_c
                                                      const AttributeDomain domain,
                                                      ResourceScope &scope)
 {
-  Span<MVert> verts{mesh.mvert, mesh.totvert};
-  Span<MEdge> edges{mesh.medge, mesh.totedge};
-  Span<MPoly> polys{mesh.mpoly, mesh.totpoly};
-  Span<MLoop> loops{mesh.mloop, mesh.totloop};
-
   switch (domain) {
     case ATTR_DOMAIN_FACE: {
-      return scope.add_value(mesh_face_normals(mesh, verts, polys, loops, mask), __func__).get();
+      return scope.add_value(mesh_face_normals_gvarray(mesh), __func__).get();
     }
     case ATTR_DOMAIN_POINT: {
-      return scope.add_value(mesh_vertex_normals(mesh, verts, polys, loops, mask), __func__).get();
+      return scope.add_value(mesh_face_normals_gvarray(mesh), __func__).get();
     }
     case ATTR_DOMAIN_EDGE: {
       /* In this case, start with vertex normals and convert to the edge domain, since the
-       * conversion from edges to vertices is very simple. Use the full mask since the edges
-       * might use the vertex normal from any index. */
-      GVArrayPtr vert_normals = mesh_vertex_normals(
-          mesh, verts, polys, loops, IndexRange(verts.size()));
-      Span<float3> vert_normals_span = vert_normals->get_internal_span().typed<float3>();
+       * conversion from edges to vertices is very simple. Use "manual" domain interpolation
+       * instead of the GeometryComponent API to avoid calculating unnecessary values and to
+       * allow normalizing the result much more simply. */
+      Span<float3> vert_normals{(float3 *)BKE_mesh_ensure_vertex_normals(&mesh), mesh.totvert};
       Array<float3> edge_normals(mask.min_array_size());
-
-      /* Use "manual" domain interpolation instead of the GeometryComponent API to avoid
-       * calculating unnecessary values and to allow normalizing the result much more simply. */
+      Span<MEdge> edges{mesh.medge, mesh.totedge};
       for (const int i : mask) {
         const MEdge &edge = edges[i];
-        edge_normals[i] = float3::interpolate(
-                              vert_normals_span[edge.v1], vert_normals_span[edge.v2], 0.5f)
-                              .normalized();
+        edge_normals[i] =
+            float3::interpolate(vert_normals[edge.v1], vert_normals[edge.v2], 0.5f).normalized();
       }
 
       return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float3>>>(
@@ -132,14 +72,11 @@ static const GVArray *construct_mesh_normals_gvarray(const MeshComponent &mesh_c
     }
     case ATTR_DOMAIN_CORNER: {
       /* The normals on corners are just the mesh's face normals, so start with the face normal
-       * array and copy the face normal for each of its corners. */
-      GVArrayPtr face_normals = mesh_face_normals(
-          mesh, verts, polys, loops, IndexRange(polys.size()));
-
-      /* In this case using the mesh component's generic domain interpolation is fine, the data
-       * will still be normalized, since the face normal is just copied to every corner. */
+       * array and copy the face normal for each of its corners. In this case using the mesh
+       * component's generic domain interpolation is fine, the data will still be normalized,
+       * since the face normal is just copied to every corner. */
       GVArrayPtr loop_normals = mesh_component.attribute_try_adapt_domain(
-          std::move(face_normals), ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER);
+          mesh_face_normals_gvarray(mesh), ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER);
       return scope.add_value(std::move(loop_normals), __func__).get();
     }
     default:



More information about the Bf-blender-cvs mailing list