[Bf-blender-cvs] [47d961a4b1c] master: Fix: Apply tilt in curves data-block normals calculation

Hans Goudey noreply at git.blender.org
Fri Apr 15 16:55:30 CEST 2022


Commit: 47d961a4b1c14b0cee2817de226ee356e711e146
Author: Hans Goudey
Date:   Fri Apr 15 09:54:15 2022 -0500
Branches: master
https://developer.blender.org/rB47d961a4b1c14b0cee2817de226ee356e711e146

Fix: Apply tilt in curves data-block normals calculation

The ported normal calculation from ceed37fc5cbb466a0 neglected to
use the tilt attribute to rotate the normals around the tangents.
This commit adds that behavior back, adding a new math header file
to avoid duplicating the rotation function for normalized axes.

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

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

M	source/blender/blenkernel/BKE_curves.hh
M	source/blender/blenkernel/intern/curve_poly.cc
M	source/blender/blenkernel/intern/curves_geometry.cc
A	source/blender/blenlib/BLI_math_rotation.hh
M	source/blender/blenlib/CMakeLists.txt
A	source/blender/blenlib/intern/math_rotation.cc
M	source/blender/blenlib/tests/BLI_math_rotation_test.cc

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

diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index 06971a2243a..3d912e10fb2 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -182,6 +182,13 @@ class CurvesGeometry : public ::CurvesGeometry {
   /** Mutable access to curve resolution. Call #tag_topology_changed after changes. */
   MutableSpan<int> resolution_for_write();
 
+  /**
+   * The angle used to rotate evaluated normals around the tangents after their calculation.
+   * Call #tag_normals_changed after changes.
+   */
+  VArray<float> tilt() const;
+  MutableSpan<float> tilt_for_write();
+
   /**
    * Which method to use for calculating the normals of evaluated points (#NormalMode).
    * Call #tag_normals_changed after changes.
diff --git a/source/blender/blenkernel/intern/curve_poly.cc b/source/blender/blenkernel/intern/curve_poly.cc
index b0ed62d38dd..2db7cd71ad3 100644
--- a/source/blender/blenkernel/intern/curve_poly.cc
+++ b/source/blender/blenkernel/intern/curve_poly.cc
@@ -6,7 +6,7 @@
 
 #include <algorithm>
 
-#include "BLI_math_vector.h"
+#include "BLI_math_rotation.hh"
 #include "BLI_math_vector.hh"
 
 #include "BKE_curves.hh"
@@ -54,20 +54,6 @@ void calculate_tangents(const Span<float3> positions,
   }
 }
 
-static float3 rotate_direction_around_axis(const float3 &direction,
-                                           const float3 &axis,
-                                           const float angle)
-{
-  BLI_ASSERT_UNIT_V3(direction);
-  BLI_ASSERT_UNIT_V3(axis);
-
-  const float3 axis_scaled = axis * math::dot(direction, axis);
-  const float3 diff = direction - axis_scaled;
-  const float3 cross = math::cross(axis, diff);
-
-  return axis_scaled + diff * std::cos(angle) + cross * std::sin(angle);
-}
-
 void calculate_normals_z_up(const Span<float3> tangents, MutableSpan<float3> normals)
 {
   BLI_assert(normals.size() == tangents.size());
@@ -98,7 +84,7 @@ static float3 calculate_next_normal(const float3 &last_normal,
   const float angle = angle_normalized_v3v3(last_tangent, current_tangent);
   if (angle != 0.0) {
     const float3 axis = math::normalize(math::cross(last_tangent, current_tangent));
-    return rotate_direction_around_axis(last_normal, axis, angle);
+    return math::rotate_direction_around_axis(last_normal, axis, angle);
   }
   return last_normal;
 }
@@ -147,7 +133,7 @@ void calculate_normals_minimum(const Span<float3> tangents,
   const float angle_step = correction_angle / normals.size();
   for (const int i : normals.index_range()) {
     const float angle = angle_step * i;
-    normals[i] = rotate_direction_around_axis(normals[i], tangents[i], angle);
+    normals[i] = math::rotate_direction_around_axis(normals[i], tangents[i], angle);
   }
 }
 
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index bdd8b3fc3d0..24e156c3c4d 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -12,6 +12,7 @@
 #include "BLI_bounds.hh"
 #include "BLI_index_mask_ops.hh"
 #include "BLI_length_parameterize.hh"
+#include "BLI_math_rotation.hh"
 
 #include "DNA_curves_types.h"
 
@@ -22,6 +23,7 @@ namespace blender::bke {
 
 static const std::string ATTR_POSITION = "position";
 static const std::string ATTR_RADIUS = "radius";
+static const std::string ATTR_TILT = "tilt";
 static const std::string ATTR_CURVE_TYPE = "curve_type";
 static const std::string ATTR_CYCLIC = "cyclic";
 static const std::string ATTR_RESOLUTION = "resolution";
@@ -330,6 +332,15 @@ MutableSpan<int8_t> CurvesGeometry::normal_mode_for_write()
   return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NORMAL_MODE);
 }
 
+VArray<float> CurvesGeometry::tilt() const
+{
+  return get_varray_attribute<float>(*this, ATTR_DOMAIN_POINT, ATTR_TILT, 0.0f);
+}
+MutableSpan<float> CurvesGeometry::tilt_for_write()
+{
+  return get_mutable_attribute<float>(*this, ATTR_DOMAIN_POINT, ATTR_TILT);
+}
+
 VArray<int8_t> CurvesGeometry::handle_types_left() const
 {
   return get_varray_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_LEFT, 0);
@@ -717,6 +728,15 @@ Span<float3> CurvesGeometry::evaluated_tangents() const
   return this->runtime->evaluated_tangent_cache;
 }
 
+static void rotate_directions_around_axes(MutableSpan<float3> directions,
+                                          const Span<float3> axes,
+                                          const Span<float> angles)
+{
+  for (const int i : directions.index_range()) {
+    directions[i] = math::rotate_direction_around_axis(directions[i], axes[i], angles[i]);
+  }
+}
+
 Span<float3> CurvesGeometry::evaluated_normals() const
 {
   if (!this->runtime->normal_cache_dirty) {
@@ -733,11 +753,16 @@ Span<float3> CurvesGeometry::evaluated_normals() const
     const Span<float3> evaluated_tangents = this->evaluated_tangents();
     const VArray<bool> cyclic = this->cyclic();
     const VArray<int8_t> normal_mode = this->normal_mode();
+    const VArray<int8_t> types = this->curve_types();
+    const VArray<float> tilt = this->tilt();
 
     this->runtime->evaluated_normal_cache.resize(this->evaluated_points_num());
     MutableSpan<float3> evaluated_normals = this->runtime->evaluated_normal_cache;
 
     threading::parallel_for(this->curves_range(), 128, [&](IndexRange curves_range) {
+      /* Reuse a buffer for the evaluated tilts. */
+      Vector<float> evaluated_tilts;
+
       for (const int curve_index : curves_range) {
         const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
         if (UNLIKELY(evaluated_points.is_empty())) {
@@ -754,6 +779,27 @@ Span<float3> CurvesGeometry::evaluated_normals() const
                                                     evaluated_normals.slice(evaluated_points));
             break;
         }
+
+        /* If the "tilt" attribute exists, rotate the normals around the tangents by the
+         * evaluated angles. We can avoid copying the tilts to evaluate them for poly curves. */
+        if (!(tilt.is_single() && tilt.get_internal_single() == 0.0f)) {
+          const IndexRange points = this->points_for_curve(curve_index);
+          Span<float> curve_tilt = tilt.get_internal_span().slice(points);
+          if (types[curve_index] == CURVE_TYPE_POLY) {
+            rotate_directions_around_axes(evaluated_normals.slice(evaluated_points),
+                                          evaluated_tangents.slice(evaluated_points),
+                                          curve_tilt);
+          }
+          else {
+            evaluated_tilts.clear();
+            evaluated_tilts.resize(evaluated_points.size());
+            this->interpolate_to_evaluated(
+                curve_index, curve_tilt, evaluated_tilts.as_mutable_span());
+            rotate_directions_around_axes(evaluated_normals.slice(evaluated_points),
+                                          evaluated_tangents.slice(evaluated_points),
+                                          evaluated_tilts.as_span());
+          }
+        }
       }
     });
   });
