[Bf-blender-cvs] [d1519df6a85] geometry-nodes-curve-support: Geometry Nodes Curves: Expose cyclic attribute, fix cyclic sampling

Hans Goudey noreply at git.blender.org
Mon Apr 5 20:15:16 CEST 2021


Commit: d1519df6a85eda5be2e6831c21f0a43995c7b633
Author: Hans Goudey
Date:   Mon Apr 5 13:14:56 2021 -0500
Branches: geometry-nodes-curve-support
https://developer.blender.org/rBd1519df6a85eda5be2e6831c21f0a43995c7b633

Geometry Nodes Curves: Expose cyclic attribute, fix cyclic sampling

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

M	source/blender/blenkernel/BKE_derived_curve.hh
M	source/blender/blenkernel/BKE_geometry_set.hh
M	source/blender/blenkernel/intern/derived_curve.cc
M	source/blender/blenkernel/intern/geometry_component_curve.cc
M	source/blender/blenlib/BLI_vector.hh
M	source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc

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

diff --git a/source/blender/blenkernel/BKE_derived_curve.hh b/source/blender/blenkernel/BKE_derived_curve.hh
index 0f0b228b7ac..bbfb305fe47 100644
--- a/source/blender/blenkernel/BKE_derived_curve.hh
+++ b/source/blender/blenkernel/BKE_derived_curve.hh
@@ -54,6 +54,7 @@ class Spline {
     Poly,
   };
   Type type;
+  bool is_cyclic = false;
 
   virtual int size() const = 0;
   virtual int resolution() const = 0;
