Curves: Improve IndexMask usage in curves sculpt brushes
Unify the handling of masks for affected curves in a few of the sculpt brushes. In the grow shrink brush, replace a more custom "influences per thread" solution. In the puff brush, use a full array of weights, and build the mask earlier. In the snake hook brush, use the selection properly (I observed a 2-3x improvement with a small selection).
This commit is contained in:
@@ -51,7 +51,7 @@ class CurvesEffect {
|
||||
public:
|
||||
virtual ~CurvesEffect() = default;
|
||||
virtual void execute(CurvesGeometry &curves,
|
||||
Span<int> curve_indices,
|
||||
const IndexMask &curve_mask,
|
||||
Span<float> move_distances_cu,
|
||||
MutableSpan<float3> positions_cu) = 0;
|
||||
};
|
||||
@@ -85,16 +85,15 @@ class ShrinkCurvesEffect : public CurvesEffect {
|
||||
ShrinkCurvesEffect(const Brush &brush) : brush_(brush) {}
|
||||
|
||||
void execute(CurvesGeometry &curves,
|
||||
const Span<int> curve_indices,
|
||||
const IndexMask &curve_mask,
|
||||
const Span<float> move_distances_cu,
|
||||
MutableSpan<float3> positions_cu) override
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) {
|
||||
curve_mask.foreach_segment(GrainSize(256), [&](IndexMaskSegment segment) {
|
||||
ParameterizationBuffers data;
|
||||
for (const int influence_i : range) {
|
||||
const int curve_i = curve_indices[influence_i];
|
||||
const float move_distance_cu = move_distances_cu[influence_i];
|
||||
for (const int curve_i : segment) {
|
||||
const float move_distance_cu = move_distances_cu[curve_i];
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
this->shrink_curve(positions_cu.slice(points), move_distance_cu, data);
|
||||
}
|
||||
@@ -135,16 +134,15 @@ class ShrinkCurvesEffect : public CurvesEffect {
|
||||
*/
|
||||
class ExtrapolateCurvesEffect : public CurvesEffect {
|
||||
void execute(CurvesGeometry &curves,
|
||||
const Span<int> curve_indices,
|
||||
const IndexMask &curve_mask,
|
||||
const Span<float> move_distances_cu,
|
||||
MutableSpan<float3> positions_cu) override
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) {
|
||||
curve_mask.foreach_segment(GrainSize(256), [&](IndexMaskSegment segment) {
|
||||
MoveAndResampleBuffers resample_buffer;
|
||||
for (const int influence_i : range) {
|
||||
const int curve_i = curve_indices[influence_i];
|
||||
const float move_distance_cu = move_distances_cu[influence_i];
|
||||
for (const int curve_i : segment) {
|
||||
const float move_distance_cu = move_distances_cu[curve_i];
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
if (points.size() <= 1) {
|
||||
continue;
|
||||
@@ -175,27 +173,24 @@ class ScaleCurvesEffect : public CurvesEffect {
|
||||
ScaleCurvesEffect(bool scale_up, const Brush &brush) : scale_up_(scale_up), brush_(brush) {}
|
||||
|
||||
void execute(CurvesGeometry &curves,
|
||||
const Span<int> curve_indices,
|
||||
const IndexMask &curve_mask,
|
||||
const Span<float> move_distances_cu,
|
||||
MutableSpan<float3> positions_cu) override
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) {
|
||||
for (const int influence_i : range) {
|
||||
const int curve_i = curve_indices[influence_i];
|
||||
const float move_distance_cu = move_distances_cu[influence_i];
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
curve_mask.foreach_index(GrainSize(256), [&](const int64_t curve_i) {
|
||||
const float move_distance_cu = move_distances_cu[curve_i];
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
|
||||
const float old_length = this->compute_poly_curve_length(positions_cu.slice(points));
|
||||
const float length_diff = scale_up_ ? move_distance_cu : -move_distance_cu;
|
||||
const float min_length = brush_.curves_sculpt_settings->minimum_length;
|
||||
const float new_length = std::max(min_length, old_length + length_diff);
|
||||
const float scale_factor = safe_divide(new_length, old_length);
|
||||
const float old_length = this->compute_poly_curve_length(positions_cu.slice(points));
|
||||
const float length_diff = scale_up_ ? move_distance_cu : -move_distance_cu;
|
||||
const float min_length = brush_.curves_sculpt_settings->minimum_length;
|
||||
const float new_length = std::max(min_length, old_length + length_diff);
|
||||
const float scale_factor = safe_divide(new_length, old_length);
|
||||
|
||||
const float3 &root_pos_cu = positions_cu[points[0]];
|
||||
for (float3 &pos_cu : positions_cu.slice(points.drop_front(1))) {
|
||||
pos_cu = (pos_cu - root_pos_cu) * scale_factor + root_pos_cu;
|
||||
}
|
||||
const float3 &root_pos_cu = positions_cu[points[0]];
|
||||
for (float3 &pos_cu : positions_cu.slice(points.drop_front(1))) {
|
||||
pos_cu = (pos_cu - root_pos_cu) * scale_factor + root_pos_cu;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -255,11 +250,6 @@ struct CurvesEffectOperationExecutor {
|
||||
float2 brush_pos_start_re_;
|
||||
float2 brush_pos_end_re_;
|
||||
|
||||
struct Influences {
|
||||
Vector<int> curve_indices;
|
||||
Vector<float> move_distances_cu;
|
||||
};
|
||||
|
||||
CurvesEffectOperationExecutor(const bContext &C) : ctx_(C) {}
|
||||
|
||||
void execute(CurvesEffectOperation &self,
|
||||
@@ -314,22 +304,25 @@ struct CurvesEffectOperationExecutor {
|
||||
return;
|
||||
}
|
||||
|
||||
Array<float> move_distances_cu(curves_->curves_num());
|
||||
|
||||
/* Compute influences. */
|
||||
threading::EnumerableThreadSpecific<Influences> influences_for_thread;
|
||||
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_TUBE) {
|
||||
this->gather_influences_projected(influences_for_thread);
|
||||
this->gather_influences_projected(move_distances_cu);
|
||||
}
|
||||
else if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
|
||||
this->gather_influences_spherical(influences_for_thread);
|
||||
this->gather_influences_spherical(move_distances_cu);
|
||||
}
|
||||
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask curves_mask = IndexMask::from_predicate(
|
||||
curve_selection_, GrainSize(4096), memory, [&](const int64_t curve_i) {
|
||||
return move_distances_cu[curve_i] > 0.0f;
|
||||
});
|
||||
|
||||
/* Execute effect. */
|
||||
MutableSpan<float3> positions_cu = curves_->positions_for_write();
|
||||
threading::parallel_for_each(influences_for_thread, [&](const Influences &influences) {
|
||||
BLI_assert(influences.curve_indices.size() == influences.move_distances_cu.size());
|
||||
self_->effect_->execute(
|
||||
*curves_, influences.curve_indices, influences.move_distances_cu, positions_cu);
|
||||
});
|
||||
self_->effect_->execute(*curves_, curves_mask, move_distances_cu, positions_cu);
|
||||
|
||||
curves_->tag_positions_changed();
|
||||
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
|
||||
@@ -337,8 +330,7 @@ struct CurvesEffectOperationExecutor {
|
||||
ED_region_tag_redraw(ctx_.region);
|
||||
}
|
||||
|
||||
void gather_influences_projected(
|
||||
threading::EnumerableThreadSpecific<Influences> &influences_for_thread)
|
||||
void gather_influences_projected(MutableSpan<float> move_distances_cu)
|
||||
{
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
|
||||
@@ -357,84 +349,75 @@ struct CurvesEffectOperationExecutor {
|
||||
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
|
||||
const float brush_radius_sq_re = pow2f(brush_radius_re);
|
||||
|
||||
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
|
||||
Influences &local_influences = influences_for_thread.local();
|
||||
curve_selection_.foreach_index(GrainSize(256), [&](int64_t curve_i) {
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
|
||||
for (const int curve_i : curves_range) {
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const float curve_selection_factor = curve_selection_factors_[curve_i];
|
||||
|
||||
const float curve_selection_factor = curve_selection_factors_[curve_i];
|
||||
float max_move_distance_cu = 0.0f;
|
||||
for (const float4x4 &brush_transform_inv : symmetry_brush_transforms_inv) {
|
||||
for (const int segment_i : points.drop_back(1)) {
|
||||
const float3 p1_cu = math::transform_point(brush_transform_inv,
|
||||
deformation.positions[segment_i]);
|
||||
const float3 p2_cu = math::transform_point(brush_transform_inv,
|
||||
deformation.positions[segment_i + 1]);
|
||||
|
||||
float max_move_distance_cu = 0.0f;
|
||||
for (const float4x4 &brush_transform_inv : symmetry_brush_transforms_inv) {
|
||||
for (const int segment_i : points.drop_back(1)) {
|
||||
const float3 p1_cu = math::transform_point(brush_transform_inv,
|
||||
deformation.positions[segment_i]);
|
||||
const float3 p2_cu = math::transform_point(brush_transform_inv,
|
||||
deformation.positions[segment_i + 1]);
|
||||
float2 p1_re, p2_re;
|
||||
ED_view3d_project_float_v2_m4(ctx_.region, p1_cu, p1_re, projection.ptr());
|
||||
ED_view3d_project_float_v2_m4(ctx_.region, p2_cu, p2_re, projection.ptr());
|
||||
|
||||
float2 p1_re, p2_re;
|
||||
ED_view3d_project_float_v2_m4(ctx_.region, p1_cu, p1_re, projection.ptr());
|
||||
ED_view3d_project_float_v2_m4(ctx_.region, p2_cu, p2_re, projection.ptr());
|
||||
float2 closest_on_brush_re;
|
||||
float2 closest_on_segment_re;
|
||||
float lambda_on_brush;
|
||||
float lambda_on_segment;
|
||||
const float dist_to_brush_sq_re = closest_seg_seg_v2(closest_on_brush_re,
|
||||
closest_on_segment_re,
|
||||
&lambda_on_brush,
|
||||
&lambda_on_segment,
|
||||
brush_pos_start_re_,
|
||||
brush_pos_end_re_,
|
||||
p1_re,
|
||||
p2_re);
|
||||
|
||||
float2 closest_on_brush_re;
|
||||
float2 closest_on_segment_re;
|
||||
float lambda_on_brush;
|
||||
float lambda_on_segment;
|
||||
const float dist_to_brush_sq_re = closest_seg_seg_v2(closest_on_brush_re,
|
||||
closest_on_segment_re,
|
||||
&lambda_on_brush,
|
||||
&lambda_on_segment,
|
||||
brush_pos_start_re_,
|
||||
brush_pos_end_re_,
|
||||
p1_re,
|
||||
p2_re);
|
||||
|
||||
if (dist_to_brush_sq_re > brush_radius_sq_re) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
|
||||
const float radius_falloff = BKE_brush_curve_strength(
|
||||
brush_, dist_to_brush_re, brush_radius_re);
|
||||
const float weight = brush_strength_ * radius_falloff * curve_selection_factor;
|
||||
|
||||
const float3 closest_on_segment_cu = math::interpolate(
|
||||
p1_cu, p2_cu, lambda_on_segment);
|
||||
|
||||
float3 brush_start_pos_wo, brush_end_pos_wo;
|
||||
ED_view3d_win_to_3d(
|
||||
ctx_.v3d,
|
||||
ctx_.region,
|
||||
math::transform_point(transforms_.curves_to_world, closest_on_segment_cu),
|
||||
brush_pos_start_re_,
|
||||
brush_start_pos_wo);
|
||||
ED_view3d_win_to_3d(
|
||||
ctx_.v3d,
|
||||
ctx_.region,
|
||||
math::transform_point(transforms_.curves_to_world, closest_on_segment_cu),
|
||||
brush_pos_end_re_,
|
||||
brush_end_pos_wo);
|
||||
const float3 brush_start_pos_cu = math::transform_point(transforms_.world_to_curves,
|
||||
brush_start_pos_wo);
|
||||
const float3 brush_end_pos_cu = math::transform_point(transforms_.world_to_curves,
|
||||
brush_end_pos_wo);
|
||||
|
||||
const float move_distance_cu = weight *
|
||||
math::distance(brush_start_pos_cu, brush_end_pos_cu);
|
||||
max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu);
|
||||
if (dist_to_brush_sq_re > brush_radius_sq_re) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (max_move_distance_cu > 0.0f) {
|
||||
local_influences.curve_indices.append(curve_i);
|
||||
local_influences.move_distances_cu.append(max_move_distance_cu);
|
||||
|
||||
const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
|
||||
const float radius_falloff = BKE_brush_curve_strength(
|
||||
brush_, dist_to_brush_re, brush_radius_re);
|
||||
const float weight = brush_strength_ * radius_falloff * curve_selection_factor;
|
||||
|
||||
const float3 closest_on_segment_cu = math::interpolate(p1_cu, p2_cu, lambda_on_segment);
|
||||
|
||||
float3 brush_start_pos_wo, brush_end_pos_wo;
|
||||
ED_view3d_win_to_3d(
|
||||
ctx_.v3d,
|
||||
ctx_.region,
|
||||
math::transform_point(transforms_.curves_to_world, closest_on_segment_cu),
|
||||
brush_pos_start_re_,
|
||||
brush_start_pos_wo);
|
||||
ED_view3d_win_to_3d(
|
||||
ctx_.v3d,
|
||||
ctx_.region,
|
||||
math::transform_point(transforms_.curves_to_world, closest_on_segment_cu),
|
||||
brush_pos_end_re_,
|
||||
brush_end_pos_wo);
|
||||
const float3 brush_start_pos_cu = math::transform_point(transforms_.world_to_curves,
|
||||
brush_start_pos_wo);
|
||||
const float3 brush_end_pos_cu = math::transform_point(transforms_.world_to_curves,
|
||||
brush_end_pos_wo);
|
||||
|
||||
const float move_distance_cu = weight *
|
||||
math::distance(brush_start_pos_cu, brush_end_pos_cu);
|
||||
max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu);
|
||||
}
|
||||
}
|
||||
move_distances_cu[curve_i] = max_move_distance_cu;
|
||||
});
|
||||
}
|
||||
|
||||
void gather_influences_spherical(
|
||||
threading::EnumerableThreadSpecific<Influences> &influences_for_thread)
|
||||
void gather_influences_spherical(MutableSpan<float> move_distances_cu)
|
||||
{
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
|
||||
@@ -459,55 +442,47 @@ struct CurvesEffectOperationExecutor {
|
||||
eCurvesSymmetryType(curves_id_->symmetry));
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
|
||||
Influences &local_influences = influences_for_thread.local();
|
||||
curve_selection_.foreach_index(GrainSize(256), [&](int64_t curve_i) {
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
|
||||
for (const int curve_i : curves_range) {
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const float curve_selection_factor = curve_selection_factors_[curve_i];
|
||||
|
||||
float max_move_distance_cu = 0.0f;
|
||||
float max_move_distance_cu = 0.0f;
|
||||
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
|
||||
const float3 brush_pos_start_transformed_cu = math::transform_point(brush_transform,
|
||||
brush_pos_start_cu);
|
||||
const float3 brush_pos_end_transformed_cu = math::transform_point(brush_transform,
|
||||
brush_pos_end_cu);
|
||||
|
||||
const float curve_selection_factor = curve_selection_factors_[curve_i];
|
||||
for (const int segment_i : points.drop_back(1)) {
|
||||
const float3 &p1_cu = deformation.positions[segment_i];
|
||||
const float3 &p2_cu = deformation.positions[segment_i + 1];
|
||||
|
||||
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
|
||||
const float3 brush_pos_start_transformed_cu = math::transform_point(brush_transform,
|
||||
brush_pos_start_cu);
|
||||
const float3 brush_pos_end_transformed_cu = math::transform_point(brush_transform,
|
||||
brush_pos_end_cu);
|
||||
float3 closest_on_segment_cu;
|
||||
float3 closest_on_brush_cu;
|
||||
isect_seg_seg_v3(p1_cu,
|
||||
p2_cu,
|
||||
brush_pos_start_transformed_cu,
|
||||
brush_pos_end_transformed_cu,
|
||||
closest_on_segment_cu,
|
||||
closest_on_brush_cu);
|
||||
|
||||
for (const int segment_i : points.drop_back(1)) {
|
||||
const float3 &p1_cu = deformation.positions[segment_i];
|
||||
const float3 &p2_cu = deformation.positions[segment_i + 1];
|
||||
|
||||
float3 closest_on_segment_cu;
|
||||
float3 closest_on_brush_cu;
|
||||
isect_seg_seg_v3(p1_cu,
|
||||
p2_cu,
|
||||
brush_pos_start_transformed_cu,
|
||||
brush_pos_end_transformed_cu,
|
||||
closest_on_segment_cu,
|
||||
closest_on_brush_cu);
|
||||
|
||||
const float dist_to_brush_sq_cu = math::distance_squared(closest_on_segment_cu,
|
||||
closest_on_brush_cu);
|
||||
if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
|
||||
const float radius_falloff = BKE_brush_curve_strength(
|
||||
brush_, dist_to_brush_cu, brush_radius_cu);
|
||||
const float weight = brush_strength_ * radius_falloff * curve_selection_factor;
|
||||
|
||||
const float move_distance_cu = weight * brush_pos_diff_length_cu;
|
||||
max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu);
|
||||
const float dist_to_brush_sq_cu = math::distance_squared(closest_on_segment_cu,
|
||||
closest_on_brush_cu);
|
||||
if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (max_move_distance_cu > 0.0f) {
|
||||
local_influences.curve_indices.append(curve_i);
|
||||
local_influences.move_distances_cu.append(max_move_distance_cu);
|
||||
|
||||
const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
|
||||
const float radius_falloff = BKE_brush_curve_strength(
|
||||
brush_, dist_to_brush_cu, brush_radius_cu);
|
||||
const float weight = brush_strength_ * radius_falloff * curve_selection_factor;
|
||||
|
||||
const float move_distance_cu = weight * brush_pos_diff_length_cu;
|
||||
max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu);
|
||||
}
|
||||
}
|
||||
move_distances_cu[curve_i] = max_move_distance_cu;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -142,7 +142,7 @@ struct PuffOperationExecutor {
|
||||
*curves_, curve_selection_, curves_id_->flag & CV_SCULPT_COLLISION_ENABLED);
|
||||
}
|
||||
|
||||
Array<float> curve_weights(curve_selection_.size(), 0.0f);
|
||||
Array<float> curve_weights(curves_->curves_num());
|
||||
|
||||
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_TUBE) {
|
||||
this->find_curve_weights_projected_with_symmetry(curve_weights);
|
||||
@@ -154,20 +154,15 @@ struct PuffOperationExecutor {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
this->puff(curve_weights);
|
||||
|
||||
Vector<int64_t> changed_curves_indices;
|
||||
changed_curves_indices.reserve(curve_selection_.size());
|
||||
for (int64_t select_i : curve_selection_.index_range()) {
|
||||
if (curve_weights[select_i] > 0.0f) {
|
||||
changed_curves_indices.append(curve_selection_[select_i]);
|
||||
}
|
||||
}
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask changed_curves_mask = IndexMask::from_indices<int64_t>(changed_curves_indices,
|
||||
memory);
|
||||
const IndexMask curves_mask = IndexMask::from_predicate(
|
||||
curve_selection_, GrainSize(4096), memory, [&](const int64_t curve_i) {
|
||||
return curve_weights[curve_i] > 0.0f;
|
||||
});
|
||||
|
||||
self_->constraint_solver_.solve_step(*curves_, changed_curves_mask, surface_, transforms_);
|
||||
this->puff(curves_mask, curve_weights);
|
||||
|
||||
self_->constraint_solver_.solve_step(*curves_, curves_mask, surface_, transforms_);
|
||||
|
||||
curves_->tag_positions_changed();
|
||||
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
|
||||
@@ -199,34 +194,32 @@ struct PuffOperationExecutor {
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
|
||||
for (const int curve_selection_i : range) {
|
||||
const int curve_i = curve_selection_[curve_selection_i];
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const float3 first_pos_cu = math::transform_point(brush_transform_inv,
|
||||
deformation.positions[points[0]]);
|
||||
float2 prev_pos_re;
|
||||
ED_view3d_project_float_v2_m4(ctx_.region, first_pos_cu, prev_pos_re, projection.ptr());
|
||||
for (const int point_i : points.drop_front(1)) {
|
||||
const float3 pos_cu = math::transform_point(brush_transform_inv,
|
||||
deformation.positions[point_i]);
|
||||
float2 pos_re;
|
||||
ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.ptr());
|
||||
BLI_SCOPED_DEFER([&]() { prev_pos_re = pos_re; });
|
||||
curve_selection_.foreach_index(GrainSize(256), [&](const int64_t curve_i) {
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const float3 first_pos_cu = math::transform_point(brush_transform_inv,
|
||||
deformation.positions[points[0]]);
|
||||
float2 prev_pos_re;
|
||||
ED_view3d_project_float_v2_m4(ctx_.region, first_pos_cu, prev_pos_re, projection.ptr());
|
||||
float max_weight = 0.0f;
|
||||
for (const int point_i : points.drop_front(1)) {
|
||||
const float3 pos_cu = math::transform_point(brush_transform_inv,
|
||||
deformation.positions[point_i]);
|
||||
float2 pos_re;
|
||||
ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.ptr());
|
||||
BLI_SCOPED_DEFER([&]() { prev_pos_re = pos_re; });
|
||||
|
||||
const float dist_to_brush_sq_re = dist_squared_to_line_segment_v2(
|
||||
brush_pos_re_, prev_pos_re, pos_re);
|
||||
if (dist_to_brush_sq_re > brush_radius_sq_re) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
|
||||
const float radius_falloff = BKE_brush_curve_strength(
|
||||
brush_, dist_to_brush_re, brush_radius_re);
|
||||
const float weight = radius_falloff;
|
||||
math::max_inplace(r_curve_weights[curve_selection_i], weight);
|
||||
const float dist_to_brush_sq_re = dist_squared_to_line_segment_v2(
|
||||
brush_pos_re_, prev_pos_re, pos_re);
|
||||
if (dist_to_brush_sq_re > brush_radius_sq_re) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
|
||||
const float radius_falloff = BKE_brush_curve_strength(
|
||||
brush_, dist_to_brush_re, brush_radius_re);
|
||||
math::max_inplace(max_weight, radius_falloff);
|
||||
}
|
||||
r_curve_weights[curve_i] = max_weight;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -263,39 +256,35 @@ struct PuffOperationExecutor {
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
|
||||
for (const int curve_selection_i : range) {
|
||||
const int curve_i = curve_selection_[curve_selection_i];
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int point_i : points.drop_front(1)) {
|
||||
const float3 &prev_pos_cu = deformation.positions[point_i - 1];
|
||||
const float3 &pos_cu = deformation.positions[point_i];
|
||||
const float dist_to_brush_sq_cu = dist_squared_to_line_segment_v3(
|
||||
brush_pos_cu, prev_pos_cu, pos_cu);
|
||||
if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
|
||||
const float radius_falloff = BKE_brush_curve_strength(
|
||||
brush_, dist_to_brush_cu, brush_radius_cu);
|
||||
const float weight = radius_falloff;
|
||||
math::max_inplace(r_curve_weights[curve_selection_i], weight);
|
||||
curve_selection_.foreach_index(GrainSize(256), [&](const int64_t curve_i) {
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
float max_weight = 0.0f;
|
||||
for (const int point_i : points.drop_front(1)) {
|
||||
const float3 &prev_pos_cu = deformation.positions[point_i - 1];
|
||||
const float3 &pos_cu = deformation.positions[point_i];
|
||||
const float dist_to_brush_sq_cu = dist_squared_to_line_segment_v3(
|
||||
brush_pos_cu, prev_pos_cu, pos_cu);
|
||||
if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
|
||||
const float radius_falloff = BKE_brush_curve_strength(
|
||||
brush_, dist_to_brush_cu, brush_radius_cu);
|
||||
math::max_inplace(max_weight, radius_falloff);
|
||||
}
|
||||
r_curve_weights[curve_i] = max_weight;
|
||||
});
|
||||
}
|
||||
|
||||
void puff(const Span<float> curve_weights)
|
||||
void puff(const IndexMask &selection, const Span<float> curve_weights)
|
||||
{
|
||||
BLI_assert(curve_weights.size() == curve_selection_.size());
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
MutableSpan<float3> positions_cu = curves_->positions_for_write();
|
||||
|
||||
threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
|
||||
selection.foreach_segment(GrainSize(256), [&](IndexMaskSegment segment) {
|
||||
Vector<float> accumulated_lengths_cu;
|
||||
for (const int curve_selection_i : range) {
|
||||
const int curve_i = curve_selection_[curve_selection_i];
|
||||
for (const int curve_i : segment) {
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const int first_point_i = points[0];
|
||||
const float3 first_pos_cu = positions_cu[first_point_i];
|
||||
@@ -339,7 +328,7 @@ struct PuffOperationExecutor {
|
||||
const float3 goal_pos_cu = first_pos_cu + length_param_cu * normal_cu;
|
||||
|
||||
const float weight = 0.01f * brush_strength_ * point_factors_[point_i] *
|
||||
curve_weights[curve_selection_i];
|
||||
curve_weights[curve_i];
|
||||
float3 new_pos_cu = math::interpolate(old_pos_cu, goal_pos_cu, weight);
|
||||
|
||||
/* Make sure the point does not move closer to the root point than it was initially. This
|
||||
|
||||
@@ -186,9 +186,9 @@ struct SnakeHookOperatorExecutor {
|
||||
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
|
||||
const float brush_radius_sq_re = pow2f(brush_radius_re);
|
||||
|
||||
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
|
||||
curve_selection_.foreach_segment(GrainSize(256), [&](const IndexMaskSegment segment) {
|
||||
MoveAndResampleBuffers resample_buffer;
|
||||
for (const int curve_i : curves_range) {
|
||||
for (const int curve_i : segment) {
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const int last_point_i = points.last();
|
||||
const float3 old_pos_cu = deformation.positions[last_point_i];
|
||||
@@ -272,9 +272,9 @@ struct SnakeHookOperatorExecutor {
|
||||
const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
|
||||
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
|
||||
|
||||
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
|
||||
curve_selection_.foreach_segment(GrainSize(256), [&](const IndexMaskSegment segment) {
|
||||
MoveAndResampleBuffers resample_buffer;
|
||||
for (const int curve_i : curves_range) {
|
||||
for (const int curve_i : segment) {
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const int last_point_i = points.last();
|
||||
const float3 old_pos_cu = deformation.positions[last_point_i];
|
||||
|
||||
Reference in New Issue
Block a user