Blender V4.3
multiplane_scrape.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
8#include "BLI_math_matrix.h"
9#include "BLI_math_matrix.hh"
10#include "BLI_math_rotation.h"
12#include "BLI_span.hh"
13#include "BLI_task.h"
14
15#include "DNA_brush_types.h"
16#include "DNA_object_types.h"
17
18#include "BKE_brush.hh"
19#include "BKE_ccg.hh"
20#include "BKE_mesh.hh"
21#include "BKE_paint.hh"
22#include "BKE_pbvh_api.hh"
23#include "BKE_subdiv_ccg.hh"
24
25#include "GPU_immediate.hh"
26#include "GPU_matrix.hh"
27
28#include "bmesh.hh"
29
30#include <cmath>
31#include <cstdlib>
32
36
38
40 std::array<float3, 2> area_cos;
41 std::array<float3, 2> area_nos;
42 std::array<int, 2> area_count;
43};
44
53
55{
56 ScrapeSampleData joined = a;
57
58 joined.area_cos[0] = a.area_cos[0] + b.area_cos[0];
59 joined.area_cos[1] = a.area_cos[1] + b.area_cos[1];
60
61 joined.area_nos[0] = a.area_nos[0] + b.area_nos[0];
62 joined.area_nos[1] = a.area_nos[1] + b.area_nos[1];
63
64 joined.area_count[0] = a.area_count[0] + b.area_count[0];
65 joined.area_count[1] = a.area_count[1] + b.area_count[1];
66 return joined;
67}
68
70 const Span<float3> local_positions,
71 const std::array<float4, 2> &scrape_planes,
72 const MutableSpan<float> factors)
73{
74 BLI_assert(positions.size() == local_positions.size());
75 BLI_assert(positions.size() == factors.size());
76
77 for (const int i : local_positions.index_range()) {
78 const bool plane_index = local_positions[i][0] <= 0.0f;
79 if (plane_point_side_v3(scrape_planes[plane_index], positions[i]) <= 0.0f) {
80 factors[i] = 0.0f;
81 }
82 }
83}
84
85BLI_NOINLINE static void calc_distances(const Span<float3> local_positions,
86 const MutableSpan<float> distances)
87{
88 BLI_assert(local_positions.size() == distances.size());
89
90 for (const int i : local_positions.index_range()) {
91 /* Deform the local space along the Y axis to avoid artifacts on curved strokes. */
92 /* This produces a not round brush tip. */
93 float3 local = local_positions[i];
94 local[1] *= 2.0f;
95 distances[i] = math::length(local);
96 }
97}
98
99BLI_NOINLINE static void calc_translations(const Span<float3> positions,
100 const Span<float3> local_positions,
101 const std::array<float4, 2> &scrape_planes,
102 const MutableSpan<float3> translations)
103{
104 for (const int i : positions.index_range()) {
105 const bool plane_index = local_positions[i][0] <= 0.0f;
107 closest_to_plane_normalized_v3(closest, scrape_planes[plane_index], positions[i]);
108 translations[i] = closest - positions[i];
109 }
110}
111
112BLI_NOINLINE static void accumulate_samples(const Span<float3> positions,
113 const Span<float3> local_positions,
114 const Span<float3> normals,
115 const Span<float> factors,
117{
118 for (const int i : positions.index_range()) {
119 if (factors[i] <= 0.0f) {
120 continue;
121 }
122 const bool plane_index = local_positions[i].x <= 0.0f;
123 sample.area_nos[plane_index] += normals[i] * factors[i];
124 sample.area_cos[plane_index] += positions[i];
125 sample.area_count[plane_index]++;
126 }
127}
128
129static void sample_node_surface_mesh(const Depsgraph &depsgraph,
130 const Object &object,
131 const Brush &brush,
132 const float4x4 &mat,
133 const Span<float3> vert_positions,
134 const Span<float3> vert_normals,
135 const MeshAttributeData &attribute_data,
136 const bke::pbvh::MeshNode &node,
138 LocalData &tls)
139{
140 const SculptSession &ss = *object.sculpt;
141 const StrokeCache &cache = *ss.cache;
142
143 const Span<int> verts = node.verts();
144 const MutableSpan positions = gather_data_mesh(vert_positions, verts, tls.positions);
145
146 tls.factors.resize(verts.size());
147 const MutableSpan<float> factors = tls.factors;
148 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
149 filter_region_clip_factors(ss, positions, factors);
150 if (brush.flag & BRUSH_FRONTFACE) {
151 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
152 }
153 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
154
155 const float radius = cache.radius * brush.normal_radius_factor;
156
157 tls.distances.resize(verts.size());
158 const MutableSpan<float> distances = tls.distances;
159 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
160 filter_distances_with_radius(radius, distances, factors);
161 apply_hardness_to_distances(radius, cache.hardness, distances);
163 eBrushCurvePreset(brush.curve_preset), brush.curve, distances, radius, factors);
164
165 tls.local_positions.resize(verts.size());
166 MutableSpan<float3> local_positions = tls.local_positions;
167 transform_positions(positions, mat, local_positions);
168
169 const MutableSpan normals = gather_data_mesh(vert_normals, verts, tls.normals);
170
171 accumulate_samples(positions, local_positions, normals, factors, sample);
172}
173
174static void sample_node_surface_grids(const Depsgraph &depsgraph,
175 const Object &object,
176 const Brush &brush,
177 const float4x4 &mat,
178 const bke::pbvh::GridsNode &node,
180 LocalData &tls)
181{
182 SculptSession &ss = *object.sculpt;
183 const StrokeCache &cache = *ss.cache;
184 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
185
186 const Span<int> grids = node.grids();
187 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
188
189 tls.factors.resize(positions.size());
190 const MutableSpan<float> factors = tls.factors;
191 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
192 filter_region_clip_factors(ss, positions, factors);
193 if (brush.flag & BRUSH_FRONTFACE) {
194 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
195 }
196 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
197
198 const float radius = cache.radius * brush.normal_radius_factor;
199
200 tls.distances.resize(positions.size());
201 const MutableSpan<float> distances = tls.distances;
202 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
203 filter_distances_with_radius(radius, distances, factors);
204 apply_hardness_to_distances(radius, cache.hardness, distances);
206 eBrushCurvePreset(brush.curve_preset), brush.curve, distances, radius, factors);
207
208 tls.local_positions.resize(positions.size());
209 MutableSpan<float3> local_positions = tls.local_positions;
210 transform_positions(positions, mat, local_positions);
211
212 tls.normals.resize(positions.size());
213 MutableSpan<float3> normals = tls.normals;
214 gather_grids_normals(subdiv_ccg, grids, normals);
215
216 accumulate_samples(positions, local_positions, normals, factors, sample);
217}
218
219static void sample_node_surface_bmesh(const Depsgraph &depsgraph,
220 const Object &object,
221 const Brush &brush,
222 const float4x4 &mat,
223 const bke::pbvh::BMeshNode &node,
225 LocalData &tls)
226{
227 const SculptSession &ss = *object.sculpt;
228 const StrokeCache &cache = *ss.cache;
229
231 const_cast<bke::pbvh::BMeshNode *>(&node));
232
233 const MutableSpan positions = gather_bmesh_positions(verts, tls.positions);
234
235 tls.factors.resize(verts.size());
236 const MutableSpan<float> factors = tls.factors;
238 filter_region_clip_factors(ss, positions, factors);
239 if (brush.flag & BRUSH_FRONTFACE) {
240 calc_front_face(cache.view_normal_symm, verts, factors);
241 }
242 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
243
244 const float radius = cache.radius * brush.normal_radius_factor;
245
246 tls.distances.resize(verts.size());
247 const MutableSpan<float> distances = tls.distances;
248 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
249 filter_distances_with_radius(radius, distances, factors);
250 apply_hardness_to_distances(radius, cache.hardness, distances);
252 eBrushCurvePreset(brush.curve_preset), brush.curve, distances, radius, factors);
253
254 tls.local_positions.resize(verts.size());
255 MutableSpan<float3> local_positions = tls.local_positions;
256 transform_positions(positions, mat, local_positions);
257
258 tls.normals.resize(verts.size());
259 MutableSpan<float3> normals = tls.normals;
260 gather_bmesh_normals(verts, normals);
261
262 accumulate_samples(positions, local_positions, normals, factors, sample);
263}
264
266 const Object &object,
267 const Brush &brush,
268 const float4x4 &mat,
269 const IndexMask &node_mask)
270{
271 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
273 switch (pbvh.type()) {
275 Mesh &mesh = *static_cast<Mesh *>(object.data);
276 const MeshAttributeData attribute_data(mesh.attributes());
278 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(depsgraph, object);
279 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, object);
281 node_mask.index_range(),
282 1,
284 [&](const IndexRange range, ScrapeSampleData sample) {
285 LocalData &tls = all_tls.local();
286 node_mask.slice(range).foreach_index([&](const int i) {
287 sample_node_surface_mesh(depsgraph,
288 object,
289 brush,
290 mat,
291 positions_eval,
292 vert_normals,
293 attribute_data,
294 nodes[i],
295 sample,
296 tls);
297 });
298 return sample;
299 },
301 break;
302 }
306 node_mask.index_range(),
307 1,
309 [&](const IndexRange range, ScrapeSampleData sample) {
310 LocalData &tls = all_tls.local();
311 node_mask.slice(range).foreach_index([&](const int i) {
312 sample_node_surface_grids(depsgraph, object, brush, mat, nodes[i], sample, tls);
313 });
314 return sample;
315 },
317 break;
318 }
320 const Span<bke::pbvh::BMeshNode> nodes = pbvh.nodes<bke::pbvh::BMeshNode>();
322 node_mask.index_range(),
323 1,
324 ScrapeSampleData{},
325 [&](const IndexRange range, ScrapeSampleData sample) {
326 LocalData &tls = all_tls.local();
327 node_mask.slice(range).foreach_index([&](const int i) {
328 sample_node_surface_bmesh(depsgraph, object, brush, mat, nodes[i], sample, tls);
329 });
330 return sample;
331 },
333 break;
334 }
335 }
337 return {};
338}
339
340static void calc_faces(const Depsgraph &depsgraph,
341 const Sculpt &sd,
342 const Brush &brush,
343 const float4x4 &mat,
344 const std::array<float4, 2> &scrape_planes,
345 const float angle,
346 const float strength,
347 const Span<float3> vert_normals,
348 const MeshAttributeData &attribute_data,
349 const bke::pbvh::MeshNode &node,
350 Object &object,
351 LocalData &tls,
352 const PositionDeformData &position_data)
353{
354 SculptSession &ss = *object.sculpt;
355 const StrokeCache &cache = *ss.cache;
356
357 const Span<int> verts = node.verts();
358 const MutableSpan positions = gather_data_mesh(position_data.eval, verts, tls.positions);
359
360 tls.factors.resize(verts.size());
361 const MutableSpan<float> factors = tls.factors;
362 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
363 filter_region_clip_factors(ss, positions, factors);
364 if (brush.flag & BRUSH_FRONTFACE) {
365 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
366 }
367 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
368
369 tls.distances.resize(verts.size());
370 const MutableSpan<float> distances = tls.distances;
371 /* NOTE: The distances are not used from this call, it's only used for filtering. */
372 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
373 filter_distances_with_radius(cache.radius, distances, factors);
374
375 tls.local_positions.resize(verts.size());
376 MutableSpan<float3> local_positions = tls.local_positions;
377 transform_positions(positions, mat, local_positions);
378
379 if (angle >= 0.0f) {
380 filter_plane_side_factors(positions, local_positions, scrape_planes, factors);
381 }
382
383 calc_distances(local_positions, distances);
384
385 apply_hardness_to_distances(cache, distances);
386 calc_brush_strength_factors(cache, brush, distances, factors);
387
388 tls.translations.resize(verts.size());
389 MutableSpan<float3> translations = tls.translations;
390 calc_translations(positions, local_positions, scrape_planes, translations);
391
392 filter_plane_trim_limit_factors(brush, cache, translations, factors);
393
394 scale_factors(factors, strength);
395 scale_translations(translations, factors);
396
397 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
398 position_data.deform(translations, verts);
399}
400
401static void calc_grids(const Depsgraph &depsgraph,
402 const Sculpt &sd,
403 const Brush &brush,
404 const float4x4 &mat,
405 const std::array<float4, 2> &scrape_planes,
406 const float angle,
407 const float strength,
408 const bke::pbvh::GridsNode &node,
409 Object &object,
410 LocalData &tls)
411{
412 SculptSession &ss = *object.sculpt;
413 const StrokeCache &cache = *ss.cache;
414 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
415
416 const Span<int> grids = node.grids();
417 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
418
419 tls.factors.resize(positions.size());
420 const MutableSpan<float> factors = tls.factors;
421 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
422 filter_region_clip_factors(ss, positions, factors);
423 if (brush.flag & BRUSH_FRONTFACE) {
424 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
425 }
426 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
427
428 tls.distances.resize(positions.size());
429 const MutableSpan<float> distances = tls.distances;
430 /* NOTE: The distances are not used from this call, it's only used for filtering. */
431 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
432 filter_distances_with_radius(cache.radius, distances, factors);
433
434 tls.local_positions.resize(positions.size());
435 MutableSpan<float3> local_positions = tls.local_positions;
436 transform_positions(positions, mat, local_positions);
437
438 if (angle >= 0.0f) {
439 filter_plane_side_factors(positions, local_positions, scrape_planes, factors);
440 }
441
442 calc_distances(local_positions, distances);
443
444 apply_hardness_to_distances(cache, distances);
445 calc_brush_strength_factors(cache, brush, distances, factors);
446
447 tls.translations.resize(positions.size());
448 MutableSpan<float3> translations = tls.translations;
449 calc_translations(positions, local_positions, scrape_planes, translations);
450
451 filter_plane_trim_limit_factors(brush, cache, translations, factors);
452
453 scale_factors(factors, strength);
454 scale_translations(translations, factors);
455
456 clip_and_lock_translations(sd, ss, positions, translations);
457 apply_translations(translations, grids, subdiv_ccg);
458}
459
460static void calc_bmesh(const Depsgraph &depsgraph,
461 const Sculpt &sd,
462 const Brush &brush,
463 const float4x4 &mat,
464 const std::array<float4, 2> &scrape_planes,
465 const float angle,
466 const float strength,
468 Object &object,
469 LocalData &tls)
470{
471 SculptSession &ss = *object.sculpt;
472 const StrokeCache &cache = *ss.cache;
473
475 const MutableSpan positions = gather_bmesh_positions(verts, tls.positions);
476
477 tls.factors.resize(verts.size());
478 const MutableSpan<float> factors = tls.factors;
480 filter_region_clip_factors(ss, positions, factors);
481 if (brush.flag & BRUSH_FRONTFACE) {
482 calc_front_face(cache.view_normal_symm, verts, factors);
483 }
484 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
485
486 tls.distances.resize(verts.size());
487 const MutableSpan<float> distances = tls.distances;
488 /* NOTE: The distances are not used from this call, it's only used for filtering. */
489 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
490 filter_distances_with_radius(cache.radius, distances, factors);
491
492 tls.local_positions.resize(verts.size());
493 MutableSpan<float3> local_positions = tls.local_positions;
494 transform_positions(positions, mat, local_positions);
495
496 if (angle >= 0.0f) {
497 filter_plane_side_factors(positions, local_positions, scrape_planes, factors);
498 }
499
500 calc_distances(local_positions, distances);
501
502 apply_hardness_to_distances(cache, distances);
503 calc_brush_strength_factors(cache, brush, distances, factors);
504
505 tls.translations.resize(verts.size());
506 MutableSpan<float3> translations = tls.translations;
507 calc_translations(positions, local_positions, scrape_planes, translations);
508
509 filter_plane_trim_limit_factors(brush, cache, translations, factors);
510
511 scale_factors(factors, strength);
512 scale_translations(translations, factors);
513
514 clip_and_lock_translations(sd, ss, positions, translations);
515 apply_translations(translations, verts);
516}
517
519 const Sculpt &sd,
520 Object &object,
521 const IndexMask &node_mask)
522{
523 SculptSession &ss = *object.sculpt;
524 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
525 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
526
527 const bool flip = (ss.cache->bstrength < 0.0f);
528 const float radius = flip ? -ss.cache->radius : ss.cache->radius;
529 const float offset = SCULPT_brush_plane_offset_get(sd, ss);
530 const float displace = -radius * offset;
531
532 float3 area_no_sp;
533 float3 area_co;
534 calc_brush_plane(depsgraph, brush, object, node_mask, area_no_sp, area_co);
535
536 float3 area_no;
538 area_no = calc_area_normal(depsgraph, brush, object, node_mask).value_or(float3(0));
539 }
540 else {
541 area_no = area_no_sp;
542 }
543
544 /* Delay the first daub because grab delta is not setup. */
547 return;
548 }
549
551 return;
552 }
553
554 area_co = area_no_sp * ss.cache->scale * displace;
555
556 /* Init brush local space matrix. */
557 float4x4 mat = float4x4::identity();
558 mat.x_axis() = math::cross(area_no, ss.cache->grab_delta_symm);
559 mat.y_axis() = math::cross(area_no, mat.x_axis());
560 mat.z_axis() = area_no;
561 mat.location() = ss.cache->location_symm;
562 /* NOTE: #math::normalize behaves differently for some reason. */
563 normalize_m4(mat.ptr());
564 mat = math::invert(mat);
565
566 /* Update matrix for the cursor preview. */
567 if (ss.cache->mirror_symmetry_pass == 0 && ss.cache->radial_symmetry_pass == 0) {
568 ss.cache->stroke_local_mat = mat;
569 }
570
571 /* Dynamic mode. */
572
574 /* Sample the individual normal and area center of the areas at both sides of the cursor. */
575 const ScrapeSampleData sample = sample_surface(depsgraph, object, brush, mat, node_mask);
576
577 /* Use the plane centers to check if we are sculpting along a concave or convex edge. */
578 const std::array<float3, 2> sampled_plane_co{
579 sample.area_cos[0] * 1.0f / float(sample.area_count[0]),
580 sample.area_cos[1] * 1.0f / float(sample.area_count[1])};
581 const float3 mid_co = math::midpoint(sampled_plane_co[0], sampled_plane_co[1]);
582
583 /* Calculate the scrape planes angle based on the sampled normals. */
584 const std::array<float3, 2> sampled_plane_normals{
585 math::normalize(sample.area_nos[0] * 1.0f / float(sample.area_count[0])),
586 math::normalize(sample.area_nos[1] * 1.0f / float(sample.area_count[1]))};
587
588 float sampled_angle = angle_v3v3(sampled_plane_normals[0], sampled_plane_normals[1]);
589 const std::array<float3, 2> sampled_cv{area_no, ss.cache->location_symm - mid_co};
590
591 sampled_angle += DEG2RADF(brush.multiplane_scrape_angle) * ss.cache->pressure;
592
593 /* Invert the angle if we are sculpting along a concave edge. */
594 if (math::dot(sampled_cv[0], sampled_cv[1]) < 0.0f) {
595 sampled_angle = -sampled_angle;
596 }
597
598 /* In dynamic mode, set the angle to 0 when inverting the brush, so you can trim plane
599 * surfaces without changing the brush. */
600 if (flip) {
601 sampled_angle = 0.0f;
602 }
603 else {
604 area_co = ss.cache->location_symm;
605 }
606
607 /* Interpolate between the previous and new sampled angles to avoid artifacts when if angle
608 * difference between two samples is too big. */
610 RAD2DEGF(sampled_angle), ss.cache->multiplane_scrape_angle, 0.2f);
611 }
612 else {
613 /* Standard mode: Scrape with the brush property fixed angle. */
614 area_co = ss.cache->location_symm;
616 if (flip) {
617 ss.cache->multiplane_scrape_angle *= -1.0f;
618 }
619 }
620
621 /* Calculate the final left and right scrape planes. */
622 float3 plane_no;
623 float3 plane_no_rot;
624 const float3 y_axis(0.0f, 1.0f, 0.0f);
625 const float4x4 mat_inv = math::invert(mat);
626
627 std::array<float4, 2> multiplane_scrape_planes;
628
629 mul_v3_mat3_m4v3(plane_no, mat.ptr(), area_no);
631 plane_no_rot, plane_no, y_axis, DEG2RADF(-ss.cache->multiplane_scrape_angle * 0.5f));
632 mul_v3_mat3_m4v3(plane_no, mat_inv.ptr(), plane_no_rot);
633 normalize_v3(plane_no);
634 plane_from_point_normal_v3(multiplane_scrape_planes[1], area_co, plane_no);
635
636 mul_v3_mat3_m4v3(plane_no, mat.ptr(), area_no);
638 plane_no_rot, plane_no, y_axis, DEG2RADF(ss.cache->multiplane_scrape_angle * 0.5f));
639 mul_v3_mat3_m4v3(plane_no, mat_inv.ptr(), plane_no_rot);
640 normalize_v3(plane_no);
641 plane_from_point_normal_v3(multiplane_scrape_planes[0], area_co, plane_no);
642
643 const float strength = std::abs(ss.cache->bstrength);
644
646 switch (pbvh.type()) {
647 case bke::pbvh::Type::Mesh: {
648 Mesh &mesh = *static_cast<Mesh *>(object.data);
649 const MeshAttributeData attribute_data(mesh.attributes());
651 const PositionDeformData position_data(depsgraph, object);
652 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, object);
653 node_mask.foreach_index(GrainSize(1), [&](const int i) {
654 LocalData &tls = all_tls.local();
656 sd,
657 brush,
658 mat,
659 multiplane_scrape_planes,
661 strength,
662 vert_normals,
663 attribute_data,
664 nodes[i],
665 object,
666 tls,
667 position_data);
668 bke::pbvh::update_node_bounds_mesh(position_data.eval, nodes[i]);
669 });
670 break;
671 }
672 case bke::pbvh::Type::Grids: {
673 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
674 MutableSpan<float3> positions = subdiv_ccg.positions;
676 node_mask.foreach_index(GrainSize(1), [&](const int i) {
677 LocalData &tls = all_tls.local();
679 sd,
680 brush,
681 mat,
682 multiplane_scrape_planes,
684 strength,
685 nodes[i],
686 object,
687 tls);
688 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
689 });
690 break;
691 }
692 case bke::pbvh::Type::BMesh: {
694 node_mask.foreach_index(GrainSize(1), [&](const int i) {
695 LocalData &tls = all_tls.local();
697 sd,
698 brush,
699 mat,
700 multiplane_scrape_planes,
702 strength,
703 nodes[i],
704 object,
705 tls);
706 bke::pbvh::update_node_bounds_bmesh(nodes[i]);
707 });
708 break;
709 }
710 }
711 pbvh.tag_positions_changed(node_mask);
712 bke::pbvh::flush_bounds_to_parents(pbvh);
713}
714
716 const Brush &brush,
717 const SculptSession &ss,
718 const float outline_col[3],
719 const float outline_alpha)
720{
722 return;
723 }
724
725 float4x4 local_mat_inv = math::invert(ss.cache->stroke_local_mat);
726 GPU_matrix_mul(local_mat_inv.ptr());
727 float angle = ss.cache->multiplane_scrape_angle;
728 if (ss.cache->pen_flip || ss.cache->invert) {
729 angle = -angle;
730 }
731
732 float offset = ss.cache->radius * 0.25f;
733
734 const float3 p{0.0f, 0.0f, ss.cache->radius};
735 const float3 y_axis{0.0f, 1.0f, 0.0f};
736 float3 p_l;
737 float3 p_r;
738 const float3 area_center(0);
739 rotate_v3_v3v3fl(p_r, p, y_axis, DEG2RADF((angle + 180) * 0.5f));
740 rotate_v3_v3v3fl(p_l, p, y_axis, DEG2RADF(-(angle + 180) * 0.5f));
741
743 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
744 immVertex3f(gpuattr, p_r[0], p_r[1] + offset, p_r[2]);
745 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
746 immVertex3f(gpuattr, p_l[0], p_l[1] + offset, p_l[2]);
747
748 immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]);
749 immVertex3f(gpuattr, p_r[0], p_r[1] - offset, p_r[2]);
750 immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]);
751 immVertex3f(gpuattr, p_l[0], p_l[1] - offset, p_l[2]);
752
753 immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]);
754 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
755
756 immVertex3f(gpuattr, p_r[0], p_r[1] - offset, p_r[2]);
757 immVertex3f(gpuattr, p_r[0], p_r[1] + offset, p_r[2]);
758
759 immVertex3f(gpuattr, p_l[0], p_l[1] - offset, p_l[2]);
760 immVertex3f(gpuattr, p_l[0], p_l[1] + offset, p_l[2]);
761
762 immEnd();
763
764 immUniformColor3fvAlpha(outline_col, outline_alpha * 0.1f);
766 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
767 immVertex3f(gpuattr, p_r[0], p_r[1] + offset, p_r[2]);
768 immVertex3f(gpuattr, p_r[0], p_r[1] - offset, p_r[2]);
769 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
770 immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]);
771 immVertex3f(gpuattr, p_r[0], p_r[1] - offset, p_r[2]);
772
773 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
774 immVertex3f(gpuattr, p_l[0], p_l[1] + offset, p_l[2]);
775 immVertex3f(gpuattr, p_l[0], p_l[1] - offset, p_l[2]);
776 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
777 immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]);
778 immVertex3f(gpuattr, p_l[0], p_l[1] - offset, p_l[2]);
779
780 immEnd();
781}
782
783} // namespace blender::ed::sculpt_paint
void BKE_brush_calc_curve_factors(eBrushCurvePreset preset, const CurveMapping *cumap, blender::Span< float > distances, float brush_radius, blender::MutableSpan< float > factors)
Definition brush.cc:1265
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:654
A BVH for high poly meshes.
const blender::Set< BMVert *, 0 > & BKE_pbvh_bmesh_node_unique_verts(blender::bke::pbvh::BMeshNode *node)
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_NOINLINE
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition math_geom.cc:215
MINLINE float plane_point_side_v3(const float plane[4], const float co[3])
void closest_to_plane_normalized_v3(float r_close[3], const float plane[4], const float pt[3])
Definition math_geom.cc:440
void mul_v3_mat3_m4v3(float r[3], const float mat[4][4], const float vec[3])
void normalize_m4(float R[4][4]) ATTR_NONNULL()
#define DEG2RADF(_deg)
#define RAD2DEGF(_rad)
void rotate_v3_v3v3fl(float r[3], const float p[3], const float axis[3], float angle)
float angle_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float n[3])
unsigned int uint
eBrushCurvePreset
@ BRUSH_ORIGINAL_NORMAL
@ BRUSH_FRONTFACE
eBrushFalloffShape
@ BRUSH_MULTIPLANE_SCRAPE_PLANES_PREVIEW
@ BRUSH_MULTIPLANE_SCRAPE_DYNAMIC
@ SCULPT_DISP_DIR_AREA
Object is a sort of wrapper for general info.
void immEnd()
void immVertex3f(uint attr_id, float x, float y, float z)
void immBegin(GPUPrimType, uint vertex_len)
void immUniformColor3fvAlpha(const float rgb[3], float a)
#define GPU_matrix_mul(x)
@ GPU_PRIM_LINES
@ GPU_PRIM_TRIS
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
bool closest(btVector3 &v)
constexpr int64_t size() const
Definition BLI_span.hh:494
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
void resize(const int64_t new_size)
void tag_positions_changed(const IndexMask &node_mask)
Definition pbvh.cc:549
Span< NodeT > nodes() const
void deform(MutableSpan< float3 > translations, Span< int > verts) const
Definition sculpt.cc:7139
void foreach_index(Fn &&fn) const
local_group_size(16, 16) .push_constant(Type b
const Depsgraph * depsgraph
draw_view in_light_buf[] float
static float verts[][3]
static void transform_positions(const Span< blender::float3 > src, const blender::float4x4 &transform, blender::MutableSpan< blender::float3 > dst)
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2846
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2502
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2482
void calc_grids_factors(const Depsgraph &depsgraph, const Object &object, const Cache &cache, const bke::pbvh::GridsNode &node, Span< int > grids, MutableSpan< float > factors)
void calc_vert_factors(const Depsgraph &depsgraph, const Object &object, const Cache &cache, const bke::pbvh::MeshNode &node, Span< int > verts, MutableSpan< float > factors)
static BLI_NOINLINE void calc_translations(const Set< BMVert *, 0 > &verts, const float3 &direction, const MutableSpan< float3 > translations)
static BLI_NOINLINE void fill_factor_from_hide_and_mask(const Mesh &mesh, const Span< int > face_indices, const MutableSpan< float > r_factors)
void fill_factor_from_hide_and_mask(Span< bool > hide_vert, Span< float > mask, Span< int > verts, MutableSpan< float > r_factors)
Definition sculpt.cc:6490
static void calc_bmesh(const Depsgraph &depsgraph, const Sculpt &sd, const Brush &brush, const float4x4 &mat, const std::array< float4, 2 > &scrape_planes, const float angle, const float strength, bke::pbvh::BMeshNode &node, Object &object, LocalData &tls)
MutableSpan< float3 > gather_grids_positions(const SubdivCCG &subdiv_ccg, const Span< int > grids, Vector< float3 > &positions)
void gather_bmesh_positions(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > positions)
Definition sculpt.cc:6054
void calc_brush_strength_factors(const StrokeCache &cache, const Brush &brush, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:6889
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:6862
void gather_bmesh_normals(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > normals)
Definition sculpt.cc:6072
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:6772
void do_multiplane_scrape_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
void filter_region_clip_factors(const SculptSession &ss, Span< float3 > vert_positions, Span< int > verts, MutableSpan< float > factors)
Definition sculpt.cc:6639
void calc_brush_distances(const SculptSession &ss, Span< float3 > vert_positions, Span< int > vert_indices, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:6722
static BLI_NOINLINE void calc_translations(const Span< float3 > positions, const Span< float3 > local_positions, const std::array< float4, 2 > &scrape_planes, const MutableSpan< float3 > translations)
void scale_translations(MutableSpan< float3 > translations, Span< float > factors)
Definition sculpt.cc:7210
static void sample_node_surface_bmesh(const Depsgraph &depsgraph, const Object &object, const Brush &brush, const float4x4 &mat, const bke::pbvh::BMeshNode &node, ScrapeSampleData &sample, LocalData &tls)
static BLI_NOINLINE void filter_plane_side_factors(const Span< float3 > positions, const Span< float3 > local_positions, const std::array< float4, 2 > &scrape_planes, const MutableSpan< float > factors)
void transform_positions(Span< float3 > src, const float4x4 &transform, MutableSpan< float3 > dst)
Definition sculpt.cc:7278
static BLI_NOINLINE void accumulate_samples(const Span< float3 > positions, const Span< float3 > local_positions, const Span< float3 > normals, const Span< float > factors, ScrapeSampleData &sample)
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7227
void clip_and_lock_translations(const Sculpt &sd, const SculptSession &ss, Span< float3 > positions, Span< int > verts, MutableSpan< float3 > translations)
Definition sculpt.cc:7022
static void calc_grids(const Depsgraph &depsgraph, const Sculpt &sd, const Brush &brush, const float4x4 &mat, const std::array< float4, 2 > &scrape_planes, const float angle, const float strength, const bke::pbvh::GridsNode &node, Object &object, LocalData &tls)
void calc_brush_plane(const Depsgraph &depsgraph, const Brush &brush, Object &ob, const IndexMask &node_mask, float3 &r_area_no, float3 &r_area_co)
Definition sculpt.cc:2789
std::optional< float3 > calc_area_normal(const Depsgraph &depsgraph, const Brush &brush, const Object &ob, const IndexMask &node_mask)
Definition sculpt.cc:1848
void filter_plane_trim_limit_factors(const Brush &brush, const StrokeCache &cache, Span< float3 > translations, MutableSpan< float > factors)
Definition sculpt.cc:7518
void apply_translations(Span< float3 > translations, Span< int > verts, MutableSpan< float3 > positions)
Definition sculpt.cc:6958
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6082
static void calc_faces(const Depsgraph &depsgraph, const Sculpt &sd, const Brush &brush, const float4x4 &mat, const std::array< float4, 2 > &scrape_planes, const float angle, const float strength, const Span< float3 > vert_normals, const MeshAttributeData &attribute_data, const bke::pbvh::MeshNode &node, Object &object, LocalData &tls, const PositionDeformData &position_data)
static void sample_node_surface_grids(const Depsgraph &depsgraph, const Object &object, const Brush &brush, const float4x4 &mat, const bke::pbvh::GridsNode &node, ScrapeSampleData &sample, LocalData &tls)
void calc_front_face(const float3 &view_normal, Span< float3 > normals, MutableSpan< float > factors)
Definition sculpt.cc:6581
void gather_grids_normals(const SubdivCCG &subdiv_ccg, Span< int > grids, MutableSpan< float3 > normals)
Definition sculpt.cc:6065
static ScrapeSampleData join_samples(const ScrapeSampleData &a, const ScrapeSampleData &b)
static void sample_node_surface_mesh(const Depsgraph &depsgraph, const Object &object, const Brush &brush, const float4x4 &mat, const Span< float3 > vert_positions, const Span< float3 > vert_normals, const MeshAttributeData &attribute_data, const bke::pbvh::MeshNode &node, ScrapeSampleData &sample, LocalData &tls)
void multiplane_scrape_preview_draw(const uint gpuattr, const Brush &brush, const SculptSession &ss, const float outline_col[3], const float outline_alpha)
static ScrapeSampleData sample_surface(const Depsgraph &depsgraph, const Object &object, const Brush &brush, const float4x4 &mat, const IndexMask &node_mask)
static BLI_NOINLINE void calc_distances(const Span< float3 > local_positions, const MutableSpan< float > distances)
T length(const VecBase< T, Size > &a)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
CartesianBasis invert(const CartesianBasis &basis)
T midpoint(const T &a, const T &b)
AxisSigned cross(const AxisSigned a, const AxisSigned b)
T interpolate(const T &a, const T &b, const FactorT &t)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
Definition BLI_task.hh:153
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:513
float SCULPT_brush_plane_offset_get(const Sculpt &sd, const SculptSession &ss)
Definition sculpt.cc:2883
float multiplane_scrape_angle
int sculpt_plane
float normal_radius_factor
int curve_preset
struct CurveMapping * curve
char falloff_shape
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:427
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:405
blender::Array< blender::float3 > positions
const c_style_mat & ptr() const
std::unique_ptr< auto_mask::Cache > automasking