[Bf-blender-cvs] [05ce5276db7] master: Geometry nodes: Output curve normals from the normal node

Hans Goudey noreply at git.blender.org
Tue Sep 21 20:40:00 CEST 2021


Commit: 05ce5276db7be4f742b6558d723a989eae4963a3
Author: Hans Goudey
Date:   Tue Sep 21 13:39:46 2021 -0500
Branches: master
https://developer.blender.org/rB05ce5276db7be4f742b6558d723a989eae4963a3

Geometry nodes: Output curve normals from the normal node

The code is basically the same as rB4d51af68adb273.

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

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 07818f2a3ad..f92086acdf0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
@@ -14,10 +14,13 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+#include "BLI_task.hh"
+
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
 
 #include "BKE_mesh.h"
+#include "BKE_spline.hh"
 
 #include "node_geometry_util.hh"
 
@@ -147,6 +150,95 @@ static const GVArray *construct_mesh_normals_gvarray(const MeshComponent &mesh_c
   }
 }
 
+static void calculate_bezier_normals(const BezierSpline &spline, MutableSpan<float3> normals)
+{
+  Span<int> offsets = spline.control_point_offsets();
+  Span<float3> evaluated_normals = spline.evaluated_normals();
+  for (const int i : IndexRange(spline.size())) {
+    normals[i] = evaluated_normals[offsets[i]];
+  }
+}
+
+static void calculate_poly_normals(const PolySpline &spline, MutableSpan<float3> normals)
+{
+  normals.copy_from(spline.evaluated_normals());
+}
+
+/**
+ * Because NURBS control points are not necessarily on the path, the normal at the control points
+ * is not well defined, so create a temporary poly spline to find the normals. This requires extra
+ * copying currently, but may be more efficient in the future if attributes have some form of CoW.
+ */
+static void calculate_nurbs_normals(const NURBSpline &spline, MutableSpan<float3> normals)
+{
+  PolySpline poly_spline;
+  poly_spline.resize(spline.size());
+  poly_spline.positions().copy_from(spline.positions());
+  normals.copy_from(poly_spline.evaluated_normals());
+}
+
+static Array<float3> curve_normal_point_domain(const CurveEval &curve)
+{
+  Span<SplinePtr> splines = curve.splines();
+  Array<int> offsets = curve.control_point_offsets();
+  const int total_size = offsets.last();
+  Array<float3> normals(total_size);
+
+  threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
+    for (const int i : range) {
+      const Spline &spline = *splines[i];
+      MutableSpan spline_normals{normals.as_mutable_span().slice(offsets[i], spline.size())};
+      switch (splines[i]->type()) {
+        case Spline::Type::Bezier:
+          calculate_bezier_normals(static_cast<const BezierSpline &>(spline), spline_normals);
+          break;
+        case Spline::Type::Poly:
+          calculate_poly_normals(static_cast<const PolySpline &>(spline), spline_normals);
+          break;
+        case Spline::Type::NURBS:
+          calculate_nurbs_normals(static_cast<const NURBSpline &>(spline), spline_normals);
+          break;
+      }
+    }
+  });
+  return normals;
+}
+
+static const GVArray *construct_curve_normal_gvarray(const CurveComponent &component,
+                                                     const AttributeDomain domain,
+                                                     ResourceScope &scope)
+{
+  const CurveEval *curve = component.get_for_read();
+  if (curve == nullptr) {
+    return nullptr;
+  }
+
+  if (domain == ATTR_DOMAIN_POINT) {
+    const Span<SplinePtr> splines = curve->splines();
+
+    /* Use a reference to evaluated normals if possible to avoid an allocation and a copy.
+     * This is only possible when there is only one poly spline. */
+    if (splines.size() == 1 && splines.first()->type() == Spline::Type::Poly) {
+      const PolySpline &spline = static_cast<PolySpline &>(*splines.first());
+      return &scope.construct<fn::GVArray_For_Span<float3>>(spline.evaluated_normals());
+    }
+
+    Array<float3> normals = curve_normal_point_domain(*curve);
+    return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals));
+  }
+
+  if (domain == ATTR_DOMAIN_CURVE) {
+    Array<float3> point_normals = curve_normal_point_domain(*curve);
+    GVArrayPtr gvarray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(
+        std::move(point_normals));
+    GVArrayPtr spline_normals = component.attribute_try_adapt_domain(
+        std::move(gvarray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
+    return scope.add_value(std::move(spline_normals)).get();
+  }
+
+  return nullptr;
+}
+
 class NormalFieldInput final : public fn::FieldInput {
  public:
   NormalFieldInput() : fn::FieldInput(CPPType::get<float3>(), "Normal")
@@ -173,8 +265,8 @@ class NormalFieldInput final : public fn::FieldInput {
         return construct_mesh_normals_gvarray(mesh_component, *mesh, mask, domain, scope);
       }
       if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
-        /* TODO: Add curve normals support. */
-        return nullptr;
+        const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+        return construct_curve_normal_gvarray(curve_component, domain, scope);
       }
     }
     return nullptr;



More information about the Bf-blender-cvs mailing list