Blender V4.5
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);
167 eBrushCurvePreset(brush.curve_preset), brush.curve, distances, radius, factors);
168
169 tls.local_positions.resize(verts.size());
170 MutableSpan<float3> local_positions = tls.local_positions;
171 transform_positions(positions, mat, local_positions);
172
173 const MutableSpan normals = gather_data_mesh(vert_normals, verts, tls.normals);
174
175 accumulate_samples(positions, local_positions, normals, factors, sample);
176}
177
178static void sample_node_surface_grids(const Depsgraph &depsgraph,
179 const Object &object,
180 const Brush &brush,
181 const float4x4 &mat,
182 const bke::pbvh::GridsNode &node,
184 LocalData &tls)
185{
186 SculptSession &ss = *object.sculpt;
187 const StrokeCache &cache = *ss.cache;
188 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
189
190 const Span<int> grids = node.grids();
191 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
192
193 tls.factors.resize(positions.size());
194 const MutableSpan<float> factors = tls.factors;
195 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
196 filter_region_clip_factors(ss, positions, factors);
197 if (brush.flag & BRUSH_FRONTFACE) {
198 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
199 }
200 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
201
202 const float radius = cache.radius * brush.normal_radius_factor;
203
204 tls.distances.resize(positions.size());
205 const MutableSpan<float> distances = tls.distances;
206 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
207 filter_distances_with_radius(radius, distances, factors);
208 apply_hardness_to_distances(radius, cache.hardness, distances);
210 eBrushCurvePreset(brush.curve_preset), brush.curve, distances, radius, factors);
211
212 tls.local_positions.resize(positions.size());
213 MutableSpan<float3> local_positions = tls.local_positions;
214 transform_positions(positions, mat, local_positions);
215
216 tls.normals.resize(positions.size());
218 gather_grids_normals(subdiv_ccg, grids, normals);
219
220 accumulate_samples(positions, local_positions, normals, factors, sample);
221}
222
223static void sample_node_surface_bmesh(const Depsgraph &depsgraph,
224 const Object &object,
225 const Brush &brush,
226 const float4x4 &mat,
227 const bke::pbvh::BMeshNode &node,
229 LocalData &tls)
230{
231 const SculptSession &ss = *object.sculpt;
232 const StrokeCache &cache = *ss.cache;
233
235 const_cast<bke::pbvh::BMeshNode *>(&node));
236
237 const MutableSpan positions = gather_bmesh_positions(verts, tls.positions);
238
239 tls.factors.resize(verts.size());
240 const MutableSpan<float> factors = tls.factors;
242 filter_region_clip_factors(ss, positions, factors);
243 if (brush.flag & BRUSH_FRONTFACE) {
244 calc_front_face(cache.view_normal_symm, verts, factors);
245 }
246 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
247
248 const float radius = cache.radius * brush.normal_radius_factor;
249
250 tls.distances.resize(verts.size());
251 const MutableSpan<float> distances = tls.distances;
252 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
253 filter_distances_with_radius(radius, distances, factors);
254 apply_hardness_to_distances(radius, cache.hardness, distances);
256 eBrushCurvePreset(brush.curve_preset), brush.curve, distances, radius, factors);
257
258 tls.local_positions.resize(verts.size());
259 MutableSpan<float3> local_positions = tls.local_positions;
260 transform_positions(positions, mat, local_positions);
261
262 tls.normals.resize(verts.size());
265
266 accumulate_samples(positions, local_positions, normals, factors, sample);
267}
268
275static std::optional<ScrapeSampleData> sample_surface(const Depsgraph &depsgraph,
276 const Object &object,
277 const Brush &brush,
278 const float4x4 &mat,
279 const IndexMask &node_mask)
280{
281 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
284 switch (pbvh.type()) {
286 Mesh &mesh = *static_cast<Mesh *>(object.data);
287 const MeshAttributeData attribute_data(mesh);
289 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(depsgraph, object);
290 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, object);
292 node_mask.index_range(),
293 1,
295 [&](const IndexRange range, ScrapeSampleData sample) {
296 LocalData &tls = all_tls.local();
297 node_mask.slice(range).foreach_index([&](const int i) {
298 sample_node_surface_mesh(depsgraph,
299 object,
300 brush,
301 mat,
302 positions_eval,
303 vert_normals,
304 attribute_data,
305 nodes[i],
306 sample,
307 tls);
308 });
309 return sample;
310 },
312 break;
313 }
317 node_mask.index_range(),
318 1,
320 [&](const IndexRange range, ScrapeSampleData sample) {
321 LocalData &tls = all_tls.local();
322 node_mask.slice(range).foreach_index([&](const int i) {
323 sample_node_surface_grids(depsgraph, object, brush, mat, nodes[i], sample, tls);
324 });
325 return sample;
326 },
328 break;
329 }
333 node_mask.index_range(),
334 1,
335 ScrapeSampleData{},
336 [&](const IndexRange range, ScrapeSampleData sample) {
337 LocalData &tls = all_tls.local();
338 node_mask.slice(range).foreach_index([&](const int i) {
339 sample_node_surface_bmesh(depsgraph, object, brush, mat, nodes[i], sample, tls);
340 });
341 return sample;
342 },
344 break;
345 }
346 }
347
348 return result.has_samples() ? std::make_optional(result) : std::nullopt;
349}
350
351static void calc_faces(const Depsgraph &depsgraph,
352 const Sculpt &sd,
353 const Brush &brush,
354 const float4x4 &mat,
355 const std::array<float4, 2> &scrape_planes,
356 const float angle,
357 const float strength,
358 const Span<float3> vert_normals,
359 const MeshAttributeData &attribute_data,
360 const bke::pbvh::MeshNode &node,
361 Object &object,
362 LocalData &tls,
363 const PositionDeformData &position_data)
364{
365 SculptSession &ss = *object.sculpt;
366 const StrokeCache &cache = *ss.cache;
367
368 const Span<int> verts = node.verts();
369 const MutableSpan positions = gather_data_mesh(position_data.eval, verts, tls.positions);
370
371 tls.factors.resize(verts.size());
372 const MutableSpan<float> factors = tls.factors;
373 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
374 filter_region_clip_factors(ss, positions, factors);
375 if (brush.flag & BRUSH_FRONTFACE) {
376 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
377 }
378 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
379
380 tls.distances.resize(verts.size());
381 const MutableSpan<float> distances = tls.distances;
382 /* NOTE: The distances are not used from this call, it's only used for filtering. */
383 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
384 filter_distances_with_radius(cache.radius, distances, factors);
385
386 tls.local_positions.resize(verts.size());
387 MutableSpan<float3> local_positions = tls.local_positions;
388 transform_positions(positions, mat, local_positions);
389
390 if (angle >= 0.0f) {
391 filter_plane_side_factors(positions, local_positions, scrape_planes, factors);
392 }
393
394 calc_distances(local_positions, distances);
395 /* TODO: Using the radius for the filter here is probably too high, but due to the Y-axis
396 * deformation, a simple value of 1.0 isn't correct. */
397 filter_distances_with_radius(cache.radius, distances, factors);
398
399 apply_hardness_to_distances(cache, distances);
400 calc_brush_strength_factors(cache, brush, distances, factors);
401
402 tls.translations.resize(verts.size());
403 MutableSpan<float3> translations = tls.translations;
404 calc_translations(positions, local_positions, scrape_planes, translations);
405
406 filter_plane_trim_limit_factors(brush, cache, translations, factors);
407
408 scale_factors(factors, strength);
409 scale_translations(translations, factors);
410
411 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
412 position_data.deform(translations, verts);
413}
414
415static void calc_grids(const Depsgraph &depsgraph,
416 const Sculpt &sd,
417 const Brush &brush,
418 const float4x4 &mat,
419 const std::array<float4, 2> &scrape_planes,
420 const float angle,
421 const float strength,
422 const bke::pbvh::GridsNode &node,
423 Object &object,
424 LocalData &tls)
425{
426 SculptSession &ss = *object.sculpt;
427 const StrokeCache &cache = *ss.cache;
428 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
429
430 const Span<int> grids = node.grids();
431 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
432
433 tls.factors.resize(positions.size());
434 const MutableSpan<float> factors = tls.factors;
435 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
436 filter_region_clip_factors(ss, positions, factors);
437 if (brush.flag & BRUSH_FRONTFACE) {
438 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
439 }
440 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
441
442 tls.distances.resize(positions.size());
443 const MutableSpan<float> distances = tls.distances;
444 /* NOTE: The distances are not used from this call, it's only used for filtering. */
445 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
446 filter_distances_with_radius(cache.radius, distances, factors);
447
448 tls.local_positions.resize(positions.size());
449 MutableSpan<float3> local_positions = tls.local_positions;
450 transform_positions(positions, mat, local_positions);
451
452 if (angle >= 0.0f) {
453 filter_plane_side_factors(positions, local_positions, scrape_planes, factors);
454 }
455
456 calc_distances(local_positions, distances);
457 /* TODO: Using the radius for the filter here is probably too high, but due to the Y-axis
458 * deformation, a simple value of 1.0 isn't correct. */
459 filter_distances_with_radius(cache.radius, distances, factors);
460
461 apply_hardness_to_distances(cache, distances);
462 calc_brush_strength_factors(cache, brush, distances, factors);
463
464 tls.translations.resize(positions.size());
465 MutableSpan<float3> translations = tls.translations;
466 calc_translations(positions, local_positions, scrape_planes, translations);
467
468 filter_plane_trim_limit_factors(brush, cache, translations, factors);
469
470 scale_factors(factors, strength);
471 scale_translations(translations, factors);
472
473 clip_and_lock_translations(sd, ss, positions, translations);
474 apply_translations(translations, grids, subdiv_ccg);
475}
476
477static void calc_bmesh(const Depsgraph &depsgraph,
478 const Sculpt &sd,
479 const Brush &brush,
480 const float4x4 &mat,
481 const std::array<float4, 2> &scrape_planes,
482 const float angle,
483 const float strength,
485 Object &object,
486 LocalData &tls)
487{
488 SculptSession &ss = *object.sculpt;
489 const StrokeCache &cache = *ss.cache;
490
492 const MutableSpan positions = gather_bmesh_positions(verts, tls.positions);
493
494 tls.factors.resize(verts.size());
495 const MutableSpan<float> factors = tls.factors;
497 filter_region_clip_factors(ss, positions, factors);
498 if (brush.flag & BRUSH_FRONTFACE) {
499 calc_front_face(cache.view_normal_symm, verts, factors);
500 }
501 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
502
503 tls.distances.resize(verts.size());
504 const MutableSpan<float> distances = tls.distances;
505 /* NOTE: The distances are not used from this call, it's only used for filtering. */
506 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
507 filter_distances_with_radius(cache.radius, distances, factors);
508
509 tls.local_positions.resize(verts.size());
510 MutableSpan<float3> local_positions = tls.local_positions;
511 transform_positions(positions, mat, local_positions);
512
513 if (angle >= 0.0f) {
514 filter_plane_side_factors(positions, local_positions, scrape_planes, factors);
515 }
516
517 calc_distances(local_positions, distances);
518 /* TODO: Using the radius for the filter here is probably too high, but due to the Y-axis
519 * deformation, a simple value of 1.0 isn't correct. */
520 filter_distances_with_radius(cache.radius, distances, factors);
521
522 apply_hardness_to_distances(cache, distances);
523 calc_brush_strength_factors(cache, brush, distances, factors);
524
525 tls.translations.resize(verts.size());
526 MutableSpan<float3> translations = tls.translations;
527 calc_translations(positions, local_positions, scrape_planes, translations);
528
529 filter_plane_trim_limit_factors(brush, cache, translations, factors);
530
531 scale_factors(factors, strength);
532 scale_translations(translations, factors);
533
534 clip_and_lock_translations(sd, ss, positions, translations);
535 apply_translations(translations, verts);
536}
537
539 const Sculpt &sd,
540 Object &object,
541 const IndexMask &node_mask)
542{
543 SculptSession &ss = *object.sculpt;
544 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
545 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
546
547 const bool flip = (ss.cache->bstrength < 0.0f);
548 const float radius = flip ? -ss.cache->radius : ss.cache->radius;
549 const float offset = brush_plane_offset_get(brush, ss);
550 const float displace = -radius * offset;
551
552 float3 sculpt_plane_normal;
553 float3 area_position;
554 calc_brush_plane(depsgraph, brush, object, node_mask, sculpt_plane_normal, area_position);
555
556 float3 area_normal = sculpt_plane_normal;
557 /* Ignore brush settings and recalculate the area normal. */
559 area_normal = calc_area_normal(depsgraph, brush, object, node_mask).value_or(float3(0));
560 }
561
562 /* Delay the first daub because grab delta is not setup. */
565 return;
566 }
567
569 return;
570 }
571
572 area_position += area_normal * ss.cache->scale * displace;
573
574 /* Init brush local space matrix. */
576 mat.x_axis() = math::cross(area_normal, ss.cache->grab_delta_symm);
577 mat.y_axis() = math::cross(area_normal, mat.x_axis());
578 mat.z_axis() = area_normal;
579 mat.location() = ss.cache->location_symm;
580 /* NOTE: #math::normalize behaves differently for some reason. */
581 normalize_m4(mat.ptr());
582 mat = math::invert(mat);
583
584 /* Update matrix for the cursor preview. */
585 if (ss.cache->mirror_symmetry_pass == 0 && ss.cache->radial_symmetry_pass == 0) {
586 ss.cache->stroke_local_mat = mat;
587 }
588
589 /* Dynamic mode. */
590
592 /* Sample the individual normal and area center of the areas at both sides of the cursor. */
593 const std::optional<ScrapeSampleData> sample = sample_surface(
594 depsgraph, object, brush, mat, node_mask);
595 if (!sample) {
596 return;
597 }
598
599 BLI_assert(sample->has_samples());
600
601 /* Use the plane centers to check if we are sculpting along a concave or convex edge. */
602 const std::array<float3, 2> sampled_plane_co{
603 sample->area_cos[0] * 1.0f / float(sample->area_count[0]),
604 sample->area_cos[1] * 1.0f / float(sample->area_count[1])};
605 const float3 mid_co = math::midpoint(sampled_plane_co[0], sampled_plane_co[1]);
606
607 /* Calculate the scrape planes angle based on the sampled normals. */
608 const std::array<float3, 2> sampled_plane_normals{
609 math::normalize(sample->area_nos[0] * 1.0f / float(sample->area_count[0])),
610 math::normalize(sample->area_nos[1] * 1.0f / float(sample->area_count[1]))};
611
612 float sampled_angle = angle_v3v3(sampled_plane_normals[0], sampled_plane_normals[1]);
613 const std::array<float3, 2> sampled_cv{area_normal, ss.cache->location_symm - mid_co};
614
615 sampled_angle += DEG2RADF(brush.multiplane_scrape_angle) * ss.cache->pressure;
616
617 /* Invert the angle if we are sculpting along a concave edge. */
618 if (math::dot(sampled_cv[0], sampled_cv[1]) < 0.0f) {
619 sampled_angle = -sampled_angle;
620 }
621
622 /* In dynamic mode, set the angle to 0 when inverting the brush, so you can trim plane
623 * surfaces without changing the brush. */
624 if (flip) {
625 sampled_angle = 0.0f;
626 }
627 else {
628 area_position = ss.cache->location_symm;
629 }
630
631 /* Interpolate between the previous and new sampled angles to avoid artifacts when if angle
632 * difference between two samples is too big. */
634 RAD2DEGF(sampled_angle), ss.cache->multiplane_scrape_angle, 0.2f);
635 }
636 else {
637 /* Standard mode: Scrape with the brush property fixed angle. */
638 area_position = ss.cache->location_symm;
640 if (flip) {
641 ss.cache->multiplane_scrape_angle *= -1.0f;
642 }
643 }
644
645 /* Calculate the final left and right scrape planes. */
646 float3 plane_no;
647 float3 plane_no_rot;
648 const float3 y_axis(0.0f, 1.0f, 0.0f);
649 const float4x4 mat_inv = math::invert(mat);
650
651 std::array<float4, 2> multiplane_scrape_planes;
652
653 mul_v3_mat3_m4v3(plane_no, mat.ptr(), area_normal);
655 plane_no_rot, plane_no, y_axis, DEG2RADF(-ss.cache->multiplane_scrape_angle * 0.5f));
656 mul_v3_mat3_m4v3(plane_no, mat_inv.ptr(), plane_no_rot);
657 normalize_v3(plane_no);
658 plane_from_point_normal_v3(multiplane_scrape_planes[1], area_position, plane_no);
659
660 mul_v3_mat3_m4v3(plane_no, mat.ptr(), area_normal);
662 plane_no_rot, plane_no, y_axis, DEG2RADF(ss.cache->multiplane_scrape_angle * 0.5f));
663 mul_v3_mat3_m4v3(plane_no, mat_inv.ptr(), plane_no_rot);
664 normalize_v3(plane_no);
665 plane_from_point_normal_v3(multiplane_scrape_planes[0], area_position, plane_no);
666
667 const float strength = std::abs(ss.cache->bstrength);
668
670 switch (pbvh.type()) {
672 Mesh &mesh = *static_cast<Mesh *>(object.data);
673 const MeshAttributeData attribute_data(mesh);
675 const PositionDeformData position_data(depsgraph, object);
676 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, object);
677 node_mask.foreach_index(GrainSize(1), [&](const int i) {
678 LocalData &tls = all_tls.local();
680 sd,
681 brush,
682 mat,
683 multiplane_scrape_planes,
685 strength,
686 vert_normals,
687 attribute_data,
688 nodes[i],
689 object,
690 tls,
691 position_data);
692 bke::pbvh::update_node_bounds_mesh(position_data.eval, nodes[i]);
693 });
694 break;
695 }
697 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
698 MutableSpan<float3> positions = subdiv_ccg.positions;
700 node_mask.foreach_index(GrainSize(1), [&](const int i) {
701 LocalData &tls = all_tls.local();
703 sd,
704 brush,
705 mat,
706 multiplane_scrape_planes,
708 strength,
709 nodes[i],
710 object,
711 tls);
712 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
713 });
714 break;
715 }
718 node_mask.foreach_index(GrainSize(1), [&](const int i) {
719 LocalData &tls = all_tls.local();
721 sd,
722 brush,
723 mat,
724 multiplane_scrape_planes,
726 strength,
727 nodes[i],
728 object,
729 tls);
731 });
732 break;
733 }
734 }
735 pbvh.tag_positions_changed(node_mask);
737}
738
740 const Brush &brush,
741 const SculptSession &ss,
742 const float outline_col[3],
743 const float outline_alpha)
744{
746 return;
747 }
748
749 float4x4 local_mat_inv = math::invert(ss.cache->stroke_local_mat);
750 GPU_matrix_mul(local_mat_inv.ptr());
752 if (ss.cache->pen_flip || ss.cache->invert) {
753 angle = -angle;
754 }
755
756 float offset = ss.cache->radius * 0.25f;
757
758 const float3 p{0.0f, 0.0f, ss.cache->radius};
759 const float3 y_axis{0.0f, 1.0f, 0.0f};
760 float3 p_l;
761 float3 p_r;
762 const float3 area_center(0);
763 rotate_v3_v3v3fl(p_r, p, y_axis, DEG2RADF((angle + 180) * 0.5f));
764 rotate_v3_v3v3fl(p_l, p, y_axis, DEG2RADF(-(angle + 180) * 0.5f));
765
767 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[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, p_l[0], p_l[1] + offset, p_l[2]);
771
772 immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]);
773 immVertex3f(gpuattr, p_r[0], p_r[1] - offset, p_r[2]);
774 immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]);
775 immVertex3f(gpuattr, p_l[0], p_l[1] - offset, p_l[2]);
776
777 immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]);
778 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
779
780 immVertex3f(gpuattr, p_r[0], p_r[1] - offset, p_r[2]);
781 immVertex3f(gpuattr, p_r[0], p_r[1] + offset, p_r[2]);
782
783 immVertex3f(gpuattr, p_l[0], p_l[1] - offset, p_l[2]);
784 immVertex3f(gpuattr, p_l[0], p_l[1] + offset, p_l[2]);
785
786 immEnd();
787
788 immUniformColor3fvAlpha(outline_col, outline_alpha * 0.1f);
790 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
791 immVertex3f(gpuattr, p_r[0], p_r[1] + offset, p_r[2]);
792 immVertex3f(gpuattr, p_r[0], p_r[1] - offset, p_r[2]);
793 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
794 immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]);
795 immVertex3f(gpuattr, p_r[0], p_r[1] - offset, p_r[2]);
796
797 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
798 immVertex3f(gpuattr, p_l[0], p_l[1] + offset, p_l[2]);
799 immVertex3f(gpuattr, p_l[0], p_l[1] - offset, p_l[2]);
800 immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]);
801 immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]);
802 immVertex3f(gpuattr, p_l[0], p_l[1] - offset, p_l[2]);
803
804 immEnd();
805}
806
807} // 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:1381
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:641
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
@ SCULPT_DISP_DIR_AREA
eBrushCurvePreset
@ BRUSH_ORIGINAL_NORMAL
@ BRUSH_FRONTFACE
eBrushFalloffShape
@ BRUSH_MULTIPLANE_SCRAPE_PLANES_PREVIEW
@ BRUSH_MULTIPLANE_SCRAPE_DYNAMIC
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:559
Span< NodeT > nodes() const
void flush_bounds_to_parents()
Definition pbvh.cc:1122
void deform(MutableSpan< float3 > translations, Span< int > verts) const
Definition sculpt.cc:7443
void foreach_index(Fn &&fn) const
static float verts[][3]
static float normals[][3]
VecBase< float, 3 > float3
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:2912
void update_node_bounds_bmesh(BMeshNode &node)
Definition pbvh.cc:1110
void update_node_bounds_mesh(Span< float3 > positions, MeshNode &node)
Definition pbvh.cc:1090
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2435
void update_node_bounds_grids(int grid_area, Span< float3 > positions, GridsNode &node)
Definition pbvh.cc:1099
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2416
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:6351
void calc_brush_strength_factors(const StrokeCache &cache, const Brush &brush, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7167
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:7140
void gather_bmesh_normals(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > normals)
Definition sculpt.cc:6369
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7089
void filter_region_clip_factors(const SculptSession &ss, Span< float3 > vert_positions, Span< int > verts, MutableSpan< float > factors)
Definition sculpt.cc:6956
void scale_translations(MutableSpan< float3 > translations, Span< float > factors)
Definition sculpt.cc:7476
void transform_positions(Span< float3 > src, const float4x4 &transform, MutableSpan< float3 > dst)
Definition sculpt.cc:7544
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7493
void clip_and_lock_translations(const Sculpt &sd, const SculptSession &ss, Span< float3 > positions, Span< int > verts, MutableSpan< float3 > translations)
Definition sculpt.cc:7316
void calc_brush_distances(const SculptSession &ss, Span< float3 > vert_positions, Span< int > vert, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:7039
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:2891
std::optional< float3 > calc_area_normal(const Depsgraph &depsgraph, const Brush &brush, const Object &ob, const IndexMask &node_mask)
Definition sculpt.cc:1814
void filter_plane_trim_limit_factors(const Brush &brush, const StrokeCache &cache, Span< float3 > translations, MutableSpan< float > factors)
Definition sculpt.cc:7859
void apply_translations(Span< float3 > translations, Span< int > verts, MutableSpan< float3 > positions)
Definition sculpt.cc:7249
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6379
float brush_plane_offset_get(const Brush &brush, const SculptSession &ss)
Definition sculpt.cc:2974
void calc_front_face(const float3 &view_normal, Span< float3 > normals, MutableSpan< float > factors)
Definition sculpt.cc:6898
void gather_grids_normals(const SubdivCCG &subdiv_ccg, Span< int > grids, MutableSpan< float3 > normals)
Definition sculpt.cc:6362
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: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:543
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:437
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:415
blender::Array< blender::float3 > positions
const c_style_mat & ptr() const
std::unique_ptr< auto_mask::Cache > automasking
i
Definition text_draw.cc:230