67 struct ParameterizationBuffers {
74 void reinitialize(
const int points_num)
95 ParameterizationBuffers data;
96 for (const int influence_i : range) {
97 const int curve_i = curve_indices[influence_i];
98 const float move_distance_cu = move_distances_cu[influence_i];
99 const IndexRange points = curves.points_for_curve(curve_i);
100 this->shrink_curve(positions_cu.slice(points), move_distance_cu, data);
107 const float shrink_length,
108 ParameterizationBuffers &
data)
const
110 namespace lp = length_parameterize;
116 lp::accumulate_lengths<float3>(
data.old_positions,
false,
data.old_lengths);
118 const float min_length = brush_.curves_sculpt_settings->minimum_length;
119 const float old_length =
data.old_lengths.last();
120 const float new_length =
std::max(min_length, old_length - shrink_length);
121 const float length_factor =
std::clamp(new_length / old_length, 0.0f, 1.0f);
123 data.sample_lengths.first() = 0.0f;
124 for (
const int i :
data.old_lengths.index_range()) {
125 data.sample_lengths[i + 1] =
data.old_lengths[i] * length_factor;
144 for (const int influence_i : range) {
145 const int curve_i = curve_indices[influence_i];
146 const float move_distance_cu = move_distances_cu[influence_i];
147 const IndexRange curve_points = curves.points_for_curve(curve_i);
149 if (curve_points.size() <= 1) {
153 const float3 old_last_pos_cu = positions_cu[curve_points.last()];
156 const float3 direction_reference_point =
157 positions_cu[curve_points.size() > 2 ? curve_points[curve_points.size() / 2] :
158 curve_points.first()];
159 const float3 direction = math::normalize(old_last_pos_cu - direction_reference_point);
161 const float3 new_last_pos_cu = old_last_pos_cu + direction * move_distance_cu;
162 move_last_point_and_resample(positions_cu.slice(curve_points), new_last_pos_cu);
187 for (const int influence_i : range) {
188 const int curve_i = curve_indices[influence_i];
189 const float move_distance_cu = move_distances_cu[influence_i];
190 const IndexRange points = curves.points_for_curve(curve_i);
192 const float old_length = this->compute_poly_curve_length(positions_cu.slice(points));
193 const float length_diff = scale_up_ ? move_distance_cu : -move_distance_cu;
194 const float min_length = brush_.curves_sculpt_settings->minimum_length;
195 const float new_length = std::max(min_length, old_length + length_diff);
196 const float scale_factor = safe_divide(new_length, old_length);
198 const float3 &root_pos_cu = positions_cu[points[0]];
199 for (float3 &pos_cu : positions_cu.slice(points.drop_front(1))) {
200 pos_cu = (pos_cu - root_pos_cu) * scale_factor + root_pos_cu;
221 std::unique_ptr<CurvesEffect> effect_;
222 float2 last_mouse_position_;
281 curves_id_ =
static_cast<Curves *
>(object_->
data);
302 brush_pos_start_re_ =
self.last_mouse_position_;
314 brush_radius_base_re_)) {
315 self.brush_3d_ = *brush_3d;
325 this->gather_influences_projected(influences_for_thread);
328 this->gather_influences_spherical(influences_for_thread);
355 for (
const float4x4 brush_transform : symmetry_brush_transforms) {
356 symmetry_brush_transforms_inv.
append(brush_transform.inverted());
359 const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
360 const float brush_radius_sq_re =
pow2f(brush_radius_re);
363 Influences &local_influences = influences_for_thread.local();
365 for (const int curve_i : curves_range) {
366 const IndexRange points = curves_->points_for_curve(curve_i);
368 const float curve_selection_factor = curve_selection_factors_[curve_i];
370 float max_move_distance_cu = 0.0f;
371 for (const float4x4 &brush_transform_inv : symmetry_brush_transforms_inv) {
372 for (const int segment_i : points.drop_back(1)) {
373 const float3 p1_cu = brush_transform_inv * deformation.positions[segment_i];
374 const float3 p2_cu = brush_transform_inv * deformation.positions[segment_i + 1];
377 ED_view3d_project_float_v2_m4(ctx_.region, p1_cu, p1_re, projection.values);
378 ED_view3d_project_float_v2_m4(ctx_.region, p2_cu, p2_re, projection.values);
380 float2 closest_on_brush_re;
381 float2 closest_on_segment_re;
382 float lambda_on_brush;
383 float lambda_on_segment;
384 const float dist_to_brush_sq_re = closest_seg_seg_v2(closest_on_brush_re,
385 closest_on_segment_re,
393 if (dist_to_brush_sq_re > brush_radius_sq_re) {
397 const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
398 const float radius_falloff = BKE_brush_curve_strength(
399 brush_, dist_to_brush_re, brush_radius_re);
400 const float weight = brush_strength_ * radius_falloff * curve_selection_factor;
402 const float3 closest_on_segment_cu = math::interpolate(
403 p1_cu, p2_cu, lambda_on_segment);
405 float3 brush_start_pos_wo, brush_end_pos_wo;
406 ED_view3d_win_to_3d(ctx_.v3d,
408 transforms_.curves_to_world * closest_on_segment_cu,
411 ED_view3d_win_to_3d(ctx_.v3d,
413 transforms_.curves_to_world * closest_on_segment_cu,
416 const float3 brush_start_pos_cu = transforms_.world_to_curves * brush_start_pos_wo;
417 const float3 brush_end_pos_cu = transforms_.world_to_curves * brush_end_pos_wo;
419 const float move_distance_cu = weight *
420 math::distance(brush_start_pos_cu, brush_end_pos_cu);
421 max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu);
424 if (max_move_distance_cu > 0.0f) {
425 local_influences.curve_indices.append(curve_i);
426 local_influences.move_distances_cu.append(max_move_distance_cu);
438 float3 brush_pos_start_wo, brush_pos_end_wo;
441 transforms_.curves_to_world * self_->brush_3d_.position_cu,
446 transforms_.curves_to_world * self_->brush_3d_.position_cu,
449 const float3 brush_pos_start_cu = transforms_.world_to_curves * brush_pos_start_wo;
450 const float3 brush_pos_end_cu = transforms_.world_to_curves * brush_pos_end_wo;
451 const float3 brush_pos_diff_cu = brush_pos_end_cu - brush_pos_start_cu;
452 const float brush_pos_diff_length_cu =
math::length(brush_pos_diff_cu);
453 const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
454 const float brush_radius_sq_cu =
pow2f(brush_radius_cu);
460 Influences &local_influences = influences_for_thread.local();
462 for (const int curve_i : curves_range) {
463 const IndexRange points = curves_->points_for_curve(curve_i);
465 float max_move_distance_cu = 0.0f;
467 const float curve_selection_factor = curve_selection_factors_[curve_i];
469 for (const float4x4 &brush_transform : symmetry_brush_transforms) {
470 const float3 brush_pos_start_transformed_cu = brush_transform * brush_pos_start_cu;
471 const float3 brush_pos_end_transformed_cu = brush_transform * brush_pos_end_cu;
473 for (const int segment_i : points.drop_back(1)) {
474 const float3 &p1_cu = deformation.positions[segment_i];
475 const float3 &p2_cu = deformation.positions[segment_i + 1];
477 float3 closest_on_segment_cu;
478 float3 closest_on_brush_cu;
479 isect_seg_seg_v3(p1_cu,
481 brush_pos_start_transformed_cu,
482 brush_pos_end_transformed_cu,
483 closest_on_segment_cu,
484 closest_on_brush_cu);
486 const float dist_to_brush_sq_cu = math::distance_squared(closest_on_segment_cu,
487 closest_on_brush_cu);
488 if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
492 const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
493 const float radius_falloff = BKE_brush_curve_strength(
494 brush_, dist_to_brush_cu, brush_radius_cu);
495 const float weight = brush_strength_ * radius_falloff * curve_selection_factor;
497 const float move_distance_cu = weight * brush_pos_diff_length_cu;
498 max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu);
501 if (max_move_distance_cu > 0.0f) {
502 local_influences.curve_indices.append(curve_i);
503 local_influences.move_distances_cu.append(max_move_distance_cu);
510 void CurvesEffectOperation::on_stroke_extended(
const bContext &
C,
514 executor.execute(*
this,
C, stroke_extension);
527 if (use_scale_uniform) {
528 return std::make_unique<CurvesEffectOperation>(
529 std::make_unique<ScaleCurvesEffect>(
true, brush));
531 return std::make_unique<CurvesEffectOperation>(std::make_unique<ExtrapolateCurvesEffect>());
533 if (use_scale_uniform) {
534 return std::make_unique<CurvesEffectOperation>(
535 std::make_unique<ScaleCurvesEffect>(
false, brush));
537 return std::make_unique<CurvesEffectOperation>(std::make_unique<ShrinkCurvesEffect>(brush));
int BKE_brush_size_get(const struct Scene *scene, const struct Brush *brush)
struct Scene * CTX_data_scene(const bContext *C)
struct Object * CTX_data_active_object(const bContext *C)
Low-level operations for curves.
const struct Brush * BKE_paint_brush_for_read(const struct Paint *p)
MINLINE float pow2f(float x)
#define BLI_SCOPED_DEFER(function_to_defer)
void DEG_id_tag_update(struct ID *id, int flag)
@ PAINT_FALLOFF_SHAPE_SPHERE
@ PAINT_FALLOFF_SHAPE_TUBE
@ BRUSH_CURVES_SCULPT_FLAG_SCALE_UNIFORM
struct CurvesGeometry CurvesGeometry
Object is a sort of wrapper for general info.
void ED_region_tag_redraw(struct ARegion *region)
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, const struct Object *ob, float r_pmat[4][4])
void ED_view3d_win_to_3d(const struct View3D *v3d, const struct ARegion *region, const float depth_pt[3], const float mval[2], float r_out[3])
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to curves
Platform independent time functions.
void reinitialize(const int64_t new_size)
constexpr IndexRange index_range() const
void append(const T &value)
IndexRange curves_range() const
void tag_positions_changed()
CurvesEffectOperation(std::unique_ptr< CurvesEffect > effect)
virtual ~CurvesEffect()=default
virtual void execute(CurvesGeometry &curves, Span< int > curve_indices, Span< float > move_distances_cu)=0
const Depsgraph * depsgraph
void execute(CurvesGeometry &curves, const Span< int > curve_indices, const Span< float > move_distances_cu) override
ScaleCurvesEffect(bool scale_up, const Brush &brush)
float compute_poly_curve_length(const Span< float3 > positions)
void execute(CurvesGeometry &curves, const Span< int > curve_indices, const Span< float > move_distances_cu) override
ShrinkCurvesEffect(const Brush &brush)
ccl_gpu_kernel_postfix int ccl_global int * indices
GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph, const Object &ob_orig)
int segments_num(const int points_num, const bool cyclic)
static struct PartialUpdateUser * wrap(PartialUpdateUserImpl *user)
VArray< float > get_curves_selection(const Curves &curves_id)
std::optional< CurvesBrush3D > sample_curves_3d_brush(const Depsgraph &depsgraph, const ARegion ®ion, const View3D &v3d, const RegionView3D &rv3d, const Object &curves_object, const float2 &brush_pos_re, const float brush_radius_re)
std::unique_ptr< CurvesSculptStrokeOperation > new_grow_shrink_operation(const BrushStrokeMode brush_mode, const bContext &C)
static IndexMask retrieve_selected_curves(const CurvesGeometry &curves, const eAttrDomain domain, Vector< int64_t > &r_indices)
float brush_strength_get(const Scene &scene, const Brush &brush, const StrokeExtension &stroke_extension)
Vector< float4x4 > get_symmetry_brush_transforms(const eCurvesSymmetryType symmetry)
float brush_radius_factor(const Brush &brush, const StrokeExtension &stroke_extension)
int segments_num(const int points_num, const bool cyclic)
void sample_at_lengths(Span< float > accumulated_segment_lengths, Span< float > sample_lengths, MutableSpan< int > r_segment_indices, MutableSpan< float > r_factors)
T clamp(const T &a, const T &min, const T &max)
T length(const vec_base< T, Size > &a)
T distance(const T &a, const T &b)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
void parallel_for_each(Range &range, const Function &function)
MutableSpan< float3 > positions
struct BrushCurvesSculptSettings * curves_sculpt_settings
struct ToolSettings * toolsettings
Vector< int > curve_indices
Vector< float > move_distances_cu
eBrushFalloffShape falloff_shape_
void gather_influences_spherical(threading::EnumerableThreadSpecific< Influences > &influences_for_thread)
IndexMask curve_selection_
VArray< float > curve_selection_factors_
void gather_influences_projected(threading::EnumerableThreadSpecific< Influences > &influences_for_thread)
float2 brush_pos_start_re_
float brush_radius_factor_
CurvesEffectOperationExecutor(const bContext &C)
void execute(CurvesEffectOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
CurvesSculptCommonContext ctx_
CurvesSurfaceTransforms transforms_
Vector< int64_t > selected_curve_indices_
float brush_radius_base_re_
void WM_main_add_notifier(unsigned int type, void *reference)