diff options
author | Hans Goudey <h.goudey@me.com> | 2021-05-12 18:21:12 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2021-05-12 18:21:32 +0300 |
commit | 1892b131edc76abb4439ca6fcc69b95a208ab7d7 (patch) | |
tree | e91c0a3621e5a0e46e0319b27ae622cded028b47 /source/blender/blenkernel/intern/spline_bezier.cc | |
parent | 8dc95f61f3dff4e5686c2a278bd44db714065b20 (diff) |
Geometry Nodes Curves: Expose first builtin point attributes
This commit exposes the first spline control point attributes. The
implementation incorporates the attributes into the virtual array
system, providing efficient methods to flatten the data into a
contiguous array and to apply changes from a flattened array. This
is only part of the eventual goal, which includes changes to run
attribute nodes separately for each spline to completely avoid copying.
So far `tilt` and `radius`, the two generic attributes common to
all spline types, are implemented. The more complex `position`
attribute is also added. It requires some special handling for Bezier
splines, where the control point handles need to be moved along with
the control points. To make that work I also added automatic handle
recalculation to the Bezier spline.
Differential Revision: https://developer.blender.org/D11187
Diffstat (limited to 'source/blender/blenkernel/intern/spline_bezier.cc')
-rw-r--r-- | source/blender/blenkernel/intern/spline_bezier.cc | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc index 20226dc3ed2..0bc6e71fa4d 100644 --- a/source/blender/blenkernel/intern/spline_bezier.cc +++ b/source/blender/blenkernel/intern/spline_bezier.cc @@ -119,10 +119,12 @@ MutableSpan<BezierSpline::HandleType> BezierSpline::handle_types_left() } Span<float3> BezierSpline::handle_positions_left() const { + this->ensure_auto_handles(); return handle_positions_left_; } MutableSpan<float3> BezierSpline::handle_positions_left() { + this->ensure_auto_handles(); return handle_positions_left_; } Span<BezierSpline::HandleType> BezierSpline::handle_types_right() const @@ -135,13 +137,90 @@ MutableSpan<BezierSpline::HandleType> BezierSpline::handle_types_right() } Span<float3> BezierSpline::handle_positions_right() const { + this->ensure_auto_handles(); return handle_positions_right_; } MutableSpan<float3> BezierSpline::handle_positions_right() { + this->ensure_auto_handles(); return handle_positions_right_; } +static float3 previous_position(Span<float3> positions, const bool cyclic, const int i) +{ + if (i == 0) { + if (cyclic) { + return positions[positions.size() - 1]; + } + return 2.0f * positions[i] - positions[i + 1]; + } + return positions[i - 1]; +} + +static float3 next_position(Span<float3> positions, const bool cyclic, const int i) +{ + if (i == positions.size() - 1) { + if (cyclic) { + return positions[0]; + } + return 2.0f * positions[i] - positions[i - 1]; + } + return positions[i + 1]; +} + +void BezierSpline::ensure_auto_handles() const +{ + if (!auto_handles_dirty_) { + return; + } + + std::lock_guard lock{auto_handle_mutex_}; + if (!auto_handles_dirty_) { + return; + } + + for (const int i : IndexRange(this->size())) { + if (ELEM(HandleType::Auto, handle_types_left_[i], handle_types_right_[i])) { + const float3 prev_diff = positions_[i] - previous_position(positions_, is_cyclic_, i); + const float3 next_diff = next_position(positions_, is_cyclic_, i) - positions_[i]; + float prev_len = prev_diff.length(); + float next_len = next_diff.length(); + 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 = dir.length() * 2.5614f; + if (len != 0.0f) { + if (handle_types_left_[i] == HandleType::Auto) { + const float prev_len_clamped = std::min(prev_len, next_len * 5.0f); + handle_positions_left_[i] = positions_[i] + dir * -(prev_len_clamped / len); + } + if (handle_types_right_[i] == HandleType::Auto) { + const float next_len_clamped = std::min(next_len, prev_len * 5.0f); + handle_positions_right_[i] = positions_[i] + dir * (next_len_clamped / len); + } + } + } + + if (handle_types_left_[i] == HandleType::Vector) { + const float3 prev = previous_position(positions_, is_cyclic_, i); + handle_positions_left_[i] = float3::interpolate(positions_[i], prev, 1.0f / 3.0f); + } + + if (handle_types_right_[i] == HandleType::Vector) { + const float3 next = next_position(positions_, is_cyclic_, i); + handle_positions_right_[i] = float3::interpolate(positions_[i], next, 1.0f / 3.0f); + } + } + + auto_handles_dirty_ = false; +} + void BezierSpline::translate(const blender::float3 &translation) { for (float3 &position : this->positions()) { @@ -195,6 +274,7 @@ void BezierSpline::mark_cache_invalid() tangent_cache_dirty_ = true; normal_cache_dirty_ = true; length_cache_dirty_ = true; + auto_handles_dirty_ = true; } int BezierSpline::evaluated_points_size() const @@ -389,6 +469,8 @@ Span<float3> BezierSpline::evaluated_positions() const return evaluated_position_cache_; } + this->ensure_auto_handles(); + const int eval_size = this->evaluated_points_size(); evaluated_position_cache_.resize(eval_size); |