Blender  V3.3
curves_sculpt_snake_hook.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <algorithm>
4 
6 
7 #include "BLI_float4x4.hh"
8 #include "BLI_index_mask_ops.hh"
9 #include "BLI_kdtree.h"
11 #include "BLI_rand.hh"
12 #include "BLI_vector.hh"
13 
14 #include "PIL_time.h"
15 
16 #include "DEG_depsgraph.h"
17 
18 #include "BKE_attribute_math.hh"
19 #include "BKE_brush.h"
20 #include "BKE_bvhutils.h"
21 #include "BKE_context.h"
22 #include "BKE_curves.hh"
23 #include "BKE_mesh.h"
24 #include "BKE_mesh_runtime.h"
25 #include "BKE_paint.h"
26 
27 #include "DNA_brush_enums.h"
28 #include "DNA_brush_types.h"
29 #include "DNA_curves_types.h"
30 #include "DNA_mesh_types.h"
31 #include "DNA_meshdata_types.h"
32 #include "DNA_object_types.h"
33 #include "DNA_screen_types.h"
34 #include "DNA_space_types.h"
35 
36 #include "ED_screen.h"
37 #include "ED_view3d.h"
38 
39 #include "WM_api.h"
40 
49 namespace blender::ed::sculpt_paint {
50 
52 
57  private:
58  float2 last_mouse_position_re_;
59 
60  CurvesBrush3D brush_3d_;
61 
63 
64  public:
65  void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
66 };
67 
75 
76  const CurvesSculpt *curves_sculpt_ = nullptr;
77  const Brush *brush_ = nullptr;
81 
83 
84  Object *object_ = nullptr;
85  Curves *curves_id_ = nullptr;
86  CurvesGeometry *curves_ = nullptr;
87 
91 
93 
97 
99  {
100  }
101 
103  const bContext &C,
104  const StrokeExtension &stroke_extension)
105  {
106  BLI_SCOPED_DEFER([&]() { self.last_mouse_position_re_ = stroke_extension.mouse_position; });
107 
108  self_ = &self;
110 
113 
115  brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
116  brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
117 
119 
120  curves_id_ = static_cast<Curves *>(object_->data);
122  if (curves_->curves_num() == 0) {
123  return;
124  }
125 
127 
130 
131  brush_pos_prev_re_ = self.last_mouse_position_re_;
132  brush_pos_re_ = stroke_extension.mouse_position;
134 
135  if (stroke_extension.is_first) {
137  std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
138  *ctx_.region,
139  *ctx_.v3d,
140  *ctx_.rv3d,
141  *object_,
144  if (brush_3d.has_value()) {
145  self_->brush_3d_ = *brush_3d;
146  }
147  }
148  return;
149  }
150 
153  }
154  else if (falloff_shape_ == PAINT_FALLOFF_SHAPE_TUBE) {
156  }
157  else {
159  }
160 
161  curves_->tag_positions_changed();
165  }
166 
168  {
169  const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
171  for (const float4x4 &brush_transform : symmetry_brush_transforms) {
172  this->projected_snake_hook(brush_transform);
173  }
174  }
175 
176  void projected_snake_hook(const float4x4 &brush_transform)
177  {
178  const float4x4 brush_transform_inv = brush_transform.inverted();
179  const bke::crazyspace::GeometryDeformation deformation =
181 
183 
184  float4x4 projection;
186 
187  const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
188  const float brush_radius_sq_re = pow2f(brush_radius_re);
189 
190  threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
191  for (const int curve_i : curves_range) {
192  const IndexRange points = curves_->points_for_curve(curve_i);
193  const int last_point_i = points.last();
194  const float3 old_pos_cu = deformation.positions[last_point_i];
195  const float3 old_symm_pos_cu = brush_transform_inv * old_pos_cu;
196 
197  float2 old_symm_pos_re;
198  ED_view3d_project_float_v2_m4(
199  ctx_.region, old_symm_pos_cu, old_symm_pos_re, projection.values);
200 
201  const float distance_to_brush_sq_re = math::distance_squared(old_symm_pos_re,
202  brush_pos_prev_re_);
203  if (distance_to_brush_sq_re > brush_radius_sq_re) {
204  continue;
205  }
206 
207  const float radius_falloff = BKE_brush_curve_strength(
208  brush_, std::sqrt(distance_to_brush_sq_re), brush_radius_re);
209  const float weight = brush_strength_ * radius_falloff * curve_factors_[curve_i];
210 
211  const float2 new_symm_pos_re = old_symm_pos_re + brush_pos_diff_re_ * weight;
212  float3 new_symm_pos_wo;
213  ED_view3d_win_to_3d(ctx_.v3d,
214  ctx_.region,
215  transforms_.curves_to_world * old_symm_pos_cu,
216  new_symm_pos_re,
217  new_symm_pos_wo);
218  const float3 new_pos_cu = brush_transform *
219  (transforms_.world_to_curves * new_symm_pos_wo);
220  const float3 translation_eval = new_pos_cu - old_pos_cu;
221  const float3 translation_orig = deformation.translation_from_deformed_to_original(
222  last_point_i, translation_eval);
223 
224  move_last_point_and_resample(positions_cu.slice(points),
225  positions_cu[last_point_i] + translation_orig);
226  }
227  });
228  }
229 
231  {
232  float4x4 projection;
233  ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
234 
235  float3 brush_start_wo, brush_end_wo;
236  ED_view3d_win_to_3d(ctx_.v3d,
237  ctx_.region,
238  transforms_.curves_to_world * self_->brush_3d_.position_cu,
239  brush_pos_prev_re_,
240  brush_start_wo);
241  ED_view3d_win_to_3d(ctx_.v3d,
242  ctx_.region,
243  transforms_.curves_to_world * self_->brush_3d_.position_cu,
244  brush_pos_re_,
245  brush_end_wo);
246  const float3 brush_start_cu = transforms_.world_to_curves * brush_start_wo;
247  const float3 brush_end_cu = transforms_.world_to_curves * brush_end_wo;
248 
249  const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
250 
251  const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
252  eCurvesSymmetryType(curves_id_->symmetry));
253  for (const float4x4 &brush_transform : symmetry_brush_transforms) {
254  this->spherical_snake_hook(
255  brush_transform * brush_start_cu, brush_transform * brush_end_cu, brush_radius_cu);
256  }
257  }
258 
259  void spherical_snake_hook(const float3 &brush_start_cu,
260  const float3 &brush_end_cu,
261  const float brush_radius_cu)
262  {
263  const bke::crazyspace::GeometryDeformation deformation =
264  bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
265 
266  MutableSpan<float3> positions_cu = curves_->positions_for_write();
267  const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
268  const float brush_radius_sq_cu = pow2f(brush_radius_cu);
269 
270  threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
271  for (const int curve_i : curves_range) {
272  const IndexRange points = curves_->points_for_curve(curve_i);
273  const int last_point_i = points.last();
274  const float3 old_pos_cu = deformation.positions[last_point_i];
275 
276  const float distance_to_brush_sq_cu = dist_squared_to_line_segment_v3(
277  old_pos_cu, brush_start_cu, brush_end_cu);
278  if (distance_to_brush_sq_cu > brush_radius_sq_cu) {
279  continue;
280  }
281 
282  const float distance_to_brush_cu = std::sqrt(distance_to_brush_sq_cu);
283 
284  const float radius_falloff = BKE_brush_curve_strength(
285  brush_, distance_to_brush_cu, brush_radius_cu);
286  const float weight = brush_strength_ * radius_falloff * curve_factors_[curve_i];
287 
288  const float3 translation_eval = weight * brush_diff_cu;
289  const float3 translation_orig = deformation.translation_from_deformed_to_original(
290  last_point_i, translation_eval);
291 
292  move_last_point_and_resample(positions_cu.slice(points),
293  positions_cu[last_point_i] + translation_orig);
294  }
295  });
296  }
297 };
298 
299 void SnakeHookOperation::on_stroke_extended(const bContext &C,
300  const StrokeExtension &stroke_extension)
301 {
302  SnakeHookOperatorExecutor executor{C};
303  executor.execute(*this, C, stroke_extension);
304 }
305 
306 std::unique_ptr<CurvesSculptStrokeOperation> new_snake_hook_operation()
307 {
308  return std::make_unique<SnakeHookOperation>();
309 }
310 
311 } // 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
Low-level operations for curves.
const struct Brush * BKE_paint_brush_for_read(const struct Paint *p)
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
A KD-tree for nearest neighbor search.
MINLINE float pow2f(float x)
#define BLI_SCOPED_DEFER(function_to_defer)
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
struct CurvesGeometry CurvesGeometry
eCurvesSymmetryType
Object is a sort of wrapper for general info.
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])
Platform independent time functions.
#define C
Definition: RandGen.cpp:25
#define NC_GEOM
Definition: WM_types.h:343
#define ND_DATA
Definition: WM_types.h:456
MutableSpan< float3 > positions_for_write()
IndexRange curves_range() const
Definition: BKE_curves.hh:795
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
VArray< float > get_curves_selection(const Curves &curves_id)
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)
std::unique_ptr< CurvesSculptStrokeOperation > new_snake_hook_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
char falloff_shape
CurvesGeometry geometry
struct Object * surface
void * data
struct ToolSettings * toolsettings
CurvesSculpt * curves_sculpt
void spherical_snake_hook(const float3 &brush_start_cu, const float3 &brush_end_cu, const float brush_radius_cu)
void execute(SnakeHookOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
void projected_snake_hook(const float4x4 &brush_transform)
float values[4][4]
Definition: BLI_float4x4.hh:13
float4x4 inverted() const
void WM_main_add_notifier(unsigned int type, void *reference)