Blender  V3.3
curves_sculpt_density.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <numeric>
4 
5 #include "BKE_attribute_math.hh"
6 #include "BKE_brush.h"
7 #include "BKE_bvhutils.h"
8 #include "BKE_context.h"
9 #include "BKE_geometry_set.hh"
10 #include "BKE_mesh.h"
11 #include "BKE_mesh_runtime.h"
12 #include "BKE_mesh_sample.hh"
13 #include "BKE_modifier.h"
14 #include "BKE_object.h"
15 #include "BKE_report.h"
16 
17 #include "ED_screen.h"
18 #include "ED_view3d.h"
19 
20 #include "DEG_depsgraph.h"
21 #include "DEG_depsgraph_query.h"
22 
23 #include "BLI_index_mask_ops.hh"
24 #include "BLI_kdtree.h"
25 #include "BLI_rand.hh"
26 #include "BLI_task.hh"
27 
28 #include "PIL_time.h"
29 
31 
32 #include "DNA_brush_types.h"
33 #include "DNA_mesh_types.h"
34 
35 #include "WM_api.h"
36 
37 #include "curves_sculpt_intern.hh"
38 
39 namespace blender::ed::sculpt_paint {
40 
42  private:
44  KDTree_3d *original_curve_roots_kdtree_ = nullptr;
46  KDTree_3d *deformed_curve_roots_kdtree_ = nullptr;
48  Vector<float3> new_deformed_root_positions_;
49  int original_curve_num_ = 0;
50 
52 
53  public:
55  {
56  if (original_curve_roots_kdtree_ != nullptr) {
57  BLI_kdtree_3d_free(original_curve_roots_kdtree_);
58  }
59  if (deformed_curve_roots_kdtree_ != nullptr) {
60  BLI_kdtree_3d_free(deformed_curve_roots_kdtree_);
61  }
62  }
63 
64  void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
65 };
66 
70 
71  Object *curves_ob_orig_ = nullptr;
72  Curves *curves_id_orig_ = nullptr;
74 
76  Mesh *surface_orig_ = nullptr;
77 
79  Mesh *surface_eval_ = nullptr;
83 
84  const CurvesSculpt *curves_sculpt_ = nullptr;
85  const Brush *brush_ = nullptr;
87 
91 
93 
95  {
96  }
97 
99  const bContext &C,
100  const StrokeExtension &stroke_extension)
101  {
102  self_ = &self;
104  curves_id_orig_ = static_cast<Curves *>(curves_ob_orig_->data);
106 
107  if (stroke_extension.is_first) {
108  self_->original_curve_num_ = curves_orig_->curves_num();
109  }
110 
111  if (curves_id_orig_->surface == nullptr || curves_id_orig_->surface->type != OB_MESH) {
112  report_missing_surface(stroke_extension.reports);
113  return;
114  }
115 
117  surface_orig_ = static_cast<Mesh *>(surface_ob_orig_->data);
118  if (surface_orig_->totpoly == 0) {
119  report_empty_original_surface(stroke_extension.reports);
120  return;
121  }
122 
124  if (surface_ob_eval_ == nullptr) {
125  return;
126  }
128  if (surface_eval_->totpoly == 0) {
129  report_empty_evaluated_surface(stroke_extension.reports);
130  return;
131  }
132 
137  /* Find UV map. */
138  VArraySpan<float2> surface_uv_map;
139  if (curves_id_orig_->surface_uv_map != nullptr) {
140  surface_uv_map = bke::mesh_attributes(*surface_orig_)
145  }
146  if (surface_uv_map.is_empty()) {
148  return;
149  }
150  if (surface_uv_map_eval_.is_empty()) {
152  return;
153  }
154 
156 
160  brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
161  brush_radius_re_ = brush_radius_get(*ctx_.scene, *brush_, stroke_extension);
162  brush_pos_re_ = stroke_extension.mouse_position;
163 
164  const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
166 
167  Vector<float3> new_positions_cu;
168  Vector<float2> new_uvs;
169  const double time = PIL_check_seconds_timer() * 1000000.0;
170  RandomNumberGenerator rng{*(uint32_t *)(&time)};
171 
172  /* Find potential new curve root points. */
173  if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
174  this->sample_projected_with_symmetry(rng, new_uvs, new_positions_cu);
175  }
176  else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
177  this->sample_spherical_with_symmetry(rng, new_uvs, new_positions_cu);
178  }
179  else {
181  }
182  for (float3 &pos : new_positions_cu) {
184  }
185 
186  if (stroke_extension.is_first) {
188  }
189 
190  const int already_added_curves = self_->new_deformed_root_positions_.size();
191  KDTree_3d *new_roots_kdtree = BLI_kdtree_3d_new(already_added_curves +
192  new_positions_cu.size());
193  BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(new_roots_kdtree); });
194 
195  /* Used to tag all curves that are too close to existing curves or too close to other new
196  * curves. */
197  Array<bool> new_curve_skipped(new_positions_cu.size(), false);
199  512 < already_added_curves + new_positions_cu.size(),
200  /* Build kdtree from root points created by the current stroke. */
201  [&]() {
202  for (const int i : IndexRange(already_added_curves)) {
203  BLI_kdtree_3d_insert(new_roots_kdtree, -1, self_->new_deformed_root_positions_[i]);
204  }
205  for (const int new_i : new_positions_cu.index_range()) {
206  const float3 &root_pos_cu = new_positions_cu[new_i];
207  BLI_kdtree_3d_insert(new_roots_kdtree, new_i, root_pos_cu);
208  }
209  BLI_kdtree_3d_balance(new_roots_kdtree);
210  },
211  /* Check which new root points are close to roots that existed before the current stroke
212  * started. */
213  [&]() {
215  new_positions_cu.index_range(), 128, [&](const IndexRange range) {
216  for (const int new_i : range) {
217  const float3 &new_root_pos_cu = new_positions_cu[new_i];
218  KDTreeNearest_3d nearest;
219  nearest.dist = FLT_MAX;
220  BLI_kdtree_3d_find_nearest(
221  self_->deformed_curve_roots_kdtree_, new_root_pos_cu, &nearest);
222  if (nearest.dist < brush_settings_->minimum_distance) {
223  new_curve_skipped[new_i] = true;
224  }
225  }
226  });
227  });
228 
229  /* Find new points that are too close too other new points. */
230  for (const int new_i : new_positions_cu.index_range()) {
231  if (new_curve_skipped[new_i]) {
232  continue;
233  }
234  const float3 &root_pos_cu = new_positions_cu[new_i];
235  BLI_kdtree_3d_range_search_cb_cpp(
236  new_roots_kdtree,
237  root_pos_cu,
238  brush_settings_->minimum_distance,
239  [&](const int other_new_i, const float *UNUSED(co), float UNUSED(dist_sq)) {
240  if (other_new_i == -1) {
241  new_curve_skipped[new_i] = true;
242  return false;
243  }
244  if (new_i == other_new_i) {
245  return true;
246  }
247  new_curve_skipped[other_new_i] = true;
248  return true;
249  });
250  }
251 
252  /* Remove points that are too close to others. */
253  for (int64_t i = new_positions_cu.size() - 1; i >= 0; i--) {
254  if (new_curve_skipped[i]) {
255  new_positions_cu.remove_and_reorder(i);
256  new_uvs.remove_and_reorder(i);
257  }
258  }
259  self_->new_deformed_root_positions_.extend(new_positions_cu);
260 
261  /* Find normals. */
262  if (!CustomData_has_layer(&surface_orig_->ldata, CD_NORMAL)) {
263  BKE_mesh_calc_normals_split(surface_orig_);
264  }
265  const Span<float3> corner_normals_su = {
266  reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_orig_->ldata, CD_NORMAL)),
267  surface_orig_->totloop};
268 
269  const Span<MLoopTri> surface_looptris_orig = {BKE_mesh_runtime_looptri_ensure(surface_orig_),
270  BKE_mesh_runtime_looptri_len(surface_orig_)};
271  const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris_orig};
272 
273  geometry::AddCurvesOnMeshInputs add_inputs;
274  add_inputs.uvs = new_uvs;
275  add_inputs.interpolate_length = brush_settings_->flag &
277  add_inputs.interpolate_shape = brush_settings_->flag &
279  add_inputs.interpolate_point_count = brush_settings_->flag &
281  add_inputs.fallback_curve_length = brush_settings_->curve_length;
282  add_inputs.fallback_point_count = std::max(2, brush_settings_->points_per_curve);
283  add_inputs.transforms = &transforms_;
284  add_inputs.surface = surface_orig_;
285  add_inputs.corner_normals_su = corner_normals_su;
286  add_inputs.reverse_uv_sampler = &reverse_uv_sampler;
287  add_inputs.old_roots_kdtree = self_->original_curve_roots_kdtree_;
288 
289  const geometry::AddCurvesOnMeshOutputs add_outputs = geometry::add_curves_on_mesh(
290  *curves_orig_, add_inputs);
291 
292  if (add_outputs.uv_error) {
293  report_invalid_uv_map(stroke_extension.reports);
294  }
295 
296  DEG_id_tag_update(&curves_id_orig_->id, ID_RECALC_GEOMETRY);
297  WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_orig_->id);
299  }
300 
302  {
303  const bke::crazyspace::GeometryDeformation deformation =
305  const Span<int> curve_offsets = curves_orig_->offsets();
306  const Span<float3> original_positions = curves_orig_->positions();
307  const Span<float3> deformed_positions = deformation.positions;
308  BLI_assert(original_positions.size() == deformed_positions.size());
309 
310  auto roots_kdtree_from_positions = [&](const Span<float3> positions) {
311  KDTree_3d *kdtree = BLI_kdtree_3d_new(curves_orig_->curves_num());
312  for (const int curve_i : curves_orig_->curves_range()) {
313  const int root_point_i = curve_offsets[curve_i];
314  BLI_kdtree_3d_insert(kdtree, curve_i, positions[root_point_i]);
315  }
316  BLI_kdtree_3d_balance(kdtree);
317  return kdtree;
318  };
319 
321  1024 < original_positions.size() + deformed_positions.size(),
322  [&]() {
323  self_->original_curve_roots_kdtree_ = roots_kdtree_from_positions(original_positions);
324  },
325  [&]() {
326  self_->deformed_curve_roots_kdtree_ = roots_kdtree_from_positions(deformed_positions);
327  });
328  }
329 
331  Vector<float2> &r_uvs,
332  Vector<float3> &r_positions_su)
333  {
334  float4x4 projection;
335  ED_view3d_ob_project_mat_get(ctx_.rv3d, curves_ob_orig_, projection.values);
336 
337  const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
338  eCurvesSymmetryType(curves_id_orig_->symmetry));
339  for (const float4x4 &brush_transform : symmetry_brush_transforms) {
340  const float4x4 brush_transform_inv = brush_transform.inverted();
341  const float4x4 transform = transforms_.curves_to_surface * brush_transform *
342  transforms_.world_to_curves;
343  Vector<float3> positions_su;
344  Vector<float3> bary_coords;
345  Vector<int> looptri_indices;
347  rng,
348  *surface_eval_,
349  surface_bvh_eval_,
350  brush_pos_re_,
351  brush_radius_re_,
352  [&](const float2 &pos_re, float3 &r_start_su, float3 &r_end_su) {
353  float3 start_wo, end_wo;
355  ctx_.depsgraph, ctx_.region, ctx_.v3d, pos_re, start_wo, end_wo, true);
356  r_start_su = transform * start_wo;
357  r_end_su = transform * end_wo;
358  },
359  true,
360  brush_settings_->density_add_attempts,
361  brush_settings_->density_add_attempts,
362  bary_coords,
363  looptri_indices,
364  positions_su);
365 
366  /* Remove some sampled points randomly based on the brush falloff and strength. */
367  for (int i = new_points - 1; i >= 0; i--) {
368  const float3 pos_su = positions_su[i];
369  const float3 pos_cu = brush_transform_inv * transforms_.surface_to_curves * pos_su;
370  float2 pos_re;
371  ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
372  const float dist_to_brush_re = math::distance(brush_pos_re_, pos_re);
373  const float radius_falloff = BKE_brush_curve_strength(
374  brush_, dist_to_brush_re, brush_radius_re_);
375  const float weight = brush_strength_ * radius_falloff;
376  if (rng.get_float() > weight) {
377  bary_coords.remove_and_reorder(i);
378  looptri_indices.remove_and_reorder(i);
379  positions_su.remove_and_reorder(i);
380  }
381  }
382 
383  for (const int i : bary_coords.index_range()) {
385  bary_coords[i], surface_looptris_eval_[looptri_indices[i]], surface_uv_map_eval_);
386  r_uvs.append(uv);
387  }
388  r_positions_su.extend(positions_su);
389  }
390  }
391 
393  Vector<float2> &r_uvs,
394  Vector<float3> &r_positions_su)
395  {
396  const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(*ctx_.depsgraph,
397  *ctx_.region,
398  *ctx_.v3d,
399  transforms_,
400  surface_bvh_eval_,
401  brush_pos_re_,
402  brush_radius_re_);
403  if (!brush_3d.has_value()) {
404  return;
405  }
406 
407  const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
408  eCurvesSymmetryType(curves_id_orig_->symmetry));
409  for (const float4x4 &brush_transform : symmetry_brush_transforms) {
410  const float3 brush_pos_cu = brush_transform * brush_3d->position_cu;
411  const float3 brush_pos_su = transforms_.curves_to_surface * brush_pos_cu;
412  const float brush_radius_su = transform_brush_radius(
413  transforms_.curves_to_surface, brush_pos_cu, brush_3d->radius_cu);
414  const float brush_radius_sq_su = pow2f(brush_radius_su);
415 
416  Vector<int> selected_looptri_indices;
417  BLI_bvhtree_range_query_cpp(
418  *surface_bvh_eval_.tree,
419  brush_pos_su,
420  brush_radius_su,
421  [&](const int index, const float3 &UNUSED(co), const float UNUSED(dist_sq)) {
422  selected_looptri_indices.append(index);
423  });
424 
425  const float brush_plane_area_su = M_PI * brush_radius_sq_su;
426  const float approximate_density_su = brush_settings_->density_add_attempts /
427  brush_plane_area_su;
428 
429  Vector<float3> positions_su;
430  Vector<float3> bary_coords;
431  Vector<int> looptri_indices;
433  rng,
434  *surface_eval_,
435  selected_looptri_indices,
436  brush_pos_su,
437  brush_radius_su,
438  approximate_density_su,
439  bary_coords,
440  looptri_indices,
441  positions_su);
442 
443  /* Remove some sampled points randomly based on the brush falloff and strength. */
444  for (int i = new_points - 1; i >= 0; i--) {
445  const float3 pos_su = positions_su[i];
446  const float3 pos_cu = transforms_.surface_to_curves * pos_su;
447  const float dist_to_brush_cu = math::distance(pos_cu, brush_pos_cu);
448  const float radius_falloff = BKE_brush_curve_strength(
449  brush_, dist_to_brush_cu, brush_3d->radius_cu);
450  const float weight = brush_strength_ * radius_falloff;
451  if (rng.get_float() > weight) {
452  bary_coords.remove_and_reorder(i);
453  looptri_indices.remove_and_reorder(i);
454  positions_su.remove_and_reorder(i);
455  }
456  }
457 
458  for (const int i : bary_coords.index_range()) {
460  bary_coords[i], surface_looptris_eval_[looptri_indices[i]], surface_uv_map_eval_);
461  r_uvs.append(uv);
462  }
463  r_positions_su.extend(positions_su);
464  }
465  }
466 };
467 
468 void DensityAddOperation::on_stroke_extended(const bContext &C,
469  const StrokeExtension &stroke_extension)
470 {
471  DensityAddOperationExecutor executor{C};
472  executor.execute(*this, C, stroke_extension);
473 }
474 
476  private:
478 
484  Vector<float3> deformed_root_positions_;
485 
486  public:
487  void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
488 };
489 
495  DensitySubtractOperation *self_ = nullptr;
497 
498  Object *object_ = nullptr;
499  Curves *curves_id_ = nullptr;
500  CurvesGeometry *curves_ = nullptr;
501 
504 
505  Object *surface_ob_orig_ = nullptr;
506  Mesh *surface_orig_ = nullptr;
507 
508  Object *surface_ob_eval_ = nullptr;
509  Mesh *surface_eval_ = nullptr;
511 
512  const CurvesSculpt *curves_sculpt_ = nullptr;
513  const Brush *brush_ = nullptr;
518 
520 
522 
524 
526  {
527  }
528 
530  const bContext &C,
531  const StrokeExtension &stroke_extension)
532  {
533  self_ = &self;
534 
535  object_ = CTX_data_active_object(&C);
536 
537  curves_id_ = static_cast<Curves *>(object_->data);
538  curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
539  if (curves_->curves_num() == 0) {
540  return;
541  }
542 
543  surface_ob_orig_ = curves_id_->surface;
544  if (surface_ob_orig_ == nullptr) {
545  return;
546  }
547  surface_orig_ = static_cast<Mesh *>(surface_ob_orig_->data);
548 
549  surface_ob_eval_ = DEG_get_evaluated_object(ctx_.depsgraph, surface_ob_orig_);
550  if (surface_ob_eval_ == nullptr) {
551  return;
552  }
553  surface_eval_ = BKE_object_get_evaluated_mesh(surface_ob_eval_);
554 
555  BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_LOOPTRI, 2);
556  BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval_); });
557 
558  curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
559  brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
560  brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
561  brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
562  brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
563  brush_pos_re_ = stroke_extension.mouse_position;
564 
565  minimum_distance_ = brush_->curves_sculpt_settings->minimum_distance;
566 
567  curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
568 
569  transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
570  const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
571  brush_->falloff_shape);
572 
573  if (stroke_extension.is_first) {
574  const bke::crazyspace::GeometryDeformation deformation =
576  for (const int curve_i : curves_->curves_range()) {
577  const int first_point_i = curves_->offsets()[curve_i];
578  self_->deformed_root_positions_.append(deformation.positions[first_point_i]);
579  }
580  }
581 
582  root_points_kdtree_ = BLI_kdtree_3d_new(curve_selection_.size());
583  BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(root_points_kdtree_); });
584  for (const int curve_i : curve_selection_) {
585  const float3 &pos_cu = self_->deformed_root_positions_[curve_i];
586  BLI_kdtree_3d_insert(root_points_kdtree_, curve_i, pos_cu);
587  }
588  BLI_kdtree_3d_balance(root_points_kdtree_);
589 
590  /* Find all curves that should be deleted. */
591  Array<bool> curves_to_delete(curves_->curves_num(), false);
592  if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
593  this->reduce_density_projected_with_symmetry(curves_to_delete);
594  }
595  else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
596  this->reduce_density_spherical_with_symmetry(curves_to_delete);
597  }
598  else {
600  }
601 
604  curves_->curves_range(), 4096, indices, [&](const int curve_i) {
605  return curves_to_delete[curve_i];
606  });
607 
608  /* Remove deleted curves from the stored deformed root positions. */
609  const Vector<IndexRange> ranges_to_keep = mask_to_delete.extract_ranges_invert(
610  curves_->curves_range());
611  BLI_assert(curves_->curves_num() == self_->deformed_root_positions_.size());
612  Vector<float3> new_deformed_positions;
613  for (const IndexRange range : ranges_to_keep) {
614  new_deformed_positions.extend(self_->deformed_root_positions_.as_span().slice(range));
615  }
616  self_->deformed_root_positions_ = std::move(new_deformed_positions);
617 
618  curves_->remove_curves(mask_to_delete);
619  BLI_assert(curves_->curves_num() == self_->deformed_root_positions_.size());
620 
621  DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
622  WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
624  }
625 
627  {
628  const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
629  eCurvesSymmetryType(curves_id_->symmetry));
630  for (const float4x4 &brush_transform : symmetry_brush_transforms) {
631  this->reduce_density_projected(brush_transform, curves_to_delete);
632  }
633  }
634 
635  void reduce_density_projected(const float4x4 &brush_transform,
636  MutableSpan<bool> curves_to_delete)
637  {
638  const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
639  const float brush_radius_sq_re = pow2f(brush_radius_re);
640 
641  float4x4 projection;
642  ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
643 
644  /* Randomly select the curves that are allowed to be removed, based on the brush radius and
645  * strength. */
646  Array<bool> allow_remove_curve(curves_->curves_num(), false);
647  threading::parallel_for(curves_->curves_range(), 512, [&](const IndexRange range) {
648  RandomNumberGenerator rng((int)(PIL_check_seconds_timer() * 1000000.0));
649 
650  for (const int curve_i : range) {
651  if (curves_to_delete[curve_i]) {
652  allow_remove_curve[curve_i] = true;
653  continue;
654  }
655  const float3 pos_cu = brush_transform * self_->deformed_root_positions_[curve_i];
656 
657  float2 pos_re;
658  ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
659  const float dist_to_brush_sq_re = math::distance_squared(brush_pos_re_, pos_re);
660  if (dist_to_brush_sq_re > brush_radius_sq_re) {
661  continue;
662  }
663  const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
664  const float radius_falloff = BKE_brush_curve_strength(
665  brush_, dist_to_brush_re, brush_radius_re);
666  const float weight = brush_strength_ * radius_falloff;
667  if (rng.get_float() < weight) {
668  allow_remove_curve[curve_i] = true;
669  }
670  }
671  });
672 
673  /* Detect curves that are too close to other existing curves. */
674  for (const int curve_i : curve_selection_) {
675  if (curves_to_delete[curve_i]) {
676  continue;
677  }
678  if (!allow_remove_curve[curve_i]) {
679  continue;
680  }
681  const float3 orig_pos_cu = self_->deformed_root_positions_[curve_i];
682  const float3 pos_cu = brush_transform * orig_pos_cu;
683  float2 pos_re;
684  ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
685  const float dist_to_brush_sq_re = math::distance_squared(brush_pos_re_, pos_re);
686  if (dist_to_brush_sq_re > brush_radius_sq_re) {
687  continue;
688  }
689  BLI_kdtree_3d_range_search_cb_cpp(
690  root_points_kdtree_,
691  orig_pos_cu,
692  minimum_distance_,
693  [&](const int other_curve_i, const float *UNUSED(co), float UNUSED(dist_sq)) {
694  if (other_curve_i == curve_i) {
695  return true;
696  }
697  if (allow_remove_curve[other_curve_i]) {
698  curves_to_delete[other_curve_i] = true;
699  }
700  return true;
701  });
702  }
703  }
704 
706  {
707  const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
708  const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(*ctx_.depsgraph,
709  *ctx_.region,
710  *ctx_.v3d,
711  transforms_,
712  surface_bvh_eval_,
713  brush_pos_re_,
714  brush_radius_re);
715  if (!brush_3d.has_value()) {
716  return;
717  }
718 
719  const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
720  eCurvesSymmetryType(curves_id_->symmetry));
721  for (const float4x4 &brush_transform : symmetry_brush_transforms) {
722  const float3 brush_pos_cu = brush_transform * brush_3d->position_cu;
723  this->reduce_density_spherical(brush_pos_cu, brush_3d->radius_cu, curves_to_delete);
724  }
725  }
726 
727  void reduce_density_spherical(const float3 &brush_pos_cu,
728  const float brush_radius_cu,
729  MutableSpan<bool> curves_to_delete)
730  {
731  const float brush_radius_sq_cu = pow2f(brush_radius_cu);
732 
733  /* Randomly select the curves that are allowed to be removed, based on the brush radius and
734  * strength. */
735  Array<bool> allow_remove_curve(curves_->curves_num(), false);
736  threading::parallel_for(curves_->curves_range(), 512, [&](const IndexRange range) {
737  RandomNumberGenerator rng((int)(PIL_check_seconds_timer() * 1000000.0));
738 
739  for (const int curve_i : range) {
740  if (curves_to_delete[curve_i]) {
741  allow_remove_curve[curve_i] = true;
742  continue;
743  }
744  const float3 pos_cu = self_->deformed_root_positions_[curve_i];
745 
746  const float dist_to_brush_sq_cu = math::distance_squared(brush_pos_cu, pos_cu);
747  if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
748  continue;
749  }
750  const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
751  const float radius_falloff = BKE_brush_curve_strength(
752  brush_, dist_to_brush_cu, brush_radius_cu);
753  const float weight = brush_strength_ * radius_falloff;
754  if (rng.get_float() < weight) {
755  allow_remove_curve[curve_i] = true;
756  }
757  }
758  });
759 
760  /* Detect curves that are too close to other existing curves. */
761  for (const int curve_i : curve_selection_) {
762  if (curves_to_delete[curve_i]) {
763  continue;
764  }
765  if (!allow_remove_curve[curve_i]) {
766  continue;
767  }
768  const float3 &pos_cu = self_->deformed_root_positions_[curve_i];
769  const float dist_to_brush_sq_cu = math::distance_squared(pos_cu, brush_pos_cu);
770  if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
771  continue;
772  }
773 
774  BLI_kdtree_3d_range_search_cb_cpp(
775  root_points_kdtree_,
776  pos_cu,
777  minimum_distance_,
778  [&](const int other_curve_i, const float *UNUSED(co), float UNUSED(dist_sq)) {
779  if (other_curve_i == curve_i) {
780  return true;
781  }
782  if (allow_remove_curve[other_curve_i]) {
783  curves_to_delete[other_curve_i] = true;
784  }
785  return true;
786  });
787  }
788  }
789 };
790 
791 void DensitySubtractOperation::on_stroke_extended(const bContext &C,
792  const StrokeExtension &stroke_extension)
793 {
795  executor.execute(*this, C, stroke_extension);
796 }
797 
801 static bool use_add_density_mode(const BrushStrokeMode brush_mode,
802  const bContext &C,
803  const StrokeExtension &stroke_start)
804 {
805  const Scene &scene = *CTX_data_scene(&C);
808  const ARegion &region = *CTX_wm_region(&C);
809  const View3D &v3d = *CTX_wm_view3d(&C);
810 
811  const eBrushCurvesSculptDensityMode density_mode = static_cast<eBrushCurvesSculptDensityMode>(
813  const bool use_invert = brush_mode == BRUSH_STROKE_INVERT;
814 
815  if (density_mode == BRUSH_CURVES_SCULPT_DENSITY_MODE_ADD) {
816  return !use_invert;
817  }
818  if (density_mode == BRUSH_CURVES_SCULPT_DENSITY_MODE_REMOVE) {
819  return use_invert;
820  }
821 
822  const Object &curves_ob_orig = *CTX_data_active_object(&C);
823  const Curves &curves_id_orig = *static_cast<Curves *>(curves_ob_orig.data);
824  Object *surface_ob_orig = curves_id_orig.surface;
825  if (surface_ob_orig == nullptr) {
826  return true;
827  }
828  Object *surface_ob_eval = DEG_get_evaluated_object(&depsgraph, surface_ob_orig);
829  if (surface_ob_eval == nullptr) {
830  return true;
831  }
832  const CurvesGeometry &curves = CurvesGeometry::wrap(curves_id_orig.geometry);
833  if (curves.curves_num() <= 1) {
834  return true;
835  }
836  const Mesh *surface_mesh_eval = BKE_object_get_evaluated_mesh(surface_ob_eval);
837  if (surface_mesh_eval == nullptr) {
838  return true;
839  }
840 
841  const CurvesSurfaceTransforms transforms(curves_ob_orig, curves_id_orig.surface);
842  BVHTreeFromMesh surface_bvh_eval;
843  BKE_bvhtree_from_mesh_get(&surface_bvh_eval, surface_mesh_eval, BVHTREE_FROM_LOOPTRI, 2);
844  BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval); });
845 
846  const float2 brush_pos_re = stroke_start.mouse_position;
847  /* Reduce radius so that only an inner circle is used to determine the existing density. */
848  const float brush_radius_re = BKE_brush_size_get(&scene, &brush) * 0.5f;
849 
850  /* Find the surface point under the brush. */
851  const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(
852  depsgraph, region, v3d, transforms, surface_bvh_eval, brush_pos_re, brush_radius_re);
853  if (!brush_3d.has_value()) {
854  return true;
855  }
856 
857  const float3 brush_pos_cu = brush_3d->position_cu;
858  const float brush_radius_cu = brush_3d->radius_cu;
859  const float brush_radius_sq_cu = pow2f(brush_radius_cu);
860 
861  const bke::crazyspace::GeometryDeformation deformation =
863  const Span<int> offsets = curves.offsets();
864 
865  /* Compute distance from brush to curve roots. */
866  Array<std::pair<float, int>> distances_sq_to_brush(curves.curves_num());
867  threading::EnumerableThreadSpecific<int> valid_curve_count_by_thread;
868  threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange range) {
869  int &valid_curve_count = valid_curve_count_by_thread.local();
870  for (const int curve_i : range) {
871  const int root_point_i = offsets[curve_i];
872  const float3 &root_pos_cu = deformation.positions[root_point_i];
873  const float dist_sq_cu = math::distance_squared(root_pos_cu, brush_pos_cu);
874  if (dist_sq_cu < brush_radius_sq_cu) {
875  distances_sq_to_brush[curve_i] = {math::distance_squared(root_pos_cu, brush_pos_cu),
876  curve_i};
877  valid_curve_count++;
878  }
879  else {
880  distances_sq_to_brush[curve_i] = {FLT_MAX, -1};
881  }
882  }
883  });
884  const int valid_curve_count = std::accumulate(
885  valid_curve_count_by_thread.begin(), valid_curve_count_by_thread.end(), 0);
886 
887  /* Find a couple of curves that are closest to the brush center. */
888  const int check_curve_count = std::min<int>(8, valid_curve_count);
889  std::partial_sort(distances_sq_to_brush.begin(),
890  distances_sq_to_brush.begin() + check_curve_count,
891  distances_sq_to_brush.end());
892 
893  /* Compute the minimum pair-wise distance between the curve roots that are close to the brush
894  * center. */
895  float min_dist_sq_cu = FLT_MAX;
896  for (const int i : IndexRange(check_curve_count)) {
897  const float3 &pos_i = deformation.positions[offsets[distances_sq_to_brush[i].second]];
898  for (int j = i + 1; j < check_curve_count; j++) {
899  const float3 &pos_j = deformation.positions[offsets[distances_sq_to_brush[j].second]];
900  const float dist_sq_cu = math::distance_squared(pos_i, pos_j);
901  math::min_inplace(min_dist_sq_cu, dist_sq_cu);
902  }
903  }
904 
905  const float min_dist_cu = std::sqrt(min_dist_sq_cu);
906  if (min_dist_cu > brush.curves_sculpt_settings->minimum_distance) {
907  return true;
908  }
909 
910  return false;
911 }
912 
913 std::unique_ptr<CurvesSculptStrokeOperation> new_density_operation(
914  const BrushStrokeMode brush_mode, const bContext &C, const StrokeExtension &stroke_start)
915 {
916  if (use_add_density_mode(brush_mode, C, stroke_start)) {
917  return std::make_unique<DensityAddOperation>();
918  }
919  return std::make_unique<DensitySubtractOperation>();
920 }
921 
922 } // namespace blender::ed::sculpt_paint
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:30
float BKE_brush_curve_strength(const struct Brush *br, float p, float len)
int BKE_brush_size_get(const struct Scene *scene, const struct Brush *brush)
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
Definition: bvhutils.cc:1410
@ BVHTREE_FROM_LOOPTRI
Definition: BKE_bvhutils.h:73
BVHTree * BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, const struct Mesh *mesh, BVHCacheType bvh_cache_type, int tree_type)
Definition: bvhutils.cc:1213
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct Depsgraph * CTX_data_depsgraph_on_load(const bContext *C)
Definition: context.c:1536
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:784
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
bool CustomData_has_layer(const struct CustomData *data, int type)
void * CustomData_get_layer(const struct CustomData *data, int type)
void BKE_mesh_calc_normals_split(struct Mesh *mesh)
Definition: mesh.cc:1911
const struct MLoopTri * BKE_mesh_runtime_looptri_ensure(const struct Mesh *mesh)
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh)
General operations, lookup, etc. for blender objects.
struct Mesh * BKE_object_get_evaluated_mesh(const struct Object *object)
const struct Brush * BKE_paint_brush_for_read(const struct Paint *p)
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
sqrt(x)+1/max(0
A KD-tree for nearest neighbor search.
MINLINE float pow2f(float x)
#define M_PI
Definition: BLI_math_base.h:20
#define BLI_SCOPED_DEFER(function_to_defer)
#define UNUSED(x)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
struct Object * DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
eBrushFalloffShape
@ PAINT_FALLOFF_SHAPE_SPHERE
@ PAINT_FALLOFF_SHAPE_TUBE
@ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT
@ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH
@ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE
eBrushCurvesSculptDensityMode
@ BRUSH_CURVES_SCULPT_DENSITY_MODE_REMOVE
@ BRUSH_CURVES_SCULPT_DENSITY_MODE_ADD
eCurvesSymmetryType
@ OB_MESH
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
bool ED_view3d_win_to_segment_clipped(const struct Depsgraph *depsgraph, const struct ARegion *region, const struct View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_end[3], bool do_clip_planes)
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, const struct Object *ob, float r_pmat[4][4])
void ED_view3d_project_float_v2_m4(const struct ARegion *region, const float co[3], float r_co[2], const float mat[4][4])
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.
#define C
Definition: RandGen.cpp:25
#define NC_GEOM
Definition: WM_types.h:343
#define ND_DATA
Definition: WM_types.h:456
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
int64_t size() const
Vector< IndexRange > extract_ranges_invert(const IndexRange full_range, Vector< int64_t > *r_skip_amounts=nullptr) const
Definition: index_mask.cc:100
constexpr int64_t size() const
Definition: BLI_span.hh:240
constexpr bool is_empty() const
Definition: BLI_span.hh:248
int64_t size() const
Definition: BLI_vector.hh:694
void remove_and_reorder(const int64_t index)
Definition: BLI_vector.hh:743
void append(const T &value)
Definition: BLI_vector.hh:433
IndexRange index_range() const
Definition: BLI_vector.hh:920
void extend(Span< T > array)
Definition: BLI_vector.hh:530
GAttributeReader lookup(const AttributeIDRef &attribute_id) const
IndexRange curves_range() const
Definition: BKE_curves.hh:795
void remove_curves(IndexMask curves_to_delete)
static CurvesGeometry & wrap(::CurvesGeometry &dna_struct)
Definition: BKE_curves.hh:138
Span< float3 > positions() const
void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override
double time
Scene scene
const Depsgraph * depsgraph
uint pos
ccl_gpu_kernel_postfix int ccl_global int * indices
GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph, const Object &ob_orig)
Definition: crazyspace.cc:595
static struct PartialUpdateUser * wrap(PartialUpdateUserImpl *user)
T sample_corner_attrribute_with_bary_coords(const float3 &bary_weights, const MLoopTri &looptri, const Span< T > corner_attribute)
int sample_surface_points_spherical(RandomNumberGenerator &rng, const Mesh &mesh, Span< int > looptri_indices_to_sample, const float3 &sample_pos, float sample_radius, float approximate_density, Vector< float3 > &r_bary_coords, Vector< int > &r_looptri_indices, Vector< float3 > &r_positions)
Definition: mesh_sample.cc:264
int sample_surface_points_projected(RandomNumberGenerator &rng, const Mesh &mesh, BVHTreeFromMesh &mesh_bvhtree, const float2 &sample_pos_re, float sample_radius_re, FunctionRef< void(const float2 &pos_re, float3 &r_start, float3 &r_end)> region_position_to_ray, bool front_face_only, int tries_num, int max_points, Vector< float3 > &r_bary_coords, Vector< int > &r_looptri_indices, Vector< float3 > &r_positions)
AttributeAccessor mesh_attributes(const Mesh &mesh)
std::optional< CurvesBrush3D > sample_curves_surface_3d_brush(const Depsgraph &depsgraph, const ARegion &region, const View3D &v3d, const CurvesSurfaceTransforms &transforms, const BVHTreeFromMesh &surface_bvh, const float2 &brush_pos_re, const float brush_radius_re)
void report_invalid_uv_map(ReportList *reports)
void report_empty_evaluated_surface(ReportList *reports)
float brush_radius_get(const Scene &scene, const Brush &brush, const StrokeExtension &stroke_extension)
void report_missing_uv_map_on_original_surface(ReportList *reports)
static bool use_add_density_mode(const BrushStrokeMode brush_mode, const bContext &C, const StrokeExtension &stroke_start)
void report_missing_uv_map_on_evaluated_surface(ReportList *reports)
void report_missing_surface(ReportList *reports)
void report_empty_original_surface(ReportList *reports)
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)
std::unique_ptr< CurvesSculptStrokeOperation > new_density_operation(const BrushStrokeMode brush_mode, const bContext &C, const StrokeExtension &stroke_start)
float transform_brush_radius(const float4x4 &transform, const float3 &brush_position, const float old_radius)
AddCurvesOnMeshOutputs add_curves_on_mesh(bke::CurvesGeometry &curves, const AddCurvesOnMeshInputs &inputs)
IndexMask find_indices_based_on_predicate(const IndexMask indices_to_check, const int64_t parallel_grain_size, Vector< int64_t > &r_indices, const Predicate &predicate)
T distance_squared(const vec_base< T, Size > &a, const vec_base< T, Size > &b)
T distance(const T &a, const T &b)
void min_inplace(T &a, const T &b)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
void parallel_invoke(Functions &&...functions)
Definition: BLI_task.hh:99
MutableSpan< float3 > positions
BrushStrokeMode
Definition: paint_intern.h:448
@ BRUSH_STROKE_INVERT
Definition: paint_intern.h:450
unsigned int uint32_t
Definition: stdint.h:80
__int64 int64_t
Definition: stdint.h:89
struct BVHTree * tree
Definition: BKE_bvhutils.h:50
char falloff_shape
struct BrushCurvesSculptSettings * curves_sculpt_settings
CurvesGeometry geometry
struct Object * surface
char * surface_uv_map
int totpoly
int totloop
CustomData ldata
void * data
struct ToolSettings * toolsettings
CurvesSculpt * curves_sculpt
void sample_projected_with_symmetry(RandomNumberGenerator &rng, Vector< float2 > &r_uvs, Vector< float3 > &r_positions_su)
void sample_spherical_with_symmetry(RandomNumberGenerator &rng, Vector< float2 > &r_uvs, Vector< float3 > &r_positions_su)
void execute(DensityAddOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
void execute(DensitySubtractOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
void reduce_density_spherical(const float3 &brush_pos_cu, const float brush_radius_cu, MutableSpan< bool > curves_to_delete)
void reduce_density_projected_with_symmetry(MutableSpan< bool > curves_to_delete)
void reduce_density_spherical_with_symmetry(MutableSpan< bool > curves_to_delete)
void reduce_density_projected(const float4x4 &brush_transform, MutableSpan< bool > curves_to_delete)
float values[4][4]
Definition: BLI_float4x4.hh:13
float4x4 inverted() const
double PIL_check_seconds_timer(void)
Definition: time.c:64
float max
void WM_main_add_notifier(unsigned int type, void *reference)