Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
| /* SPDX-License-Identifier: GPL-2.0-or-later */ | /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||||
| #include <algorithm> | #include <algorithm> | ||||
| #include "curves_sculpt_intern.hh" | #include "curves_sculpt_intern.hh" | ||||
| #include "BLI_float4x4.hh" | #include "BLI_float4x4.hh" | ||||
| #include "BLI_index_mask_ops.hh" | #include "BLI_index_mask_ops.hh" | ||||
| #include "BLI_kdtree.h" | #include "BLI_kdtree.h" | ||||
| #include "BLI_length_parameterize.hh" | |||||
| #include "BLI_rand.hh" | #include "BLI_rand.hh" | ||||
| #include "BLI_vector.hh" | #include "BLI_vector.hh" | ||||
| #include "PIL_time.h" | #include "PIL_time.h" | ||||
| #include "DEG_depsgraph.h" | #include "DEG_depsgraph.h" | ||||
| #include "BKE_attribute_math.hh" | #include "BKE_attribute_math.hh" | ||||
| ▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) { | ||||
| const float radius_falloff = pow2f(1.0f - distance_screen / brush_radius); | const float radius_falloff = pow2f(1.0f - distance_screen / brush_radius); | ||||
| const float weight = brush_strength * radius_falloff; | const float weight = brush_strength * radius_falloff; | ||||
| const float2 new_position_screen = old_position_screen + mouse_diff * weight; | const float2 new_position_screen = old_position_screen + mouse_diff * weight; | ||||
| float3 new_position; | float3 new_position; | ||||
| ED_view3d_win_to_3d(v3d, region, ob_mat * old_position, new_position_screen, new_position); | ED_view3d_win_to_3d(v3d, region, ob_mat * old_position, new_position_screen, new_position); | ||||
| new_position = ob_imat * new_position; | new_position = ob_imat * new_position; | ||||
| this->move_last_point_and_resample(positions, curve_points, new_position); | this->move_last_point_and_resample(positions.slice(curve_points), new_position); | ||||
| } | } | ||||
| }); | }); | ||||
| curves.tag_positions_changed(); | curves.tag_positions_changed(); | ||||
| DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY); | DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY); | ||||
| ED_region_tag_redraw(region); | ED_region_tag_redraw(region); | ||||
| } | } | ||||
| void move_last_point_and_resample(MutableSpan<float3> positions, | void move_last_point_and_resample(MutableSpan<float3> positions, | ||||
| const IndexRange curve_points, | |||||
| const float3 &new_last_point_position) const | const float3 &new_last_point_position) const | ||||
| { | { | ||||
| Vector<float> old_lengths; | positions.last() = new_last_point_position; | ||||
| old_lengths.append(0.0f); | |||||
| /* Used to (1) normalize the segment sizes over time and (2) support making zero-length | Array<float> lengths(length_parameterize::lengths_size(positions.size(), false)); | ||||
| * segments */ | length_parameterize::accumulate_lengths<float3>(positions, false, lengths); | ||||
| const float extra_length = 0.001f; | |||||
| for (const int segment_i : IndexRange(curve_points.size() - 1)) { | length_parameterize::LengthResampler sampler(lengths, false); | ||||
| const float3 &p1 = positions[curve_points[segment_i]]; | sampler.sample(positions.size()); | ||||
| const float3 &p2 = positions[curve_points[segment_i] + 1]; | |||||
| const float length = math::distance(p1, p2); | sampler.interpolate_with_samples<float3>(positions, positions); | ||||
| old_lengths.append(old_lengths.last() + length + extra_length); | |||||
| } | |||||
| Vector<float> point_factors; | |||||
| for (float &old_length : old_lengths) { | |||||
| point_factors.append(old_length / old_lengths.last()); | |||||
| } | |||||
| PolySpline new_spline; | |||||
| new_spline.resize(curve_points.size()); | |||||
| MutableSpan<float3> new_spline_positions = new_spline.positions(); | |||||
| for (const int i : IndexRange(curve_points.size() - 1)) { | |||||
| new_spline_positions[i] = positions[curve_points[i]]; | |||||
| } | |||||
| new_spline_positions.last() = new_last_point_position; | |||||
| new_spline.mark_cache_invalid(); | |||||
| for (const int i : IndexRange(curve_points.size())) { | |||||
| const float factor = point_factors[i]; | |||||
| const Spline::LookupResult lookup = new_spline.lookup_evaluated_factor(factor); | |||||
| const float index_factor = lookup.evaluated_index + lookup.factor; | |||||
| float3 p; | |||||
| new_spline.sample_with_index_factors<float3>( | |||||
| new_spline_positions, {&index_factor, 1}, {&p, 1}); | |||||
| positions[curve_points[i]] = p; | |||||
| } | |||||
| } | } | ||||
| }; | }; | ||||
| std::unique_ptr<CurvesSculptStrokeOperation> new_snake_hook_operation() | std::unique_ptr<CurvesSculptStrokeOperation> new_snake_hook_operation() | ||||
| { | { | ||||
| return std::make_unique<SnakeHookOperation>(); | return std::make_unique<SnakeHookOperation>(); | ||||
| } | } | ||||
| } // namespace blender::ed::sculpt_paint | } // namespace blender::ed::sculpt_paint | ||||