Blender V5.0
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_geom.h"
9#include "BLI_math_matrix.h"
10#include "BLI_math_matrix.hh"
11#include "BLI_math_rotation.h"
13#include "BLI_span.hh"
14
15#include "DNA_brush_types.h"
16#include "DNA_object_types.h"
17
18#include "BKE_brush.hh"
19#include "BKE_mesh.hh"
20#include "BKE_paint.hh"
21#include "BKE_paint_bvh.hh"
22#include "BKE_subdiv_ccg.hh"
23
24#include "GPU_immediate.hh"
25#include "GPU_matrix.hh"
26
27#include "bmesh.hh"
28
29#include <cmath>
30#include <cstdlib>
31
35
37
39 std::array<float3, 2> area_cos;
40 std::array<float3, 2> area_nos;
41 std::array<int, 2> area_count;
42
43 bool has_samples() const
44 {
45 return area_count[0] != 0 && area_count[1] != 0;
46 }
47};
48
57
59{
60 ScrapeSampleData joined = a;
61
62 joined.area_cos[0] = a.area_cos[0] + b.area_cos[0];
63 joined.area_cos[1] = a.area_cos[1] + b.area_cos[1];
64
65 joined.area_nos[0] = a.area_nos[0] + b.area_nos[0];
66 joined.area_nos[1] = a.area_nos[1] + b.area_nos[1];
67
68 joined.area_count[0] = a.area_count[0] + b.area_count[0];
69 joined.area_count[1] = a.area_count[1] + b.area_count[1];
70 return joined;
71}
72
74 const Span<float3> local_positions,
75 const std::array<float4, 2> &scrape_planes,
76 const MutableSpan<float> factors)
77{
78 BLI_assert(positions.size() == local_positions.size());
79 BLI_assert(positions.size() == factors.size());
80
81 for (const int i : local_positions.index_range()) {
82 const bool plane_index = local_positions[i][0] <= 0.0f;
83 if (plane_point_side_v3(scrape_planes[plane_index], positions[i]) <= 0.0f) {
84 factors[i] = 0.0f;
85 }
86 }
87}
88
89BLI_NOINLINE static void calc_distances(const Span<float3> local_positions,
90 const MutableSpan<float> distances)
91{
92 BLI_assert(local_positions.size() == distances.size());
93
94 for (const int i : local_positions.index_range()) {
95 /* Deform the local space along the Y axis to avoid artifacts on curved strokes. */
96 /* This produces a not round brush tip. */
97 float3 local = local_positions[i];
98 local[1] *= 2.0f;
99 distances[i] = math::length(local);
100 }
101}
102
103BLI_NOINLINE static void calc_translations(const Span<float3> positions,
104 const Span<float3> local_positions,
105 const std::array<float4, 2> &scrape_planes,
106 const MutableSpan<float3> translations)
107{
108 for (const int i : positions.index_range()) {
109 const bool plane_index = local_positions[i][0] <= 0.0f;
111 closest_to_plane_normalized_v3(closest, scrape_planes[plane_index], positions[i]);
112 translations[i] = closest - positions[i];
113 }
114}
115
116BLI_NOINLINE static void accumulate_samples(const Span<float3> positions,
117 const Span<float3> local_positions,
118 const Span<float3> normals,
119 const Span<float> factors,
121{
122 for (const int i : positions.index_range()) {
123 if (factors[i] <= 0.0f) {
124 continue;
125 }
126 const bool plane_index = local_positions[i].x <= 0.0f;
127 sample.area_nos[plane_index] += normals[i] * factors[i];
128 sample.area_cos[plane_index] += positions[i];
129 sample.area_count[plane_index]++;
130 }
131}
132
133static void sample_node_surface_mesh(const Depsgraph &depsgraph,
134 const Object &object,
135 const Brush &brush,
136 const float4x4 &mat,
137 const Span<float3> vert_positions,
138 const Span<float3> vert_normals,
139 const MeshAttributeData &attribute_data,
140 const bke::pbvh::MeshNode &node,
142 LocalData &tls)
143{
144 const SculptSession &ss = *object.sculpt;
145 const StrokeCache &cache = *ss.cache;
146
147 const Span<int> verts = node.verts();
148 const MutableSpan positions = gather_data_mesh(vert_positions, verts, tls.positions);
149
150 tls.factors.resize(verts.size());
151 const MutableSpan<float> factors = tls.factors;
152 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
153 filter_region_clip_factors(ss, positions, factors);
154 if (brush.flag & BRUSH_FRONTFACE) {
155 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
156 }
157 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
158
159 const float radius = cache.radius * brush.normal_radius_factor;
160
161 tls.distances.resize(verts.size());
162 const MutableSpan<float> distances = tls.distances;
163 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
164 filter_distances_with_radius(radius, distances, factors);
165 apply_hardness_to_distances(radius, cache.hardness, distances);
168 distances,
169 radius,
170 factors);
171
172 tls.local_positions.resize(verts.size());
173 MutableSpan<float3> local_positions = tls.local_positions;
174 math::transform_points(positions, mat, local_positions, false);
175
176 const MutableSpan normals = gather_data_mesh(vert_normals, verts, tls.normals);
177
178 accumulate_samples(positions, local_positions, normals, factors, sample);
179}
180
181static void sample_node_surface_grids(const Depsgraph &depsgraph,
182 const Object &object,
183 const Brush &brush,
184 const float4x4 &mat,
185 const bke::pbvh::GridsNode &node,
187 LocalData &tls)
188{
189 SculptSession &ss = *object.sculpt;
190 const StrokeCache &cache = *ss.cache;
191 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
192
193 const Span<int> grids = node.grids();
194 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
195
196 tls.factors.resize(positions.size());
197 const MutableSpan<float> factors = tls.factors;
198 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
199 filter_region_clip_factors(ss, positions, factors);
200 if (brush.flag & BRUSH_FRONTFACE) {
201 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
202 }
203 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
204
205 const float radius = cache.radius * brush.normal_radius_factor;
206
207 tls.distances.resize(positions.size());
208 const MutableSpan<float> distances = tls.distances;
209 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
210 filter_distances_with_radius(radius, distances, factors);
211 apply_hardness_to_distances(radius, cache.hardness, distances);
214 distances,
215 radius,
216 factors);
217
218 tls.local_positions.resize(positions.size());
219 MutableSpan<float3> local_positions = tls.local_positions;
220 math::transform_points(positions, mat, local_positions, false);
221
222 tls.normals.resize(positions.size());
224 gather_grids_normals(subdiv_ccg, grids, normals);
225
226 accumulate_samples(positions, local_positions, normals, factors, sample);
227}
228
229static void sample_node_surface_bmesh(const Depsgraph &depsgraph,
230 const Object &object,
231 const Brush &brush,
232 const float4x4 &mat,
233 const bke::pbvh::BMeshNode &node,
235 LocalData &tls)
236{
237 const SculptSession &ss = *object.sculpt;
238 const StrokeCache &cache = *ss.cache;
239
241 const_cast<bke::pbvh::BMeshNode *>(&node));
242
243 const MutableSpan positions = gather_bmesh_positions(verts, tls.positions);
244
245 tls.factors.resize(verts.size());
246 const MutableSpan<float> factors = tls.factors;
248 filter_region_clip_factors(ss, positions, factors);
249 if (brush.flag & BRUSH_FRONTFACE) {
250 calc_front_face(cache.view_normal_symm, verts, factors);
251 }
252 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
253
254 const float radius = cache.radius * brush.normal_radius_factor;
255
256 tls.distances.resize(verts.size());
257 const MutableSpan<float> distances = tls.distances;
258 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
259 filter_distances_with_radius(radius, distances, factors);
260 apply_hardness_to_distances(radius, cache.hardness, distances);
263 distances,
264 radius,
265 factors);
266
267 tls.local_positions.resize(verts.size());
268 MutableSpan<float3> local_positions = tls.local_positions;
269 math::transform_points(positions, mat, local_positions, false);
270
271 tls.normals.resize(verts.size());
274
275 accumulate_samples(positions, local_positions, normals, factors, sample);
276}
277
284static std::optional<ScrapeSampleData> sample_surface(const Depsgraph &depsgraph,
285 const Object &object,
286 const Brush &brush,
287 const float4x4 &mat,
288 const IndexMask &node_mask)
289{
290 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
293 switch (pbvh.type()) {
295 Mesh &mesh = *static_cast<Mesh *>(object.data);
296 const MeshAttributeData attribute_data(mesh);
298 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(depsgraph, object);
299 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, object);
301 node_mask.index_range(),
302 1,
304 [&](const IndexRange range, ScrapeSampleData sample) {
305 LocalData &tls = all_tls.local();
306 node_mask.slice(range).foreach_index([&](const int i) {
307 sample_node_surface_mesh(depsgraph,
308 object,
309 brush,
310 mat,
311 positions_eval,
312 vert_normals,
313 attribute_data,
314 nodes[i],
315 sample,
316 tls);
317 });
318 return sample;
319 },
321 break;
322 }
326 node_mask.index_range(),
327 1,
329 [&](const IndexRange range, ScrapeSampleData sample) {
330 LocalData &tls = all_tls.local();
331 node_mask.slice(range).foreach_index([&](const int i) {
332 sample_node_surface_grids(depsgraph, object, brush, mat, nodes[i], sample, tls);
333 });
334 return sample;
335 },
337 break;
338 }
342 node_mask.index_range(),
343 1,
344 ScrapeSampleData{},
345 [&](const IndexRange range, ScrapeSampleData sample) {
346 LocalData &tls = all_tls.local();
347 node_mask.slice(range).foreach_index([&](const int i) {
348 sample_node_surface_bmesh(depsgraph, object, brush, mat, nodes[i], sample, tls);
349 });
350 return sample;
351 },
353 break;
354 }
355 }
356
357 return result.has_samples() ? std::make_optional(result) : std::nullopt;
358}
359
360static void calc_faces(const Depsgraph &depsgraph,
361 const Sculpt &sd,
362 const Brush &brush,
363 const float4x4 &mat,
364 const std::array<float4, 2> &scrape_planes,
365 const float angle,
366 const float strength,
367 const Span<float3> vert_normals,
368 const MeshAttributeData &attribute_data,
369 const bke::pbvh::MeshNode &node,
370 Object &object,
371 LocalData &tls,
372 const PositionDeformData &position_data)
373{
374 SculptSession &ss = *object.sculpt;
375 const StrokeCache &cache = *ss.cache;
376
377 const Span<int> verts = node.verts();
378 const MutableSpan positions = gather_data_mesh(position_data.eval, verts, tls.positions);
379
380 tls.factors.resize(verts.size());
381 const MutableSpan<float> factors = tls.factors;
382 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
383 filter_region_clip_factors(ss, positions, factors);
384 if (brush.flag & BRUSH_FRONTFACE) {
385 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
386 }
387 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
388
389 tls.distances.resize(verts.size());
390 const MutableSpan<float> distances = tls.distances;
391 /* NOTE: The distances are not used from this call, it's only used for filtering. */
392 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
393 filter_distances_with_radius(cache.radius, distances, factors);
394
395 tls.local_positions.resize(verts.size());
396 MutableSpan<float3> local_positions = tls.local_positions;
397 math::transform_points(positions, mat, local_positions, false);
398
399 if (angle >= 0.0f) {
400 filter_plane_side_factors(positions, local_positions, scrape_planes, factors);
401 }
402
403 calc_distances(local_positions, distances);
404 /* TODO: Using the radius for the filter here is probably too high, but due to the Y-axis
405 * deformation, a simple value of 1.0 isn't correct. */
406 filter_distances_with_radius(cache.radius, distances, factors);
407
408 apply_hardness_to_distances(cache, distances);
409 calc_brush_strength_factors(cache, brush, distances, factors);
410
411 tls.translations.resize(verts.size());
412 MutableSpan<float3> translations = tls.translations;
413 calc_translations(positions, local_positions, scrape_planes, translations);
414
415 filter_plane_trim_limit_factors(brush, cache, translations, factors);
416
417 scale_factors(factors, strength);
418 scale_translations(translations, factors);
419
420 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
421 position_data.deform(translations, verts);
422}
423
424static void calc_grids(const Depsgraph &depsgraph,
425 const Sculpt &sd,
426 const Brush &brush,
427 const float4x4 &mat,
428 const std::array<float4, 2> &scrape_planes,
429 const float angle,
430 const float strength,
431 const bke::pbvh::GridsNode &node,
432 Object &object,
433 LocalData &tls)
434{
435 SculptSession &ss = *object.sculpt;
436 const StrokeCache &cache = *ss.cache;
437 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
438
439 const Span<int> grids = node.grids();
440 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
441
442 tls.factors.resize(positions.size());
443 const MutableSpan<float> factors = tls.factors;
444 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
445 filter_region_clip_factors(ss, positions, factors);
446 if (brush.flag & BRUSH_FRONTFACE) {
447 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
448 }
449 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
450
451 tls.distances.resize(positions.size());
452 const MutableSpan<float> distances = tls.distances;
453 /* NOTE: The distances are not used from this call, it's only used for filtering. */
454 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
455 filter_distances_with_radius(cache.radius, distances, factors);
456
457 tls.local_positions.resize(positions.size());
458 MutableSpan<float3> local_positions = tls.local_positions;
459 math::transform_points(positions, mat, local_positions, false);
460
461 if (angle >= 0.0f) {
462 filter_plane_side_factors(positions, local_positions, scrape_planes, factors);
463 }
464
465 calc_distances(local_positions, distances);
466 /* TODO: Using the radius for the filter here is probably too high, but due to the Y-axis
467 * deformation, a simple value of 1.0 isn't correct. */
468 filter_distances_with_radius(cache.radius, distances, factors);
469
470 apply_hardness_to_distances(cache, distances);
471 calc_brush_strength_factors(cache, brush, distances, factors);
472
473 tls.translations.resize(positions.size());
474 MutableSpan<float3> translations = tls.translations;
475 calc_translations(positions, local_positions, scrape_planes, translations);
476
477 filter_plane_trim_limit_factors(brush, cache, translations, factors);
478
479 scale_factors(factors, strength);
480 scale_translations(translations, factors);
481
482 clip_and_lock_translations(sd, ss, positions, translations);
483 apply_translations(translations, grids, subdiv_ccg);
484}
485
486static void calc_bmesh(const Depsgraph &depsgraph,
487 const Sculpt &sd,
488 const Brush &brush,
489 const float4x4 &mat,
490 const std::array<float4, 2> &scrape_planes,
491 const float angle,
492 const float strength,
494 Object &object,
495 LocalData &tls)
496{
497 SculptSession &ss = *object.sculpt;
498 const StrokeCache &cache = *ss.cache;
499
501 const MutableSpan positions = gather_bmesh_positions(verts, tls.positions);
502
503 tls.factors.resize(verts.size());
504 const MutableSpan<float> factors = tls.factors;
506 filter_region_clip_factors(ss, positions, factors);
507 if (brush.flag & BRUSH_FRONTFACE) {
508 calc_front_face(cache.view_normal_symm, verts, factors);
509 }
510 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
511
512 tls.distances.resize(verts.size());
513 const MutableSpan<float> distances = tls.distances;
514 /* NOTE: The distances are not used from this call, it's only used for filtering. */
515 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
516 filter_distances_with_radius(cache.radius, distances, factors);
517
518 tls.local_positions.resize(verts.size());
519 MutableSpan<float3> local_positions = tls.local_positions;
520 math::transform_points(positions, mat, local_positions, false);
521
522 if (angle >= 0.0f) {
523 filter_plane_side_factors(positions, local_positions, scrape_planes, factors);
524 }
525
526 calc_distances(local_positions, distances);
527 /* TODO: Using the radius for the filter here is probably too high, but due to the Y-axis
528 * deformation, a simple value of 1.0 isn't correct. */
529 filter_distances_with_radius(cache.radius, distances, factors);
530
531 apply_hardness_to_distances(cache, distances);
532 calc_brush_strength_factors(cache, brush, distances, factors);
533
534 tls.translations.resize(verts.size());
535 MutableSpan<float3> translations = tls.translations;
536 calc_translations(positions, local_positions, scrape_planes, translations);
537
538 filter_plane_trim_limit_factors(brush, cache, translations, factors);
539
540 scale_factors(factors, strength);
541 scale_translations(translations, factors);
542
543 clip_and_lock_translations(sd, ss, positions, translations);
544 apply_translations(translations, verts);
545}
546
548 const Sculpt &sd,
549 Object &object,
550 const IndexMask &node_mask)
551{
552 SculptSession &ss = *object.sculpt;
553 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
554 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
555
556 const bool flip = (ss.cache->bstrength < 0.0f);
557 const float radius = flip ? -ss.cache->radius : ss.cache->radius;
558 const float offset = brush_plane_offset_get(brush, ss);
559 const float displace = -radius * offset;
560
561 float3 sculpt_plane_normal;
562 float3 area_position;
563 calc_brush_plane(depsgraph, brush, object, node_mask, sculpt_plane_normal, area_position);
564
565 float3 area_normal = sculpt_plane_normal;
566 /* Ignore brush settings and recalculate the area normal. */
568 area_normal = calc_area_normal(depsgraph, brush, object, node_mask).value_or(float3(0));
569 }
570
571 /* Delay the first daub because grab delta is not setup. */
574 return;
575 }
576
578 return;
579 }
580
581 area_position += area_normal * ss.cache->scale * displace;
582
583 /* Init brush local space matrix. */
585 mat.x_axis() = math::cross(area_normal, ss.cache->grab_delta_symm);
586 mat.y_axis() = math::cross(area_normal, mat.x_axis());
587 mat.z_axis() = area_normal;
588 mat.location() = ss.cache->location_symm;
589 /* NOTE: #math::normalize behaves differently for some reason. */
590 normalize_m4(mat.ptr());
591 mat = math::invert(mat);
592
593 /* Update matrix for the cursor preview. */
594 if (ss.cache->mirror_symmetry_pass == 0 && ss.cache->radial_symmetry_pass == 0) {
595 ss.cache->stroke_local_mat = mat;
596 }
597
598 /* Dynamic mode. */
599
601 /* Sample the individual normal and area center of the areas at both sides of the cursor. */
602 const std::optional<ScrapeSampleData> sample = sample_surface(
603 depsgraph, object, brush, mat, node_mask);
604 if (!sample) {
605 return;
606 }
607
608 BLI_assert(sample->has_samples());
609
610 /* Use the plane centers to check if we are sculpting along a concave or convex edge. */
611 const std::array<float3, 2> sampled_plane_co{
612 sample->area_cos[0] * 1.0f / float(sample->area_count[0]),
613 sample->area_cos[1] * 1.0f / float(sample->area_count[1])};
614 const float3 mid_co = math::midpoint(sampled_plane_co[0], sampled_plane_co[1]);
615
616 /* Calculate the scrape planes angle based on the sampled normals. */
617 const std::array<float3, 2> sampled_plane_normals{
618 math::normalize(sample->area_nos[0] * 1.0f / float(sample->area_count[0])),
619 math::normalize(sample->area_nos[1] * 1.0f / float(sample->area_count[1]))};
620
621 float sampled_angle = angle_v3v3(sampled_plane_normals[0], sampled_plane_normals[1]);
622 const std::array<float3, 2> sampled_cv{area_normal, ss.cache->location_symm - mid_co};
623
624 sampled_angle += DEG2RADF(brush.multiplane_scrape_angle) * ss.cache->pressure;
625
626 /* Invert the angle if we are sculpting along a concave edge. */
627 if (math::dot(sampled_cv[0], sampled_cv[1]) < 0.0f) {
628 sampled_angle = -sampled_angle;
629 }
630
631 /* In dynamic mode, set the angle to 0 when inverting the brush, so you can trim plane
632 * surfaces without changing the brush. */
633 if (flip) {
634 sampled_angle = 0.0f;
635 }
636 else {
637 area_position = ss.cache->location_symm;
638 }
639
640 /* Interpolate between the previous and new sampled angles to avoid artifacts when if angle
641 * difference between two samples is too big. */
643 RAD2DEGF(sampled_angle), ss.cache->multiplane_scrape_angle, 0.2f);
644 }
645 else {
646 /* Standard mode: Scrape with the brush property fixed angle. */
647 area_position = ss.cache->location_symm;
649 if (flip) {
650 ss.cache->multiplane_scrape_angle *= -1.0f;
651 }
652 }
653
654 /* Calculate the final left and right scrape planes. */
655 float3 plane_no;
656 float3 plane_no_rot;
657 const float3 y_axis(0.0f, 1.0f, 0.0f);
658 const float4x4 mat_inv = math::invert(mat);
659
660 std::array<float4, 2> multiplane_scrape_planes;
661
662 mul_v3_mat3_m4v3(plane_no, mat.ptr(), area_normal);
664 plane_no_rot, plane_no, y_axis, DEG2RADF(-ss.cache->multiplane_scrape_angle * 0.5f));
665 mul_v3_mat3_m4v3(plane_no, mat_inv.ptr(), plane_no_rot);
666 normalize_v3(plane_no);
667 plane_from_point_normal_v3(multiplane_scrape_planes[1], area_position, plane_no);
668
669 mul_v3_mat3_m4v3(plane_no, mat.ptr(), area_normal);
671 plane_no_rot, plane_no, y_axis, DEG2RADF(ss.cache->multiplane_scrape_angle * 0.5f));
672 mul_v3_mat3_m4v3(plane_no, mat_inv.ptr(), plane_no_rot);
673 normalize_v3(plane_no);
674 plane_from_point_normal_v3(multiplane_scrape_planes[0], area_position, plane_no);
675
676 const float strength = std::abs(ss.cache->bstrength);
677
679 switch (pbvh.type()) {
681 Mesh &mesh = *static_cast<Mesh *>(object.data);
682 const MeshAttributeData attribute_data(mesh);
684 const PositionDeformData position_data(depsgraph, object);
685 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, object);
686 node_mask.foreach_index(GrainSize(1), [&](const int i) {
687 LocalData &tls = all_tls.local();
689 sd,
690 brush,
691 mat,
692 multiplane_scrape_planes,
694 strength,
695 vert_normals,
696 attribute_data,
697 nodes[i],
698 object,
699 tls,
700 position_data);
701 bke::pbvh::update_node_bounds_mesh(position_data.eval, nodes[i]);
702 });
703 break;
704 }
706 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
707 MutableSpan<float3> positions = subdiv_ccg.positions;
709 node_mask.foreach_index(GrainSize(1), [&](const int i) {
710 LocalData &tls = all_tls.local();
712 sd,
713 brush,
714 mat,
715 multiplane_scrape_planes,
717 strength,
718 nodes[i],
719 object,
720 tls);
721 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
722 });
723 break;
724 }
727 node_mask.foreach_index(GrainSize(1), [&](const int i) {
728 LocalData &tls = all_tls.local();
730 sd,
731 brush,
732 mat,
733 multiplane_scrape_planes,
735 strength,
736 nodes[i],
737 object,
738 tls);
740 });
741 break;
742 }
743 }
744 pbvh.tag_positions_changed(node_mask);
746}
747
749 const Brush &brush,
750 const SculptSession &ss,
751 const float outline_col[3],
752 const float outline_alpha)
753{
755 return;
756 }
757
758 float4x4 local_mat_inv = math::invert(ss.cache->stroke_local_mat);
759 GPU_matrix_mul(local_mat_inv.ptr());
761 if (ss.cache->pen_flip || ss.cache->invert) {
762 angle = -angle;
763 }
764
765 float offset = ss.cache->radius * 0.25f;
766
767 const float3 p{0.0f, 0.0f, ss.cache->radius};
768 const float3 y_axis{0.0f, 1.0f, 0.0f};
769 float3 p_l;
770 float3 p_r;
771 const float3 area_center(0);
772 rotate_v3_v3v3fl(p_r, p, y_axis, DEG2RADF((angle + 180) * 0.5f));
773 rotate_v3_v3v3fl(p_l, p, y_axis, DEG2RADF(-(angle + 180) * 0.5f));
774
776 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
777 immVertex3f(gpuattr, p_r[0], p_r[1] + offset, p_r[2]);
778 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
779 immVertex3f(gpuattr, p_l[0], p_l[1] + offset, p_l[2]);
780
781 immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]);
782 immVertex3f(gpuattr, p_r[0], p_r[1] - offset, p_r[2]);
783 immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]);
784 immVertex3f(gpuattr, p_l[0], p_l[1] - offset, p_l[2]);
785
786 immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]);
787 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
788
789 immVertex3f(gpuattr, p_r[0], p_r[1] - offset, p_r[2]);
790 immVertex3f(gpuattr, p_r[0], p_r[1] + offset, p_r[2]);
791
792 immVertex3f(gpuattr, p_l[0], p_l[1] - offset, p_l[2]);
793 immVertex3f(gpuattr, p_l[0], p_l[1] + offset, p_l[2]);
794
795 immEnd();
796
797 immUniformColor3fvAlpha(outline_col, outline_alpha * 0.1f);
799 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
800 immVertex3f(gpuattr, p_r[0], p_r[1] + offset, p_r[2]);
801 immVertex3f(gpuattr, p_r[0], p_r[1] - offset, p_r[2]);
802 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
803 immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]);
804 immVertex3f(gpuattr, p_r[0], p_r[1] - offset, p_r[2]);
805
806 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
807 immVertex3f(gpuattr, p_l[0], p_l[1] + offset, p_l[2]);
808 immVertex3f(gpuattr, p_l[0], p_l[1] - offset, p_l[2]);
809 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
810 immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]);
811 immVertex3f(gpuattr, p_l[0], p_l[1] - offset, p_l[2]);
812
813 immEnd();
814}
815
816} // namespace blender::ed::sculpt_paint::brushes
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:1448
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:650
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(a)
Definition BLI_assert.h:46
#define BLI_NOINLINE
#define DEG2RADF(_deg)
#define RAD2DEGF(_rad)
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition math_geom.cc:217
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:442
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()
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:117
BPy_StructRNA * depsgraph
bool closest(btVector3 &v)
void resize(const int64_t new_size)
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
void tag_positions_changed(const IndexMask &node_mask)
Definition pbvh.cc:635
Span< NodeT > nodes() const
void flush_bounds_to_parents()
Definition pbvh.cc:1306
void foreach_index(Fn &&fn) const
nullptr float
static float verts[][3]
static float normals[][3]
VecBase< float, 3 > float3
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:3052
void update_node_bounds_bmesh(BMeshNode &node)
Definition pbvh.cc:1294
void update_node_bounds_mesh(Span< float3 > positions, MeshNode &node)
Definition pbvh.cc:1274
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1059
void update_node_bounds_grids(int grid_area, Span< float3 > positions, GridsNode &node)
Definition pbvh.cc:1283
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1040
void calc_vert_factors(const Depsgraph &depsgraph, const Object &object, const Cache &automasking, const bke::pbvh::MeshNode &node, Span< int > verts, MutableSpan< float > factors)
void calc_grids_factors(const Depsgraph &depsgraph, const Object &object, const Cache &automasking, const bke::pbvh::GridsNode &node, Span< int > grids, MutableSpan< float > factors)
static BLI_NOINLINE void calc_translations(const Set< BMVert *, 0 > &verts, const float3 &direction, const MutableSpan< float3 > translations)
static void calc_bmesh(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const Brush &brush, const float3 &direction, const float strength, bke::pbvh::BMeshNode &node, LocalData &tls)
static void calc_faces(const Depsgraph &depsgraph, const Sculpt &sd, const Brush &brush, const float4 &test_plane, const float strength, const MeshAttributeData &attribute_data, const Span< float3 > vert_normals, const bke::pbvh::MeshNode &node, Object &object, LocalData &tls, const PositionDeformData &position_data)
Definition clay.cc:56
static void calc_grids(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const Brush &brush, const float4 &test_plane, const float strength, bke::pbvh::GridsNode &node, LocalData &tls)
Definition clay.cc:93
static BLI_NOINLINE void fill_factor_from_hide_and_mask(const Mesh &mesh, const Span< int > face_indices, const MutableSpan< float > r_factors)
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)
void multiplane_scrape_preview_draw(uint gpuattr, const Brush &brush, const SculptSession &ss, const float outline_col[3], float outline_alpha)
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)
static BLI_NOINLINE void calc_distances(const Span< float3 > local_positions, const MutableSpan< float > distances)
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)
static ScrapeSampleData join_samples(const ScrapeSampleData &a, const ScrapeSampleData &b)
void do_multiplane_scrape_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
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)
static std::optional< ScrapeSampleData > sample_surface(const Depsgraph &depsgraph, const Object &object, const Brush &brush, const float4x4 &mat, const IndexMask &node_mask)
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)
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:6367
void calc_brush_strength_factors(const StrokeCache &cache, const Brush &brush, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7183
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:7156
void gather_bmesh_normals(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > normals)
Definition sculpt.cc:6385
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7105
void filter_region_clip_factors(const SculptSession &ss, Span< float3 > vert_positions, Span< int > verts, MutableSpan< float > factors)
Definition sculpt.cc:6972
void scale_translations(MutableSpan< float3 > translations, Span< float > factors)
Definition sculpt.cc:7495
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7512
void clip_and_lock_translations(const Sculpt &sd, const SculptSession &ss, Span< float3 > positions, Span< int > verts, MutableSpan< float3 > translations)
Definition sculpt.cc:7335
void calc_brush_distances(const SculptSession &ss, Span< float3 > vert_positions, Span< int > vert, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:7055
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:2910
std::optional< float3 > calc_area_normal(const Depsgraph &depsgraph, const Brush &brush, const Object &ob, const IndexMask &node_mask)
Definition sculpt.cc:1833
void filter_plane_trim_limit_factors(const Brush &brush, const StrokeCache &cache, Span< float3 > translations, MutableSpan< float > factors)
Definition sculpt.cc:7863
void apply_translations(Span< float3 > translations, Span< int > verts, MutableSpan< float3 > positions)
Definition sculpt.cc:7268
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6395
float brush_plane_offset_get(const Brush &brush, const SculptSession &ss)
Definition sculpt.cc:2993
void calc_front_face(const float3 &view_normal, Span< float3 > normals, MutableSpan< float > factors)
Definition sculpt.cc:6914
void gather_grids_normals(const SubdivCCG &subdiv_ccg, Span< int > grids, MutableSpan< float3 > normals)
Definition sculpt.cc:6378
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)
void transform_points(const float4x4 &transform, MutableSpan< float3 > points, bool use_threading=true)
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
Definition BLI_task.hh:151
MatBase< float, 4, 4 > float4x4
VecBase< float, 3 > float3
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:542
float multiplane_scrape_angle
int sculpt_plane
float normal_radius_factor
char falloff_shape
struct CurveMapping * curve_distance_falloff
int curve_distance_falloff_preset
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:417
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:395
blender::Array< blender::float3 > positions
const c_style_mat & ptr() const
std::unique_ptr< auto_mask::Cache > automasking
i
Definition text_draw.cc:230