diff --git a/source/blender/blenlib/BLI_math_rotation.hh b/source/blender/blenlib/BLI_math_rotation.hh
new file mode 100644
index 00000000000..e8b746b34df
--- /dev/null
+++ b/source/blender/blenlib/BLI_math_rotation.hh
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+/** \file
+ * \ingroup bli
+ */
+
+#include "BLI_math_vec_types.hh"
+
+namespace blender::math {
+
+/**
+ * Rotate the unit-length \a direction around the unit-length \a axis by the \a angle.
+ */
+float3 rotate_direction_around_axis(const float3 &direction, const float3 &axis, float angle);
+
+}  // namespace blender::math
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 99e07264276..e8a3851e082 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -94,6 +94,7 @@ set(SRC
   intern/math_interp.c
   intern/math_matrix.c
   intern/math_rotation.c
+  intern/math_rotation.cc
   intern/math_solvers.c
   intern/math_statistics.c
   intern/math_time.c
@@ -251,6 +252,7 @@ set(SRC
   BLI_math_matrix.h
   BLI_math_mpq.hh
   BLI_math_rotation.h
+  BLI_math_rotation.hh
   BLI_math_solvers.h
   BLI_math_statistics.h
   BLI_math_time.h
diff --git a/source/blender/blenlib/intern/math_rotation.cc b/source/blender/blenlib/intern/math_rotation.cc
new file mode 100644
index 00000000000..74300d55954
--- /dev/null
+++ b/source/blender/blenlib/intern/math_rotation.cc
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup bli
+ */
+
+#include "BLI_math_base.h"
+#include "BLI_math_rotation.hh"
+#include "BLI_math_vector.h"
+#include "BLI_math_vector.hh"
+
+namespace blender::math {
+
+float3 rotate_direction_around_axis(const float3 &direction, const float3 &axis, const float angle)
+{
+  BLI_ASSERT_UNIT_V3(direction);
+  BLI_ASSERT_UNIT_V3(axis);
+
+  const float3 axis_scaled = axis * math::dot(direction, axis);
+  const float3 diff = direction - axis_scaled;
+  const float3 cross = math::cross(axis, diff);
+
+  return axis_scaled + diff * std::cos(angle) + cross * std::sin(angle);
+}
+
+}  // namespace blender::math
diff --git a/source/blender/blenlib/tests/BLI_math_rotation_test.cc b/source/blender/blenlib/tests/BLI_math_rotation_test.cc
index a10e441cfbe..a283118bea2 100644
--- a/source/blender/blenlib/tests/BLI_math_rotation_test.cc
+++ b/source/blender/blenlib/tests/BLI_math_rotation_test.cc
@@ -4,6 +4,8 @@
 
 #include "BLI_math_base.h"
 #include "BLI_math_rotation.h"
+#include "BLI_math_rotation.hh"
+#include "BLI_math_vector.hh"
 
 #include <cmath>
 
@@ -147,3 +149,23 @@ TEST(math_rotation, quat_split_swing_and_twist_negative)
   EXPECT_V4_NEAR(swing, expected_swing, FLT_EPSILON);
   EXPECT_V4_NEAR(twist, expected_twist, FLT_EPSILON);
 }
+
+namespace blender::math::tests {
+
+TEST(math_rotation, RotateDirectionAroundAxis)
+{
+  const float3 a = rotate_direction_around_axis({1, 0, 0}, {0, 0, 1}, M_PI_2);
+  EXPECT_NEAR(a.x, 0.0f, FLT_EPSILON);
+  EXPECT_NEAR(a.y, 1.0f, FLT_EPSILON);
+  EXPECT_NEAR(a.z, 0.0f, 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list