Blender  V3.3
curves_sculpt_smooth.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BKE_brush.h"
4 #include "BKE_context.h"
5 #include "BKE_crazyspace.hh"
6 
7 #include "ED_screen.h"
8 #include "ED_view3d.h"
9 
10 #include "DEG_depsgraph.h"
11 
12 #include "DNA_brush_types.h"
13 
14 #include "WM_api.h"
15 
17 
18 #include "curves_sculpt_intern.hh"
19 
20 namespace blender::ed::sculpt_paint {
21 
23  private:
25  CurvesBrush3D brush_3d_;
26 
27  friend struct SmoothOperationExecutor;
28 
29  public:
30  void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
31 };
32 
38  SmoothOperation *self_ = nullptr;
40 
41  Object *object_ = nullptr;
42  Curves *curves_id_ = nullptr;
43  CurvesGeometry *curves_ = nullptr;
44 
48 
49  const CurvesSculpt *curves_sculpt_ = nullptr;
50  const Brush *brush_ = nullptr;
55 
57 
59  {
60  }
61 
62  void execute(SmoothOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
63  {
64  UNUSED_VARS(C, stroke_extension);
65  self_ = &self;
66 
68  curves_id_ = static_cast<Curves *>(object_->data);
70  if (curves_->curves_num() == 0) {
71  return;
72  }
73 
77  brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
78  brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
79  brush_pos_re_ = stroke_extension.mouse_position;
80 
84 
85  const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
87  if (stroke_extension.is_first) {
88  if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
89  self.brush_3d_ = *sample_curves_3d_brush(*ctx_.depsgraph,
90  *ctx_.region,
91  *ctx_.v3d,
92  *ctx_.rv3d,
93  *object_,
96  }
97  }
98 
99  Array<float> point_smooth_factors(curves_->points_num(), 0.0f);
100 
101  if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
102  this->find_projected_smooth_factors_with_symmetry(point_smooth_factors);
103  }
104  else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
105  this->find_spherical_smooth_factors_with_symmetry(point_smooth_factors);
106  }
107  else {
109  }
110 
111  this->smooth(point_smooth_factors);
116  }
117 
119  {
120  const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
122  for (const float4x4 &brush_transform : symmetry_brush_transforms) {
123  this->find_projected_smooth_factors(brush_transform, r_point_smooth_factors);
124  }
125  }
126 
127  void find_projected_smooth_factors(const float4x4 &brush_transform,
128  MutableSpan<float> r_point_smooth_factors)
129  {
130  const float4x4 brush_transform_inv = brush_transform.inverted();
131 
132  const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
133  const float brush_radius_sq_re = pow2f(brush_radius_re);
134 
135  float4x4 projection;
137 
138  const bke::crazyspace::GeometryDeformation deformation =
140 
142  for (const int curve_i : curve_selection_.slice(range)) {
143  const IndexRange points = curves_->points_for_curve(curve_i);
144  for (const int point_i : points) {
145  const float3 &pos_cu = brush_transform_inv * deformation.positions[point_i];
146  float2 pos_re;
147  ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
148  const float dist_to_brush_sq_re = math::distance_squared(pos_re, brush_pos_re_);
149  if (dist_to_brush_sq_re > brush_radius_sq_re) {
150  continue;
151  }
152 
153  const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
154  const float radius_falloff = BKE_brush_curve_strength(
155  brush_, dist_to_brush_re, brush_radius_re);
156  /* Used to make the brush easier to use. Otherwise a strength of 1 would be way too
157  * large. */
158  const float weight_factor = 0.1f;
159  const float weight = weight_factor * brush_strength_ * radius_falloff *
160  point_factors_[point_i];
161  math::max_inplace(r_point_smooth_factors[point_i], weight);
162  }
163  }
164  });
165  }
166 
168  {
169  float4x4 projection;
170  ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
171 
172  float3 brush_pos_wo;
173  ED_view3d_win_to_3d(ctx_.v3d,
174  ctx_.region,
175  transforms_.curves_to_world * self_->brush_3d_.position_cu,
176  brush_pos_re_,
177  brush_pos_wo);
178  const float3 brush_pos_cu = transforms_.world_to_curves * brush_pos_wo;
179  const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
180 
181  const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
182  eCurvesSymmetryType(curves_id_->symmetry));
183  for (const float4x4 &brush_transform : symmetry_brush_transforms) {
184  this->find_spherical_smooth_factors(
185  brush_transform * brush_pos_cu, brush_radius_cu, r_point_smooth_factors);
186  }
187  }
188 
189  void find_spherical_smooth_factors(const float3 &brush_pos_cu,
190  const float brush_radius_cu,
191  MutableSpan<float> r_point_smooth_factors)
192  {
193  const float brush_radius_sq_cu = pow2f(brush_radius_cu);
194  const bke::crazyspace::GeometryDeformation deformation =
195  bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
196 
197  threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
198  for (const int curve_i : curve_selection_.slice(range)) {
199  const IndexRange points = curves_->points_for_curve(curve_i);
200  for (const int point_i : points) {
201  const float3 &pos_cu = deformation.positions[point_i];
202  const float dist_to_brush_sq_cu = math::distance_squared(pos_cu, brush_pos_cu);
203  if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
204  continue;
205  }
206 
207  const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
208  const float radius_falloff = BKE_brush_curve_strength(
209  brush_, dist_to_brush_cu, brush_radius_cu);
210  /* Used to make the brush easier to use. Otherwise a strength of 1 would be way too
211  * large. */
212  const float weight_factor = 0.1f;
213  const float weight = weight_factor * brush_strength_ * radius_falloff *
214  point_factors_[point_i];
215  math::max_inplace(r_point_smooth_factors[point_i], weight);
216  }
217  }
218  });
219  }
220 
221  void smooth(const Span<float> point_smooth_factors)
222  {
223  MutableSpan<float3> positions = curves_->positions_for_write();
224  threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
225  Vector<float3> old_positions;
226  for (const int curve_i : curve_selection_.slice(range)) {
227  const IndexRange points = curves_->points_for_curve(curve_i);
228  old_positions.clear();
229  old_positions.extend(positions.slice(points));
230  for (const int i : IndexRange(points.size()).drop_front(1).drop_back(1)) {
231  const int point_i = points[i];
232  const float smooth_factor = point_smooth_factors[point_i];
233  if (smooth_factor == 0.0f) {
234  continue;
235  }
236  /* Move towards the middle of the neighboring points. */
237  const float3 old_pos = old_positions[i];
238  const float3 &prev_pos = old_positions[i - 1];
239  const float3 &next_pos = old_positions[i + 1];
240  const float3 goal_pos = math::midpoint(prev_pos, next_pos);
241  const float3 new_pos = math::interpolate(old_pos, goal_pos, smooth_factor);
242  positions[point_i] = new_pos;
243  }
244  }
245  });
246  }
247 };
248 
249 void SmoothOperation::on_stroke_extended(const bContext &C,
250  const StrokeExtension &stroke_extension)
251 {
252  SmoothOperationExecutor executor{C};
253  executor.execute(*this, C, stroke_extension);
254 }
255 
256 std::unique_ptr<CurvesSculptStrokeOperation> new_smooth_operation()
257 {
258  return std::make_unique<SmoothOperation>();
259 }
260 
261 } // namespace blender::ed::sculpt_paint
int BKE_brush_size_get(const struct Scene *scene, const struct Brush *brush)
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
const struct Brush * BKE_paint_brush_for_read(const struct Paint *p)
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
MINLINE float pow2f(float x)
#define UNUSED_VARS(...)
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
eBrushFalloffShape
@ PAINT_FALLOFF_SHAPE_SPHERE
@ PAINT_FALLOFF_SHAPE_TUBE
eCurvesSymmetryType
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
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])
#define C
Definition: RandGen.cpp:25
#define NC_GEOM
Definition: WM_types.h:343
#define ND_DATA
Definition: WM_types.h:456
IndexRange index_range() const
static CurvesGeometry & wrap(::CurvesGeometry &dna_struct)
Definition: BKE_curves.hh:138
void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override
GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph, const Object &ob_orig)
Definition: crazyspace.cc:595
std::optional< CurvesBrush3D > sample_curves_3d_brush(const Depsgraph &depsgraph, const ARegion &region, const View3D &v3d, const RegionView3D &rv3d, const Object &curves_object, const float2 &brush_pos_re, const float brush_radius_re)
VArray< float > get_point_selection(const Curves &curves_id)
std::unique_ptr< CurvesSculptStrokeOperation > new_smooth_operation()
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)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
MutableSpan< float3 > positions
char falloff_shape
CurvesGeometry geometry
struct Object * surface
void * data
struct ToolSettings * toolsettings
CurvesSculpt * curves_sculpt
void find_spherical_smooth_factors(const float3 &brush_pos_cu, const float brush_radius_cu, MutableSpan< float > r_point_smooth_factors)
void find_projected_smooth_factors(const float4x4 &brush_transform, MutableSpan< float > r_point_smooth_factors)
void smooth(const Span< float > point_smooth_factors)
void execute(SmoothOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
void find_spherical_smooth_factors_with_symmetry(MutableSpan< float > r_point_smooth_factors)
void find_projected_smooth_factors_with_symmetry(MutableSpan< float > r_point_smooth_factors)
float values[4][4]
Definition: BLI_float4x4.hh:13
float4x4 inverted() const
void WM_main_add_notifier(unsigned int type, void *reference)