Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
| /* SPDX-License-Identifier: GPL-2.0-or-later */ | /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||||
| #include <algorithm> | #include <algorithm> | ||||
| #include "BLI_enumerable_thread_specific.hh" | #include "BLI_enumerable_thread_specific.hh" | ||||
| #include "BLI_float4x4.hh" | #include "BLI_float4x4.hh" | ||||
| #include "BLI_kdtree.h" | #include "BLI_length_parameterize.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" | ||||
| #include "BKE_brush.h" | #include "BKE_brush.h" | ||||
| #include "BKE_bvhutils.h" | |||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_curves.hh" | #include "BKE_curves.hh" | ||||
| #include "BKE_mesh.h" | |||||
| #include "BKE_mesh_runtime.h" | |||||
| #include "BKE_paint.h" | #include "BKE_paint.h" | ||||
| #include "BKE_spline.hh" | |||||
| #include "DNA_brush_enums.h" | #include "DNA_brush_enums.h" | ||||
| #include "DNA_brush_types.h" | #include "DNA_brush_types.h" | ||||
| #include "DNA_curves_types.h" | #include "DNA_curves_types.h" | ||||
| #include "DNA_mesh_types.h" | |||||
| #include "DNA_meshdata_types.h" | |||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "DNA_screen_types.h" | #include "DNA_screen_types.h" | ||||
| #include "DNA_space_types.h" | #include "DNA_space_types.h" | ||||
| #include "ED_screen.h" | #include "ED_screen.h" | ||||
| #include "ED_view3d.h" | #include "ED_view3d.h" | ||||
| #include "WM_api.h" | #include "WM_api.h" | ||||
| Show All 27 Lines | |||||
| /** | /** | ||||
| * Make curves smaller by trimming the end off. | * Make curves smaller by trimming the end off. | ||||
| */ | */ | ||||
| class ShrinkCurvesEffect : public CurvesEffect { | class ShrinkCurvesEffect : public CurvesEffect { | ||||
| private: | private: | ||||
| const Brush &brush_; | const Brush &brush_; | ||||
| /** Storage of per-curve parameterization data to avoid reallocation. */ | |||||
| struct ParameterizationBuffers { | |||||
| Array<float3> old_positions; | |||||
| Array<float> old_lengths; | |||||
| Array<float> sample_lengths; | |||||
| Array<int> indices; | |||||
| Array<float> factors; | |||||
| void reinitialize(const int points_num) | |||||
| { | |||||
| this->old_positions.reinitialize(points_num); | |||||
| this->old_lengths.reinitialize(length_parameterize::segments_num(points_num, false)); | |||||
| this->sample_lengths.reinitialize(points_num); | |||||
| this->indices.reinitialize(points_num); | |||||
| this->factors.reinitialize(points_num); | |||||
| } | |||||
| }; | |||||
| public: | public: | ||||
| ShrinkCurvesEffect(const Brush &brush) : brush_(brush) | ShrinkCurvesEffect(const Brush &brush) : brush_(brush) | ||||
| { | { | ||||
| } | } | ||||
| void execute(CurvesGeometry &curves, | void execute(CurvesGeometry &curves, | ||||
| const Span<int> curve_indices, | const Span<int> curve_indices, | ||||
| const Span<float> move_distances_cu) override | const Span<float> move_distances_cu) override | ||||
| { | { | ||||
| MutableSpan<float3> positions_cu = curves.positions_for_write(); | MutableSpan<float3> positions_cu = curves.positions_for_write(); | ||||
| threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) { | threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) { | ||||
| ParameterizationBuffers data; | |||||
| for (const int influence_i : range) { | for (const int influence_i : range) { | ||||
| const int curve_i = curve_indices[influence_i]; | const int curve_i = curve_indices[influence_i]; | ||||
| const float move_distance_cu = move_distances_cu[influence_i]; | const float move_distance_cu = move_distances_cu[influence_i]; | ||||
| const IndexRange curve_points = curves.points_for_curve(curve_i); | const IndexRange points = curves.points_for_curve(curve_i); | ||||
| this->shrink_curve(positions_cu, curve_points, move_distance_cu); | this->shrink_curve(positions_cu.slice(points), move_distance_cu, data); | ||||
| } | } | ||||
| }); | }); | ||||
| } | } | ||||
| private: | |||||
| void shrink_curve(MutableSpan<float3> positions, | void shrink_curve(MutableSpan<float3> positions, | ||||
| const IndexRange curve_points, | const float shrink_length, | ||||
| const float shrink_length) const | ParameterizationBuffers &data) const | ||||
| { | { | ||||
| PolySpline spline; | namespace lp = length_parameterize; | ||||
| spline.resize(curve_points.size()); | data.reinitialize(positions.size()); | ||||
| MutableSpan<float3> spline_positions = spline.positions(); | |||||
| spline_positions.copy_from(positions.slice(curve_points)); | /* Copy the old positions to facilitate mixing from neighbors for the resulting curve. */ | ||||
| spline.mark_cache_invalid(); | data.old_positions.as_mutable_span().copy_from(positions); | ||||
| lp::accumulate_lengths<float3>(data.old_positions, false, data.old_lengths); | |||||
| const float min_length = brush_.curves_sculpt_settings->minimum_length; | const float min_length = brush_.curves_sculpt_settings->minimum_length; | ||||
| const float old_length = spline.length(); | const float old_length = data.old_lengths.last(); | ||||
| const float new_length = std::max(min_length, old_length - shrink_length); | const float new_length = std::max(min_length, old_length - shrink_length); | ||||
| const float length_factor = std::clamp(new_length / old_length, 0.0f, 1.0f); | const float length_factor = std::clamp(new_length / old_length, 0.0f, 1.0f); | ||||
| Vector<float> old_point_lengths; | data.sample_lengths.first() = 0.0f; | ||||
| old_point_lengths.append(0.0f); | for (const int i : data.old_lengths.index_range()) { | ||||
| for (const int i : spline_positions.index_range().drop_back(1)) { | data.sample_lengths[i + 1] = data.old_lengths[i] * length_factor; | ||||
| const float3 &p1 = spline_positions[i]; | |||||
| const float3 &p2 = spline_positions[i + 1]; | |||||
| const float length = math::distance(p1, p2); | |||||
| old_point_lengths.append(old_point_lengths.last() + length); | |||||
| } | |||||
| for (const int i : spline_positions.index_range()) { | |||||
| const float eval_length = old_point_lengths[i] * length_factor; | |||||
| const Spline::LookupResult lookup = spline.lookup_evaluated_length(eval_length); | |||||
| const float index_factor = lookup.evaluated_index + lookup.factor; | |||||
| float3 p; | |||||
| spline.sample_with_index_factors<float3>(spline_positions, {&index_factor, 1}, {&p, 1}); | |||||
| positions[curve_points[i]] = p; | |||||
| } | } | ||||
| lp::sample_at_lengths(data.old_lengths, data.sample_lengths, data.indices, data.factors); | |||||
| lp::linear_interpolation<float3>(data.old_positions, data.indices, data.factors, positions); | |||||
| } | } | ||||
| }; | }; | ||||
| /** | /** | ||||
| * Make the curves longer by extrapolating them linearly. | * Make the curves longer by extrapolating them linearly. | ||||
| */ | */ | ||||
| class ExtrapolateCurvesEffect : public CurvesEffect { | class ExtrapolateCurvesEffect : public CurvesEffect { | ||||
| void execute(CurvesGeometry &curves, | void execute(CurvesGeometry &curves, | ||||
| ▲ Show 20 Lines • Show All 399 Lines • Show Last 20 Lines | |||||