Blender V5.0
sculpt_cloth.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
8#include "sculpt_cloth.hh"
9
10#include "MEM_guardedalloc.h"
11
12#include "BLI_array_utils.hh"
14#include "BLI_math_geom.h"
15#include "BLI_math_matrix.h"
16#include "BLI_math_matrix.hh"
17#include "BLI_math_rotation.h"
18#include "BLI_math_vector.hh"
19#include "BLI_ordered_edge.hh"
20#include "BLI_utildefines.h"
21#include "BLI_vector.hh"
22
23#include "BLT_translation.hh"
24
25#include "DNA_brush_types.h"
27#include "DNA_object_types.h"
28#include "DNA_scene_types.h"
29
30#include "BKE_brush.hh"
31#include "BKE_ccg.hh"
32#include "BKE_collision.h"
33#include "BKE_context.hh"
34#include "BKE_layer.hh"
35#include "BKE_mesh.hh"
36#include "BKE_modifier.hh"
37#include "BKE_paint.hh"
38#include "BKE_paint_bvh.hh"
39#include "BKE_subdiv_ccg.hh"
40
42
43#include "WM_api.hh"
44#include "WM_types.hh"
45
46#include "ED_sculpt.hh"
47
48#include "mesh_brush_common.hh"
49#include "sculpt_automask.hh"
50#include "sculpt_face_set.hh"
51#include "sculpt_filter.hh"
52#include "sculpt_hide.hh"
53#include "sculpt_intern.hh"
54#include "sculpt_undo.hh"
55
56#include "RNA_access.hh"
57#include "RNA_define.hh"
58
59#include "GPU_immediate.hh"
60#include "GPU_immediate_util.hh"
61#include "GPU_matrix.hh"
62#include "GPU_state.hh"
63
64#include "bmesh.hh"
65
66#include <cmath>
67#include <cstring>
68
70
72 const Span<int> grids,
74{
75 const int grid_verts_num = grids.size() * key.grid_area;
76 indices.resize(grid_verts_num);
77 for (const int i : grids.index_range()) {
79 indices.as_mutable_span().slice(i * key.grid_area, key.grid_area),
80 grids[i] * key.grid_area);
81 }
82 return indices;
83}
84
87{
88 indices.resize(verts.size());
89 int i = 0;
90 for (const BMVert *vert : verts) {
92 i++;
93 }
94 return indices;
95}
96
98 const BitGroupVector<> &grid_hidden,
99 const Span<int> grids,
101{
102 if (grid_hidden.is_empty()) {
103 return calc_vert_indices_grids(key, grids, indices);
104 }
105 const int grid_verts_num = grids.size() * key.grid_area;
106 indices.reserve(grid_verts_num);
107 for (const int i : grids.index_range()) {
108 const int start = grids[i] * key.grid_area;
109 bits::foreach_0_index(grid_hidden[grids[i]],
110 [&](const int offset) { indices.append(start + offset); });
111 }
112 return indices;
113}
114
117{
118 indices.reserve(verts.size());
119 for (const BMVert *vert : verts) {
120 if (!BM_elem_flag_test(vert, BM_ELEM_HIDDEN)) {
121 indices.append(BM_elem_index_get(vert));
122 }
123 }
124 return indices;
125}
126
128 const Span<int> verts,
129 Vector<int> &r_offset_data,
130 Vector<int> &r_data)
131{
132 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
133
134 r_offset_data.resize(verts.size() + 1);
135 r_data.clear();
136
137 for (const int i : verts.index_range()) {
138 r_offset_data[i] = r_data.size();
139 SubdivCCGNeighbors neighbors;
141 subdiv_ccg, SubdivCCGCoord::from_index(key, verts[i]), false, neighbors);
142
143 for (const SubdivCCGCoord coord : neighbors.coords) {
144 r_data.append(coord.to_index(key));
145 }
146 }
147
148 r_offset_data.last() = r_data.size();
149 return GroupedSpan<int>(r_offset_data.as_span(), r_data.as_span());
150}
151
153 const Span<int> verts,
154 Vector<int> &r_offset_data,
155 Vector<int> &r_data)
156{
157 BMeshNeighborVerts neighbors;
158
159 r_offset_data.resize(verts.size() + 1);
160 r_data.clear();
161
162 for (const int i : verts.index_range()) {
163 r_offset_data[i] = r_data.size();
164 BMVert *vert = BM_vert_at_index(&const_cast<BMesh &>(bm), verts[i]);
165 for (const BMVert *neighbor : vert_neighbors_get_bmesh(*vert, neighbors)) {
166 r_data.append(BM_elem_index_get(neighbor));
167 }
168 }
169 r_offset_data.last() = r_data.size();
170 return GroupedSpan<int>(r_offset_data.as_span(), r_data.as_span());
171}
172
174{
175 if (!ss.cache || !brush) {
176 return float3(0);
177 }
179 return ss.cache->initial_location_symm;
180 }
181 return ss.cache->location_symm;
182}
183
185 const Brush &brush,
186 IndexMaskMemory &memory)
187{
188 const SculptSession &ss = *object.sculpt;
189 BLI_assert(ss.cache);
191 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
192
193 switch (brush.cloth_simulation_area_type) {
195 const float radius_squared = math::square(ss.cache->initial_radius *
196 (1.0 + brush.cloth_sim_limit));
197 return bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
198 return node_in_sphere(node, ss.cache->initial_location_symm, radius_squared, false);
199 });
200 }
202 return bke::pbvh::all_leaf_nodes(pbvh, memory);
204 const float radius_squared = math::square(ss.cache->radius * (1.0 + brush.cloth_sim_limit));
205 return bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
206 return node_in_sphere(node, ss.cache->location_symm, radius_squared, false);
207 });
208 }
209 }
210
212 return {};
213}
214
215bool is_cloth_deform_brush(const Brush &brush)
216{
219 /* All brushes that are not the cloth brush deform the simulation using softbody
220 * constraints instead of applying forces. */
223}
224
226 const float radius,
227 const float3 &location,
228 const float3 &co)
229{
231 /* All brushes that are not the cloth brush do not use simulation areas. */
232 return 1.0f;
233 }
234
235 /* Global simulation does not have any falloff as the entire mesh is being simulated. */
237 return 1.0f;
238 }
239
240 const float distance = math::distance(location, co);
241 const float limit = radius + (radius * brush.cloth_sim_limit);
242 const float falloff = radius + (radius * brush.cloth_sim_limit * brush.cloth_sim_falloff);
243
244 if (distance > limit) {
245 /* Outside the limits. */
246 return 0.0f;
247 }
248 if (distance < falloff) {
249 /* Before the falloff area. */
250 return 1.0f;
251 }
252 /* Do a smooth-step transition inside the falloff area. */
253 float p = 1.0f - ((distance - falloff) / (limit - falloff));
254 return 3.0f * p * p - 2.0f * p * p * p;
255}
256
258 const float radius,
259 const float3 &location,
260 const Span<float3> positions,
261 const MutableSpan<float> factors)
262{
263 BLI_assert(positions.size() == factors.size());
264
265 for (const int i : positions.index_range()) {
266 factors[i] *= cloth_brush_simulation_falloff_get(brush, radius, location, positions[i]);
267 }
268}
269
270#define CLOTH_LENGTH_CONSTRAINTS_BLOCK 100000
271#define CLOTH_SIMULATION_ITERATIONS 5
272
273#define CLOTH_SOLVER_DISPLACEMENT_FACTOR 0.6f
274#define CLOTH_MAX_CONSTRAINTS_PER_VERTEX 1024
275#define CLOTH_SIMULATION_TIME_STEP 0.01f
276#define CLOTH_DEFORMATION_SNAKEHOOK_STRENGTH 0.35f
277#define CLOTH_DEFORMATION_TARGET_STRENGTH 0.01f
278#define CLOTH_DEFORMATION_GRAB_STRENGTH 0.1f
279
281 const int node_index,
282 const int v1,
283 const int v2,
284 const Span<float3> init_positions)
285{
286 LengthConstraint length_constraint{};
287
288 length_constraint.elem_index_a = v1;
289 length_constraint.elem_index_b = v2;
290
291 length_constraint.node = node_index;
292
293 length_constraint.elem_position_a = cloth_sim.pos[v1];
294 length_constraint.elem_position_b = cloth_sim.pos[v2];
295
296 length_constraint.type = SCULPT_CLOTH_CONSTRAINT_STRUCTURAL;
297
298 length_constraint.length = math::distance(init_positions[v1], init_positions[v2]);
299 length_constraint.strength = 1.0f;
300
301 cloth_sim.length_constraints.append(length_constraint);
302}
303
305 const int node_index,
306 const int v,
307 const float strength)
308{
309 LengthConstraint length_constraint{};
310
311 length_constraint.elem_index_a = v;
312 length_constraint.elem_index_b = v;
313
314 length_constraint.node = node_index;
315
316 length_constraint.elem_position_a = cloth_sim.pos[v];
317 length_constraint.elem_position_b = cloth_sim.softbody_pos[v];
318
319 length_constraint.type = SCULPT_CLOTH_CONSTRAINT_SOFTBODY;
320
321 length_constraint.length = 0.0f;
322 length_constraint.strength = strength;
323
324 cloth_sim.length_constraints.append(length_constraint);
325}
326
328 const int node_index,
329 const int v,
330 const float strength)
331{
332 LengthConstraint length_constraint{};
333
334 length_constraint.elem_index_a = v;
335 length_constraint.elem_index_b = v;
336
337 length_constraint.node = node_index;
338
339 length_constraint.elem_position_a = cloth_sim.pos[v];
340 length_constraint.elem_position_b = cloth_sim.init_pos[v];
341
342 length_constraint.type = SCULPT_CLOTH_CONSTRAINT_PIN;
343
344 length_constraint.length = 0.0f;
345 length_constraint.strength = strength;
346
347 cloth_sim.length_constraints.append(length_constraint);
348}
349
351 const int node_index,
352 const int v,
353 const float strength)
354{
355 LengthConstraint length_constraint{};
356
357 length_constraint.elem_index_a = v;
358 length_constraint.elem_index_b = v;
359
360 length_constraint.node = node_index;
361
362 length_constraint.type = SCULPT_CLOTH_CONSTRAINT_DEFORMATION;
363
364 length_constraint.elem_position_a = cloth_sim.pos[v];
365 length_constraint.elem_position_b = cloth_sim.deformation_pos[v];
366
367 length_constraint.length = 0.0f;
368 length_constraint.strength = strength;
369
370 cloth_sim.length_constraints.append(length_constraint);
371}
372
373static void add_constraints_for_verts(const Object &object,
374 const Brush *brush,
375 const float3 &cloth_sim_initial_location,
376 const float cloth_sim_radius,
377 const Span<float3> init_positions,
378 const int node_index,
379 const Span<int> verts,
380 const GroupedSpan<int> vert_neighbors,
381 SimulationData &cloth_sim,
382 Set<OrderedEdge> &created_length_constraints)
383{
384 const SculptSession &ss = *object.sculpt;
385
386 const bool is_brush_has_stroke_cache = ss.cache != nullptr && brush != nullptr;
387 const bool pin_simulation_boundary = is_brush_has_stroke_cache &&
391
392 /* Brush can be nullptr in tools that use the solver without relying of constraints with
393 * deformation positions. */
394 const bool cloth_is_deform_brush = is_brush_has_stroke_cache && is_cloth_deform_brush(*brush);
395
396 const bool use_falloff_plane = brush->cloth_force_falloff_type ==
398 float radius_squared = 0.0f;
399 if (cloth_is_deform_brush) {
400 radius_squared = ss.cache->initial_radius * ss.cache->initial_radius;
401 }
402
403 /* Only limit the constraint creation to a radius when the simulation is local. */
404 const float cloth_sim_radius_squared = brush->cloth_simulation_area_type ==
406 cloth_sim_radius * cloth_sim_radius :
407 FLT_MAX;
408
409 for (const int i : verts.index_range()) {
410 const int vert = verts[i];
411 const float len_squared = math::distance_squared(init_positions[vert],
412 cloth_sim_initial_location);
413 if (len_squared < cloth_sim_radius_squared) {
414 if (cloth_sim.softbody_strength > 0.0f) {
415 cloth_brush_add_softbody_constraint(cloth_sim, node_index, vert, 1.0f);
416 }
417
418 const Span<int> neighbors = vert_neighbors[i];
419
420 /* As we don't know the order of the neighbor vertices, we create all possible combinations
421 * between the neighbor and the original vertex as length constraints. */
422 /* This results on a pattern that contains structural, shear and bending constraints for all
423 * vertices, but constraints are repeated taking more memory than necessary. */
424 for (const int neighbor : neighbors) {
425 if (created_length_constraints.add({vert, neighbor})) {
426 cloth_brush_add_length_constraint(cloth_sim, node_index, vert, neighbor, init_positions);
427 }
428 }
429 for (const int a : neighbors) {
430 for (const int b : neighbors) {
431 if (a != b) {
432 if (created_length_constraints.add({a, b})) {
433 cloth_brush_add_length_constraint(cloth_sim, node_index, a, b, init_positions);
434 }
435 }
436 }
437 }
438 }
439
440 if (is_brush_has_stroke_cache && brush->sculpt_brush_type == SCULPT_BRUSH_TYPE_CLOTH) {
441 /* The cloth brush works by applying forces in most of its modes, but some of them require
442 * deformation coordinates to make the simulation stable. */
444 if (use_falloff_plane) {
445 /* With plane falloff the strength of the constraints is set when applying the
446 * deformation forces. */
448 cloth_sim, node_index, vert, CLOTH_DEFORMATION_GRAB_STRENGTH);
449 }
450 else if (len_squared < radius_squared) {
451 /* With radial falloff deformation constraints are created with different strengths and
452 * only inside the radius of the brush. */
453 const float fade = BKE_brush_curve_strength(
454 brush, std::sqrt(len_squared), ss.cache->radius);
456 cloth_sim, node_index, vert, fade * CLOTH_DEFORMATION_GRAB_STRENGTH);
457 }
458 }
460 /* Cloth Snake Hook creates deformation constraint with fixed strength because the strength
461 * is controlled per iteration using cloth_sim.deformation_strength. */
463 cloth_sim, node_index, vert, CLOTH_DEFORMATION_SNAKEHOOK_STRENGTH);
464 }
465 }
466 else if (!cloth_sim.deformation_pos.is_empty()) {
467 /* Any other tool that target the cloth simulation handle the falloff in
468 * their own code when modifying the deformation coordinates of the simulation, so
469 * deformation constraints are created with a fixed strength for all vertices. */
471 cloth_sim, node_index, vert, CLOTH_DEFORMATION_TARGET_STRENGTH);
472 }
473
474 if (pin_simulation_boundary) {
475 const float sim_falloff = cloth_brush_simulation_falloff_get(
476 *brush, ss.cache->initial_radius, ss.cache->location_symm, init_positions[vert]);
477 /* Vertex is inside the area of the simulation without any falloff applied. */
478 if (sim_falloff < 1.0f) {
479 /* Create constraints with more strength the closer the vertex is to the simulation
480 * boundary. */
481 cloth_brush_add_pin_constraint(cloth_sim, node_index, vert, 1.0f - sim_falloff);
482 }
483 }
484 }
485}
486
488 Object &object,
489 const IndexMask &node_mask,
490 SimulationData &cloth_sim,
491 const float3 &initial_location,
492 const float radius)
493{
494 SculptSession &ss = *object.sculpt;
495 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
496 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
497
498 /* TODO: Multi-threaded needs to be disabled for this task until implementing the optimization of
499 * storing the constraints per node. */
500 /* Currently all constrains are added to the same global array which can't be accessed from
501 * different threads. */
502
503 IndexMaskMemory memory;
504 Set<OrderedEdge> created_length_constraints;
505 Vector<int> vert_indices;
506 Vector<int> neighbor_offsets;
507 Vector<int> neighbor_data;
508 switch (pbvh.type()) {
511 const IndexMask uninitialized_nodes = IndexMask::from_predicate(
512 node_mask, GrainSize(1024), memory, [&](const int i) {
513 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
514 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_UNINITIALIZED;
515 });
516 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
517 const OffsetIndices faces = mesh.faces();
518 const Span<int> corner_verts = mesh.corner_verts();
519 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
520 const bke::AttributeAccessor attributes = mesh.attributes();
521 const VArraySpan<bool> hide_vert = *attributes.lookup<bool>(".hide_vert",
523 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly",
525
526 Span<float3> init_positions;
527 VArraySpan<float3> persistent_position;
528 if (brush != nullptr && brush->flag & BRUSH_PERSISTENT) {
529 persistent_position = *attributes.lookup<float3>(".sculpt_persistent_co",
531 }
532 if (persistent_position.is_empty()) {
533 init_positions = cloth_sim.init_pos;
534 }
535 else {
536 init_positions = persistent_position;
537 }
538 uninitialized_nodes.foreach_index([&](const int i) {
539 const Span<int> verts = hide::node_visible_verts(nodes[i], hide_vert, vert_indices);
541 corner_verts,
542 vert_to_face_map,
543 hide_poly,
544 verts,
545 neighbor_offsets,
546 neighbor_data);
548 brush,
549 initial_location,
550 radius,
551 init_positions,
552 cloth_sim.node_state_index.lookup(&nodes[i]),
553 verts,
554 neighbors,
555 cloth_sim,
556 created_length_constraints);
557 });
558 break;
559 }
562 const IndexMask uninitialized_nodes = IndexMask::from_predicate(
563 node_mask, GrainSize(1024), memory, [&](const int i) {
564 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
565 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_UNINITIALIZED;
566 });
567 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
568 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
569 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
570
571 Span<float3> init_positions;
572 Span<float3> persistent_position;
573 const std::optional<PersistentMultiresData> persistent_multires_data =
575 if (brush != nullptr && brush->flag & BRUSH_PERSISTENT && persistent_multires_data) {
576 persistent_position = persistent_multires_data->positions;
577 }
578 if (persistent_position.is_empty()) {
579 init_positions = cloth_sim.init_pos;
580 }
581 else {
582 init_positions = persistent_position;
583 }
584 uninitialized_nodes.foreach_index([&](const int i) {
586 key, grid_hidden, nodes[i].grids(), vert_indices);
588 subdiv_ccg, verts, neighbor_offsets, neighbor_data);
590 brush,
591 initial_location,
592 radius,
593 init_positions,
594 cloth_sim.node_state_index.lookup(&nodes[i]),
595 verts,
596 neighbors,
597 cloth_sim,
598 created_length_constraints);
599 });
600 break;
601 }
604 const IndexMask uninitialized_nodes = IndexMask::from_predicate(
605 node_mask, GrainSize(1024), memory, [&](const int i) {
606 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
607 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_UNINITIALIZED;
608 });
609 BMesh &bm = *ss.bm;
611 uninitialized_nodes.foreach_index([&](const int i) {
613 const Span<int> verts = calc_visible_vert_indices_bmesh(bm_verts, vert_indices);
615 bm, verts, neighbor_offsets, neighbor_data);
617 brush,
618 initial_location,
619 radius,
620 cloth_sim.init_pos,
621 cloth_sim.node_state_index.lookup(&nodes[i]),
622 verts,
623 neighbors,
624 cloth_sim,
625 created_length_constraints);
626 });
627 break;
628 }
629 }
630}
631
633 const Span<float3> forces,
634 const Span<int> verts)
635{
636 const float mass_inv = math::rcp(cloth_sim.mass);
637 for (const int i : verts.index_range()) {
638 cloth_sim.acceleration[verts[i]] += forces[i] * mass_inv;
639 }
640}
641
643 const Span<int> verts,
644 const Span<float> factors)
645{
646 MutableSpan<float> length_constraint_tweak = cloth_sim.length_constraint_tweak;
647 for (const int i : verts.index_range()) {
648 length_constraint_tweak[verts[i]] += factors[i] * 0.01f;
649 }
650}
651
653 const float4 &plane,
654 const MutableSpan<float> distances)
655{
656 for (const int i : positions.index_range()) {
657 distances[i] = dist_to_plane_v3(positions[i], plane);
658 }
659}
660
662 const float min,
663 const float max)
664{
665 for (float &factor : factors) {
666 factor = std::clamp(factor, min, max);
667 }
668}
669
671 const Span<int> verts,
672 const MutableSpan<float> factors,
673 const bool use_falloff_plane,
674 const float3 &grab_delta_symmetry)
675{
676 for (const int i : verts.index_range()) {
677 cloth_sim.deformation_pos[verts[i]] = cloth_sim.init_pos[verts[i]] +
678 grab_delta_symmetry * factors[i];
679 }
680 if (use_falloff_plane) {
681 clamp_factors(factors, 0.0f, 1.0f);
683 }
684 else {
686 }
687}
688
690 const Span<int> verts,
691 const MutableSpan<float> factors,
692 const float3 &grab_delta_symmetry)
693{
694 for (const int i : verts.index_range()) {
695 const int vert = verts[i];
696 cloth_sim.deformation_pos[vert] = cloth_sim.pos[vert] + grab_delta_symmetry * factors[i];
697 }
699}
700
701BLI_NOINLINE static void calc_pinch_forces(const Span<float3> positions,
702 const float3 &location,
703 const MutableSpan<float3> forces)
704{
705 for (const int i : forces.index_range()) {
706 forces[i] = math::normalize(location - positions[i]);
707 }
708}
709
711 const float4 &plane,
712 const float3 &plane_normal,
713 const MutableSpan<float3> forces)
714{
715 for (const int i : positions.index_range()) {
716 const float distance = dist_signed_to_plane_v3(positions[i], plane);
717 forces[i] = math::normalize(plane_normal * -distance);
718 }
719}
720
722 const float4x4 &imat,
723 const float3 &location,
724 const MutableSpan<float3> forces)
725{
726 const float3 x_object_space = math::normalize(imat.x_axis());
727 const float3 z_object_space = math::normalize(imat.z_axis());
728 for (const int i : positions.index_range()) {
729 const float3 disp_center = math::normalize(location - positions[i]);
730 const float3 x_disp = x_object_space * math::dot(disp_center, x_object_space);
731 const float3 z_disp = z_object_space * math::dot(disp_center, z_object_space);
732 forces[i] = x_disp + z_disp;
733 }
734}
735
746
751
752static void calc_forces_mesh(const Depsgraph &depsgraph,
753 Object &ob,
754 const Brush &brush,
755 const float3 &offset,
756 const float4x4 &imat,
757 const float3 &sim_location,
758 const float3 &gravity,
759 const std::optional<FalloffPlane> &falloff_plane,
760 const MeshAttributeData &attribute_data,
761 const Span<float3> positions_eval,
762 const Span<float3> vert_normals,
763 const bke::pbvh::MeshNode &node,
764 LocalData &tls)
765{
766 SculptSession &ss = *ob.sculpt;
767 SimulationData &cloth_sim = *ss.cache->cloth_sim;
768 const StrokeCache &cache = *ss.cache;
769
770 const Span<int> verts = node.verts();
771 const MutableSpan positions = gather_data_mesh(positions_eval, verts, tls.positions);
772 const MutableSpan init_positions = gather_data_mesh(
773 cloth_sim.init_pos.as_span(), verts, tls.init_positions);
774 const Span<float3> current_positions = brush.cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB ?
775 init_positions :
776 positions;
777
778 tls.factors.resize(verts.size());
779 const MutableSpan<float> factors = tls.factors;
780 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
781 filter_region_clip_factors(ss, current_positions, factors);
782
783 calc_brush_simulation_falloff(brush, cache.radius, sim_location, positions, factors);
784
785 tls.translations.resize(verts.size());
786 const MutableSpan<float3> forces = tls.translations;
787
788 /* Apply gravity in the entire simulation area before brush distances are taken into account. */
789 if (!math::is_zero(gravity)) {
790 translations_from_offset_and_factors(gravity, factors, forces);
791 apply_forces(cloth_sim, forces, verts);
792 }
793
794 if (brush.flag & BRUSH_FRONTFACE) {
795 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
796 }
797
798 tls.distances.resize(verts.size());
799 const MutableSpan<float> distances = tls.distances;
800 if (falloff_plane) {
801 calc_distances_to_plane(current_positions, falloff_plane->plane, distances);
802 }
803 else {
805 ss, current_positions, eBrushFalloffShape(brush.falloff_shape), distances);
806 }
807 filter_distances_with_radius(cache.radius, distances, factors);
808 apply_hardness_to_distances(cache, distances);
809 calc_brush_strength_factors(cache, brush, distances, factors);
810
811 const auto_mask::Cache *automask = auto_mask::active_cache_get(ss);
812 auto_mask::calc_vert_factors(depsgraph, ob, automask, node, verts, factors);
813
814 calc_brush_texture_factors(ss, brush, current_positions, factors);
815
816 scale_factors(factors, cache.bstrength);
817
818 switch (brush.cloth_deform_type) {
821 math::normalize(cache.location_symm - cache.last_location_symm), factors, forces);
822 apply_forces(cloth_sim, forces, verts);
823 break;
825 translations_from_offset_and_factors(-offset, factors, forces);
826 apply_forces(cloth_sim, forces, verts);
827 break;
830 cloth_sim, verts, factors, falloff_plane.has_value(), cache.grab_delta_symm);
831 break;
833 apply_snake_hook_brush(cloth_sim, verts, factors, cache.grab_delta_symm);
834 break;
836 if (falloff_plane) {
837 calc_plane_pinch_forces(positions, falloff_plane->plane, falloff_plane->normal, forces);
838 }
839 else {
840 calc_pinch_forces(positions, cache.location_symm, forces);
841 }
842 scale_translations(forces, factors);
843 apply_forces(cloth_sim, forces, verts);
844 break;
846 calc_perpendicular_pinch_forces(positions, imat, cache.location_symm, forces);
847 scale_translations(forces, factors);
848 apply_forces(cloth_sim, forces, verts);
849 break;
850 }
852 gather_data_mesh(vert_normals, verts, forces);
853 scale_translations(forces, factors);
854 apply_forces(cloth_sim, forces, verts);
855 break;
857 expand_length_constraints(cloth_sim, verts, factors);
858 break;
859 }
860}
861
862static void calc_forces_grids(const Depsgraph &depsgraph,
863 Object &ob,
864 const Brush &brush,
865 const float3 &offset,
866 const float4x4 &imat,
867 const float3 &sim_location,
868 const float3 &gravity,
869 const std::optional<FalloffPlane> &falloff_plane,
870 const bke::pbvh::GridsNode &node,
871 LocalData &tls)
872{
873 SculptSession &ss = *ob.sculpt;
874 SimulationData &cloth_sim = *ss.cache->cloth_sim;
875 const StrokeCache &cache = *ss.cache;
876 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
877 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
878
879 const Span<int> grids = node.grids();
880 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
881 const MutableSpan init_positions = gather_data_grids(
882 subdiv_ccg, cloth_sim.init_pos.as_span(), grids, tls.init_positions);
883 const Span<float3> current_positions = brush.cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB ?
884 init_positions :
885 positions;
886
887 tls.factors.resize(positions.size());
888 const MutableSpan<float> factors = tls.factors;
889 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
890 filter_region_clip_factors(ss, current_positions, factors);
891
892 calc_brush_simulation_falloff(brush, cache.radius, sim_location, positions, factors);
893
894 const Span<int> verts = calc_vert_indices_grids(key, grids, tls.vert_indices);
895
896 tls.translations.resize(verts.size());
897 const MutableSpan<float3> forces = tls.translations;
898
899 /* Apply gravity in the entire simulation area before brush distances are taken into account. */
900 if (!math::is_zero(gravity)) {
901 translations_from_offset_and_factors(gravity, factors, forces);
902 apply_forces(cloth_sim, forces, verts);
903 }
904
905 if (brush.flag & BRUSH_FRONTFACE) {
906 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
907 }
908
909 tls.distances.resize(verts.size());
910 const MutableSpan<float> distances = tls.distances;
911 if (falloff_plane) {
912 calc_distances_to_plane(current_positions, falloff_plane->plane, distances);
913 }
914 else {
916 ss, current_positions, eBrushFalloffShape(brush.falloff_shape), distances);
917 }
918 filter_distances_with_radius(cache.radius, distances, factors);
919 apply_hardness_to_distances(cache, distances);
920 calc_brush_strength_factors(cache, brush, distances, factors);
921
922 const auto_mask::Cache *automask = auto_mask::active_cache_get(ss);
923 auto_mask::calc_grids_factors(depsgraph, ob, automask, node, grids, factors);
924
925 calc_brush_texture_factors(ss, brush, current_positions, factors);
926
927 scale_factors(factors, cache.bstrength);
928
929 switch (brush.cloth_deform_type) {
932 math::normalize(cache.location_symm - cache.last_location_symm), factors, forces);
933 apply_forces(cloth_sim, forces, verts);
934 break;
936 translations_from_offset_and_factors(-offset, factors, forces);
937 apply_forces(cloth_sim, forces, verts);
938 break;
941 cloth_sim, verts, factors, falloff_plane.has_value(), cache.grab_delta_symm);
942 break;
944 apply_snake_hook_brush(cloth_sim, verts, factors, cache.grab_delta_symm);
945 break;
947 if (falloff_plane) {
948 calc_plane_pinch_forces(positions, falloff_plane->plane, falloff_plane->normal, forces);
949 }
950 else {
951 calc_pinch_forces(positions, cache.location_symm, forces);
952 }
953 scale_translations(forces, factors);
954 apply_forces(cloth_sim, forces, verts);
955 break;
957 calc_perpendicular_pinch_forces(positions, imat, cache.location_symm, forces);
958 scale_translations(forces, factors);
959 apply_forces(cloth_sim, forces, verts);
960 break;
961 }
963 gather_grids_normals(subdiv_ccg, grids, forces);
964 scale_translations(forces, factors);
965 apply_forces(cloth_sim, forces, verts);
966 break;
968 expand_length_constraints(cloth_sim, verts, factors);
969 break;
970 }
971}
972
973static void calc_forces_bmesh(const Depsgraph &depsgraph,
974 Object &ob,
975 const Brush &brush,
976 const float3 &offset,
977 const float4x4 &imat,
978 const float3 &sim_location,
979 const float3 &gravity,
980 const std::optional<FalloffPlane> &falloff_plane,
982 LocalData &tls)
983{
984 SculptSession &ss = *ob.sculpt;
985 SimulationData &cloth_sim = *ss.cache->cloth_sim;
986 const StrokeCache &cache = *ss.cache;
987
988 const Set<BMVert *, 0> &bm_verts = BKE_pbvh_bmesh_node_unique_verts(&node);
990
991 const MutableSpan positions = gather_bmesh_positions(bm_verts, tls.positions);
992 const MutableSpan init_positions = gather_data_mesh(
993 cloth_sim.init_pos.as_span(), verts, tls.init_positions);
994 const Span<float3> current_positions = brush.cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB ?
995 init_positions :
996 positions;
997
998 tls.factors.resize(verts.size());
999 const MutableSpan<float> factors = tls.factors;
1000 fill_factor_from_hide_and_mask(*ss.bm, bm_verts, factors);
1001 filter_region_clip_factors(ss, current_positions, factors);
1002
1003 calc_brush_simulation_falloff(brush, cache.radius, sim_location, positions, factors);
1004
1005 tls.translations.resize(verts.size());
1006 const MutableSpan<float3> forces = tls.translations;
1007
1008 /* Apply gravity in the entire simulation area before brush distances are taken into account. */
1009 if (!math::is_zero(gravity)) {
1010 translations_from_offset_and_factors(gravity, factors, forces);
1011 apply_forces(cloth_sim, forces, verts);
1012 }
1013
1014 if (brush.flag & BRUSH_FRONTFACE) {
1015 calc_front_face(cache.view_normal_symm, bm_verts, factors);
1016 }
1017
1018 tls.distances.resize(verts.size());
1019 const MutableSpan<float> distances = tls.distances;
1020 if (falloff_plane) {
1021 calc_distances_to_plane(current_positions, falloff_plane->plane, distances);
1022 }
1023 else {
1025 ss, current_positions, eBrushFalloffShape(brush.falloff_shape), distances);
1026 }
1027 filter_distances_with_radius(cache.radius, distances, factors);
1028 apply_hardness_to_distances(cache, distances);
1029 calc_brush_strength_factors(cache, brush, distances, factors);
1030
1031 const auto_mask::Cache *automask = auto_mask::active_cache_get(ss);
1032 auto_mask::calc_vert_factors(depsgraph, ob, automask, node, bm_verts, factors);
1033
1034 calc_brush_texture_factors(ss, brush, current_positions, factors);
1035
1036 scale_factors(factors, cache.bstrength);
1037
1038 switch (brush.cloth_deform_type) {
1041 math::normalize(cache.location_symm - cache.last_location_symm), factors, forces);
1042 apply_forces(cloth_sim, forces, verts);
1043 break;
1045 translations_from_offset_and_factors(-offset, factors, forces);
1046 apply_forces(cloth_sim, forces, verts);
1047 break;
1050 cloth_sim, verts, factors, falloff_plane.has_value(), cache.grab_delta_symm);
1051 break;
1053 apply_snake_hook_brush(cloth_sim, verts, factors, cache.grab_delta_symm);
1054 break;
1056 if (falloff_plane) {
1057 calc_plane_pinch_forces(positions, falloff_plane->plane, falloff_plane->normal, forces);
1058 }
1059 else {
1060 calc_pinch_forces(positions, cache.location_symm, forces);
1061 }
1062 scale_translations(forces, factors);
1063 apply_forces(cloth_sim, forces, verts);
1064 break;
1066 calc_perpendicular_pinch_forces(positions, imat, cache.location_symm, forces);
1067 scale_translations(forces, factors);
1068 apply_forces(cloth_sim, forces, verts);
1069 break;
1070 }
1072 gather_bmesh_normals(bm_verts, forces);
1073 scale_translations(forces, factors);
1074 apply_forces(cloth_sim, forces, verts);
1075 break;
1077 expand_length_constraints(cloth_sim, verts, factors);
1078 break;
1079 }
1080}
1081
1083 const Depsgraph &depsgraph)
1084{
1086 DEGObjectIterSettings deg_iter_settings = {nullptr};
1087 deg_iter_settings.depsgraph = &const_cast<Depsgraph &>(depsgraph);
1090 DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, ob) {
1091 if (STREQ(object.id.name, ob->id.name)) {
1092 continue;
1093 }
1094
1097 if (!cmd) {
1098 continue;
1099 }
1100
1101 if (!cmd->bvhtree) {
1102 continue;
1103 }
1104
1106 col.ob = ob;
1107 col.collmd = cmd;
1108 collision_move_object(cmd, 1.0, 0.0, true);
1109 cache.append(col);
1110 }
1112 return cache;
1113}
1114
1119
1120static void cloth_brush_collision_cb(void *userdata,
1121 int index,
1122 const BVHTreeRay *ray,
1123 BVHTreeRayHit *hit)
1124{
1126 CollisionModifierData *col_data = col->col_data;
1127 const int3 vert_tri = col_data->vert_tris[index];
1128 float (*positions)[3] = col_data->x;
1129 float *tri[3], no[3], co[3];
1130
1131 tri[0] = positions[vert_tri[0]];
1132 tri[1] = positions[vert_tri[1]];
1133 tri[2] = positions[vert_tri[2]];
1134 float dist = 0.0f;
1135
1136 bool tri_hit = isect_ray_tri_watertight_v3(
1137 ray->origin, &col->isect_precalc, UNPACK3(tri), &dist, nullptr);
1138 normal_tri_v3(no, UNPACK3(tri));
1139 madd_v3_v3v3fl(co, ray->origin, ray->direction, dist);
1140
1141 if (tri_hit && dist < hit->dist) {
1142 hit->index = index;
1143 hit->dist = dist;
1144
1145 copy_v3_v3(hit->co, co);
1146 copy_v3_v3(hit->no, no);
1147 }
1148}
1149
1150static void cloth_brush_solve_collision(const Object &object,
1151 SimulationData &cloth_sim,
1152 const int i)
1153{
1154 const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT;
1155
1156 const float4x4 &object_to_world = object.object_to_world();
1157 const float4x4 &world_to_object = object.world_to_object();
1158
1159 for (const ColliderCache &collider_cache : cloth_sim.collider_list) {
1160 const float3 pos_world_space = math::transform_point(object_to_world, cloth_sim.pos[i]);
1161 const float3 prev_pos_world_space = math::transform_point(object_to_world,
1162 cloth_sim.last_iteration_pos[i]);
1163
1164 BVHTreeRayHit hit{};
1165 hit.index = -1;
1166
1167 const float3 ray_normal = math::normalize_and_get_length(
1168 pos_world_space - prev_pos_world_space, hit.dist);
1169
1171 CollisionModifierData *collmd = collider_cache.collmd;
1172 col.col_data = collmd;
1173 isect_ray_tri_watertight_v3_precalc(&col.isect_precalc, ray_normal);
1174
1176 prev_pos_world_space,
1177 ray_normal,
1178 0.3f,
1179 &hit,
1181 &col,
1182 raycast_flag);
1183
1184 if (hit.index == -1) {
1185 continue;
1186 }
1187
1188 const float3 collision_disp = float3(hit.no) * 0.005f;
1189
1190 float4 friction_plane;
1191 plane_from_point_normal_v3(friction_plane, hit.co, hit.no);
1192 float3 pos_on_friction_plane;
1193 closest_to_plane_v3(pos_on_friction_plane, friction_plane, pos_world_space);
1194 constexpr float friction_factor = 0.35f;
1195 const float3 movement_disp = (pos_on_friction_plane - float3(hit.co)) * friction_factor;
1196
1197 cloth_sim.pos[i] = math::transform_point(world_to_object,
1198 float3(hit.co) + movement_disp + collision_disp);
1199 }
1200}
1201
1203 const Brush *brush,
1204 const float3 &sim_location,
1205 const Span<int> verts,
1206 const MutableSpan<float> factors,
1207 LocalData &tls,
1208 SimulationData &cloth_sim)
1209{
1210 const SculptSession &ss = *object.sculpt;
1211
1212 tls.diffs.resize(verts.size());
1213 const MutableSpan<float3> pos_diff = tls.diffs;
1214 for (const int i : verts.index_range()) {
1215 pos_diff[i] = cloth_sim.pos[verts[i]] - cloth_sim.prev_pos[verts[i]];
1216 }
1217
1218 for (const int vert : verts) {
1219 cloth_sim.prev_pos[vert] = cloth_sim.pos[vert];
1220 }
1221
1222 for (const int i : verts.index_range()) {
1223 const int vert = verts[i];
1224 cloth_sim.pos[vert] += cloth_sim.acceleration[vert] * factors[i] * CLOTH_SIMULATION_TIME_STEP;
1225 }
1226
1227 scale_factors(factors, 1.0f - cloth_sim.damping);
1228 if (ss.cache) {
1229 const MutableSpan positions = gather_data_mesh(
1230 cloth_sim.init_pos.as_span(), verts, tls.positions);
1231 calc_brush_simulation_falloff(*brush, ss.cache->radius, sim_location, positions, factors);
1232 }
1233 scale_translations(pos_diff, factors);
1234
1235 for (const int i : verts.index_range()) {
1236 const int vert = verts[i];
1237 cloth_sim.pos[vert] += pos_diff[i];
1238 }
1239
1240 for (const int vert : verts) {
1241 cloth_brush_solve_collision(object, cloth_sim, vert);
1242 }
1243
1244 for (const int vert : verts) {
1245 cloth_sim.last_iteration_pos[vert] = cloth_sim.pos[vert];
1246 }
1247
1248 cloth_sim.acceleration.as_mutable_span().fill_indices(verts, float3(0));
1249}
1250
1251static void calc_constraint_factors(const Depsgraph &depsgraph,
1252 const Object &object,
1253 const Brush *brush,
1254 const float3 &sim_location,
1255 const Span<float3> init_positions,
1256 const MutableSpan<float> cloth_factors)
1257{
1258 const SculptSession &ss = *object.sculpt;
1259 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1260 IndexMaskMemory memory;
1261 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1262
1263 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
1264
1265 struct LocalData {
1268 };
1270 switch (pbvh.type()) {
1271 case bke::pbvh::Type::Mesh: {
1272 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1273 const MeshAttributeData attribute_data(mesh);
1275 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1276 LocalData &tls = all_tls.local();
1277 const Span<int> verts = nodes[i].verts();
1278 tls.factors.resize(verts.size());
1279 const MutableSpan<float> factors = tls.factors;
1281 attribute_data.hide_vert, attribute_data.mask, verts, factors);
1282 auto_mask::calc_vert_factors(depsgraph, object, automasking, nodes[i], verts, factors);
1283 if (ss.cache) {
1284 const MutableSpan positions = gather_data_mesh(init_positions, verts, tls.positions);
1286 *brush, ss.cache->radius, sim_location, positions, factors);
1287 }
1288 scatter_data_mesh(factors.as_span(), verts, cloth_factors);
1289 });
1290 break;
1291 }
1293 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1294 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1296 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1297 LocalData &tls = all_tls.local();
1298 const Span<int> grids = nodes[i].grids();
1299 const int grid_verts_num = grids.size() * key.grid_area;
1300 tls.factors.resize(grid_verts_num);
1301 const MutableSpan<float> factors = tls.factors;
1302 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
1303 auto_mask::calc_grids_factors(depsgraph, object, automasking, nodes[i], grids, factors);
1304 if (ss.cache) {
1305 const Span<float3> positions = gather_data_grids(
1306 subdiv_ccg, init_positions, grids, tls.positions);
1308 *brush, ss.cache->radius, sim_location, positions, factors);
1309 }
1310 scatter_data_grids(subdiv_ccg, factors.as_span(), grids, cloth_factors);
1311 });
1312 break;
1313 }
1315 const BMesh &bm = *ss.bm;
1317 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1318 LocalData &tls = all_tls.local();
1320 const_cast<bke::pbvh::BMeshNode *>(&nodes[i]));
1321 tls.factors.resize(verts.size());
1322 const MutableSpan<float> factors = tls.factors;
1324 auto_mask::calc_vert_factors(depsgraph, object, automasking, nodes[i], verts, factors);
1325 if (ss.cache) {
1326 const MutableSpan positions = gather_data_bmesh(init_positions, verts, tls.positions);
1328 *brush, ss.cache->radius, sim_location, positions, factors);
1329 }
1330 scatter_data_bmesh(factors.as_span(), verts, cloth_factors);
1331 });
1332 break;
1333 }
1334 }
1335}
1336
1337static void cloth_brush_satisfy_constraints(const Depsgraph &depsgraph,
1338 const Object &object,
1339 const Brush *brush,
1340 SimulationData &cloth_sim)
1341{
1342 const SculptSession &ss = *object.sculpt;
1343
1344 const float3 sim_location = cloth_brush_simulation_location_get(ss, brush);
1345
1346 /* Precalculate factors into an array since we need random access to specific vertex values. */
1347 Array<float> factors(SCULPT_vertex_count_get(object));
1348 calc_constraint_factors(depsgraph, object, brush, sim_location, cloth_sim.init_pos, factors);
1349
1350 for (int constraint_it = 0; constraint_it < CLOTH_SIMULATION_ITERATIONS; constraint_it++) {
1351 for (const LengthConstraint &constraint : cloth_sim.length_constraints) {
1352 if (cloth_sim.node_state[constraint.node] != SCULPT_CLOTH_NODE_ACTIVE) {
1353 /* Skip all constraints that were created for inactive nodes. */
1354 continue;
1355 }
1356
1357 const int v1 = constraint.elem_index_a;
1358 const int v2 = constraint.elem_index_b;
1359
1360 const float3 v1_to_v2 = float3(constraint.elem_position_b) -
1361 float3(constraint.elem_position_a);
1362 const float current_distance = math::length(v1_to_v2);
1363 float3 correction_vector;
1364
1365 const float constraint_distance = constraint.length +
1366 (cloth_sim.length_constraint_tweak[v1] * 0.5f) +
1367 (cloth_sim.length_constraint_tweak[v2] * 0.5f);
1368
1369 if (current_distance > 0.0f) {
1370 correction_vector = v1_to_v2 * CLOTH_SOLVER_DISPLACEMENT_FACTOR *
1371 (1.0f - (constraint_distance / current_distance));
1372 }
1373 else {
1374 correction_vector = v1_to_v2 * CLOTH_SOLVER_DISPLACEMENT_FACTOR;
1375 }
1376
1377 const float3 correction_vector_half = correction_vector * 0.5f;
1378
1379 const float factor_v1 = factors[v1];
1380 const float factor_v2 = factors[v2];
1381
1382 float deformation_strength = 1.0f;
1383 if (constraint.type == SCULPT_CLOTH_CONSTRAINT_DEFORMATION) {
1384 deformation_strength = (cloth_sim.deformation_strength[v1] +
1385 cloth_sim.deformation_strength[v2]) *
1386 0.5f;
1387 }
1388
1389 if (constraint.type == SCULPT_CLOTH_CONSTRAINT_SOFTBODY) {
1390 const float softbody_plasticity = brush ? brush->cloth_constraint_softbody_strength : 0.0f;
1391 cloth_sim.pos[v1] += correction_vector_half *
1392 (1.0f * factor_v1 * constraint.strength * softbody_plasticity);
1393 cloth_sim.softbody_pos[v1] += correction_vector_half * -1.0f * factor_v1 *
1394 constraint.strength * (1.0f - softbody_plasticity);
1395 }
1396 else {
1397 cloth_sim.pos[v1] += correction_vector_half * 1.0f * factor_v1 * constraint.strength *
1398 deformation_strength;
1399 if (v1 != v2) {
1400 cloth_sim.pos[v2] += correction_vector_half * -1.0f * factor_v2 * constraint.strength *
1401 deformation_strength;
1402 }
1403 }
1404 }
1405 }
1406}
1407
1408void do_simulation_step(const Depsgraph &depsgraph,
1409 const Sculpt &sd,
1410 Object &object,
1411 SimulationData &cloth_sim,
1412 const IndexMask &node_mask)
1413{
1414 SculptSession &ss = *object.sculpt;
1415 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1416 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1417
1418 /* Update the constraints. */
1419 cloth_brush_satisfy_constraints(depsgraph, object, brush, cloth_sim);
1420
1421 const float3 sim_location = cloth_brush_simulation_location_get(ss, brush);
1422
1423 IndexMaskMemory memory;
1425 switch (pbvh.type()) {
1426 case bke::pbvh::Type::Mesh: {
1428 const IndexMask active_nodes = IndexMask::from_predicate(
1429 node_mask, GrainSize(1024), memory, [&](const int i) {
1430 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1431 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_ACTIVE;
1432 });
1433 Mesh &mesh = *static_cast<Mesh *>(object.data);
1434 const MeshAttributeData attribute_data(mesh);
1435 const PositionDeformData position_data(depsgraph, object);
1436 active_nodes.foreach_index(GrainSize(1), [&](const int i) {
1437 LocalData &tls = all_tls.local();
1438 const Span<int> verts = nodes[i].verts();
1439
1440 tls.factors.resize(verts.size());
1441 const MutableSpan<float> factors = tls.factors;
1443 attribute_data.hide_vert, attribute_data.mask, verts, factors);
1444 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
1445 auto_mask::calc_vert_factors(depsgraph, object, automasking, nodes[i], verts, factors);
1446
1447 solve_verts_simulation(object, brush, sim_location, verts, factors, tls, cloth_sim);
1448
1449 tls.translations.resize(verts.size());
1450 const MutableSpan<float3> translations = tls.translations;
1451 for (const int i : verts.index_range()) {
1452 translations[i] = cloth_sim.pos[verts[i]] - position_data.eval[verts[i]];
1453 }
1454
1455 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
1456 position_data.deform(translations, verts);
1457
1458 cloth_sim.node_state[cloth_sim.node_state_index.lookup(&nodes[i])] =
1460 bke::pbvh::update_node_bounds_mesh(position_data.eval, nodes[i]);
1461 });
1462 break;
1463 }
1466 const IndexMask active_nodes = IndexMask::from_predicate(
1467 node_mask, GrainSize(1024), memory, [&](const int i) {
1468 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1469 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_ACTIVE;
1470 });
1471 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1472 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1473 const Span<float3> cloth_positions = cloth_sim.pos;
1474 MutableSpan<float3> positions = subdiv_ccg.positions;
1475 active_nodes.foreach_index(GrainSize(1), [&](const int i) {
1476 LocalData &tls = all_tls.local();
1477 const Span<int> grids = nodes[i].grids();
1478 const int grid_verts_num = grids.size() * key.grid_area;
1479
1480 tls.factors.resize(grid_verts_num);
1481 const MutableSpan<float> factors = tls.factors;
1482 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
1483 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
1484 auto_mask::calc_grids_factors(depsgraph, object, automasking, nodes[i], grids, factors);
1485
1486 const Span<int> verts = calc_vert_indices_grids(key, grids, tls.vert_indices);
1487 solve_verts_simulation(object, brush, sim_location, verts, factors, tls, cloth_sim);
1488
1489 for (const int grid : grids) {
1490 const IndexRange grid_range = bke::ccg::grid_range(key, grid);
1491 positions.slice(grid_range).copy_from(cloth_positions.slice(grid_range));
1492 }
1493
1494 cloth_sim.node_state[cloth_sim.node_state_index.lookup(&nodes[i])] =
1496 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
1497 });
1498 break;
1499 }
1502 const IndexMask active_nodes = IndexMask::from_predicate(
1503 node_mask, GrainSize(1024), memory, [&](const int i) {
1504 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1505 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_ACTIVE;
1506 });
1507 BMesh &bm = *ss.bm;
1508 active_nodes.foreach_index(GrainSize(1), [&](const int i) {
1509 LocalData &tls = all_tls.local();
1511
1512 tls.factors.resize(verts.size());
1513 const MutableSpan<float> factors = tls.factors;
1515 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
1516 auto_mask::calc_vert_factors(depsgraph, object, automasking, nodes[i], verts, factors);
1517
1518 const Span<int> vert_indices = calc_vert_indices_bmesh(verts, tls.vert_indices);
1519 solve_verts_simulation(object, brush, sim_location, vert_indices, factors, tls, cloth_sim);
1520
1521 for (BMVert *vert : verts) {
1522 copy_v3_v3(vert->co, cloth_sim.pos[BM_elem_index_get(vert)]);
1523 }
1524
1525 cloth_sim.node_state[cloth_sim.node_state_index.lookup(&nodes[i])] =
1528 });
1529 break;
1530 }
1531 }
1532 pbvh.tag_positions_changed(node_mask);
1534}
1535
1536static void cloth_brush_apply_brush_forces(const Depsgraph &depsgraph,
1537 const Sculpt &sd,
1538 Object &ob,
1539 const IndexMask &node_mask)
1540{
1541 SculptSession &ss = *ob.sculpt;
1542 StrokeCache &cache = *ss.cache;
1543 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
1544
1545 float3 area_no;
1546 float3 area_co;
1547 float3 offset;
1548
1549 if (math::is_zero(cache.grab_delta_symm)) {
1550 return;
1551 }
1552
1553 float3 grab_delta = math::normalize(cache.grab_delta_symm);
1554
1555 /* Calculate push offset. */
1557 offset = cache.sculpt_normal_symm * cache.radius * cache.scale * 2.0f;
1558 }
1559
1563 {
1564 calc_brush_plane(depsgraph, brush, ob, node_mask, area_no, area_co);
1565
1566 /* Initialize stroke local space matrix. */
1567 mat.x_axis() = math::cross(area_no, cache.grab_delta_symm);
1568 mat.y_axis() = math::cross(area_no, mat.x_axis());
1569 mat.z_axis() = area_no;
1570 mat.location() = cache.location_symm;
1571 normalize_m4(mat.ptr());
1572
1573 /* Update matrix for the cursor preview. */
1574 if (cache.mirror_symmetry_pass == 0) {
1575 cache.stroke_local_mat = mat;
1576 }
1577 }
1578
1580 /* Set the deformation strength to 0. Brushes will initialize the strength in the required
1581 * area. */
1582 cache.cloth_sim->deformation_strength.fill(0.0f);
1583 }
1584
1585 const float3 sim_location = cloth_brush_simulation_location_get(ss, &brush);
1586
1587 /* Gravity */
1588 float3 gravity(0);
1589 if (cache.supports_gravity) {
1590 gravity += cache.gravity_direction_symm * -sd.gravity_factor;
1591 }
1592
1593 std::optional<FalloffPlane> falloff_plane;
1595 falloff_plane.emplace();
1596 falloff_plane->normal = math::normalize(grab_delta);
1597 plane_from_point_normal_v3(falloff_plane->plane, area_co, falloff_plane->normal);
1598 }
1599
1601
1603 switch (pbvh.type()) {
1604 case bke::pbvh::Type::Mesh: {
1605 const Mesh &mesh = *static_cast<Mesh *>(ob.data);
1606 const MeshAttributeData attribute_data(mesh);
1607 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(depsgraph, ob);
1608 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1610 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1611 LocalData &tls = all_tls.local();
1613 ob,
1614 brush,
1615 offset,
1616 mat,
1617 sim_location,
1618 gravity,
1619 falloff_plane,
1620 attribute_data,
1621 positions_eval,
1622 vert_normals,
1623 nodes[i],
1624 tls);
1625 });
1626 break;
1627 }
1630 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1631 LocalData &tls = all_tls.local();
1633 ob,
1634 brush,
1635 offset,
1636 mat,
1637 sim_location,
1638 gravity,
1639 falloff_plane,
1640 nodes[i],
1641 tls);
1642 });
1643 break;
1644 }
1647 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1648 LocalData &tls = all_tls.local();
1650 ob,
1651 brush,
1652 offset,
1653 mat,
1654 sim_location,
1655 gravity,
1656 falloff_plane,
1657 nodes[i],
1658 tls);
1659 });
1660 break;
1661 }
1662 }
1663}
1664
1665/* Allocates nodes state and initializes them to Uninitialized, so constraints can be created for
1666 * them. */
1668{
1669 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1670 IndexMaskMemory memory;
1671 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1673
1674 switch (pbvh.type()) {
1675 case bke::pbvh::Type::Mesh: {
1677 node_mask.foreach_index([&](const int i) { cloth_sim.node_state_index.add(&nodes[i], i); });
1678 break;
1679 }
1682 node_mask.foreach_index([&](const int i) { cloth_sim.node_state_index.add(&nodes[i], i); });
1683 break;
1684 }
1687 node_mask.foreach_index([&](const int i) { cloth_sim.node_state_index.add(&nodes[i], i); });
1688 break;
1689 }
1690 }
1691}
1692
1693static void copy_positions_to_array(const Depsgraph &depsgraph,
1694 const Object &object,
1695 MutableSpan<float3> positions)
1696{
1697 const SculptSession &ss = *object.sculpt;
1698 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1699 switch (pbvh.type()) {
1702 break;
1704 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1705 positions.copy_from(subdiv_ccg.positions);
1706 break;
1707 }
1709 BM_mesh_vert_coords_get(ss.bm, positions);
1710 break;
1711 }
1712}
1713
1714static void copy_normals_to_array(const Depsgraph &depsgraph,
1715 const Object &object,
1717{
1718 const SculptSession &ss = *object.sculpt;
1719 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1720 switch (pbvh.type()) {
1723 break;
1725 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1726 normals.copy_from(subdiv_ccg.normals);
1727 break;
1728 }
1731 break;
1732 }
1733}
1734
1735std::unique_ptr<SimulationData> brush_simulation_create(const Depsgraph &depsgraph,
1736 Object &ob,
1737 const float cloth_mass,
1738 const float cloth_damping,
1739 const float cloth_softbody_strength,
1740 const bool use_collisions,
1741 const bool needs_deform_coords)
1742{
1743 const int totverts = SCULPT_vertex_count_get(ob);
1744 std::unique_ptr<SimulationData> cloth_sim = std::make_unique<SimulationData>();
1745
1746 cloth_sim->length_constraints.reserve(CLOTH_LENGTH_CONSTRAINTS_BLOCK);
1747
1748 cloth_sim->acceleration = Array<float3>(totverts, float3(0));
1749 cloth_sim->pos = Array<float3>(totverts, float3(0));
1750 cloth_sim->length_constraint_tweak = Array<float>(totverts, 0.0f);
1751
1752 cloth_sim->init_pos.reinitialize(totverts);
1753 copy_positions_to_array(depsgraph, ob, cloth_sim->init_pos);
1754
1755 cloth_sim->last_iteration_pos = cloth_sim->init_pos;
1756 cloth_sim->prev_pos = cloth_sim->init_pos;
1757
1758 cloth_sim->init_no.reinitialize(totverts);
1759 copy_normals_to_array(depsgraph, ob, cloth_sim->init_no);
1760
1761 if (needs_deform_coords) {
1762 cloth_sim->deformation_pos = cloth_sim->init_pos;
1763 cloth_sim->deformation_strength = Array<float>(totverts, 1.0f);
1764 }
1765
1766 if (cloth_softbody_strength > 0.0f) {
1767 cloth_sim->softbody_pos = cloth_sim->init_pos;
1768 }
1769
1770 cloth_sim->mass = cloth_mass;
1771 cloth_sim->damping = cloth_damping;
1772 cloth_sim->softbody_strength = cloth_softbody_strength;
1773
1774 if (use_collisions) {
1775 cloth_sim->collider_list = cloth_brush_collider_cache_create(ob, depsgraph);
1776 }
1777
1779
1780 return cloth_sim;
1781}
1782
1784 const Object &object,
1785 SimulationData &cloth_sim)
1786{
1787 copy_positions_to_array(depsgraph, object, cloth_sim.pos);
1788}
1789
1790void sim_activate_nodes(Object &object, SimulationData &cloth_sim, const IndexMask &node_mask)
1791{
1792 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1793
1794 /* Activate the nodes inside the simulation area. */
1795 switch (pbvh.type()) {
1796 case bke::pbvh::Type::Mesh: {
1798 node_mask.foreach_index([&](const int i) {
1799 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1800 cloth_sim.node_state[node_index] = SCULPT_CLOTH_NODE_ACTIVE;
1801 });
1802 break;
1803 }
1806 node_mask.foreach_index([&](const int i) {
1807 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1808 cloth_sim.node_state[node_index] = SCULPT_CLOTH_NODE_ACTIVE;
1809 });
1810 break;
1811 }
1814 node_mask.foreach_index([&](const int i) {
1815 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1816 cloth_sim.node_state[node_index] = SCULPT_CLOTH_NODE_ACTIVE;
1817 });
1818 break;
1819 }
1820 }
1821}
1822
1824 Object &ob,
1825 const IndexMask &node_mask)
1826{
1827 SculptSession &ss = *ob.sculpt;
1828 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1829 const float radius = ss.cache->initial_radius;
1830 const float limit = radius + (radius * brush->cloth_sim_limit);
1831 const float3 sim_location = cloth_brush_simulation_location_get(ss, brush);
1832 ensure_nodes_constraints(sd, ob, node_mask, *ss.cache->cloth_sim, sim_location, limit);
1833}
1834
1835void do_cloth_brush(const Depsgraph &depsgraph,
1836 const Sculpt &sd,
1837 Object &ob,
1838 const IndexMask &node_mask)
1839{
1840 SculptSession &ss = *ob.sculpt;
1841 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1842
1843 if (!ss.cache->cloth_sim) {
1845 ob,
1846 brush->cloth_mass,
1847 brush->cloth_damping,
1850 is_cloth_deform_brush(*brush));
1851 }
1852
1855 /* When using simulation a fixed local simulation area, constraints are created only using
1856 * the initial stroke position and initial radius (per symmetry pass) instead of per node.
1857 * This allows to skip unnecessary constraints that will never be simulated, making the
1858 * solver faster. When the simulation starts for a node, the node gets activated and all its
1859 * constraints are considered final. As the same node can be included inside the brush radius
1860 * from multiple symmetry passes, the cloth brush can't activate the node for simulation yet
1861 * as this will cause the ensure constraints function to skip the node in the next symmetry
1862 * passes. It needs to build the constraints here and skip simulating the first step, so all
1863 * passes can add their constraints to all affected nodes. */
1865 }
1866 /* The first step of a symmetry pass is never simulated as deformation modes need valid delta
1867 * for brush tip alignment. */
1868 return;
1869 }
1870
1871 /* Ensure the constraints for the nodes. */
1873
1874 /* Store the initial state in the simulation. */
1876
1877 /* Enable the nodes that should be simulated. */
1878 sim_activate_nodes(ob, *ss.cache->cloth_sim, node_mask);
1879
1880 /* Apply forces to the vertices. */
1881 cloth_brush_apply_brush_forces(depsgraph, sd, ob, node_mask);
1882
1883 /* Update and write the simulation to the nodes. */
1884 do_simulation_step(depsgraph, sd, ob, *ss.cache->cloth_sim, node_mask);
1885}
1886
1888
1889void simulation_limits_draw(const uint gpuattr,
1890 const Brush &brush,
1891 const float location[3],
1892 const float normal[3],
1893 const float rds,
1894 const float line_width,
1895 const float outline_col[3],
1896 const float alpha)
1897{
1898 float cursor_trans[4][4], cursor_rot[4][4];
1899 const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
1900 float quat[4];
1901 unit_m4(cursor_trans);
1902 translate_m4(cursor_trans, location[0], location[1], location[2]);
1903 rotation_between_vecs_to_quat(quat, z_axis, normal);
1904 quat_to_mat4(cursor_rot, quat);
1906 GPU_matrix_mul(cursor_trans);
1907 GPU_matrix_mul(cursor_rot);
1908
1909 GPU_line_width(line_width);
1910 immUniformColor3fvAlpha(outline_col, alpha * 0.5f);
1912 gpuattr, 0, 0, rds + (rds * brush.cloth_sim_limit * brush.cloth_sim_falloff), 320);
1913 immUniformColor3fvAlpha(outline_col, alpha * 0.7f);
1914 imm_draw_circle_wire_3d(gpuattr, 0, 0, rds + rds * brush.cloth_sim_limit, 80);
1916}
1917
1919 SculptSession &ss,
1920 const float outline_col[3],
1921 float outline_alpha)
1922{
1923 float4x4 local_mat = ss.cache->stroke_local_mat;
1924
1926 add_v3_v3v3(local_mat[3], ss.cache->location, ss.cache->grab_delta);
1927 }
1928
1929 GPU_matrix_mul(local_mat.ptr());
1930
1931 const float dist = ss.cache->radius;
1932 const float arrow_x = ss.cache->radius * 0.2f;
1933 const float arrow_y = ss.cache->radius * 0.1f;
1934
1935 immUniformColor3fvAlpha(outline_col, outline_alpha);
1936 GPU_line_width(2.0f);
1938 immVertex3f(gpuattr, dist, 0.0f, 0.0f);
1939 immVertex3f(gpuattr, -dist, 0.0f, 0.0f);
1940 immEnd();
1941
1943 immVertex3f(gpuattr, dist, 0.0f, 0.0f);
1944 immVertex3f(gpuattr, dist - arrow_x, arrow_y, 0.0f);
1945 immVertex3f(gpuattr, dist - arrow_x, -arrow_y, 0.0f);
1946
1947 immVertex3f(gpuattr, -dist, 0.0f, 0.0f);
1948 immVertex3f(gpuattr, -dist + arrow_x, arrow_y, 0.0f);
1949 immVertex3f(gpuattr, -dist + arrow_x, -arrow_y, 0.0f);
1950
1951 immEnd();
1952}
1953
1954/* Cloth Filter. */
1955
1963
1965 {int(ClothFilterType::Gravity), "GRAVITY", 0, "Gravity", "Applies gravity to the simulation"},
1966 {int(ClothFilterType::Inflate), "INFLATE", 0, "Inflate", "Inflates the cloth"},
1967 {int(ClothFilterType::Expand), "EXPAND", 0, "Expand", "Expands the cloth's dimensions"},
1969 "PINCH",
1970 0,
1971 "Pinch",
1972 "Pulls the cloth to the cursor's start position"},
1974 "SCALE",
1975 0,
1976 "Scale",
1977 "Scales the mesh as a soft body using the origin of the object as scale"},
1978 {0, nullptr, 0, nullptr, nullptr},
1979};
1980
1983 "LOCAL",
1984 0,
1985 "Local",
1986 "Use the local axis to limit the force and set the gravity direction"},
1988 "WORLD",
1989 0,
1990 "World",
1991 "Use the global axis to limit the force and set the gravity direction"},
1993 "VIEW",
1994 0,
1995 "View",
1996 "Use the view axis to limit the force and set the gravity direction"},
1997 {0, nullptr, 0, nullptr, nullptr},
1998};
1999
2005
2007 {CLOTH_FILTER_FORCE_X, "X", 0, "X", "Apply force in the X axis"},
2008 {CLOTH_FILTER_FORCE_Y, "Y", 0, "Y", "Apply force in the Y axis"},
2009 {CLOTH_FILTER_FORCE_Z, "Z", 0, "Z", "Apply force in the Z axis"},
2010 {0, nullptr, 0, nullptr, nullptr},
2011};
2012
2014{
2015 return ELEM(filter_type, ClothFilterType::Scale);
2016}
2017
2019 const filter::Cache &filter_cache,
2020 const MutableSpan<float3> forces)
2021{
2022 const float3x3 to_object_space = filter::to_object_space(filter_cache);
2023 for (const int i : forces.index_range()) {
2024 float3 force(0.0f);
2025 if (filter_cache.orientation == filter::FilterOrientation::View) {
2026 /* When using the view orientation apply gravity in the -Y axis, this way objects will
2027 * fall down instead of backwards. */
2028 force[1] = -factors[i];
2029 }
2030 else {
2031 force[2] = -factors[i];
2032 }
2033 forces[i] = to_object_space * force;
2034 }
2035}
2036
2044
2046 const Span<int> verts,
2047 const Span<float> factors,
2048 FilterLocalData &tls)
2049{
2050 const MutableSpan translations = gather_data_mesh(
2051 filter_cache.cloth_sim->init_pos.as_span(), verts, tls.forces);
2052 scale_translations(translations, factors);
2053 filter::zero_disabled_axis_components(filter_cache, translations);
2054 for (const int i : verts.index_range()) {
2055 filter_cache.cloth_sim->deformation_pos[verts[i]] =
2056 filter_cache.cloth_sim->init_pos[verts[i]] + translations[i];
2057 }
2058}
2059
2060static void apply_filter_forces_mesh(const Depsgraph &depsgraph,
2061 const ClothFilterType filter_type,
2062 const float filter_strength,
2063 const float3 &gravity,
2064 const Span<float3> positions_eval,
2065 const Span<float3> vert_normals,
2066 const GroupedSpan<int> vert_to_face_map,
2067 const MeshAttributeData &attribute_data,
2068 const bke::pbvh::MeshNode &node,
2069 Object &object,
2070 FilterLocalData &tls)
2071{
2072 const SculptSession &ss = *object.sculpt;
2073 SimulationData &cloth_sim = *ss.filter_cache->cloth_sim;
2074
2075 const Span<int> verts = node.verts();
2076
2077 tls.factors.resize(verts.size());
2078 const MutableSpan<float> factors = tls.factors;
2079 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
2080 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
2081 auto_mask::calc_vert_factors(depsgraph, object, automasking, node, verts, factors);
2082
2084 for (const int i : verts.index_range()) {
2085 const int vert = verts[i];
2087 vert_to_face_map, attribute_data.face_sets, vert, ss.filter_cache->active_face_set))
2088 {
2089 factors[i] = 0.0f;
2090 }
2091 }
2092 }
2093
2094 scale_factors(factors, filter_strength);
2095
2096 tls.forces.resize(verts.size());
2097 const MutableSpan<float3> forces = tls.forces;
2098 if (!math::is_zero(gravity)) {
2099 forces.fill(gravity);
2100 apply_forces(cloth_sim, forces, verts);
2101 }
2102
2103 switch (filter_type) {
2105 calc_gravity_forces(factors, *ss.filter_cache, forces);
2106 apply_forces(cloth_sim, tls.forces, verts);
2107 break;
2109 gather_data_mesh(vert_normals, verts, forces);
2110 scale_translations(forces, factors);
2111 apply_forces(cloth_sim, tls.forces, verts);
2112 break;
2114 expand_length_constraints(cloth_sim, verts, factors);
2115 break;
2118
2119 gather_data_mesh(positions_eval, verts, tls.positions),
2121 forces);
2122 scale_translations(forces, factors);
2123 apply_forces(cloth_sim, tls.forces, verts);
2124 break;
2126 apply_scale_filter(*ss.filter_cache, verts, factors, tls);
2127 break;
2128 }
2129}
2130
2131static void apply_filter_forces_grids(const Depsgraph &depsgraph,
2132 const Span<int> face_sets,
2133 const ClothFilterType filter_type,
2134 const float filter_strength,
2135 const float3 &gravity,
2136 const bke::pbvh::GridsNode &node,
2137 Object &object,
2138 FilterLocalData &tls)
2139{
2140 const SculptSession &ss = *object.sculpt;
2141 SimulationData &cloth_sim = *ss.filter_cache->cloth_sim;
2142 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
2143 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
2144
2145 const Span<int> grids = node.grids();
2146 const int grid_verts_num = grids.size() * key.grid_area;
2147
2148 tls.factors.resize(grid_verts_num);
2149 const MutableSpan<float> factors = tls.factors;
2150 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
2151 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
2152 auto_mask::calc_grids_factors(depsgraph, object, automasking, node, grids, factors);
2153
2155 for (const int i : grids.index_range()) {
2157 subdiv_ccg, face_sets, grids[i], ss.filter_cache->active_face_set))
2158 {
2159 factors.slice(i * key.grid_area, key.grid_area).fill(0.0f);
2160 }
2161 }
2162 }
2163
2164 scale_factors(factors, filter_strength);
2165
2166 const Span<int> verts = calc_vert_indices_grids(key, grids, tls.vert_indices);
2167
2168 tls.forces.resize(verts.size());
2169 const MutableSpan<float3> forces = tls.forces;
2170 if (!math::is_zero(gravity)) {
2171 forces.fill(gravity);
2172 apply_forces(cloth_sim, forces, verts);
2173 }
2174
2175 switch (filter_type) {
2177 calc_gravity_forces(factors, *ss.filter_cache, forces);
2178 apply_forces(cloth_sim, tls.forces, verts);
2179 break;
2181 gather_grids_normals(subdiv_ccg, grids, forces);
2182 scale_translations(forces, factors);
2183 apply_forces(cloth_sim, tls.forces, verts);
2184 break;
2186 expand_length_constraints(cloth_sim, verts, factors);
2187 break;
2190
2191 gather_grids_positions(subdiv_ccg, grids, tls.positions),
2193 forces);
2194 scale_translations(forces, factors);
2195 apply_forces(cloth_sim, tls.forces, verts);
2196 break;
2198 apply_scale_filter(*ss.filter_cache, verts, factors, tls);
2199 break;
2200 }
2201}
2202
2203static void apply_filter_forces_bmesh(const Depsgraph &depsgraph,
2204 const ClothFilterType filter_type,
2205 const float filter_strength,
2206 const float3 &gravity,
2208 Object &object,
2209 FilterLocalData &tls)
2210{
2211 const SculptSession &ss = *object.sculpt;
2212 SimulationData &cloth_sim = *ss.filter_cache->cloth_sim;
2213 const BMesh &bm = *ss.bm;
2214
2216
2217 tls.factors.resize(verts.size());
2218 const MutableSpan<float> factors = tls.factors;
2220 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
2221 auto_mask::calc_vert_factors(depsgraph, object, automasking, node, verts, factors);
2222
2224 const int face_set_offset = CustomData_get_offset_named(
2225 &bm.pdata, CD_PROP_INT32, ".sculpt_face_set");
2226 int i = 0;
2227 for (const BMVert *vert : verts) {
2228 if (!face_set::vert_has_face_set(face_set_offset, *vert, ss.filter_cache->active_face_set)) {
2229 factors[i] = 0.0f;
2230 }
2231 i++;
2232 }
2233 }
2234
2235 scale_factors(factors, filter_strength);
2236
2237 const Span<int> vert_indices = calc_vert_indices_bmesh(verts, tls.vert_indices);
2238
2239 tls.forces.resize(verts.size());
2240 const MutableSpan<float3> forces = tls.forces;
2241 if (!math::is_zero(gravity)) {
2242 forces.fill(gravity);
2243 apply_forces(cloth_sim, forces, vert_indices);
2244 }
2245
2246 switch (filter_type) {
2248 calc_gravity_forces(factors, *ss.filter_cache, forces);
2249 apply_forces(cloth_sim, tls.forces, vert_indices);
2250 break;
2252 gather_bmesh_normals(verts, forces);
2253 scale_translations(forces, factors);
2254 apply_forces(cloth_sim, tls.forces, vert_indices);
2255 break;
2257 expand_length_constraints(cloth_sim, vert_indices, factors);
2258 break;
2261
2264 forces);
2265 scale_translations(forces, factors);
2266 apply_forces(cloth_sim, tls.forces, vert_indices);
2267 break;
2269 apply_scale_filter(*ss.filter_cache, vert_indices, factors, tls);
2270 break;
2271 }
2272}
2273
2275 wmOperator *op,
2276 const wmEvent *event)
2277{
2278 Object &object = *CTX_data_active_object(C);
2280 SculptSession &ss = *object.sculpt;
2281 const Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
2282 const ClothFilterType filter_type = ClothFilterType(RNA_enum_get(op->ptr, "type"));
2283 float filter_strength = RNA_float_get(op->ptr, "strength");
2284
2285 if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
2286 MEM_delete(ss.filter_cache);
2287 ss.filter_cache = nullptr;
2288 undo::push_end(object);
2290 return OPERATOR_FINISHED;
2291 }
2292
2293 if (event->type != MOUSEMOVE) {
2295 }
2296
2297 const float len = event->prev_press_xy[0] - event->xy[0];
2298 filter_strength = filter_strength * -len * 0.001f * UI_SCALE_FAC;
2299
2301
2303
2305
2306 const IndexMask &node_mask = ss.filter_cache->node_mask;
2307
2308 if (auto_mask::is_enabled(sd, object, nullptr) && ss.filter_cache->automasking &&
2310 {
2311 ss.filter_cache->automasking->calc_cavity_factor(*depsgraph, object, node_mask);
2312 }
2313
2314 float3 gravity(0.0f);
2315 if (sd.gravity_object) {
2316 gravity = sd.gravity_object->object_to_world().ptr()[2];
2317 }
2318 else {
2319 gravity[2] = -1.0f;
2320 }
2321 gravity *= sd.gravity_factor * filter_strength;
2322
2323 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
2324
2326 switch (pbvh.type()) {
2327 case bke::pbvh::Type::Mesh: {
2328 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(*depsgraph, object);
2329 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(*depsgraph, object);
2330 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
2331 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
2332 const MeshAttributeData attribute_data(mesh);
2334 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2335 FilterLocalData &tls = all_tls.local();
2337 filter_type,
2338 filter_strength,
2339 gravity,
2340 positions_eval,
2341 vert_normals,
2342 vert_to_face_map,
2343 attribute_data,
2344 nodes[i],
2345 object,
2346 tls);
2347 bke::pbvh::update_node_bounds_mesh(positions_eval, nodes[i]);
2348 });
2349 break;
2350 }
2352 const Mesh &base_mesh = *static_cast<const Mesh *>(object.data);
2353 const bke::AttributeAccessor attributes = base_mesh.attributes();
2354 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set",
2356 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
2357 MutableSpan<float3> positions = subdiv_ccg.positions;
2359 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2360 FilterLocalData &tls = all_tls.local();
2362 *depsgraph, face_sets, filter_type, filter_strength, gravity, nodes[i], object, tls);
2363 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
2364 });
2365 break;
2366 }
2369 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2370 FilterLocalData &tls = all_tls.local();
2372 *depsgraph, filter_type, filter_strength, gravity, nodes[i], object, tls);
2374 });
2375 break;
2376 }
2377 }
2378 pbvh.tag_positions_changed(node_mask);
2380
2381 /* Activate all nodes. */
2382 sim_activate_nodes(object, *ss.filter_cache->cloth_sim, node_mask);
2383
2384 /* Update and write the simulation to the nodes. */
2385 do_simulation_step(*depsgraph, sd, object, *ss.filter_cache->cloth_sim, node_mask);
2386
2389}
2390
2392 wmOperator *op,
2393 const wmEvent *event)
2394{
2395 const Scene &scene = *CTX_data_scene(C);
2399 SculptSession &ss = *ob.sculpt;
2400
2401 const View3D *v3d = CTX_wm_view3d(C);
2402 const Base *base = CTX_data_active_base(C);
2403 if (!BKE_base_is_visible(v3d, base)) {
2404 return OPERATOR_CANCELLED;
2405 }
2406
2407 const ClothFilterType filter_type = ClothFilterType(RNA_enum_get(op->ptr, "type"));
2408
2409 /* Update the active vertex */
2410 float2 mval_fl{float(event->mval[0]), float(event->mval[1])};
2412 cursor_geometry_info_update(C, &cgi, mval_fl, false);
2413
2414 /* Needs mask data to be available as it is used when solving the constraints. */
2416
2418 return OPERATOR_CANCELLED;
2419 }
2420
2421 undo::push_begin(scene, ob, op);
2423 ob,
2424 sd,
2426 mval_fl,
2427 RNA_float_get(op->ptr, "area_normal_radius"),
2428 RNA_float_get(op->ptr, "strength"));
2429
2430 if (auto_mask::is_enabled(sd, ob, nullptr)) {
2432 }
2433
2434 const float cloth_mass = RNA_float_get(op->ptr, "cloth_mass");
2435 const float cloth_damping = RNA_float_get(op->ptr, "cloth_damping");
2436 const bool use_collisions = RNA_boolean_get(op->ptr, "use_collisions");
2438 *depsgraph,
2439 ob,
2440 cloth_mass,
2441 cloth_damping,
2442 0.0f,
2443 use_collisions,
2445
2447
2448 float3 origin(0);
2450 sd, ob, ss.filter_cache->node_mask, *ss.filter_cache->cloth_sim, origin, FLT_MAX);
2451
2452 const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets");
2453 if (use_face_sets) {
2455 }
2456 else {
2458 }
2459
2460 const int force_axis = RNA_enum_get(op->ptr, "force_axis");
2461 ss.filter_cache->enabled_axis[0] = force_axis & CLOTH_FILTER_FORCE_X;
2462 ss.filter_cache->enabled_axis[1] = force_axis & CLOTH_FILTER_FORCE_Y;
2463 ss.filter_cache->enabled_axis[2] = force_axis & CLOTH_FILTER_FORCE_Z;
2464
2466
2469}
2470
2472{
2473 ot->name = "Filter Cloth";
2474 ot->idname = "SCULPT_OT_cloth_filter";
2475 ot->description = "Applies a cloth simulation deformation to the entire mesh";
2476
2479 ot->poll = SCULPT_mode_poll;
2480
2481 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2482
2484
2485 ot->prop = RNA_def_enum(ot->srna,
2486 "type",
2489 "Filter Type",
2490 "Operation that is going to be applied to the mesh");
2492 RNA_def_enum_flag(ot->srna,
2493 "force_axis",
2496 "Force Axis",
2497 "Apply the force in the selected axis");
2498 RNA_def_enum(ot->srna,
2499 "orientation",
2502 "Orientation",
2503 "Orientation of the axis to limit the filter force");
2504 RNA_def_float(ot->srna,
2505 "cloth_mass",
2506 1.0f,
2507 0.0f,
2508 2.0f,
2509 "Cloth Mass",
2510 "Mass of each simulation particle",
2511 0.0f,
2512 1.0f);
2513 RNA_def_float(ot->srna,
2514 "cloth_damping",
2515 0.0f,
2516 0.0f,
2517 1.0f,
2518 "Cloth Damping",
2519 "How much the applied forces are propagated through the cloth",
2520 0.0f,
2521 1.0f);
2522 ot->prop = RNA_def_boolean(ot->srna,
2523 "use_face_sets",
2524 false,
2525 "Use Face Sets",
2526 "Apply the filter only to the Face Set under the cursor");
2527 ot->prop = RNA_def_boolean(ot->srna,
2528 "use_collisions",
2529 false,
2530 "Use Collisions",
2531 "Collide with other collider objects in the scene");
2532}
2533
2534} // namespace blender::ed::sculpt_paint::cloth
float BKE_brush_curve_strength(eBrushCurvePreset preset, const CurveMapping *cumap, float distance, float brush_radius)
Definition brush.cc:1577
void collision_move_object(struct CollisionModifierData *collmd, float step, float prevstep, bool moving_bvh)
Definition collision.cc:59
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Base * CTX_data_active_base(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
bool BKE_base_is_visible(const View3D *v3d, const Base *base)
ModifierData * BKE_modifiers_findby_type(const Object *ob, ModifierType type)
#define SCULPT_FACE_SET_NONE
Definition BKE_paint.hh:324
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:650
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2797
A BVH for high poly meshes.
const blender::Set< BMVert *, 0 > & BKE_pbvh_bmesh_node_unique_verts(blender::bke::pbvh::BMeshNode *node)
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord, bool include_duplicates, SubdivCCGNeighbors &r_neighbors)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_NOINLINE
#define BVH_RAYCAST_DEFAULT
@ BVH_RAYCAST_WATERTIGHT
int BLI_bvhtree_ray_cast_ex(const BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata, int flag)
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
void isect_ray_tri_watertight_v3_precalc(struct IsectRayPrecalc *isect_precalc, const float ray_direction[3])
float dist_to_plane_v3(const float p[3], const float plane[4])
Definition math_geom.cc:502
float dist_signed_to_plane_v3(const float p[3], const float plane[4])
Definition math_geom.cc:495
bool isect_ray_tri_watertight_v3(const float ray_origin[3], const struct IsectRayPrecalc *isect_precalc, const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2])
void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3])
Definition math_geom.cc:435
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:41
void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
void normalize_m4(float R[4][4]) ATTR_NONNULL()
void unit_m4(float m[4][4])
void rotation_between_vecs_to_quat(float q[4], const float v1[3], const float v2[3])
void quat_to_mat4(float m[4][4], const float q[4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
unsigned int uint
#define UNPACK3(a)
#define ELEM(...)
#define STREQ(a, b)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
#define DEG_OBJECT_ITER_BEGIN(settings_, instance_)
#define DEG_OBJECT_ITER_END
@ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY
@ DEG_ITER_OBJECT_FLAG_VISIBLE
@ DEG_ITER_OBJECT_FLAG_DUPLI
@ BRUSH_AUTOMASKING_CAVITY_ALL
@ BRUSH_DEFORM_TARGET_CLOTH_SIM
@ SCULPT_BRUSH_TYPE_CLOTH
@ BRUSH_FRONTFACE
@ BRUSH_PERSISTENT
@ BRUSH_CLOTH_DEFORM_DRAG
@ BRUSH_CLOTH_DEFORM_EXPAND
@ BRUSH_CLOTH_DEFORM_GRAB
@ BRUSH_CLOTH_DEFORM_PINCH_POINT
@ BRUSH_CLOTH_DEFORM_PUSH
@ BRUSH_CLOTH_DEFORM_INFLATE
@ BRUSH_CLOTH_DEFORM_SNAKE_HOOK
@ BRUSH_CLOTH_DEFORM_PINCH_PERPENDICULAR
eBrushFalloffShape
@ BRUSH_CLOTH_PIN_SIMULATION_BOUNDARY
@ BRUSH_CLOTH_USE_COLLISION
@ BRUSH_CLOTH_FORCE_FALLOFF_PLANE
@ BRUSH_CLOTH_SIMULATION_AREA_LOCAL
@ BRUSH_CLOTH_SIMULATION_AREA_DYNAMIC
@ BRUSH_CLOTH_SIMULATION_AREA_GLOBAL
@ CD_PROP_INT32
@ eModifierType_Collision
Object is a sort of wrapper for general info.
#define UI_SCALE_FAC
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
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)
void imm_draw_circle_wire_3d(uint pos, float x, float y, float radius, int nsegments)
void imm_draw_circle_dashed_3d(uint pos, float x, float y, float radius, int nsegments)
void GPU_matrix_push()
#define GPU_matrix_mul(x)
void GPU_matrix_pop()
@ GPU_PRIM_LINES
@ GPU_PRIM_TRIS
void GPU_line_width(float width)
Definition gpu_state.cc:166
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
@ KM_RELEASE
Definition WM_types.hh:312
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
@ BM_ELEM_HIDDEN
#define BM_elem_index_get(ele)
#define BM_elem_flag_test(ele, hflag)
BMesh * bm
void BM_mesh_vert_coords_get(BMesh *bm, MutableSpan< float3 > positions)
void BM_mesh_vert_normals_get(BMesh *bm, MutableSpan< float3 > normals)
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
BPy_StructRNA * depsgraph
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:248
AttributeSet attributes
constexpr void fill_indices(Span< IndexT > indices, const T &value) const
Definition BLI_span.hh:526
void resize(const int64_t new_size)
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
constexpr Span< T > as_span() const
Definition BLI_span.hh:661
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:739
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
int64_t size() const
void append(const T &value)
const T & last(const int64_t n=0) const
void resize(const int64_t new_size)
Span< T > as_span() const
GAttributeReader lookup(const StringRef attribute_id) const
void tag_positions_changed(const IndexMask &node_mask)
Definition pbvh.cc:635
Span< NodeT > nodes() const
int nodes_num() const
Definition pbvh.cc:590
void flush_bounds_to_parents()
Definition pbvh.cc:1306
void foreach_index(Fn &&fn) const
nullptr float
static ushort indices[]
static float verts[][3]
static float normals[][3]
uint col
float distance(VecOp< float, D >, VecOp< float, D >) RET
ccl_device_inline float len_squared(const float2 a)
static char faces[256]
void fill_index_range(MutableSpan< T > span, const T start=0)
void foreach_0_index(const BitSpanT &data, Fn &&fn)
IndexRange grid_range(const int grid_area, const int grid)
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
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2628
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
const Cache * active_cache_get(const SculptSession &ss)
Cache & filter_cache_ensure(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob)
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)
bool is_enabled(const Sculpt &sd, const Object &object, const Brush *br)
static BLI_NOINLINE void solve_verts_simulation(const Object &object, const Brush *brush, const float3 &sim_location, const Span< int > verts, const MutableSpan< float > factors, LocalData &tls, SimulationData &cloth_sim)
static void sculpt_cloth_ensure_constraints_in_simulation_area(const Sculpt &sd, Object &ob, const IndexMask &node_mask)
void plane_falloff_preview_draw(const uint gpuattr, SculptSession &ss, const float outline_col[3], float outline_alpha)
static void calc_forces_mesh(const Depsgraph &depsgraph, Object &ob, const Brush &brush, const float3 &offset, const float4x4 &imat, const float3 &sim_location, const float3 &gravity, const std::optional< FalloffPlane > &falloff_plane, const MeshAttributeData &attribute_data, const Span< float3 > positions_eval, const Span< float3 > vert_normals, const bke::pbvh::MeshNode &node, LocalData &tls)
static void calc_forces_grids(const Depsgraph &depsgraph, Object &ob, const Brush &brush, const float3 &offset, const float4x4 &imat, const float3 &sim_location, const float3 &gravity, const std::optional< FalloffPlane > &falloff_plane, const bke::pbvh::GridsNode &node, LocalData &tls)
static BLI_NOINLINE void apply_grab_brush(SimulationData &cloth_sim, const Span< int > verts, const MutableSpan< float > factors, const bool use_falloff_plane, const float3 &grab_delta_symmetry)
static BLI_NOINLINE void calc_perpendicular_pinch_forces(const Span< float3 > positions, const float4x4 &imat, const float3 &location, const MutableSpan< float3 > forces)
static void cloth_sim_initialize_default_node_state(Object &object, SimulationData &cloth_sim)
static BLI_NOINLINE void calc_distances_to_plane(const Span< float3 > positions, const float4 &plane, const MutableSpan< float > distances)
static float3 cloth_brush_simulation_location_get(const SculptSession &ss, const Brush *brush)
static BLI_NOINLINE void apply_scale_filter(filter::Cache &filter_cache, const Span< int > verts, const Span< float > factors, FilterLocalData &tls)
static void cloth_brush_add_deformation_constraint(SimulationData &cloth_sim, const int node_index, const int v, const float strength)
static MutableSpan< int > calc_visible_vert_indices_bmesh(const Set< BMVert *, 0 > &verts, Vector< int > &indices)
static void copy_positions_to_array(const Depsgraph &depsgraph, const Object &object, MutableSpan< float3 > positions)
static bool cloth_filter_is_deformation_filter(ClothFilterType filter_type)
bool is_cloth_deform_brush(const Brush &brush)
static void add_constraints_for_verts(const Object &object, const Brush *brush, const float3 &cloth_sim_initial_location, const float cloth_sim_radius, const Span< float3 > init_positions, const int node_index, const Span< int > verts, const GroupedSpan< int > vert_neighbors, SimulationData &cloth_sim, Set< OrderedEdge > &created_length_constraints)
static void cloth_brush_apply_brush_forces(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
static void calc_constraint_factors(const Depsgraph &depsgraph, const Object &object, const Brush *brush, const float3 &sim_location, const Span< float3 > init_positions, const MutableSpan< float > cloth_factors)
static BLI_NOINLINE void calc_plane_pinch_forces(const Span< float3 > positions, const float4 &plane, const float3 &plane_normal, const MutableSpan< float3 > forces)
void SCULPT_OT_cloth_filter(wmOperatorType *ot)
static void apply_filter_forces_grids(const Depsgraph &depsgraph, const Span< int > face_sets, const ClothFilterType filter_type, const float filter_strength, const float3 &gravity, const bke::pbvh::GridsNode &node, Object &object, FilterLocalData &tls)
static GroupedSpan< int > calc_vert_neighbor_indices_bmesh(const BMesh &bm, const Span< int > verts, Vector< int > &r_offset_data, Vector< int > &r_data)
static void copy_normals_to_array(const Depsgraph &depsgraph, const Object &object, MutableSpan< float3 > normals)
static EnumPropertyItem prop_cloth_filter_type[]
void brush_store_simulation_state(const Depsgraph &depsgraph, const Object &object, SimulationData &cloth_sim)
static BLI_NOINLINE void calc_gravity_forces(const Span< float > factors, const filter::Cache &filter_cache, const MutableSpan< float3 > forces)
void ensure_nodes_constraints(const Sculpt &sd, Object &object, const IndexMask &node_mask, SimulationData &cloth_sim, const float3 &initial_location, const float radius)
void sim_activate_nodes(Object &object, SimulationData &cloth_sim, const IndexMask &node_mask)
static BLI_NOINLINE void calc_brush_simulation_falloff(const Brush &brush, const float radius, const float3 &location, const Span< float3 > positions, const MutableSpan< float > factors)
static void cloth_brush_collision_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
static void calc_forces_bmesh(const Depsgraph &depsgraph, Object &ob, const Brush &brush, const float3 &offset, const float4x4 &imat, const float3 &sim_location, const float3 &gravity, const std::optional< FalloffPlane > &falloff_plane, bke::pbvh::BMeshNode &node, LocalData &tls)
static BLI_NOINLINE void expand_length_constraints(SimulationData &cloth_sim, const Span< int > verts, const Span< float > factors)
static float cloth_brush_simulation_falloff_get(const Brush &brush, const float radius, const float3 &location, const float3 &co)
static void cloth_brush_add_pin_constraint(SimulationData &cloth_sim, const int node_index, const int v, const float strength)
IndexMask brush_affected_nodes_gather(const Object &object, const Brush &brush, IndexMaskMemory &memory)
static void cloth_brush_satisfy_constraints(const Depsgraph &depsgraph, const Object &object, const Brush *brush, SimulationData &cloth_sim)
void do_simulation_step(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, SimulationData &cloth_sim, const IndexMask &node_mask)
static void apply_filter_forces_bmesh(const Depsgraph &depsgraph, const ClothFilterType filter_type, const float filter_strength, const float3 &gravity, bke::pbvh::BMeshNode &node, Object &object, FilterLocalData &tls)
static MutableSpan< int > calc_vert_indices_grids(const CCGKey &key, const Span< int > grids, Vector< int > &indices)
static BLI_NOINLINE void clamp_factors(const MutableSpan< float > factors, const float min, const float max)
static void cloth_brush_add_length_constraint(SimulationData &cloth_sim, const int node_index, const int v1, const int v2, const Span< float3 > init_positions)
static BLI_NOINLINE void apply_forces(SimulationData &cloth_sim, const Span< float3 > forces, const Span< int > verts)
static EnumPropertyItem prop_cloth_filter_force_axis_items[]
static wmOperatorStatus sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
static BLI_NOINLINE void apply_snake_hook_brush(SimulationData &cloth_sim, const Span< int > verts, const MutableSpan< float > factors, const float3 &grab_delta_symmetry)
static wmOperatorStatus sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static MutableSpan< int > calc_vert_indices_bmesh(const Set< BMVert *, 0 > &verts, Vector< int > &indices)
static void cloth_brush_add_softbody_constraint(SimulationData &cloth_sim, const int node_index, const int v, const float strength)
static void apply_filter_forces_mesh(const Depsgraph &depsgraph, const ClothFilterType filter_type, const float filter_strength, const float3 &gravity, const Span< float3 > positions_eval, const Span< float3 > vert_normals, const GroupedSpan< int > vert_to_face_map, const MeshAttributeData &attribute_data, const bke::pbvh::MeshNode &node, Object &object, FilterLocalData &tls)
static void cloth_brush_solve_collision(const Object &object, SimulationData &cloth_sim, const int i)
void simulation_limits_draw(const uint gpuattr, const Brush &brush, const float location[3], const float normal[3], const float rds, const float line_width, const float outline_col[3], const float alpha)
std::unique_ptr< SimulationData > brush_simulation_create(const Depsgraph &depsgraph, Object &ob, const float cloth_mass, const float cloth_damping, const float cloth_softbody_strength, const bool use_collisions, const bool needs_deform_coords)
static MutableSpan< int > calc_visible_vert_indices_grids(const CCGKey &key, const BitGroupVector<> &grid_hidden, const Span< int > grids, Vector< int > &indices)
static BLI_NOINLINE void calc_pinch_forces(const Span< float3 > positions, const float3 &location, const MutableSpan< float3 > forces)
static Vector< ColliderCache > cloth_brush_collider_cache_create(Object &object, const Depsgraph &depsgraph)
void do_cloth_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
static GroupedSpan< int > calc_vert_neighbor_indices_grids(const SubdivCCG &subdiv_ccg, const Span< int > verts, Vector< int > &r_offset_data, Vector< int > &r_data)
static EnumPropertyItem prop_cloth_filter_orientation_items[]
bool vert_has_face_set(const GroupedSpan< int > vert_to_face_map, const Span< int > face_sets, const int vert, const int face_set)
Definition sculpt.cc:252
int active_face_set_get(const Object &object)
Definition sculpt.cc:196
void zero_disabled_axis_components(const filter::Cache &filter_cache, MutableSpan< float3 > vectors)
void cache_init(bContext *C, Object &ob, Sculpt &sd, undo::Type undo_type, const float mval_fl[2], float area_normal_radius, float start_strength)
float3x3 to_object_space(const filter::Cache &filter_cache)
void register_operator_props(wmOperatorType *ot)
Span< int > node_visible_verts(const bke::pbvh::MeshNode &node, const Span< bool > hide_vert, Vector< int > &indices)
void push_begin(const Scene &scene, Object &ob, const wmOperator *op)
void fill_factor_from_hide_and_mask(Span< bool > hide_vert, Span< float > mask, Span< int > verts, MutableSpan< float > r_factors)
Definition sculpt.cc:6823
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 scatter_data_bmesh(Span< T > node_data, const Set< BMVert *, 0 > &verts, MutableSpan< T > dst)
Definition sculpt.cc:6461
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 gather_data_grids(const SubdivCCG &subdiv_ccg, Span< T > src, Span< int > grids, MutableSpan< T > node_data)
Definition sculpt.cc:6405
void vert_random_access_ensure(Object &object)
Definition sculpt.cc:141
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:7156
GroupedSpan< int > calc_vert_neighbors(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face, Span< bool > hide_poly, Span< int > verts, Vector< int > &r_offset_data, Vector< int > &r_data)
Definition sculpt.cc:7597
void gather_bmesh_normals(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > normals)
Definition sculpt.cc:6385
Vector< BMVert *, 64 > BMeshNeighborVerts
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 gather_data_bmesh(Span< T > src, const Set< BMVert *, 0 > &verts, MutableSpan< T > node_data)
Definition sculpt.cc:6421
void scale_translations(MutableSpan< float3 > translations, Span< float > factors)
Definition sculpt.cc:7495
bool report_if_shape_key_is_locked(const Object &ob, ReportList *reports)
Definition sculpt.cc:127
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
bool cursor_geometry_info_update(bContext *C, CursorGeometryInfo *out, const float2 &mval, const bool use_sampled_normal)
Definition sculpt.cc:4685
void flush_update_done(const bContext *C, Object &ob, const UpdateType update_type)
Definition sculpt.cc:5146
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6435
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
Span< BMVert * > vert_neighbors_get_bmesh(BMVert &vert, BMeshNeighborVerts &r_neighbors)
Definition sculpt.cc:387
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6395
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
void flush_update_step(const bContext *C, const UpdateType update_type)
Definition sculpt.cc:5098
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
void translations_from_offset_and_factors(const float3 &offset, Span< float > factors, MutableSpan< float3 > r_translations)
Definition sculpt.cc:7531
void scatter_data_grids(const SubdivCCG &subdiv_ccg, Span< T > node_data, Span< int > grids, MutableSpan< T > dst)
Definition sculpt.cc:6445
T distance(const T &a, const T &b)
T length(const VecBase< T, Size > &a)
QuaternionBase< T > normalize_and_get_length(const QuaternionBase< T > &q, T &out_length)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
bool is_zero(const T &a)
AxisSigned cross(const AxisSigned a, const AxisSigned b)
T rcp(const T &a)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
T square(const T &a)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< float, 2 > float2
VecBase< int32_t, 3 > int3
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
CCL_NAMESPACE_BEGIN ccl_device float fade(const float t)
Definition noise.h:18
const char * name
float RNA_float_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_enum_flag(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:542
bool SCULPT_mode_poll(bContext *C)
Definition sculpt.cc:3677
int SCULPT_vertex_count_get(const Object &object)
Definition sculpt.cc:151
#define CLOTH_SOLVER_DISPLACEMENT_FACTOR
#define CLOTH_LENGTH_CONSTRAINTS_BLOCK
#define CLOTH_DEFORMATION_SNAKEHOOK_STRENGTH
#define CLOTH_DEFORMATION_GRAB_STRENGTH
#define CLOTH_DEFORMATION_TARGET_STRENGTH
#define CLOTH_SIMULATION_ITERATIONS
#define CLOTH_SIMULATION_TIME_STEP
#define min(a, b)
Definition sort.cc:36
#define FLT_MAX
Definition stdcycles.h:14
float origin[3]
float direction[3]
float cloth_mass
char sculpt_brush_type
int cloth_deform_type
float cloth_sim_falloff
char falloff_shape
float cloth_sim_limit
int cloth_simulation_area_type
int deform_target
float cloth_constraint_softbody_strength
int cloth_force_falloff_type
float cloth_damping
int grid_area
Definition BKE_ccg.hh:35
struct CollisionModifierData * collmd
struct SculptSession * sculpt
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:417
blender::ed::sculpt_paint::filter::Cache * filter_cache
Definition BKE_paint.hh:418
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:395
blender::float3 active_vert_position(const Depsgraph &depsgraph, const Object &object) const
Definition paint.cc:2403
std::optional< PersistentMultiresData > persistent_multires_data()
Definition paint.cc:2442
struct Object * gravity_object
float gravity_factor
int to_index(const CCGKey &key) const
static SubdivCCGCoord from_index(const CCGKey &key, int index)
SubdivCCGNeighborCoords coords
blender::Array< blender::float3 > normals
blender::Array< blender::float3 > positions
const c_style_mat & ptr() const
std::unique_ptr< cloth::SimulationData > cloth_sim
Map< const bke::pbvh::Node *, int > node_state_index
std::unique_ptr< cloth::SimulationData > cloth_sim
std::unique_ptr< auto_mask::Cache > automasking
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
int mval[2]
Definition WM_types.hh:763
struct ReportList * reports
struct PointerRNA * ptr
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
uint len
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
@ MOUSEMOVE
@ LEFTMOUSE
wmOperatorType * ot
Definition wm_files.cc:4237