Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2022-04-01 16:11:58 +0300
committerHans Goudey <h.goudey@me.com>2022-04-01 16:12:41 +0300
commit00ba51d37bf5b152176409b393eafbb0ad9333e6 (patch)
tree499a1503c59f3558101bba52cef10d64c39a57fd /source/blender/blenkernel/intern/curve_bezier.cc
parenta250d3d1b7d8d497c21a1ef845e64f07e68beda9 (diff)
Geometry Nodes: Port set handle nodes to new data-block
This commit ports the "Set Handle Positions" and "Set Hanle Type" nodes to use the new curves data-block. The nodes become simpler and likely much faster too, though they're usually not the bottleneck anyway. Most of the code is ported from `BezierSpline` directly. The majority of the complexity comes from the interaction between different automatically calculated handle types. In comparison `BezierSpline`, the calculation of auto handles is done eagerly-- mostly because it's simpler. Eventually lazy calculation might be good to add. Differential Revision: https://developer.blender.org/D14464
Diffstat (limited to 'source/blender/blenkernel/intern/curve_bezier.cc')
-rw-r--r--source/blender/blenkernel/intern/curve_bezier.cc125
1 files changed, 125 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/curve_bezier.cc b/source/blender/blenkernel/intern/curve_bezier.cc
index 0d3bb2e3a7d..30a5869c976 100644
--- a/source/blender/blenkernel/intern/curve_bezier.cc
+++ b/source/blender/blenkernel/intern/curve_bezier.cc
@@ -58,6 +58,131 @@ void calculate_evaluated_offsets(const Span<int8_t> handle_types_left,
evaluated_offsets.last() = offset;
}
+static float3 calculate_aligned_handle(const float3 &position,
+ const float3 &other_handle,
+ const float3 &aligned_handle)
+{
+ /* Keep track of the old length of the opposite handle. */
+ const float length = math::distance(aligned_handle, position);
+ /* Set the other handle to directly opposite from the current handle. */
+ const float3 dir = math::normalize(other_handle - position);
+ return position - dir * length;
+}
+
+static void calculate_point_handles(const HandleType type_left,
+ const HandleType type_right,
+ const float3 position,
+ const float3 prev_position,
+ const float3 next_position,
+ float3 &left,
+ float3 &right)
+{
+ if (ELEM(BEZIER_HANDLE_AUTO, type_left, type_right)) {
+ const float3 prev_diff = position - prev_position;
+ const float3 next_diff = next_position - position;
+ float prev_len = math::length(prev_diff);
+ float next_len = math::length(next_diff);
+ if (prev_len == 0.0f) {
+ prev_len = 1.0f;
+ }
+ if (next_len == 0.0f) {
+ next_len = 1.0f;
+ }
+ const float3 dir = next_diff / next_len + prev_diff / prev_len;
+
+ /* This magic number is unfortunate, but comes from elsewhere in Blender. */
+ const float len = math::length(dir) * 2.5614f;
+ if (len != 0.0f) {
+ if (type_left == BEZIER_HANDLE_AUTO) {
+ const float prev_len_clamped = std::min(prev_len, next_len * 5.0f);
+ left = position + dir * -(prev_len_clamped / len);
+ }
+ if (type_right == BEZIER_HANDLE_AUTO) {
+ const float next_len_clamped = std::min(next_len, prev_len * 5.0f);
+ right = position + dir * (next_len_clamped / len);
+ }
+ }
+ }
+
+ if (type_left == BEZIER_HANDLE_VECTOR) {
+ left = math::interpolate(position, prev_position, 1.0f / 3.0f);
+ }
+
+ if (type_right == BEZIER_HANDLE_VECTOR) {
+ right = math::interpolate(position, next_position, 1.0f / 3.0f);
+ }
+
+ /* When one of the handles is "aligned" handle, it must be aligned with the other, i.e. point in
+ * the opposite direction. Don't handle the case of two aligned handles, because code elsewhere
+ * should keep the pair consistent, and the relative locations aren't affected by other points
+ * anyway. */
+ if (type_left == BEZIER_HANDLE_ALIGN && type_right != BEZIER_HANDLE_ALIGN) {
+ left = calculate_aligned_handle(position, right, left);
+ }
+ else if (type_left != BEZIER_HANDLE_ALIGN && type_right == BEZIER_HANDLE_ALIGN) {
+ right = calculate_aligned_handle(position, left, right);
+ }
+}
+
+void set_handle_position(const float3 &position,
+ const HandleType type,
+ const HandleType type_other,
+ const float3 &new_handle,
+ float3 &handle,
+ float3 &handle_other)
+{
+ /* Don't bother when the handle positions are calculated automatically anyway. */
+ if (ELEM(type, BEZIER_HANDLE_AUTO, BEZIER_HANDLE_VECTOR)) {
+ return;
+ }
+
+ handle = new_handle;
+ if (type_other == BEZIER_HANDLE_ALIGN) {
+ handle_other = calculate_aligned_handle(position, handle, handle_other);
+ }
+}
+
+void calculate_auto_handles(const bool cyclic,
+ const Span<int8_t> types_left,
+ const Span<int8_t> types_right,
+ const Span<float3> positions,
+ MutableSpan<float3> positions_left,
+ MutableSpan<float3> positions_right)
+{
+ const int points_num = positions.size();
+ if (points_num == 1) {
+ return;
+ }
+
+ calculate_point_handles(HandleType(types_left.first()),
+ HandleType(types_right.first()),
+ positions.first(),
+ cyclic ? positions.last() : 2.0f * positions.first() - positions[1],
+ positions[1],
+ positions_left.first(),
+ positions_right.first());
+
+ threading::parallel_for(IndexRange(1, points_num - 2), 1024, [&](IndexRange range) {
+ for (const int i : range) {
+ calculate_point_handles(HandleType(types_left[i]),
+ HandleType(types_right[i]),
+ positions[i],
+ positions[i - 1],
+ positions[i + 1],
+ positions_left[i],
+ positions_right[i]);
+ }
+ });
+
+ calculate_point_handles(HandleType(types_left.last()),
+ HandleType(types_right.last()),
+ positions.last(),
+ positions.last(1),
+ cyclic ? positions.first() : 2.0f * positions.last() - positions.last(1),
+ positions_left.last(),
+ positions_right.last());
+}
+
void evaluate_segment(const float3 &point_0,
const float3 &point_1,
const float3 &point_2,