Blender V5.0
plane.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
20
22
23#include "DNA_brush_types.h"
24#include "DNA_mesh_types.h"
25#include "DNA_object_types.h"
26#include "DNA_scene_types.h"
27
28#include "BKE_brush.hh"
29#include "BKE_mesh.hh"
30#include "BKE_paint.hh"
31#include "BKE_paint_bvh.hh"
32#include "BKE_subdiv_ccg.hh"
33
35#include "BLI_math_matrix.hh"
36#include "BLI_task.hh"
37
41
42#include "bmesh.hh"
43
45
46inline namespace plane_cc {
47
55
56static void calc_local_positions(const float4x4 &mat,
57 const Span<int> verts,
58 const Span<float3> positions,
59 const MutableSpan<float3> local_positions)
60{
61 for (const int i : verts.index_range()) {
62 local_positions[i] = math::transform_point(mat, positions[verts[i]]);
63 }
64}
65
78static void calc_local_distances(const float height,
79 const float depth,
80 const MutableSpan<float3> local_positions,
81 const MutableSpan<float> distances)
82{
83 if (height != 0.0f) {
84 const float height_rcp = math::rcp(height);
85
86 for (const int i : local_positions.index_range()) {
87 const float3 &position = local_positions[i];
88 if (position.z >= 0.0f) {
89 distances[i] = math::length(float3(position.x, position.y, position.z * height_rcp));
90 }
91 }
92 }
93 else {
94 for (const int i : local_positions.index_range()) {
95 if (local_positions[i].z >= 0.0f) {
96 distances[i] = 1.0f;
97 }
98 }
99 }
100
101 if (depth != 0.0f) {
102 const float depth_rcp = math::rcp(depth);
103
104 for (const int i : local_positions.index_range()) {
105 const float3 &position = local_positions[i];
106 if (position.z < 0.0f) {
107 distances[i] = math::length(float3(position.x, position.y, position.z * depth_rcp));
108 }
109 }
110 }
111 else {
112 for (const int i : local_positions.index_range()) {
113 if (local_positions[i].z < 0.0f) {
114 distances[i] = 1.0f;
115 }
116 }
117 }
118}
119
120/*
121 * Scales factors by `height` (if local z > 0) or `depth` (if local z < 0).
122 * This is necessary to "normalize" the strength contribute given by the local z distance.
123 *
124 * Note that if `height = 0`, the falloff strength of the vertices
125 * above the plane is 0 (see #calc_local_distances), hence
126 * the factor for such vertices is already 0.
127 *
128 * The same is true for vertices below the plane if `depth` = 0.
129 */
130static void scale_factors_by_height_and_depth(const float height,
131 const float depth,
132 const MutableSpan<float3> local_positions,
133 const MutableSpan<float> factors)
134{
135 if (!ELEM(height, 1.0f, 0.0f)) {
136 for (const int i : factors.index_range()) {
137 if (local_positions[i].z > 0.0f) {
138 factors[i] *= height;
139 }
140 }
141 }
142
143 if (!ELEM(depth, 0.0f, 1.0f)) {
144 for (const int i : factors.index_range()) {
145 if (local_positions[i].z < 0.0f) {
146 factors[i] *= depth;
147 }
148 }
149 }
150}
151
152/*
153 * Computes the translation vectors for the Plane brush.
154 *
155 * The translation of a vertex with index `i`, position `P`, and plane projection `Q`
156 * is determined by the vector `PQ` scaled by `factors[i]` and `strength`.
157 *
158 * In local (brush) space, `PQ` is given by:
159 * `PQ = Q - P = (x, y, 0) - (x, y, z) = (0, 0, -z)`
160 *
161 * Therefore, the translation in object space is:
162 * `T = A * (0, 0, -z) * factors[i] * strength`
163 *
164 * where `A` is the 3x3 local-to-object transformation matrix.
165 *
166 * Given how the local space is defined, `A * (0, 0, -z)` simplifies to:
167 * `-z * radius * plane_normal`
168 *
169 * Substituting this back, the translation becomes:
170 * `T = -z * radius * plane_normal * factors[i] * strength`
171 * which is equal to:
172 * `(factors[i] * z) * (-plane_normal * radius * strength)`
173 */
174static void calc_translations(const float3 &plane_normal,
175 const float radius,
176 const float strength,
177 const MutableSpan<float3> local_positions,
178 const MutableSpan<float> factors,
179 const MutableSpan<float3> r_translations)
180{
181 for (const int i : local_positions.index_range()) {
182 factors[i] *= local_positions[i].z;
183 }
184
185 const float3 &offset = -plane_normal * radius * strength;
186 translations_from_offset_and_factors(offset, factors, r_translations);
187}
188
189static void calc_faces(const Depsgraph &depsgraph,
190 const Sculpt &sd,
191 const Brush &brush,
192 const float4x4 &mat,
193 const float3 &plane_normal,
194 const float strength,
195 const float height,
196 const float depth,
197 const MeshAttributeData &attribute_data,
198 const Span<float3> vert_normals,
199 const bke::pbvh::MeshNode &node,
200 Object &object,
201 LocalData &tls,
202 const PositionDeformData &position_data)
203{
204 const SculptSession &ss = *object.sculpt;
205 const StrokeCache &cache = *ss.cache;
206
207 const Span<int> verts = node.verts();
208
209 tls.factors.resize(verts.size());
210 const MutableSpan<float> factors = tls.factors;
211 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
212 filter_region_clip_factors(ss, position_data.eval, verts, factors);
213
214 if (brush.flag & BRUSH_FRONTFACE) {
215 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
216 }
217
218 tls.positions.resize(verts.size());
219 const MutableSpan<float3> local_positions = tls.positions;
220 calc_local_positions(mat, verts, position_data.eval, local_positions);
221
222 tls.distances.resize(verts.size());
223 const MutableSpan<float> distances = tls.distances;
224 calc_local_distances(height, depth, local_positions, distances);
225 filter_distances_with_radius(1.0f, distances, factors);
226
227 apply_hardness_to_distances(1.0f, cache.hardness, distances);
230 distances,
231 1.0f,
232 factors);
233
234 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
235
236 calc_brush_texture_factors(ss, brush, position_data.eval, verts, factors);
237
238 tls.translations.resize(verts.size());
239 const MutableSpan<float3> translations = tls.translations;
240 scale_factors_by_height_and_depth(height, depth, local_positions, factors);
241 calc_translations(plane_normal, cache.radius, strength, local_positions, factors, translations);
242
243 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
244 position_data.deform(translations, verts);
245}
246
247static void calc_grids(const Depsgraph &depsgraph,
248 const Sculpt &sd,
249 Object &object,
250 const Brush &brush,
251 const float4x4 &mat,
252 const float3 &plane_normal,
253 const float strength,
254 const float height,
255 const float depth,
257 LocalData &tls)
258{
259 SculptSession &ss = *object.sculpt;
260 const StrokeCache &cache = *ss.cache;
261 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
262
263 const Span<int> grids = node.grids();
264 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
265
266 tls.factors.resize(positions.size());
267 const MutableSpan<float> factors = tls.factors;
268 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
269 filter_region_clip_factors(ss, positions, factors);
270
271 if (brush.flag & BRUSH_FRONTFACE) {
272 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
273 }
274
275 tls.local_positions.resize(positions.size());
276 const MutableSpan<float3> local_positions = tls.local_positions;
277 math::transform_points(positions, mat, local_positions, false);
278
279 tls.distances.resize(positions.size());
280 const MutableSpan<float> distances = tls.distances;
281 calc_local_distances(height, depth, local_positions, distances);
282 filter_distances_with_radius(1.0f, distances, factors);
283
284 apply_hardness_to_distances(1.0f, cache.hardness, distances);
287 distances,
288 1.0f,
289 factors);
290
291 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
292
293 calc_brush_texture_factors(ss, brush, positions, factors);
294
295 tls.translations.resize(positions.size());
296 const MutableSpan<float3> translations = tls.translations;
297 scale_factors_by_height_and_depth(height, depth, local_positions, factors);
298 calc_translations(plane_normal, cache.radius, strength, local_positions, factors, translations);
299
300 clip_and_lock_translations(sd, ss, positions, translations);
301 apply_translations(translations, grids, subdiv_ccg);
302}
303
304static void calc_bmesh(const Depsgraph &depsgraph,
305 const Sculpt &sd,
306 Object &object,
307 const Brush &brush,
308 const float4x4 &mat,
309 const float3 &plane_normal,
310 const float strength,
311 const float height,
312 const float depth,
314 LocalData &tls)
315{
316 SculptSession &ss = *object.sculpt;
317 const StrokeCache &cache = *ss.cache;
318
320 const MutableSpan positions = gather_bmesh_positions(verts, tls.positions);
321
322 tls.factors.resize(verts.size());
323 const MutableSpan<float> factors = tls.factors;
325 filter_region_clip_factors(ss, positions, factors);
326 if (brush.flag & BRUSH_FRONTFACE) {
327 calc_front_face(cache.view_normal_symm, verts, factors);
328 }
329
330 tls.local_positions.resize(positions.size());
331 const MutableSpan<float3> local_positions = tls.local_positions;
332 math::transform_points(positions, mat, local_positions, false);
333
334 tls.distances.resize(positions.size());
335 const MutableSpan<float> distances = tls.distances;
336 calc_local_distances(height, depth, local_positions, distances);
337 filter_distances_with_radius(1.0f, distances, factors);
338
339 apply_hardness_to_distances(1.0f, cache.hardness, distances);
342 distances,
343 1.0f,
344 factors);
345
346 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
347
348 calc_brush_texture_factors(ss, brush, positions, factors);
349
350 tls.translations.resize(positions.size());
351 const MutableSpan<float3> translations = tls.translations;
352 scale_factors_by_height_and_depth(height, depth, local_positions, factors);
353 calc_translations(plane_normal, cache.radius, strength, local_positions, factors, translations);
354
355 clip_and_lock_translations(sd, ss, positions, translations);
356 apply_translations(translations, verts);
357}
358
359} // namespace plane_cc
360
361void do_plane_brush(const Depsgraph &depsgraph,
362 const Sculpt &sd,
363 Object &object,
364 const IndexMask &node_mask,
365 const float3 &plane_normal,
366 const float3 &plane_center)
367{
368 const SculptSession &ss = *object.sculpt;
369 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
370 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
371
373 return;
374 }
375
376 float3 normal = plane_normal;
377 float3 center = plane_center;
378
379 normal = tilt_apply_to_normal(normal, *ss.cache, brush.tilt_strength_factor);
380
381 const bool flip = ss.cache->initial_direction_flipped;
382 const float offset = brush_plane_offset_get(brush, ss);
383 const float displace = ss.cache->radius * offset * (flip ? -1.0f : 1.0f);
384 center += normal * ss.cache->scale * displace;
385
387 mat.x_axis() = math::cross(normal, ss.cache->grab_delta_symm);
388 mat.y_axis() = math::cross(normal, mat.x_axis());
389 mat.z_axis() = normal;
390 mat.location() = center;
391 mat = math::normalize(mat);
392
394 float4x4 tmat = mat * scale;
395
396 mat = math::invert(tmat);
397
398 float strength = ss.cache->bstrength;
399 float height = brush.plane_height;
400 float depth = brush.plane_depth;
401
402 if (flip) {
403 switch (brush.plane_inversion_mode) {
405 strength *= -1.0f;
406 break;
407 }
409 std::swap(height, depth);
410 break;
411 }
412 }
413 }
414
416 switch (pbvh.type()) {
418 const Mesh &mesh = *static_cast<Mesh *>(object.data);
419 const MeshAttributeData attribute_data(mesh);
420 const PositionDeformData position_data(depsgraph, object);
421 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, object);
423 node_mask.foreach_index(GrainSize(1), [&](const int i) {
424 LocalData &tls = all_tls.local();
426 sd,
427 brush,
428 mat,
429 normal,
430 strength,
431 height,
432 depth,
433 attribute_data,
434 vert_normals,
435 nodes[i],
436 object,
437 tls,
438 position_data);
439 bke::pbvh::update_node_bounds_mesh(position_data.eval, nodes[i]);
440 });
441 break;
442 }
444 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
445 MutableSpan<float3> positions = subdiv_ccg.positions;
447 node_mask.foreach_index(GrainSize(1), [&](const int i) {
448 LocalData &tls = all_tls.local();
450 depsgraph, sd, object, brush, mat, normal, strength, height, depth, nodes[i], tls);
451 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
452 });
453 break;
454 }
457 node_mask.foreach_index(GrainSize(1), [&](const int i) {
458 LocalData &tls = all_tls.local();
460 depsgraph, sd, object, brush, mat, normal, strength, height, depth, nodes[i], tls);
462 });
463 break;
464 }
465 }
466 pbvh.tag_positions_changed(node_mask);
468}
469
470namespace plane {
472 Object &ob,
473 const Brush &brush,
474 IndexMaskMemory &memory)
475{
476 const SculptSession &ss = *ob.sculpt;
477 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
478
479 const bool use_original = !ss.cache->accum;
480 const IndexMask initial_node_mask = gather_nodes(pbvh,
482 use_original,
486 memory);
487
488 float3 plane_center;
489 float3 plane_normal;
490 calc_brush_plane(depsgraph, brush, ob, initial_node_mask, plane_normal, plane_center);
491
492 /* Recompute the node mask using the center of the brush plane as the center.
493 *
494 * The indices of the nodes in `cursor_node_mask` have been calculated based on the cursor
495 * location. However, for the Plane brush, its effective center often deviates from the cursor
496 * location. Calculating the affected nodes using the cursor location as the center can lead to
497 * issues (see, for example, #123768). */
498 const IndexMask plane_mask = bke::pbvh::search_nodes(
499 pbvh, memory, [&](const bke::pbvh::Node &node) {
500 if (node_fully_masked_or_hidden(node)) {
501 return false;
502 }
503 return node_in_sphere(node, plane_center, ss.cache->radius_squared, use_original);
504 });
505
506 return {plane_mask, plane_center, plane_normal};
507}
508} // namespace plane
509
510} // 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 ELEM(...)
@ BRUSH_PLANE_INVERT_DISPLACEMENT
@ BRUSH_PLANE_SWAP_HEIGHT_AND_DEPTH
eBrushCurvePreset
@ BRUSH_FRONTFACE
eBrushFalloffShape
Object is a sort of wrapper for general info.
BPy_StructRNA * depsgraph
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
void resize(const int64_t new_size)
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
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
static float verts[][3]
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:3052
IndexMask search_nodes(const Tree &pbvh, IndexMaskMemory &memory, FunctionRef< bool(const Node &)> filter_fn)
Definition pbvh.cc:2663
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
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 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 calc_translations(const float3 &plane_normal, const float radius, const float strength, const MutableSpan< float3 > local_positions, const MutableSpan< float > factors, const MutableSpan< float3 > r_translations)
Definition plane.cc:174
static void scale_factors_by_height_and_depth(const float height, const float depth, const MutableSpan< float3 > local_positions, const MutableSpan< float > factors)
Definition plane.cc:130
static void calc_grids(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const Brush &brush, const float4x4 &mat, const float3 &plane_normal, const float strength, const float height, const float depth, bke::pbvh::GridsNode &node, LocalData &tls)
Definition plane.cc:247
static void calc_local_positions(const float4x4 &mat, const Span< int > verts, const Span< float3 > positions, const MutableSpan< float3 > local_positions)
Definition plane.cc:56
static void calc_local_distances(const float height, const float depth, const MutableSpan< float3 > local_positions, const MutableSpan< float > distances)
Definition plane.cc:78
static void calc_bmesh(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const Brush &brush, const float4x4 &mat, const float3 &plane_normal, const float strength, const float height, const float depth, bke::pbvh::BMeshNode &node, LocalData &tls)
Definition plane.cc:304
static void calc_faces(const Depsgraph &depsgraph, const Sculpt &sd, const Brush &brush, const float4x4 &mat, const float3 &plane_normal, const float strength, const float height, const float depth, const MeshAttributeData &attribute_data, const Span< float3 > vert_normals, const bke::pbvh::MeshNode &node, Object &object, LocalData &tls, const PositionDeformData &position_data)
Definition plane.cc:189
CursorSampleResult calc_node_mask(const Depsgraph &depsgraph, Object &ob, const Brush &brush, IndexMaskMemory &memory)
Definition plane.cc:471
void do_plane_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask, const float3 &plane_normal, const float3 &plane_center)
Definition plane.cc:361
MutableSpan< float3 > gather_grids_positions(const SubdivCCG &subdiv_ccg, const Span< int > grids, Vector< float3 > &positions)
bool node_in_sphere(const bke::pbvh::Node &node, const float3 &location, const float radius_sq, const bool original)
Definition sculpt.cc:2429
void gather_bmesh_positions(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > positions)
Definition sculpt.cc:6367
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:7156
bool node_fully_masked_or_hidden(const bke::pbvh::Node &node)
Definition sculpt.cc:2418
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 clip_and_lock_translations(const Sculpt &sd, const SculptSession &ss, Span< float3 > positions, Span< int > verts, MutableSpan< float3 > translations)
Definition sculpt.cc:7335
IndexMask gather_nodes(const bke::pbvh::Tree &pbvh, const eBrushFalloffShape falloff_shape, const bool use_original, const float3 &location, const float radius_sq, const std::optional< float3 > &ray_direction, IndexMaskMemory &memory)
Definition sculpt.cc:2502
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
void apply_translations(Span< float3 > translations, Span< int > verts, MutableSpan< float3 > positions)
Definition sculpt.cc:7268
void calc_brush_texture_factors(const SculptSession &ss, const Brush &brush, Span< float3 > vert_positions, Span< int > vert, MutableSpan< float > factors)
Definition sculpt.cc:7195
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 translations_from_offset_and_factors(const float3 &offset, Span< float > factors, MutableSpan< float3 > r_translations)
Definition sculpt.cc:7531
float3 tilt_apply_to_normal(const Object &object, const float4x4 &view_inverse, const float3 &normal, const float2 &tilt, const float tilt_strength)
Definition sculpt.cc:2690
T length(const VecBase< T, Size > &a)
bool is_zero(const T &a)
CartesianBasis invert(const CartesianBasis &basis)
AxisSigned cross(const AxisSigned a, const AxisSigned b)
MatT from_scale(const VecBase< typename MatT::base_type, ScaleDim > &scale)
T rcp(const T &a)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
void transform_points(const float4x4 &transform, MutableSpan< float3 > points, bool use_threading=true)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
MatBase< float, 4, 4 > float4x4
VecBase< float, 3 > float3
int plane_inversion_mode
float plane_depth
char falloff_shape
float tilt_strength_factor
struct CurveMapping * curve_distance_falloff
float plane_height
int curve_distance_falloff_preset
struct SculptSession * sculpt
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:417
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:395
blender::Array< blender::float3 > positions
std::unique_ptr< auto_mask::Cache > automasking
i
Definition text_draw.cc:230