@@ -76,13 +77,11 @@ class BezierSpline : public Spline {
   static constexpr inline Type static_type = Spline::Type::Bezier;
 
  private:
-  bool is_cyclic = false;
-
-  mutable std::mutex cache_mutex;
-  mutable bool cache_dirty = true;
-  mutable blender::Vector<blender::float3> evaluated_positions_cache;
-  mutable blender::Vector<blender::float3> evaluated_tangents_cache;
-  mutable blender::Vector<blender::float3> evaluated_normals_cache;
+  mutable std::mutex cache_mutex_;
+  mutable bool cache_dirty_ = true;
+  mutable blender::Vector<blender::float3> evaluated_positions_cache_;
+  mutable blender::Vector<blender::float3> evaluated_tangents_cache_;
+  mutable blender::Vector<blender::float3> evaluated_normals_cache_;
 
  public:
   int size() const final
@@ -101,7 +100,7 @@ class BezierSpline : public Spline {
 
   void mark_cache_invalid() final
   {
-    cache_dirty = true;
+    cache_dirty_ = true;
   }
 
   int evaluated_points_size() const final;
@@ -110,19 +109,19 @@ class BezierSpline : public Spline {
   blender::Span<blender::float3> evaluated_positions() const final
   {
     this->ensure_evaluation_cache();
-    return evaluated_positions_cache;
+    return evaluated_positions_cache_;
   }
 
   blender::Span<blender::float3> evaluated_tangents() const final
   {
     this->ensure_evaluation_cache();
-    return evaluated_tangents_cache;
+    return evaluated_tangents_cache_;
   }
 
   blender::Span<blender::float3> evaluated_normals() const final
   {
     this->ensure_evaluation_cache();
-    return evaluated_normals_cache;
+    return evaluated_normals_cache_;
   }
 
   ~BezierSpline() = default;
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 2565c5cdb99..e00aca80179 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -433,7 +433,7 @@ class CurveComponent : public GeometryComponent {
 
   void clear();
   bool has_curve() const;
-  void replace(DCurve *pointcloud, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+  void replace(DCurve *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
   DCurve *release();
 
   const DCurve *get_for_read() const;
diff --git a/source/blender/blenkernel/intern/derived_curve.cc b/source/blender/blenkernel/intern/derived_curve.cc
index bcebd07ebff..f3eb2b0ff25 100644
--- a/source/blender/blenkernel/intern/derived_curve.cc
+++ b/source/blender/blenkernel/intern/derived_curve.cc
@@ -82,6 +82,8 @@ DCurve *dcurve_from_dna_curve(const Curve &dna_curve)
       // spline.resolution_v = nurb->resolv;
       spline->type = Spline::Type::Bezier;
 
+      spline->is_cyclic = nurb->flagu & CU_NURB_CYCLIC;
+
       curve->splines.append(spline);
     }
     else if (nurb->type == CU_NURBS) {
@@ -107,7 +109,7 @@ int BezierSpline::evaluated_points_size() const
 {
   BLI_assert(control_points.size() > 0);
 
-  int total_len = 1;
+  int total_len = 0;
   for (const int i : IndexRange(1, this->control_points.size() - 1)) {
     const BezierPoint &point_prev = this->control_points[i - 1];
     const BezierPoint &point = this->control_points[i];
@@ -119,7 +121,17 @@ int BezierSpline::evaluated_points_size() const
     }
   }
 
-  if (!this->is_cyclic) {
+  if (this->is_cyclic) {
+    if (segment_is_vector(this->control_points.last(), this->control_points.first())) {
+      total_len++;
+    }
+    else {
+      total_len += this->resolution_u;
+    }
+  }
+  else {
+    /* Since evaulating the bezier doesn't add the final point's position,
+     * it must be added manually in the non-cyclic case. */
     total_len++;
   }
 
@@ -160,7 +172,7 @@ static void evaluate_segment_positions(const BezierPoint &point,
                             point.handle_position_b,
                             next.handle_position_a,
                             next.position,
-                            positions.slice(offset, resolution));
+                            positions.slice(offset, resolution - 1));
     offset += resolution;
   }
 }
@@ -205,6 +217,11 @@ static void calculate_tangents(Span<BezierPoint> control_points,
                                const bool is_cyclic,
                                MutableSpan<float3> tangents)
 {
+  if (positions.size() == 1) {
+    tangents.first() = float3(0.0f, 0.0f, 0.0f);
+    return;
+  }
+
   for (const int i : IndexRange(1, positions.size() - 2)) {
     tangents[i] = direction_bisect(positions[i - 1], positions[i], positions[i + 1]);
   }
@@ -231,63 +248,204 @@ static void calculate_tangents(Span<BezierPoint> control_points,
     }
 
     const BezierPoint &last_point = control_points.last();
-    if (LIKELY(first_point.handle_position_a != first_point.position)) {
-      tangents.last() = (first_point.position - first_point.handle_position_a).normalized();
+    if (LIKELY(last_point.handle_position_a != first_point.position)) {
+      tangents.last() = (last_point.handle_position_b - last_point.position).normalized();
     }
     else {
       tangents.last() = (positions.last() - positions[positions.size() - 1]).normalized();
     }
   }
+
+  for (const float3 &tangent : tangents) {
+    BLI_ASSERT_UNIT_V3(tangent);
+  }
+}
+
+static float3 initial_normal(const float3 first_tangent)
+{
+  /* TODO: Should be is "almost" zero. */
+  if (first_tangent.is_zero()) {
+    return float3(0.0f, 0.0f, 1.0f);
+  }
+
+  const float3 normal = float3::cross(first_tangent, float3(0.0f, 0.0f, 1.0f));
+  if (!normal.is_zero()) {
+    return normal.normalized();
+  }
+
+  return float3::cross(first_tangent, float3(0.0f, 1.0f, 0.0f)).normalized();
+}
+
+static float3 rotate_around_axis(const float3 dir, const float3 axis, const float angle)
+{
+  // cdef void rotateAroundAxisVec3(Vector3 *target, Vector3 *v, Vector3 *axis, float angle):
+  //   cdef Vector3 n
+  //   normalizeVec3(&n, axis)
+  //   cdef Vector3 d
+  //   scaleVec3(&d, &n, dotVec3(&n, v))
+  //   cdef Vector3 r
+  //   subVec3(&r, v, &d)
+  //   cdef Vector3 g
+  //   crossVec3(&g, &n, &r)
+  //   cdef float ca = cos(angle)
+  //   cdef float sa = sin(angle)
+  //   target.x = d.x + r.x * ca + g.x * sa
+  //   target.y = d.y + r.y * ca + g.y * sa
+  //   target.z = d.z + r.z * ca + g.z * sa
+  BLI_ASSERT_UNIT_V3(axis);
+  const float3 scaled_axis = axis * float3::dot(dir, axis);
+  const float3 sub = dir - scaled_axis;
+  const float3 cross = float3::cross(sub, sub);
+  const float sin = std::sin(angle);
+  const float cos = std::cos(angle);
+  return (scaled_axis + sub * cos + cross * sin).normalized();
+}
+
+static float3 project_on_center_plane(const float3 vector, const float3 plane_normal)
+{
+  // cdef void projectOnCenterPlaneVec3(Vector3 *result, Vector3 *v, Vector3 *planeNormal):
+  //   cdef Vector3 unitNormal, projVector
+  //   normalizeVec3(&unitNormal, planeNormal)
+  //   cdef float distance = dotVec3(v, &unitNormal)
+  //   scaleVec3(&projVector, &unitNormal, -distance)
+  //   addVec3(result, v, &projVector)
+  BLI_ASSERT_UNIT_V3(plane_normal);
+  const float distance = float3::dot(vector, plane_normal);
+  const float3 projection_vector = plane_normal * -distance;
+  return vector + projection_vector;
+}
+
+static float3 propagate_normal(const float3 last_normal,
+                               const float3 last_tangent,
+                               const float3 current_tangent)
+{
+  const float angle = angle_normalized_v3v3(last_tangent, current_tangent);
+
+  if (angle == 0.0f) {
+    return last_normal;
+  }
+
+  const float3 axis = float3::cross(last_tangent, current_tangent).normalized();
+
+  // rotateAroundAxisVec3(&newNormal, lastNormal, &axis, angle)
+  // projectOnCenterPlaneVec3(target, &newNormal, currentTangent)
+  const float3 new_normal = rotate_around_axis(last_normal, axis, angle);
+
+  return project_on_center_plane(new_normal, current_tangent).normalized();
+}
+
+static void apply_rotation_gradient(Span<float3> tangents,
+                                    MutableSpan<float3> normals,
+                                    const float full_angle)
+{
+  // cdef applyRotationGradient(Vector3DList tangents, Vector3DList normals, float fullAngle):
+  //   cdef Py_ssize_t i
+  //   cdef Vector3 normal
+  //   cdef float angle
+  //   cdef float remainingRotation = fullAngle
+  //   cdef float doneRotation = 0
+
+  //   for i in range(1, normals.length):
+  //       if angleVec3(tangents.data + i, tangents.data + i - 1) < 0.001:
+  //           rotateAroundAxisVec3(normals.data + i, &normal, tangents.data + i, doneRotation)
+  //       else:
+  //           angle = remainingRotation / (normals.length - i)
+  //           normal = normals.data[i]
+  //           rotateAroundAxisVec3(normals.data + i, &normal, tangents.data + i, angle +
+  //               doneRotation)
+  //           remainingRotation -= angle
+  //           doneRotation += angle
+
+  float remaining_rotation = full_angle;
+  float done_rotation = 0.0f;
+  for (const int i : IndexRange(1, normals.size() - 1)) {
+    if (angle_v3v3(tangents[i], tangents[i - 1]) < 0.001f) {
+      normals[i] = rotate_around_axis(normals[i], tangents[i], done_rotation);
+    }
+    else {
+      const float angle = remaining_rotation / (normals.size() - i);
+      normals[i] = rotate_around_axis(normals[i], tangents[i], angle + done_rotation);
+      remaining_rotation -= angle;
+      done_rotation += angle;
+    }
+  }
 }
 
-// static void evaluate_normals(Span<BezierPoint> control_points,
-//                              Span<float3> positions,
-//                              Span<float3> tangents,
-//                              const bool is_cyclic,
-//                              MutableSpan<Quat> normals)
-// {
+static void make_normals_cyclic(Span<float3> tangents

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list