Blender  V3.3
curves_sculpt_add.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_kdtree.h"
9 #include "BLI_rand.hh"
10 #include "BLI_vector.hh"
11 
12 #include "PIL_time.h"
13 
14 #include "DEG_depsgraph.h"
15 
16 #include "BKE_attribute_math.hh"
17 #include "BKE_brush.h"
18 #include "BKE_bvhutils.h"
19 #include "BKE_context.h"
20 #include "BKE_curves.hh"
21 #include "BKE_curves_utils.hh"
22 #include "BKE_geometry_set.hh"
23 #include "BKE_mesh.h"
24 #include "BKE_mesh_runtime.h"
25 #include "BKE_mesh_sample.hh"
26 #include "BKE_modifier.h"
27 #include "BKE_object.h"
28 #include "BKE_paint.h"
29 #include "BKE_report.h"
30 
31 #include "DNA_brush_enums.h"
32 #include "DNA_brush_types.h"
33 #include "DNA_curves_types.h"
34 #include "DNA_mesh_types.h"
35 #include "DNA_meshdata_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_screen_types.h"
38 #include "DNA_space_types.h"
39 
40 #include "ED_screen.h"
41 #include "ED_view3d.h"
42 
44 
45 #include "WM_api.h"
46 
47 #include "DEG_depsgraph_query.h"
48 
58 
60 
62  private:
64  KDTree_3d *curve_roots_kdtree_ = nullptr;
65 
66  friend struct AddOperationExecutor;
67 
68  public:
69  ~AddOperation() override
70  {
71  if (curve_roots_kdtree_ != nullptr) {
72  BLI_kdtree_3d_free(curve_roots_kdtree_);
73  }
74  }
75 
76  void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
77 };
78 
84  AddOperation *self_ = nullptr;
86 
87  Object *curves_ob_orig_ = nullptr;
88  Curves *curves_id_orig_ = nullptr;
90 
92  Mesh *surface_eval_ = nullptr;
96 
97  const CurvesSculpt *curves_sculpt_ = nullptr;
98  const Brush *brush_ = nullptr;
102 
105 
107 
109  {
110  }
111 
112  void execute(AddOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
113  {
114  self_ = &self;
116 
117  curves_id_orig_ = static_cast<Curves *>(curves_ob_orig_->data);
119 
120  if (curves_id_orig_->surface == nullptr || curves_id_orig_->surface->type != OB_MESH) {
121  report_missing_surface(stroke_extension.reports);
122  return;
123  }
124 
126 
127  Object &surface_ob_orig = *curves_id_orig_->surface;
128  Mesh &surface_orig = *static_cast<Mesh *>(surface_ob_orig.data);
129  if (surface_orig.totpoly == 0) {
130  report_empty_original_surface(stroke_extension.reports);
131  return;
132  }
133 
135  if (surface_ob_eval_ == nullptr) {
136  return;
137  }
139  if (surface_eval_->totpoly == 0) {
140  report_empty_evaluated_surface(stroke_extension.reports);
141  return;
142  }
143 
147  brush_radius_re_ = brush_radius_get(*ctx_.scene, *brush_, stroke_extension);
148  brush_pos_re_ = stroke_extension.mouse_position;
149 
151  const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
154 
155  if (add_amount_ == 0) {
156  return;
157  }
158 
159  /* Find UV map. */
160  VArraySpan<float2> surface_uv_map;
161  if (curves_id_orig_->surface_uv_map != nullptr) {
162  surface_uv_map = bke::mesh_attributes(surface_orig)
167  }
168 
169  if (surface_uv_map.is_empty()) {
171  return;
172  }
173  if (surface_uv_map_eval_.is_empty()) {
175  return;
176  }
177 
178  const double time = PIL_check_seconds_timer() * 1000000.0;
179  /* Use a pointer cast to avoid overflow warnings. */
180  RandomNumberGenerator rng{*(uint32_t *)(&time)};
181 
184 
187 
188  /* Sample points on the surface using one of multiple strategies. */
189  Vector<float2> sampled_uvs;
190  if (add_amount_ == 1) {
191  this->sample_in_center_with_symmetry(sampled_uvs);
192  }
193  else if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
194  this->sample_projected_with_symmetry(rng, sampled_uvs);
195  }
196  else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
197  this->sample_spherical_with_symmetry(rng, sampled_uvs);
198  }
199  else {
201  }
202 
203  if (sampled_uvs.is_empty()) {
204  /* No new points have been added. */
205  return;
206  }
207 
208  const Span<MLoopTri> surface_looptris_orig = {BKE_mesh_runtime_looptri_ensure(&surface_orig),
209  BKE_mesh_runtime_looptri_len(&surface_orig)};
210 
211  /* Find normals. */
212  if (!CustomData_has_layer(&surface_orig.ldata, CD_NORMAL)) {
213  BKE_mesh_calc_normals_split(&surface_orig);
214  }
215  const Span<float3> corner_normals_su = {
216  reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_orig.ldata, CD_NORMAL)),
217  surface_orig.totloop};
218 
219  const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris_orig};
220 
222  add_inputs.uvs = sampled_uvs;
223  add_inputs.interpolate_length = brush_settings_->flag &
225  add_inputs.interpolate_shape = brush_settings_->flag &
231  add_inputs.transforms = &transforms_;
232  add_inputs.reverse_uv_sampler = &reverse_uv_sampler;
233  add_inputs.surface = &surface_orig;
234  add_inputs.corner_normals_su = corner_normals_su;
235 
236  if (add_inputs.interpolate_length || add_inputs.interpolate_shape ||
237  add_inputs.interpolate_point_count) {
239  add_inputs.old_roots_kdtree = self_->curve_roots_kdtree_;
240  }
241 
243  *curves_orig_, add_inputs);
244 
245  if (add_outputs.uv_error) {
246  report_invalid_uv_map(stroke_extension.reports);
247  }
248 
252  }
253 
258  {
259  float3 ray_start_wo, ray_end_wo;
261  ctx_.depsgraph, ctx_.region, ctx_.v3d, brush_pos_re_, ray_start_wo, ray_end_wo, true);
262  const float3 ray_start_cu = transforms_.world_to_curves * ray_start_wo;
263  const float3 ray_end_cu = transforms_.world_to_curves * ray_end_wo;
264 
265  const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
267 
268  for (const float4x4 &brush_transform : symmetry_brush_transforms) {
269  const float4x4 transform = transforms_.curves_to_surface * brush_transform;
270  this->sample_in_center(r_sampled_uvs, transform * ray_start_cu, transform * ray_end_cu);
271  }
272  }
273 
274  void sample_in_center(Vector<float2> &r_sampled_uvs,
275  const float3 &ray_start_su,
276  const float3 &ray_end_su)
277  {
278  const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
279 
280  BVHTreeRayHit ray_hit;
281  ray_hit.dist = FLT_MAX;
282  ray_hit.index = -1;
284  ray_start_su,
285  ray_direction_su,
286  0.0f,
287  &ray_hit,
290 
291  if (ray_hit.index == -1) {
292  return;
293  }
294 
295  const int looptri_index = ray_hit.index;
296  const MLoopTri &looptri = surface_looptris_eval_[looptri_index];
297  const float3 brush_pos_su = ray_hit.co;
299  *surface_eval_, looptri, brush_pos_su);
300 
302  bary_coords, looptri, surface_uv_map_eval_);
303  r_sampled_uvs.append(uv);
304  }
305 
310  {
311  const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
313  for (const float4x4 &brush_transform : symmetry_brush_transforms) {
314  this->sample_projected(rng, r_sampled_uvs, brush_transform);
315  }
316  }
317 
319  Vector<float2> &r_sampled_uvs,
320  const float4x4 &brush_transform)
321  {
322  const int old_amount = r_sampled_uvs.size();
323  const int max_iterations = 100;
324  int current_iteration = 0;
325  while (r_sampled_uvs.size() < old_amount + add_amount_) {
326  if (current_iteration++ >= max_iterations) {
327  break;
328  }
329  Vector<float3> bary_coords;
330  Vector<int> looptri_indices;
331  Vector<float3> positions_su;
332 
333  const int missing_amount = add_amount_ + old_amount - r_sampled_uvs.size();
335  rng,
336  *surface_eval_,
340  [&](const float2 &pos_re, float3 &r_start_su, float3 &r_end_su) {
341  float3 start_wo, end_wo;
343  ctx_.depsgraph, ctx_.region, ctx_.v3d, pos_re, start_wo, end_wo, true);
344  const float3 start_cu = brush_transform * (transforms_.world_to_curves * start_wo);
345  const float3 end_cu = brush_transform * (transforms_.world_to_curves * end_wo);
346  r_start_su = transforms_.curves_to_surface * start_cu;
347  r_end_su = transforms_.curves_to_surface * end_cu;
348  },
350  add_amount_,
351  missing_amount,
352  bary_coords,
353  looptri_indices,
354  positions_su);
355 
356  for (const int i : IndexRange(new_points)) {
358  bary_coords[i], surface_looptris_eval_[looptri_indices[i]], surface_uv_map_eval_);
359  r_sampled_uvs.append(uv);
360  }
361  }
362  }
363 
368  {
369  const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(*ctx_.depsgraph,
370  *ctx_.region,
371  *ctx_.v3d,
372  transforms_,
376  if (!brush_3d.has_value()) {
377  return;
378  }
379 
380  float3 view_ray_start_wo, view_ray_end_wo;
382  ctx_.region,
383  ctx_.v3d,
385  view_ray_start_wo,
386  view_ray_end_wo,
387  true);
388 
389  const float3 view_ray_start_cu = transforms_.world_to_curves * view_ray_start_wo;
390  const float3 view_ray_end_cu = transforms_.world_to_curves * view_ray_end_wo;
391 
392  const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
394  for (const float4x4 &brush_transform : symmetry_brush_transforms) {
395  const float4x4 transform = transforms_.curves_to_surface * brush_transform;
396 
397  const float3 brush_pos_su = transform * brush_3d->position_cu;
398  const float3 view_direction_su = math::normalize(transform * view_ray_end_cu -
399  transform * view_ray_start_cu);
400  const float brush_radius_su = transform_brush_radius(
401  transform, brush_3d->position_cu, brush_3d->radius_cu);
402 
403  this->sample_spherical(rng, r_sampled_uvs, brush_pos_su, brush_radius_su, view_direction_su);
404  }
405  }
406 
408  Vector<float2> &r_sampled_uvs,
409  const float3 &brush_pos_su,
410  const float brush_radius_su,
411  const float3 &view_direction_su)
412  {
413  const float brush_radius_sq_su = pow2f(brush_radius_su);
414 
415  /* Find surface triangles within brush radius. */
416  Vector<int> selected_looptri_indices;
417  if (use_front_face_) {
418  BLI_bvhtree_range_query_cpp(
420  brush_pos_su,
421  brush_radius_su,
422  [&](const int index, const float3 &UNUSED(co), const float UNUSED(dist_sq)) {
423  const MLoopTri &looptri = surface_looptris_eval_[index];
424  const float3 v0_su = surface_eval_->mvert[surface_eval_->mloop[looptri.tri[0]].v].co;
425  const float3 v1_su = surface_eval_->mvert[surface_eval_->mloop[looptri.tri[1]].v].co;
426  const float3 v2_su = surface_eval_->mvert[surface_eval_->mloop[looptri.tri[2]].v].co;
427  float3 normal_su;
428  normal_tri_v3(normal_su, v0_su, v1_su, v2_su);
429  if (math::dot(normal_su, view_direction_su) >= 0.0f) {
430  return;
431  }
432  selected_looptri_indices.append(index);
433  });
434  }
435  else {
436  BLI_bvhtree_range_query_cpp(
438  brush_pos_su,
439  brush_radius_su,
440  [&](const int index, const float3 &UNUSED(co), const float UNUSED(dist_sq)) {
441  selected_looptri_indices.append(index);
442  });
443  }
444 
445  /* Density used for sampling points. This does not have to be exact, because the loop below
446  * automatically runs until enough samples have been found. If too many samples are found, some
447  * will be discarded afterwards. */
448  const float brush_plane_area_su = M_PI * brush_radius_sq_su;
449  const float approximate_density_su = add_amount_ / brush_plane_area_su;
450 
451  /* Usually one or two iterations should be enough. */
452  const int max_iterations = 5;
453  int current_iteration = 0;
454 
455  const int old_amount = r_sampled_uvs.size();
456  while (r_sampled_uvs.size() < old_amount + add_amount_) {
457  if (current_iteration++ >= max_iterations) {
458  break;
459  }
460  Vector<float3> bary_coords;
461  Vector<int> looptri_indices;
462  Vector<float3> positions_su;
464  rng,
465  *surface_eval_,
466  selected_looptri_indices,
467  brush_pos_su,
468  brush_radius_su,
469  approximate_density_su,
470  bary_coords,
471  looptri_indices,
472  positions_su);
473  for (const int i : IndexRange(new_points)) {
475  bary_coords[i], surface_looptris_eval_[looptri_indices[i]], surface_uv_map_eval_);
476  r_sampled_uvs.append(uv);
477  }
478  }
479 
480  /* Remove samples when there are too many. */
481  while (r_sampled_uvs.size() > old_amount + add_amount_) {
482  const int index_to_remove = rng.get_int32(add_amount_) + old_amount;
483  r_sampled_uvs.remove_and_reorder(index_to_remove);
484  }
485  }
486 
488  {
489  if (self_->curve_roots_kdtree_ == nullptr) {
490  self_->curve_roots_kdtree_ = BLI_kdtree_3d_new(curves_orig_->curves_num());
491  for (const int curve_i : curves_orig_->curves_range()) {
492  const int root_point_i = curves_orig_->offsets()[curve_i];
493  const float3 &root_pos_cu = curves_orig_->positions()[root_point_i];
494  BLI_kdtree_3d_insert(self_->curve_roots_kdtree_, curve_i, root_pos_cu);
495  }
496  BLI_kdtree_3d_balance(self_->curve_roots_kdtree_);
497  }
498  }
499 };
500 
501 void AddOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension)
502 {
503  AddOperationExecutor executor{C};
504  executor.execute(*this, C, stroke_extension);
505 }
506 
507 std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation()
508 {
509  return std::make_unique<AddOperation>();
510 }
511 
512 } // namespace blender::ed::sculpt_paint
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:30
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 Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
Low-level operations for curves.
Low-level operations for curves.
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
int BLI_bvhtree_ray_cast(BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:1942
A KD-tree for nearest neighbor search.
MINLINE float pow2f(float x)
#define M_PI
Definition: BLI_math_base.h:20
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:33
#define BLI_SCOPED_DEFER(function_to_defer)
#define UNUSED(x)
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
@ BRUSH_FRONTFACE
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
struct CurvesGeometry CurvesGeometry
eCurvesSymmetryType
Object is a sort of wrapper for general info.
@ 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)
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
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
bool is_empty() const
Definition: BLI_vector.hh:706
GAttributeReader lookup(const AttributeIDRef &attribute_id) const
IndexRange curves_range() const
Definition: BKE_curves.hh:795
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
float3 compute_bary_coord_in_triangle(const Mesh &mesh, const MLoopTri &looptri, const float3 &position)
Definition: mesh_sample.cc:421
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::unique_ptr< CurvesSculptStrokeOperation > new_add_operation()
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)
void report_missing_uv_map_on_evaluated_surface(ReportList *reports)
void report_missing_surface(ReportList *reports)
void report_empty_original_surface(ReportList *reports)
Vector< float4x4 > get_symmetry_brush_transforms(const eCurvesSymmetryType symmetry)
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)
T dot(const vec_base< T, Size > &a, const vec_base< T, Size > &b)
vec_base< T, Size > normalize(const vec_base< T, Size > &v)
unsigned int uint32_t
Definition: stdint.h:80
BVHTree_RayCastCallback raycast_callback
Definition: BKE_bvhutils.h:54
struct BVHTree * tree
Definition: BKE_bvhutils.h:50
float co[3]
Definition: BLI_kdopbvh.h:68
char falloff_shape
struct BrushCurvesSculptSettings * curves_sculpt_settings
CurvesGeometry geometry
struct Object * surface
char * surface_uv_map
unsigned int tri[3]
unsigned int v
float co[3]
struct MVert * mvert
struct MLoop * mloop
int totpoly
int totloop
CustomData ldata
void * data
struct ToolSettings * toolsettings
CurvesSculpt * curves_sculpt
void sample_spherical_with_symmetry(RandomNumberGenerator &rng, Vector< float2 > &r_sampled_uvs)
void sample_in_center_with_symmetry(Vector< float2 > &r_sampled_uvs)
void sample_projected_with_symmetry(RandomNumberGenerator &rng, Vector< float2 > &r_sampled_uvs)
void sample_in_center(Vector< float2 > &r_sampled_uvs, const float3 &ray_start_su, const float3 &ray_end_su)
const BrushCurvesSculptSettings * brush_settings_
void execute(AddOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
void sample_spherical(RandomNumberGenerator &rng, Vector< float2 > &r_sampled_uvs, const float3 &brush_pos_su, const float brush_radius_su, const float3 &view_direction_su)
void sample_projected(RandomNumberGenerator &rng, Vector< float2 > &r_sampled_uvs, const float4x4 &brush_transform)
double PIL_check_seconds_timer(void)
Definition: time.c:64
float max
void WM_main_add_notifier(unsigned int type, void *reference)