Blender V4.5
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 "brushes/brushes.hh"
49#include "mesh_brush_common.hh"
50#include "sculpt_automask.hh"
51#include "sculpt_face_set.hh"
52#include "sculpt_filter.hh"
53#include "sculpt_hide.hh"
54#include "sculpt_intern.hh"
55#include "sculpt_undo.hh"
56
57#include "RNA_access.hh"
58#include "RNA_define.hh"
59
60#include "GPU_immediate.hh"
61#include "GPU_immediate_util.hh"
62#include "GPU_matrix.hh"
63#include "GPU_state.hh"
64
65#include "UI_interface.hh"
66
67#include "bmesh.hh"
68
69#include <cmath>
70#include <cstdlib>
71#include <cstring>
72
74
76 const Span<int> grids,
78{
79 const int grid_verts_num = grids.size() * key.grid_area;
80 indices.resize(grid_verts_num);
81 for (const int i : grids.index_range()) {
83 indices.as_mutable_span().slice(i * key.grid_area, key.grid_area),
84 grids[i] * key.grid_area);
85 }
86 return indices;
87}
88
91{
92 indices.resize(verts.size());
93 int i = 0;
94 for (const BMVert *vert : verts) {
96 i++;
97 }
98 return indices;
99}
100
102 const BitGroupVector<> &grid_hidden,
103 const Span<int> grids,
105{
106 if (grid_hidden.is_empty()) {
107 return calc_vert_indices_grids(key, grids, indices);
108 }
109 const int grid_verts_num = grids.size() * key.grid_area;
110 indices.reserve(grid_verts_num);
111 for (const int i : grids.index_range()) {
112 const int start = grids[i] * key.grid_area;
113 bits::foreach_0_index(grid_hidden[grids[i]],
114 [&](const int offset) { indices.append(start + offset); });
115 }
116 return indices;
117}
118
121{
122 indices.reserve(verts.size());
123 for (const BMVert *vert : verts) {
124 if (!BM_elem_flag_test(vert, BM_ELEM_HIDDEN)) {
125 indices.append(BM_elem_index_get(vert));
126 }
127 }
128 return indices;
129}
130
132 const Span<int> verts,
133 Vector<int> &r_offset_data,
134 Vector<int> &r_data)
135{
136 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
137
138 r_offset_data.resize(verts.size() + 1);
139 r_data.clear();
140
141 for (const int i : verts.index_range()) {
142 r_offset_data[i] = r_data.size();
143 SubdivCCGNeighbors neighbors;
145 subdiv_ccg, SubdivCCGCoord::from_index(key, verts[i]), false, neighbors);
146
147 for (const SubdivCCGCoord coord : neighbors.coords) {
148 r_data.append(coord.to_index(key));
149 }
150 }
151
152 r_offset_data.last() = r_data.size();
153 return GroupedSpan<int>(r_offset_data.as_span(), r_data.as_span());
154}
155
157 const Span<int> verts,
158 Vector<int> &r_offset_data,
159 Vector<int> &r_data)
160{
161 BMeshNeighborVerts neighbors;
162
163 r_offset_data.resize(verts.size() + 1);
164 r_data.clear();
165
166 for (const int i : verts.index_range()) {
167 r_offset_data[i] = r_data.size();
168 BMVert *vert = BM_vert_at_index(&const_cast<BMesh &>(bm), verts[i]);
169 for (const BMVert *neighbor : vert_neighbors_get_bmesh(*vert, neighbors)) {
170 r_data.append(BM_elem_index_get(neighbor));
171 }
172 }
173 r_offset_data.last() = r_data.size();
174 return GroupedSpan<int>(r_offset_data.as_span(), r_data.as_span());
175}
176
178{
179 if (!ss.cache || !brush) {
180 return float3(0);
181 }
183 return ss.cache->initial_location_symm;
184 }
185 return ss.cache->location_symm;
186}
187
189 const Brush &brush,
190 IndexMaskMemory &memory)
191{
192 const SculptSession &ss = *object.sculpt;
193 BLI_assert(ss.cache);
195 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
196
197 switch (brush.cloth_simulation_area_type) {
199 const float radius_squared = math::square(ss.cache->initial_radius *
200 (1.0 + brush.cloth_sim_limit));
201 return bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
202 return node_in_sphere(node, ss.cache->initial_location_symm, radius_squared, false);
203 });
204 }
206 return bke::pbvh::all_leaf_nodes(pbvh, memory);
208 const float radius_squared = math::square(ss.cache->radius * (1.0 + brush.cloth_sim_limit));
209 return bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
210 return node_in_sphere(node, ss.cache->location_symm, radius_squared, false);
211 });
212 }
213 }
214
216 return {};
217}
218
219bool is_cloth_deform_brush(const Brush &brush)
220{
223 /* All brushes that are not the cloth brush deform the simulation using softbody
224 * constraints instead of applying forces. */
227}
228
230 const float radius,
231 const float3 &location,
232 const float3 &co)
233{
235 /* All brushes that are not the cloth brush do not use simulation areas. */
236 return 1.0f;
237 }
238
239 /* Global simulation does not have any falloff as the entire mesh is being simulated. */
241 return 1.0f;
242 }
243
244 const float distance = math::distance(location, co);
245 const float limit = radius + (radius * brush.cloth_sim_limit);
246 const float falloff = radius + (radius * brush.cloth_sim_limit * brush.cloth_sim_falloff);
247
248 if (distance > limit) {
249 /* Outside the limits. */
250 return 0.0f;
251 }
252 if (distance < falloff) {
253 /* Before the falloff area. */
254 return 1.0f;
255 }
256 /* Do a smooth-step transition inside the falloff area. */
257 float p = 1.0f - ((distance - falloff) / (limit - falloff));
258 return 3.0f * p * p - 2.0f * p * p * p;
259}
260
262 const float radius,
263 const float3 &location,
264 const Span<float3> positions,
265 const MutableSpan<float> factors)
266{
267 BLI_assert(positions.size() == factors.size());
268
269 for (const int i : positions.index_range()) {
270 factors[i] *= cloth_brush_simulation_falloff_get(brush, radius, location, positions[i]);
271 }
272}
273
274#define CLOTH_LENGTH_CONSTRAINTS_BLOCK 100000
275#define CLOTH_SIMULATION_ITERATIONS 5
276
277#define CLOTH_SOLVER_DISPLACEMENT_FACTOR 0.6f
278#define CLOTH_MAX_CONSTRAINTS_PER_VERTEX 1024
279#define CLOTH_SIMULATION_TIME_STEP 0.01f
280#define CLOTH_DEFORMATION_SNAKEHOOK_STRENGTH 0.35f
281#define CLOTH_DEFORMATION_TARGET_STRENGTH 0.01f
282#define CLOTH_DEFORMATION_GRAB_STRENGTH 0.1f
283
285 const int node_index,
286 const int v1,
287 const int v2,
288 const Span<float3> init_positions)
289{
290 LengthConstraint length_constraint{};
291
292 length_constraint.elem_index_a = v1;
293 length_constraint.elem_index_b = v2;
294
295 length_constraint.node = node_index;
296
297 length_constraint.elem_position_a = cloth_sim.pos[v1];
298 length_constraint.elem_position_b = cloth_sim.pos[v2];
299
300 length_constraint.type = SCULPT_CLOTH_CONSTRAINT_STRUCTURAL;
301
302 length_constraint.length = math::distance(init_positions[v1], init_positions[v2]);
303 length_constraint.strength = 1.0f;
304
305 cloth_sim.length_constraints.append(length_constraint);
306}
307
309 const int node_index,
310 const int v,
311 const float strength)
312{
313 LengthConstraint length_constraint{};
314
315 length_constraint.elem_index_a = v;
316 length_constraint.elem_index_b = v;
317
318 length_constraint.node = node_index;
319
320 length_constraint.elem_position_a = cloth_sim.pos[v];
321 length_constraint.elem_position_b = cloth_sim.softbody_pos[v];
322
323 length_constraint.type = SCULPT_CLOTH_CONSTRAINT_SOFTBODY;
324
325 length_constraint.length = 0.0f;
326 length_constraint.strength = strength;
327
328 cloth_sim.length_constraints.append(length_constraint);
329}
330
332 const int node_index,
333 const int v,
334 const float strength)
335{
336 LengthConstraint length_constraint{};
337
338 length_constraint.elem_index_a = v;
339 length_constraint.elem_index_b = v;
340
341 length_constraint.node = node_index;
342
343 length_constraint.elem_position_a = cloth_sim.pos[v];
344 length_constraint.elem_position_b = cloth_sim.init_pos[v];
345
346 length_constraint.type = SCULPT_CLOTH_CONSTRAINT_PIN;
347
348 length_constraint.length = 0.0f;
349 length_constraint.strength = strength;
350
351 cloth_sim.length_constraints.append(length_constraint);
352}
353
355 const int node_index,
356 const int v,
357 const float strength)
358{
359 LengthConstraint length_constraint{};
360
361 length_constraint.elem_index_a = v;
362 length_constraint.elem_index_b = v;
363
364 length_constraint.node = node_index;
365
366 length_constraint.type = SCULPT_CLOTH_CONSTRAINT_DEFORMATION;
367
368 length_constraint.elem_position_a = cloth_sim.pos[v];
369 length_constraint.elem_position_b = cloth_sim.deformation_pos[v];
370
371 length_constraint.length = 0.0f;
372 length_constraint.strength = strength;
373
374 cloth_sim.length_constraints.append(length_constraint);
375}
376
377static void add_constraints_for_verts(const Object &object,
378 const Brush *brush,
379 const float3 &cloth_sim_initial_location,
380 const float cloth_sim_radius,
381 const Span<float3> init_positions,
382 const int node_index,
383 const Span<int> verts,
384 const GroupedSpan<int> vert_neighbors,
385 SimulationData &cloth_sim,
386 Set<OrderedEdge> &created_length_constraints)
387{
388 const SculptSession &ss = *object.sculpt;
389
390 const bool is_brush_has_stroke_cache = ss.cache != nullptr && brush != nullptr;
391 const bool pin_simulation_boundary = is_brush_has_stroke_cache &&
395
396 /* Brush can be nullptr in tools that use the solver without relying of constraints with
397 * deformation positions. */
398 const bool cloth_is_deform_brush = is_brush_has_stroke_cache && is_cloth_deform_brush(*brush);
399
400 const bool use_falloff_plane = brush->cloth_force_falloff_type ==
402 float radius_squared = 0.0f;
403 if (cloth_is_deform_brush) {
404 radius_squared = ss.cache->initial_radius * ss.cache->initial_radius;
405 }
406
407 /* Only limit the constraint creation to a radius when the simulation is local. */
408 const float cloth_sim_radius_squared = brush->cloth_simulation_area_type ==
410 cloth_sim_radius * cloth_sim_radius :
411 FLT_MAX;
412
413 for (const int i : verts.index_range()) {
414 const int vert = verts[i];
415 const float len_squared = math::distance_squared(init_positions[vert],
416 cloth_sim_initial_location);
417 if (len_squared < cloth_sim_radius_squared) {
418 if (cloth_sim.softbody_strength > 0.0f) {
419 cloth_brush_add_softbody_constraint(cloth_sim, node_index, vert, 1.0f);
420 }
421
422 const Span<int> neighbors = vert_neighbors[i];
423
424 /* As we don't know the order of the neighbor vertices, we create all possible combinations
425 * between the neighbor and the original vertex as length constraints. */
426 /* This results on a pattern that contains structural, shear and bending constraints for all
427 * vertices, but constraints are repeated taking more memory than necessary. */
428 for (const int neighbor : neighbors) {
429 if (created_length_constraints.add({vert, neighbor})) {
430 cloth_brush_add_length_constraint(cloth_sim, node_index, vert, neighbor, init_positions);
431 }
432 }
433 for (const int a : neighbors) {
434 for (const int b : neighbors) {
435 if (a != b) {
436 if (created_length_constraints.add({a, b})) {
437 cloth_brush_add_length_constraint(cloth_sim, node_index, a, b, init_positions);
438 }
439 }
440 }
441 }
442 }
443
444 if (is_brush_has_stroke_cache && brush->sculpt_brush_type == SCULPT_BRUSH_TYPE_CLOTH) {
445 /* The cloth brush works by applying forces in most of its modes, but some of them require
446 * deformation coordinates to make the simulation stable. */
448 if (use_falloff_plane) {
449 /* With plane falloff the strength of the constraints is set when applying the
450 * deformation forces. */
452 cloth_sim, node_index, vert, CLOTH_DEFORMATION_GRAB_STRENGTH);
453 }
454 else if (len_squared < radius_squared) {
455 /* With radial falloff deformation constraints are created with different strengths and
456 * only inside the radius of the brush. */
457 const float fade = BKE_brush_curve_strength(
458 brush, std::sqrt(len_squared), ss.cache->radius);
460 cloth_sim, node_index, vert, fade * CLOTH_DEFORMATION_GRAB_STRENGTH);
461 }
462 }
464 /* Cloth Snake Hook creates deformation constraint with fixed strength because the strength
465 * is controlled per iteration using cloth_sim.deformation_strength. */
467 cloth_sim, node_index, vert, CLOTH_DEFORMATION_SNAKEHOOK_STRENGTH);
468 }
469 }
470 else if (!cloth_sim.deformation_pos.is_empty()) {
471 /* Any other tool that target the cloth simulation handle the falloff in
472 * their own code when modifying the deformation coordinates of the simulation, so
473 * deformation constraints are created with a fixed strength for all vertices. */
475 cloth_sim, node_index, vert, CLOTH_DEFORMATION_TARGET_STRENGTH);
476 }
477
478 if (pin_simulation_boundary) {
479 const float sim_falloff = cloth_brush_simulation_falloff_get(
480 *brush, ss.cache->initial_radius, ss.cache->location_symm, init_positions[vert]);
481 /* Vertex is inside the area of the simulation without any falloff applied. */
482 if (sim_falloff < 1.0f) {
483 /* Create constraints with more strength the closer the vertex is to the simulation
484 * boundary. */
485 cloth_brush_add_pin_constraint(cloth_sim, node_index, vert, 1.0f - sim_falloff);
486 }
487 }
488 }
489}
490
492 Object &object,
493 const IndexMask &node_mask,
494 SimulationData &cloth_sim,
495 const float3 &initial_location,
496 const float radius)
497{
498 SculptSession &ss = *object.sculpt;
499 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
500 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
501
502 /* TODO: Multi-threaded needs to be disabled for this task until implementing the optimization of
503 * storing the constraints per node. */
504 /* Currently all constrains are added to the same global array which can't be accessed from
505 * different threads. */
506
507 IndexMaskMemory memory;
508 Set<OrderedEdge> created_length_constraints;
509 Vector<int> vert_indices;
510 Vector<int> neighbor_offsets;
511 Vector<int> neighbor_data;
512 switch (pbvh.type()) {
515 const IndexMask uninitialized_nodes = IndexMask::from_predicate(
516 node_mask, GrainSize(1024), memory, [&](const int i) {
517 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
518 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_UNINITIALIZED;
519 });
520 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
521 const OffsetIndices faces = mesh.faces();
522 const Span<int> corner_verts = mesh.corner_verts();
523 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
524 const bke::AttributeAccessor attributes = mesh.attributes();
525 const VArraySpan<bool> hide_vert = *attributes.lookup<bool>(".hide_vert",
527 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly",
529
530 Span<float3> init_positions;
531 VArraySpan<float3> persistent_position;
532 if (brush != nullptr && brush->flag & BRUSH_PERSISTENT) {
533 persistent_position = *attributes.lookup<float3>(".sculpt_persistent_co",
535 }
536 if (persistent_position.is_empty()) {
537 init_positions = cloth_sim.init_pos;
538 }
539 else {
540 init_positions = persistent_position;
541 }
542 uninitialized_nodes.foreach_index([&](const int i) {
543 const Span<int> verts = hide::node_visible_verts(nodes[i], hide_vert, vert_indices);
545 corner_verts,
546 vert_to_face_map,
547 hide_poly,
548 verts,
549 neighbor_offsets,
550 neighbor_data);
552 brush,
553 initial_location,
554 radius,
555 init_positions,
556 cloth_sim.node_state_index.lookup(&nodes[i]),
557 verts,
558 neighbors,
559 cloth_sim,
560 created_length_constraints);
561 });
562 break;
563 }
566 const IndexMask uninitialized_nodes = IndexMask::from_predicate(
567 node_mask, GrainSize(1024), memory, [&](const int i) {
568 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
569 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_UNINITIALIZED;
570 });
571 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
572 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
573 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
574
575 Span<float3> init_positions;
576 Span<float3> persistent_position;
577 const std::optional<PersistentMultiresData> persistent_multires_data =
579 if (brush != nullptr && brush->flag & BRUSH_PERSISTENT && persistent_multires_data) {
580 persistent_position = persistent_multires_data->positions;
581 }
582 if (persistent_position.is_empty()) {
583 init_positions = cloth_sim.init_pos;
584 }
585 else {
586 init_positions = persistent_position;
587 }
588 uninitialized_nodes.foreach_index([&](const int i) {
590 key, grid_hidden, nodes[i].grids(), vert_indices);
592 subdiv_ccg, verts, neighbor_offsets, neighbor_data);
594 brush,
595 initial_location,
596 radius,
597 init_positions,
598 cloth_sim.node_state_index.lookup(&nodes[i]),
599 verts,
600 neighbors,
601 cloth_sim,
602 created_length_constraints);
603 });
604 break;
605 }
608 const IndexMask uninitialized_nodes = IndexMask::from_predicate(
609 node_mask, GrainSize(1024), memory, [&](const int i) {
610 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
611 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_UNINITIALIZED;
612 });
613 BMesh &bm = *ss.bm;
615 uninitialized_nodes.foreach_index([&](const int i) {
617 const Span<int> verts = calc_visible_vert_indices_bmesh(bm_verts, vert_indices);
619 bm, verts, neighbor_offsets, neighbor_data);
621 brush,
622 initial_location,
623 radius,
624 cloth_sim.init_pos,
625 cloth_sim.node_state_index.lookup(&nodes[i]),
626 verts,
627 neighbors,
628 cloth_sim,
629 created_length_constraints);
630 });
631 break;
632 }
633 }
634}
635
637 const Span<float3> forces,
638 const Span<int> verts)
639{
640 const float mass_inv = math::rcp(cloth_sim.mass);
641 for (const int i : verts.index_range()) {
642 cloth_sim.acceleration[verts[i]] += forces[i] * mass_inv;
643 }
644}
645
647 const Span<int> verts,
648 const Span<float> factors)
649{
650 MutableSpan<float> length_constraint_tweak = cloth_sim.length_constraint_tweak;
651 for (const int i : verts.index_range()) {
652 length_constraint_tweak[verts[i]] += factors[i] * 0.01f;
653 }
654}
655
657 const float4 &plane,
658 const MutableSpan<float> distances)
659{
660 for (const int i : positions.index_range()) {
661 distances[i] = dist_to_plane_v3(positions[i], plane);
662 }
663}
664
666 const float min,
667 const float max)
668{
669 for (float &factor : factors) {
670 factor = std::clamp(factor, min, max);
671 }
672}
673
675 const Span<int> verts,
676 const MutableSpan<float> factors,
677 const bool use_falloff_plane,
678 const float3 &grab_delta_symmetry)
679{
680 for (const int i : verts.index_range()) {
681 cloth_sim.deformation_pos[verts[i]] = cloth_sim.init_pos[verts[i]] +
682 grab_delta_symmetry * factors[i];
683 }
684 if (use_falloff_plane) {
685 clamp_factors(factors, 0.0f, 1.0f);
687 }
688 else {
690 }
691}
692
694 const Span<int> verts,
695 const MutableSpan<float> factors,
696 const float3 &grab_delta_symmetry)
697{
698 for (const int i : verts.index_range()) {
699 const int vert = verts[i];
700 cloth_sim.deformation_pos[vert] = cloth_sim.pos[vert] + grab_delta_symmetry * factors[i];
701 }
703}
704
705BLI_NOINLINE static void calc_pinch_forces(const Span<float3> positions,
706 const float3 &location,
707 const MutableSpan<float3> forces)
708{
709 for (const int i : forces.index_range()) {
710 forces[i] = math::normalize(location - positions[i]);
711 }
712}
713
715 const float4 &plane,
716 const float3 &plane_normal,
717 const MutableSpan<float3> forces)
718{
719 for (const int i : positions.index_range()) {
720 const float distance = dist_signed_to_plane_v3(positions[i], plane);
721 forces[i] = math::normalize(plane_normal * -distance);
722 }
723}
724
726 const float4x4 &imat,
727 const float3 &location,
728 const MutableSpan<float3> forces)
729{
730 const float3 x_object_space = math::normalize(imat.x_axis());
731 const float3 z_object_space = math::normalize(imat.z_axis());
732 for (const int i : positions.index_range()) {
733 const float3 disp_center = math::normalize(location - positions[i]);
734 const float3 x_disp = x_object_space * math::dot(disp_center, x_object_space);
735 const float3 z_disp = z_object_space * math::dot(disp_center, z_object_space);
736 forces[i] = x_disp + z_disp;
737 }
738}
739
750
755
756static void calc_forces_mesh(const Depsgraph &depsgraph,
757 Object &ob,
758 const Brush &brush,
759 const float3 &offset,
760 const float4x4 &imat,
761 const float3 &sim_location,
762 const float3 &gravity,
763 const std::optional<FalloffPlane> &falloff_plane,
764 const MeshAttributeData &attribute_data,
765 const Span<float3> positions_eval,
766 const Span<float3> vert_normals,
767 const bke::pbvh::MeshNode &node,
768 LocalData &tls)
769{
770 SculptSession &ss = *ob.sculpt;
771 SimulationData &cloth_sim = *ss.cache->cloth_sim;
772 const StrokeCache &cache = *ss.cache;
773
774 const Span<int> verts = node.verts();
775 const MutableSpan positions = gather_data_mesh(positions_eval, verts, tls.positions);
776 const MutableSpan init_positions = gather_data_mesh(
777 cloth_sim.init_pos.as_span(), verts, tls.init_positions);
778 const Span<float3> current_positions = brush.cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB ?
779 init_positions :
780 positions;
781
782 tls.factors.resize(verts.size());
783 const MutableSpan<float> factors = tls.factors;
784 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
785 filter_region_clip_factors(ss, current_positions, factors);
786
787 calc_brush_simulation_falloff(brush, cache.radius, sim_location, positions, factors);
788
789 tls.translations.resize(verts.size());
790 const MutableSpan<float3> forces = tls.translations;
791
792 /* Apply gravity in the entire simulation area before brush distances are taken into account. */
793 if (!math::is_zero(gravity)) {
794 translations_from_offset_and_factors(gravity, factors, forces);
795 apply_forces(cloth_sim, forces, verts);
796 }
797
798 if (brush.flag & BRUSH_FRONTFACE) {
799 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
800 }
801
802 tls.distances.resize(verts.size());
803 const MutableSpan<float> distances = tls.distances;
804 if (falloff_plane) {
805 calc_distances_to_plane(current_positions, falloff_plane->plane, distances);
806 }
807 else {
809 ss, current_positions, eBrushFalloffShape(brush.falloff_shape), distances);
810 }
811 filter_distances_with_radius(cache.radius, distances, factors);
812 apply_hardness_to_distances(cache, distances);
813 calc_brush_strength_factors(cache, brush, distances, factors);
814
815 const auto_mask::Cache *automask = auto_mask::active_cache_get(ss);
816 auto_mask::calc_vert_factors(depsgraph, ob, automask, node, verts, factors);
817
818 calc_brush_texture_factors(ss, brush, current_positions, factors);
819
820 scale_factors(factors, cache.bstrength);
821
822 switch (brush.cloth_deform_type) {
825 math::normalize(cache.location_symm - cache.last_location_symm), factors, forces);
826 apply_forces(cloth_sim, forces, verts);
827 break;
829 translations_from_offset_and_factors(-offset, factors, forces);
830 apply_forces(cloth_sim, forces, verts);
831 break;
834 cloth_sim, verts, factors, falloff_plane.has_value(), cache.grab_delta_symm);
835 break;
837 apply_snake_hook_brush(cloth_sim, verts, factors, cache.grab_delta_symm);
838 break;
840 if (falloff_plane) {
841 calc_plane_pinch_forces(positions, falloff_plane->plane, falloff_plane->normal, forces);
842 }
843 else {
844 calc_pinch_forces(positions, cache.location_symm, forces);
845 }
846 scale_translations(forces, factors);
847 apply_forces(cloth_sim, forces, verts);
848 break;
850 calc_perpendicular_pinch_forces(positions, imat, cache.location_symm, forces);
851 scale_translations(forces, factors);
852 apply_forces(cloth_sim, forces, verts);
853 break;
854 }
856 gather_data_mesh(vert_normals, verts, forces);
857 scale_translations(forces, factors);
858 apply_forces(cloth_sim, forces, verts);
859 break;
861 expand_length_constraints(cloth_sim, verts, factors);
862 break;
863 }
864}
865
866static void calc_forces_grids(const Depsgraph &depsgraph,
867 Object &ob,
868 const Brush &brush,
869 const float3 &offset,
870 const float4x4 &imat,
871 const float3 &sim_location,
872 const float3 &gravity,
873 const std::optional<FalloffPlane> &falloff_plane,
874 const bke::pbvh::GridsNode &node,
875 LocalData &tls)
876{
877 SculptSession &ss = *ob.sculpt;
878 SimulationData &cloth_sim = *ss.cache->cloth_sim;
879 const StrokeCache &cache = *ss.cache;
880 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
881 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
882
883 const Span<int> grids = node.grids();
884 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
885 const MutableSpan init_positions = gather_data_grids(
886 subdiv_ccg, cloth_sim.init_pos.as_span(), grids, tls.init_positions);
887 const Span<float3> current_positions = brush.cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB ?
888 init_positions :
889 positions;
890
891 tls.factors.resize(positions.size());
892 const MutableSpan<float> factors = tls.factors;
893 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
894 filter_region_clip_factors(ss, current_positions, factors);
895
896 calc_brush_simulation_falloff(brush, cache.radius, sim_location, positions, factors);
897
898 const Span<int> verts = calc_vert_indices_grids(key, grids, tls.vert_indices);
899
900 tls.translations.resize(verts.size());
901 const MutableSpan<float3> forces = tls.translations;
902
903 /* Apply gravity in the entire simulation area before brush distances are taken into account. */
904 if (!math::is_zero(gravity)) {
905 translations_from_offset_and_factors(gravity, factors, forces);
906 apply_forces(cloth_sim, forces, verts);
907 }
908
909 if (brush.flag & BRUSH_FRONTFACE) {
910 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
911 }
912
913 tls.distances.resize(verts.size());
914 const MutableSpan<float> distances = tls.distances;
915 if (falloff_plane) {
916 calc_distances_to_plane(current_positions, falloff_plane->plane, distances);
917 }
918 else {
920 ss, current_positions, eBrushFalloffShape(brush.falloff_shape), distances);
921 }
922 filter_distances_with_radius(cache.radius, distances, factors);
923 apply_hardness_to_distances(cache, distances);
924 calc_brush_strength_factors(cache, brush, distances, factors);
925
926 const auto_mask::Cache *automask = auto_mask::active_cache_get(ss);
927 auto_mask::calc_grids_factors(depsgraph, ob, automask, node, grids, factors);
928
929 calc_brush_texture_factors(ss, brush, current_positions, factors);
930
931 scale_factors(factors, cache.bstrength);
932
933 switch (brush.cloth_deform_type) {
936 math::normalize(cache.location_symm - cache.last_location_symm), factors, forces);
937 apply_forces(cloth_sim, forces, verts);
938 break;
940 translations_from_offset_and_factors(-offset, factors, forces);
941 apply_forces(cloth_sim, forces, verts);
942 break;
945 cloth_sim, verts, factors, falloff_plane.has_value(), cache.grab_delta_symm);
946 break;
948 apply_snake_hook_brush(cloth_sim, verts, factors, cache.grab_delta_symm);
949 break;
951 if (falloff_plane) {
952 calc_plane_pinch_forces(positions, falloff_plane->plane, falloff_plane->normal, forces);
953 }
954 else {
955 calc_pinch_forces(positions, cache.location_symm, forces);
956 }
957 scale_translations(forces, factors);
958 apply_forces(cloth_sim, forces, verts);
959 break;
961 calc_perpendicular_pinch_forces(positions, imat, cache.location_symm, forces);
962 scale_translations(forces, factors);
963 apply_forces(cloth_sim, forces, verts);
964 break;
965 }
967 gather_grids_normals(subdiv_ccg, grids, forces);
968 scale_translations(forces, factors);
969 apply_forces(cloth_sim, forces, verts);
970 break;
972 expand_length_constraints(cloth_sim, verts, factors);
973 break;
974 }
975}
976
977static void calc_forces_bmesh(const Depsgraph &depsgraph,
978 Object &ob,
979 const Brush &brush,
980 const float3 &offset,
981 const float4x4 &imat,
982 const float3 &sim_location,
983 const float3 &gravity,
984 const std::optional<FalloffPlane> &falloff_plane,
986 LocalData &tls)
987{
988 SculptSession &ss = *ob.sculpt;
989 SimulationData &cloth_sim = *ss.cache->cloth_sim;
990 const StrokeCache &cache = *ss.cache;
991
992 const Set<BMVert *, 0> &bm_verts = BKE_pbvh_bmesh_node_unique_verts(&node);
994
995 const MutableSpan positions = gather_bmesh_positions(bm_verts, tls.positions);
996 const MutableSpan init_positions = gather_data_mesh(
997 cloth_sim.init_pos.as_span(), verts, tls.init_positions);
998 const Span<float3> current_positions = brush.cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB ?
999 init_positions :
1000 positions;
1001
1002 tls.factors.resize(verts.size());
1003 const MutableSpan<float> factors = tls.factors;
1004 fill_factor_from_hide_and_mask(*ss.bm, bm_verts, factors);
1005 filter_region_clip_factors(ss, current_positions, factors);
1006
1007 calc_brush_simulation_falloff(brush, cache.radius, sim_location, positions, factors);
1008
1009 tls.translations.resize(verts.size());
1010 const MutableSpan<float3> forces = tls.translations;
1011
1012 /* Apply gravity in the entire simulation area before brush distances are taken into account. */
1013 if (!math::is_zero(gravity)) {
1014 translations_from_offset_and_factors(gravity, factors, forces);
1015 apply_forces(cloth_sim, forces, verts);
1016 }
1017
1018 if (brush.flag & BRUSH_FRONTFACE) {
1019 calc_front_face(cache.view_normal_symm, bm_verts, factors);
1020 }
1021
1022 tls.distances.resize(verts.size());
1023 const MutableSpan<float> distances = tls.distances;
1024 if (falloff_plane) {
1025 calc_distances_to_plane(current_positions, falloff_plane->plane, distances);
1026 }
1027 else {
1029 ss, current_positions, eBrushFalloffShape(brush.falloff_shape), distances);
1030 }
1031 filter_distances_with_radius(cache.radius, distances, factors);
1032 apply_hardness_to_distances(cache, distances);
1033 calc_brush_strength_factors(cache, brush, distances, factors);
1034
1035 const auto_mask::Cache *automask = auto_mask::active_cache_get(ss);
1036 auto_mask::calc_vert_factors(depsgraph, ob, automask, node, bm_verts, factors);
1037
1038 calc_brush_texture_factors(ss, brush, current_positions, factors);
1039
1040 scale_factors(factors, cache.bstrength);
1041
1042 switch (brush.cloth_deform_type) {
1045 math::normalize(cache.location_symm - cache.last_location_symm), factors, forces);
1046 apply_forces(cloth_sim, forces, verts);
1047 break;
1049 translations_from_offset_and_factors(-offset, factors, forces);
1050 apply_forces(cloth_sim, forces, verts);
1051 break;
1054 cloth_sim, verts, factors, falloff_plane.has_value(), cache.grab_delta_symm);
1055 break;
1057 apply_snake_hook_brush(cloth_sim, verts, factors, cache.grab_delta_symm);
1058 break;
1060 if (falloff_plane) {
1061 calc_plane_pinch_forces(positions, falloff_plane->plane, falloff_plane->normal, forces);
1062 }
1063 else {
1064 calc_pinch_forces(positions, cache.location_symm, forces);
1065 }
1066 scale_translations(forces, factors);
1067 apply_forces(cloth_sim, forces, verts);
1068 break;
1070 calc_perpendicular_pinch_forces(positions, imat, cache.location_symm, forces);
1071 scale_translations(forces, factors);
1072 apply_forces(cloth_sim, forces, verts);
1073 break;
1074 }
1076 gather_bmesh_normals(bm_verts, forces);
1077 scale_translations(forces, factors);
1078 apply_forces(cloth_sim, forces, verts);
1079 break;
1081 expand_length_constraints(cloth_sim, verts, factors);
1082 break;
1083 }
1084}
1085
1087 const Depsgraph &depsgraph)
1088{
1090 DEGObjectIterSettings deg_iter_settings = {nullptr};
1091 deg_iter_settings.depsgraph = &const_cast<Depsgraph &>(depsgraph);
1094 DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, ob) {
1095 if (STREQ(object.id.name, ob->id.name)) {
1096 continue;
1097 }
1098
1101 if (!cmd) {
1102 continue;
1103 }
1104
1105 if (!cmd->bvhtree) {
1106 continue;
1107 }
1108
1110 col.ob = ob;
1111 col.collmd = cmd;
1112 collision_move_object(cmd, 1.0, 0.0, true);
1113 cache.append(col);
1114 }
1116 return cache;
1117}
1118
1123
1124static void cloth_brush_collision_cb(void *userdata,
1125 int index,
1126 const BVHTreeRay *ray,
1127 BVHTreeRayHit *hit)
1128{
1130 CollisionModifierData *col_data = col->col_data;
1131 const int3 vert_tri = col_data->vert_tris[index];
1132 float(*positions)[3] = col_data->x;
1133 float *tri[3], no[3], co[3];
1134
1135 tri[0] = positions[vert_tri[0]];
1136 tri[1] = positions[vert_tri[1]];
1137 tri[2] = positions[vert_tri[2]];
1138 float dist = 0.0f;
1139
1140 bool tri_hit = isect_ray_tri_watertight_v3(
1141 ray->origin, &col->isect_precalc, UNPACK3(tri), &dist, nullptr);
1142 normal_tri_v3(no, UNPACK3(tri));
1143 madd_v3_v3v3fl(co, ray->origin, ray->direction, dist);
1144
1145 if (tri_hit && dist < hit->dist) {
1146 hit->index = index;
1147 hit->dist = dist;
1148
1149 copy_v3_v3(hit->co, co);
1150 copy_v3_v3(hit->no, no);
1151 }
1152}
1153
1154static void cloth_brush_solve_collision(const Object &object,
1155 SimulationData &cloth_sim,
1156 const int i)
1157{
1158 const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT;
1159
1160 const float4x4 &object_to_world = object.object_to_world();
1161 const float4x4 &world_to_object = object.world_to_object();
1162
1163 for (const ColliderCache &collider_cache : cloth_sim.collider_list) {
1164 const float3 pos_world_space = math::transform_point(object_to_world, cloth_sim.pos[i]);
1165 const float3 prev_pos_world_space = math::transform_point(object_to_world,
1166 cloth_sim.last_iteration_pos[i]);
1167
1168 BVHTreeRayHit hit{};
1169 hit.index = -1;
1170
1171 const float3 ray_normal = math::normalize_and_get_length(
1172 pos_world_space - prev_pos_world_space, hit.dist);
1173
1175 CollisionModifierData *collmd = collider_cache.collmd;
1176 col.col_data = collmd;
1177 isect_ray_tri_watertight_v3_precalc(&col.isect_precalc, ray_normal);
1178
1180 prev_pos_world_space,
1181 ray_normal,
1182 0.3f,
1183 &hit,
1185 &col,
1186 raycast_flag);
1187
1188 if (hit.index == -1) {
1189 continue;
1190 }
1191
1192 const float3 collision_disp = float3(hit.no) * 0.005f;
1193
1194 float4 friction_plane;
1195 plane_from_point_normal_v3(friction_plane, hit.co, hit.no);
1196 float3 pos_on_friction_plane;
1197 closest_to_plane_v3(pos_on_friction_plane, friction_plane, pos_world_space);
1198 constexpr float friction_factor = 0.35f;
1199 const float3 movement_disp = (pos_on_friction_plane - float3(hit.co)) * friction_factor;
1200
1201 cloth_sim.pos[i] = math::transform_point(world_to_object,
1202 float3(hit.co) + movement_disp + collision_disp);
1203 }
1204}
1205
1207 const Brush *brush,
1208 const float3 &sim_location,
1209 const Span<int> verts,
1210 const MutableSpan<float> factors,
1211 LocalData &tls,
1212 SimulationData &cloth_sim)
1213{
1214 const SculptSession &ss = *object.sculpt;
1215
1216 tls.diffs.resize(verts.size());
1217 const MutableSpan<float3> pos_diff = tls.diffs;
1218 for (const int i : verts.index_range()) {
1219 pos_diff[i] = cloth_sim.pos[verts[i]] - cloth_sim.prev_pos[verts[i]];
1220 }
1221
1222 for (const int vert : verts) {
1223 cloth_sim.prev_pos[vert] = cloth_sim.pos[vert];
1224 }
1225
1226 for (const int i : verts.index_range()) {
1227 const int vert = verts[i];
1228 cloth_sim.pos[vert] += cloth_sim.acceleration[vert] * factors[i] * CLOTH_SIMULATION_TIME_STEP;
1229 }
1230
1231 scale_factors(factors, 1.0f - cloth_sim.damping);
1232 if (ss.cache) {
1233 const MutableSpan positions = gather_data_mesh(
1234 cloth_sim.init_pos.as_span(), verts, tls.positions);
1235 calc_brush_simulation_falloff(*brush, ss.cache->radius, sim_location, positions, factors);
1236 }
1237 scale_translations(pos_diff, factors);
1238
1239 for (const int i : verts.index_range()) {
1240 const int vert = verts[i];
1241 cloth_sim.pos[vert] += pos_diff[i];
1242 }
1243
1244 for (const int vert : verts) {
1245 cloth_brush_solve_collision(object, cloth_sim, vert);
1246 }
1247
1248 for (const int vert : verts) {
1249 cloth_sim.last_iteration_pos[vert] = cloth_sim.pos[vert];
1250 }
1251
1252 cloth_sim.acceleration.as_mutable_span().fill_indices(verts, float3(0));
1253}
1254
1255static void calc_constraint_factors(const Depsgraph &depsgraph,
1256 const Object &object,
1257 const Brush *brush,
1258 const float3 &sim_location,
1259 const Span<float3> init_positions,
1260 const MutableSpan<float> cloth_factors)
1261{
1262 const SculptSession &ss = *object.sculpt;
1263 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1264 IndexMaskMemory memory;
1265 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1266
1267 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
1268
1269 struct LocalData {
1272 };
1274 switch (pbvh.type()) {
1275 case bke::pbvh::Type::Mesh: {
1276 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1277 const MeshAttributeData attribute_data(mesh);
1279 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1280 LocalData &tls = all_tls.local();
1281 const Span<int> verts = nodes[i].verts();
1282 tls.factors.resize(verts.size());
1283 const MutableSpan<float> factors = tls.factors;
1285 attribute_data.hide_vert, attribute_data.mask, verts, factors);
1286 auto_mask::calc_vert_factors(depsgraph, object, automasking, nodes[i], verts, factors);
1287 if (ss.cache) {
1288 const MutableSpan positions = gather_data_mesh(init_positions, verts, tls.positions);
1290 *brush, ss.cache->radius, sim_location, positions, factors);
1291 }
1292 scatter_data_mesh(factors.as_span(), verts, cloth_factors);
1293 });
1294 break;
1295 }
1297 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1298 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1300 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1301 LocalData &tls = all_tls.local();
1302 const Span<int> grids = nodes[i].grids();
1303 const int grid_verts_num = grids.size() * key.grid_area;
1304 tls.factors.resize(grid_verts_num);
1305 const MutableSpan<float> factors = tls.factors;
1306 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
1307 auto_mask::calc_grids_factors(depsgraph, object, automasking, nodes[i], grids, factors);
1308 if (ss.cache) {
1309 const Span<float3> positions = gather_data_grids(
1310 subdiv_ccg, init_positions, grids, tls.positions);
1312 *brush, ss.cache->radius, sim_location, positions, factors);
1313 }
1314 scatter_data_grids(subdiv_ccg, factors.as_span(), grids, cloth_factors);
1315 });
1316 break;
1317 }
1319 const BMesh &bm = *ss.bm;
1321 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1322 LocalData &tls = all_tls.local();
1324 const_cast<bke::pbvh::BMeshNode *>(&nodes[i]));
1325 tls.factors.resize(verts.size());
1326 const MutableSpan<float> factors = tls.factors;
1328 auto_mask::calc_vert_factors(depsgraph, object, automasking, nodes[i], verts, factors);
1329 if (ss.cache) {
1330 const MutableSpan positions = gather_data_bmesh(init_positions, verts, tls.positions);
1332 *brush, ss.cache->radius, sim_location, positions, factors);
1333 }
1334 scatter_data_bmesh(factors.as_span(), verts, cloth_factors);
1335 });
1336 break;
1337 }
1338 }
1339}
1340
1341static void cloth_brush_satisfy_constraints(const Depsgraph &depsgraph,
1342 const Object &object,
1343 const Brush *brush,
1344 SimulationData &cloth_sim)
1345{
1346 const SculptSession &ss = *object.sculpt;
1347
1348 const float3 sim_location = cloth_brush_simulation_location_get(ss, brush);
1349
1350 /* Precalculate factors into an array since we need random access to specific vertex values. */
1351 Array<float> factors(SCULPT_vertex_count_get(object));
1352 calc_constraint_factors(depsgraph, object, brush, sim_location, cloth_sim.init_pos, factors);
1353
1354 for (int constraint_it = 0; constraint_it < CLOTH_SIMULATION_ITERATIONS; constraint_it++) {
1355 for (const LengthConstraint &constraint : cloth_sim.length_constraints) {
1356 if (cloth_sim.node_state[constraint.node] != SCULPT_CLOTH_NODE_ACTIVE) {
1357 /* Skip all constraints that were created for inactive nodes. */
1358 continue;
1359 }
1360
1361 const int v1 = constraint.elem_index_a;
1362 const int v2 = constraint.elem_index_b;
1363
1364 const float3 v1_to_v2 = float3(constraint.elem_position_b) -
1365 float3(constraint.elem_position_a);
1366 const float current_distance = math::length(v1_to_v2);
1367 float3 correction_vector;
1368
1369 const float constraint_distance = constraint.length +
1370 (cloth_sim.length_constraint_tweak[v1] * 0.5f) +
1371 (cloth_sim.length_constraint_tweak[v2] * 0.5f);
1372
1373 if (current_distance > 0.0f) {
1374 correction_vector = v1_to_v2 * CLOTH_SOLVER_DISPLACEMENT_FACTOR *
1375 (1.0f - (constraint_distance / current_distance));
1376 }
1377 else {
1378 correction_vector = v1_to_v2 * CLOTH_SOLVER_DISPLACEMENT_FACTOR;
1379 }
1380
1381 const float3 correction_vector_half = correction_vector * 0.5f;
1382
1383 const float factor_v1 = factors[v1];
1384 const float factor_v2 = factors[v2];
1385
1386 float deformation_strength = 1.0f;
1387 if (constraint.type == SCULPT_CLOTH_CONSTRAINT_DEFORMATION) {
1388 deformation_strength = (cloth_sim.deformation_strength[v1] +
1389 cloth_sim.deformation_strength[v2]) *
1390 0.5f;
1391 }
1392
1393 if (constraint.type == SCULPT_CLOTH_CONSTRAINT_SOFTBODY) {
1394 const float softbody_plasticity = brush ? brush->cloth_constraint_softbody_strength : 0.0f;
1395 cloth_sim.pos[v1] += correction_vector_half *
1396 (1.0f * factor_v1 * constraint.strength * softbody_plasticity);
1397 cloth_sim.softbody_pos[v1] += correction_vector_half * -1.0f * factor_v1 *
1398 constraint.strength * (1.0f - softbody_plasticity);
1399 }
1400 else {
1401 cloth_sim.pos[v1] += correction_vector_half * 1.0f * factor_v1 * constraint.strength *
1402 deformation_strength;
1403 if (v1 != v2) {
1404 cloth_sim.pos[v2] += correction_vector_half * -1.0f * factor_v2 * constraint.strength *
1405 deformation_strength;
1406 }
1407 }
1408 }
1409 }
1410}
1411
1412void do_simulation_step(const Depsgraph &depsgraph,
1413 const Sculpt &sd,
1414 Object &object,
1415 SimulationData &cloth_sim,
1416 const IndexMask &node_mask)
1417{
1418 SculptSession &ss = *object.sculpt;
1419 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1420 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1421
1422 /* Update the constraints. */
1423 cloth_brush_satisfy_constraints(depsgraph, object, brush, cloth_sim);
1424
1425 const float3 sim_location = cloth_brush_simulation_location_get(ss, brush);
1426
1427 IndexMaskMemory memory;
1429 switch (pbvh.type()) {
1430 case bke::pbvh::Type::Mesh: {
1432 const IndexMask active_nodes = IndexMask::from_predicate(
1433 node_mask, GrainSize(1024), memory, [&](const int i) {
1434 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1435 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_ACTIVE;
1436 });
1437 Mesh &mesh = *static_cast<Mesh *>(object.data);
1438 const MeshAttributeData attribute_data(mesh);
1439 const PositionDeformData position_data(depsgraph, object);
1440 active_nodes.foreach_index(GrainSize(1), [&](const int i) {
1441 LocalData &tls = all_tls.local();
1442 const Span<int> verts = nodes[i].verts();
1443
1444 tls.factors.resize(verts.size());
1445 const MutableSpan<float> factors = tls.factors;
1447 attribute_data.hide_vert, attribute_data.mask, verts, factors);
1448 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
1449 auto_mask::calc_vert_factors(depsgraph, object, automasking, nodes[i], verts, factors);
1450
1451 solve_verts_simulation(object, brush, sim_location, verts, factors, tls, cloth_sim);
1452
1453 tls.translations.resize(verts.size());
1454 const MutableSpan<float3> translations = tls.translations;
1455 for (const int i : verts.index_range()) {
1456 translations[i] = cloth_sim.pos[verts[i]] - position_data.eval[verts[i]];
1457 }
1458
1459 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
1460 position_data.deform(translations, verts);
1461
1462 cloth_sim.node_state[cloth_sim.node_state_index.lookup(&nodes[i])] =
1465 });
1466 break;
1467 }
1470 const IndexMask active_nodes = IndexMask::from_predicate(
1471 node_mask, GrainSize(1024), memory, [&](const int i) {
1472 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1473 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_ACTIVE;
1474 });
1475 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1476 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1477 const Span<float3> cloth_positions = cloth_sim.pos;
1478 MutableSpan<float3> positions = subdiv_ccg.positions;
1479 active_nodes.foreach_index(GrainSize(1), [&](const int i) {
1480 LocalData &tls = all_tls.local();
1481 const Span<int> grids = nodes[i].grids();
1482 const int grid_verts_num = grids.size() * key.grid_area;
1483
1484 tls.factors.resize(grid_verts_num);
1485 const MutableSpan<float> factors = tls.factors;
1486 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
1487 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
1488 auto_mask::calc_grids_factors(depsgraph, object, automasking, nodes[i], grids, factors);
1489
1490 const Span<int> verts = calc_vert_indices_grids(key, grids, tls.vert_indices);
1491 solve_verts_simulation(object, brush, sim_location, verts, factors, tls, cloth_sim);
1492
1493 for (const int grid : grids) {
1494 const IndexRange grid_range = bke::ccg::grid_range(key, grid);
1495 positions.slice(grid_range).copy_from(cloth_positions.slice(grid_range));
1496 }
1497
1498 cloth_sim.node_state[cloth_sim.node_state_index.lookup(&nodes[i])] =
1500 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
1501 });
1502 break;
1503 }
1506 const IndexMask active_nodes = IndexMask::from_predicate(
1507 node_mask, GrainSize(1024), memory, [&](const int i) {
1508 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1509 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_ACTIVE;
1510 });
1511 BMesh &bm = *ss.bm;
1512 active_nodes.foreach_index(GrainSize(1), [&](const int i) {
1513 LocalData &tls = all_tls.local();
1515
1516 tls.factors.resize(verts.size());
1517 const MutableSpan<float> factors = tls.factors;
1519 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
1520 auto_mask::calc_vert_factors(depsgraph, object, automasking, nodes[i], verts, factors);
1521
1522 const Span<int> vert_indices = calc_vert_indices_bmesh(verts, tls.vert_indices);
1523 solve_verts_simulation(object, brush, sim_location, vert_indices, factors, tls, cloth_sim);
1524
1525 for (BMVert *vert : verts) {
1526 copy_v3_v3(vert->co, cloth_sim.pos[BM_elem_index_get(vert)]);
1527 }
1528
1529 cloth_sim.node_state[cloth_sim.node_state_index.lookup(&nodes[i])] =
1532 });
1533 break;
1534 }
1535 }
1536 pbvh.tag_positions_changed(node_mask);
1538}
1539
1540static void cloth_brush_apply_brush_forces(const Depsgraph &depsgraph,
1541 const Sculpt &sd,
1542 Object &ob,
1543 const IndexMask &node_mask)
1544{
1545 SculptSession &ss = *ob.sculpt;
1546 StrokeCache &cache = *ss.cache;
1547 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
1548
1549 float3 area_no;
1550 float3 area_co;
1551 float3 offset;
1552
1553 if (math::is_zero(cache.grab_delta_symm)) {
1554 return;
1555 }
1556
1557 float3 grab_delta = math::normalize(cache.grab_delta_symm);
1558
1559 /* Calculate push offset. */
1561 offset = cache.sculpt_normal_symm * cache.radius * cache.scale * 2.0f;
1562 }
1563
1567 {
1568 calc_brush_plane(depsgraph, brush, ob, node_mask, area_no, area_co);
1569
1570 /* Initialize stroke local space matrix. */
1571 mat.x_axis() = math::cross(area_no, cache.grab_delta_symm);
1572 mat.y_axis() = math::cross(area_no, mat.x_axis());
1573 mat.z_axis() = area_no;
1574 mat.location() = cache.location_symm;
1575 normalize_m4(mat.ptr());
1576
1577 /* Update matrix for the cursor preview. */
1578 if (cache.mirror_symmetry_pass == 0) {
1579 cache.stroke_local_mat = mat;
1580 }
1581 }
1582
1584 /* Set the deformation strength to 0. Brushes will initialize the strength in the required
1585 * area. */
1586 cache.cloth_sim->deformation_strength.fill(0.0f);
1587 }
1588
1589 const float3 sim_location = cloth_brush_simulation_location_get(ss, &brush);
1590
1591 /* Gravity */
1592 float3 gravity(0);
1593 if (cache.supports_gravity) {
1594 gravity += cache.gravity_direction_symm * -sd.gravity_factor;
1595 }
1596
1597 std::optional<FalloffPlane> falloff_plane;
1599 falloff_plane.emplace();
1600 falloff_plane->normal = math::normalize(grab_delta);
1601 plane_from_point_normal_v3(falloff_plane->plane, area_co, falloff_plane->normal);
1602 }
1603
1605
1607 switch (pbvh.type()) {
1608 case bke::pbvh::Type::Mesh: {
1609 const Mesh &mesh = *static_cast<Mesh *>(ob.data);
1610 const MeshAttributeData attribute_data(mesh);
1611 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(depsgraph, ob);
1612 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1614 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1615 LocalData &tls = all_tls.local();
1617 ob,
1618 brush,
1619 offset,
1620 mat,
1621 sim_location,
1622 gravity,
1623 falloff_plane,
1624 attribute_data,
1625 positions_eval,
1626 vert_normals,
1627 nodes[i],
1628 tls);
1629 });
1630 break;
1631 }
1634 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1635 LocalData &tls = all_tls.local();
1637 ob,
1638 brush,
1639 offset,
1640 mat,
1641 sim_location,
1642 gravity,
1643 falloff_plane,
1644 nodes[i],
1645 tls);
1646 });
1647 break;
1648 }
1651 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1652 LocalData &tls = all_tls.local();
1654 ob,
1655 brush,
1656 offset,
1657 mat,
1658 sim_location,
1659 gravity,
1660 falloff_plane,
1661 nodes[i],
1662 tls);
1663 });
1664 break;
1665 }
1666 }
1667}
1668
1669/* Allocates nodes state and initializes them to Uninitialized, so constraints can be created for
1670 * them. */
1672{
1673 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1674 IndexMaskMemory memory;
1675 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1677
1678 switch (pbvh.type()) {
1679 case bke::pbvh::Type::Mesh: {
1681 node_mask.foreach_index([&](const int i) { cloth_sim.node_state_index.add(&nodes[i], i); });
1682 break;
1683 }
1686 node_mask.foreach_index([&](const int i) { cloth_sim.node_state_index.add(&nodes[i], i); });
1687 break;
1688 }
1691 node_mask.foreach_index([&](const int i) { cloth_sim.node_state_index.add(&nodes[i], i); });
1692 break;
1693 }
1694 }
1695}
1696
1697static void copy_positions_to_array(const Depsgraph &depsgraph,
1698 const Object &object,
1699 MutableSpan<float3> positions)
1700{
1701 const SculptSession &ss = *object.sculpt;
1702 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1703 switch (pbvh.type()) {
1706 break;
1708 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1709 positions.copy_from(subdiv_ccg.positions);
1710 break;
1711 }
1713 BM_mesh_vert_coords_get(ss.bm, positions);
1714 break;
1715 }
1716}
1717
1718static void copy_normals_to_array(const Depsgraph &depsgraph,
1719 const Object &object,
1721{
1722 const SculptSession &ss = *object.sculpt;
1723 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1724 switch (pbvh.type()) {
1727 break;
1729 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1730 normals.copy_from(subdiv_ccg.normals);
1731 break;
1732 }
1735 break;
1736 }
1737}
1738
1739std::unique_ptr<SimulationData> brush_simulation_create(const Depsgraph &depsgraph,
1740 Object &ob,
1741 const float cloth_mass,
1742 const float cloth_damping,
1743 const float cloth_softbody_strength,
1744 const bool use_collisions,
1745 const bool needs_deform_coords)
1746{
1747 const int totverts = SCULPT_vertex_count_get(ob);
1748 std::unique_ptr<SimulationData> cloth_sim = std::make_unique<SimulationData>();
1749
1750 cloth_sim->length_constraints.reserve(CLOTH_LENGTH_CONSTRAINTS_BLOCK);
1751
1752 cloth_sim->acceleration = Array<float3>(totverts, float3(0));
1753 cloth_sim->pos = Array<float3>(totverts, float3(0));
1754 cloth_sim->length_constraint_tweak = Array<float>(totverts, 0.0f);
1755
1756 cloth_sim->init_pos.reinitialize(totverts);
1757 copy_positions_to_array(depsgraph, ob, cloth_sim->init_pos);
1758
1759 cloth_sim->last_iteration_pos = cloth_sim->init_pos;
1760 cloth_sim->prev_pos = cloth_sim->init_pos;
1761
1762 cloth_sim->init_no.reinitialize(totverts);
1763 copy_normals_to_array(depsgraph, ob, cloth_sim->init_no);
1764
1765 if (needs_deform_coords) {
1766 cloth_sim->deformation_pos = cloth_sim->init_pos;
1767 cloth_sim->deformation_strength = Array<float>(totverts, 1.0f);
1768 }
1769
1770 if (cloth_softbody_strength > 0.0f) {
1771 cloth_sim->softbody_pos = cloth_sim->init_pos;
1772 }
1773
1774 cloth_sim->mass = cloth_mass;
1775 cloth_sim->damping = cloth_damping;
1776 cloth_sim->softbody_strength = cloth_softbody_strength;
1777
1778 if (use_collisions) {
1779 cloth_sim->collider_list = cloth_brush_collider_cache_create(ob, depsgraph);
1780 }
1781
1783
1784 return cloth_sim;
1785}
1786
1788 const Object &object,
1789 SimulationData &cloth_sim)
1790{
1791 copy_positions_to_array(depsgraph, object, cloth_sim.pos);
1792}
1793
1794void sim_activate_nodes(Object &object, SimulationData &cloth_sim, const IndexMask &node_mask)
1795{
1796 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1797
1798 /* Activate the nodes inside the simulation area. */
1799 switch (pbvh.type()) {
1800 case bke::pbvh::Type::Mesh: {
1802 node_mask.foreach_index([&](const int i) {
1803 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1804 cloth_sim.node_state[node_index] = SCULPT_CLOTH_NODE_ACTIVE;
1805 });
1806 break;
1807 }
1810 node_mask.foreach_index([&](const int i) {
1811 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1812 cloth_sim.node_state[node_index] = SCULPT_CLOTH_NODE_ACTIVE;
1813 });
1814 break;
1815 }
1818 node_mask.foreach_index([&](const int i) {
1819 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1820 cloth_sim.node_state[node_index] = SCULPT_CLOTH_NODE_ACTIVE;
1821 });
1822 break;
1823 }
1824 }
1825}
1826
1828 Object &ob,
1829 const IndexMask &node_mask)
1830{
1831 SculptSession &ss = *ob.sculpt;
1832 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1833 const float radius = ss.cache->initial_radius;
1834 const float limit = radius + (radius * brush->cloth_sim_limit);
1835 const float3 sim_location = cloth_brush_simulation_location_get(ss, brush);
1836 ensure_nodes_constraints(sd, ob, node_mask, *ss.cache->cloth_sim, sim_location, limit);
1837}
1838
1839void do_cloth_brush(const Depsgraph &depsgraph,
1840 const Sculpt &sd,
1841 Object &ob,
1842 const IndexMask &node_mask)
1843{
1844 SculptSession &ss = *ob.sculpt;
1845 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1846
1847 if (!ss.cache->cloth_sim) {
1849 ob,
1850 brush->cloth_mass,
1851 brush->cloth_damping,
1854 is_cloth_deform_brush(*brush));
1855 }
1856
1859 /* When using simulation a fixed local simulation area, constraints are created only using
1860 * the initial stroke position and initial radius (per symmetry pass) instead of per node.
1861 * This allows to skip unnecessary constraints that will never be simulated, making the
1862 * solver faster. When the simulation starts for a node, the node gets activated and all its
1863 * constraints are considered final. As the same node can be included inside the brush radius
1864 * from multiple symmetry passes, the cloth brush can't activate the node for simulation yet
1865 * as this will cause the ensure constraints function to skip the node in the next symmetry
1866 * passes. It needs to build the constraints here and skip simulating the first step, so all
1867 * passes can add their constraints to all affected nodes. */
1869 }
1870 /* The first step of a symmetry pass is never simulated as deformation modes need valid delta
1871 * for brush tip alignment. */
1872 return;
1873 }
1874
1875 /* Ensure the constraints for the nodes. */
1877
1878 /* Store the initial state in the simulation. */
1880
1881 /* Enable the nodes that should be simulated. */
1882 sim_activate_nodes(ob, *ss.cache->cloth_sim, node_mask);
1883
1884 /* Apply forces to the vertices. */
1885 cloth_brush_apply_brush_forces(depsgraph, sd, ob, node_mask);
1886
1887 /* Update and write the simulation to the nodes. */
1888 do_simulation_step(depsgraph, sd, ob, *ss.cache->cloth_sim, node_mask);
1889}
1890
1892
1893void simulation_limits_draw(const uint gpuattr,
1894 const Brush &brush,
1895 const float location[3],
1896 const float normal[3],
1897 const float rds,
1898 const float line_width,
1899 const float outline_col[3],
1900 const float alpha)
1901{
1902 float cursor_trans[4][4], cursor_rot[4][4];
1903 const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
1904 float quat[4];
1905 unit_m4(cursor_trans);
1906 translate_m4(cursor_trans, location[0], location[1], location[2]);
1907 rotation_between_vecs_to_quat(quat, z_axis, normal);
1908 quat_to_mat4(cursor_rot, quat);
1910 GPU_matrix_mul(cursor_trans);
1911 GPU_matrix_mul(cursor_rot);
1912
1913 GPU_line_width(line_width);
1914 immUniformColor3fvAlpha(outline_col, alpha * 0.5f);
1916 gpuattr, 0, 0, rds + (rds * brush.cloth_sim_limit * brush.cloth_sim_falloff), 320);
1917 immUniformColor3fvAlpha(outline_col, alpha * 0.7f);
1918 imm_draw_circle_wire_3d(gpuattr, 0, 0, rds + rds * brush.cloth_sim_limit, 80);
1920}
1921
1923 SculptSession &ss,
1924 const float outline_col[3],
1925 float outline_alpha)
1926{
1927 float4x4 local_mat = ss.cache->stroke_local_mat;
1928
1930 add_v3_v3v3(local_mat[3], ss.cache->location, ss.cache->grab_delta);
1931 }
1932
1933 GPU_matrix_mul(local_mat.ptr());
1934
1935 const float dist = ss.cache->radius;
1936 const float arrow_x = ss.cache->radius * 0.2f;
1937 const float arrow_y = ss.cache->radius * 0.1f;
1938
1939 immUniformColor3fvAlpha(outline_col, outline_alpha);
1940 GPU_line_width(2.0f);
1942 immVertex3f(gpuattr, dist, 0.0f, 0.0f);
1943 immVertex3f(gpuattr, -dist, 0.0f, 0.0f);
1944 immEnd();
1945
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 immVertex3f(gpuattr, -dist, 0.0f, 0.0f);
1952 immVertex3f(gpuattr, -dist + arrow_x, arrow_y, 0.0f);
1953 immVertex3f(gpuattr, -dist + arrow_x, -arrow_y, 0.0f);
1954
1955 immEnd();
1956}
1957
1958/* Cloth Filter. */
1959
1967
1969 {int(ClothFilterType::Gravity), "GRAVITY", 0, "Gravity", "Applies gravity to the simulation"},
1970 {int(ClothFilterType::Inflate), "INFLATE", 0, "Inflate", "Inflates the cloth"},
1971 {int(ClothFilterType::Expand), "EXPAND", 0, "Expand", "Expands the cloth's dimensions"},
1973 "PINCH",
1974 0,
1975 "Pinch",
1976 "Pulls the cloth to the cursor's start position"},
1978 "SCALE",
1979 0,
1980 "Scale",
1981 "Scales the mesh as a soft body using the origin of the object as scale"},
1982 {0, nullptr, 0, nullptr, nullptr},
1983};
1984
1987 "LOCAL",
1988 0,
1989 "Local",
1990 "Use the local axis to limit the force and set the gravity direction"},
1992 "WORLD",
1993 0,
1994 "World",
1995 "Use the global axis to limit the force and set the gravity direction"},
1997 "VIEW",
1998 0,
1999 "View",
2000 "Use the view axis to limit the force and set the gravity direction"},
2001 {0, nullptr, 0, nullptr, nullptr},
2002};
2003
2009
2011 {CLOTH_FILTER_FORCE_X, "X", 0, "X", "Apply force in the X axis"},
2012 {CLOTH_FILTER_FORCE_Y, "Y", 0, "Y", "Apply force in the Y axis"},
2013 {CLOTH_FILTER_FORCE_Z, "Z", 0, "Z", "Apply force in the Z axis"},
2014 {0, nullptr, 0, nullptr, nullptr},
2015};
2016
2018{
2019 return ELEM(filter_type, ClothFilterType::Scale);
2020}
2021
2023 const filter::Cache &filter_cache,
2024 const MutableSpan<float3> forces)
2025{
2026 const float3x3 to_object_space = filter::to_object_space(filter_cache);
2027 for (const int i : forces.index_range()) {
2028 float3 force(0.0f);
2029 if (filter_cache.orientation == filter::FilterOrientation::View) {
2030 /* When using the view orientation apply gravity in the -Y axis, this way objects will
2031 * fall down instead of backwards. */
2032 force[1] = -factors[i];
2033 }
2034 else {
2035 force[2] = -factors[i];
2036 }
2037 forces[i] = to_object_space * force;
2038 }
2039}
2040
2048
2050 const Span<int> verts,
2051 const Span<float> factors,
2052 FilterLocalData &tls)
2053{
2054 const MutableSpan translations = gather_data_mesh(
2055 filter_cache.cloth_sim->init_pos.as_span(), verts, tls.forces);
2056 scale_translations(translations, factors);
2057 filter::zero_disabled_axis_components(filter_cache, translations);
2058 for (const int i : verts.index_range()) {
2059 filter_cache.cloth_sim->deformation_pos[verts[i]] =
2060 filter_cache.cloth_sim->init_pos[verts[i]] + translations[i];
2061 }
2062}
2063
2064static void apply_filter_forces_mesh(const Depsgraph &depsgraph,
2065 const ClothFilterType filter_type,
2066 const float filter_strength,
2067 const float3 &gravity,
2068 const Span<float3> positions_eval,
2069 const Span<float3> vert_normals,
2070 const GroupedSpan<int> vert_to_face_map,
2071 const MeshAttributeData &attribute_data,
2072 const bke::pbvh::MeshNode &node,
2073 Object &object,
2074 FilterLocalData &tls)
2075{
2076 const SculptSession &ss = *object.sculpt;
2077 SimulationData &cloth_sim = *ss.filter_cache->cloth_sim;
2078
2079 const Span<int> verts = node.verts();
2080
2081 tls.factors.resize(verts.size());
2082 const MutableSpan<float> factors = tls.factors;
2083 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
2084 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
2085 auto_mask::calc_vert_factors(depsgraph, object, automasking, node, verts, factors);
2086
2088 for (const int i : verts.index_range()) {
2089 const int vert = verts[i];
2091 vert_to_face_map, attribute_data.face_sets, vert, ss.filter_cache->active_face_set))
2092 {
2093 factors[i] = 0.0f;
2094 }
2095 }
2096 }
2097
2098 scale_factors(factors, filter_strength);
2099
2100 tls.forces.resize(verts.size());
2101 const MutableSpan<float3> forces = tls.forces;
2102 if (!math::is_zero(gravity)) {
2103 forces.fill(gravity);
2104 apply_forces(cloth_sim, forces, verts);
2105 }
2106
2107 switch (filter_type) {
2109 calc_gravity_forces(factors, *ss.filter_cache, forces);
2110 apply_forces(cloth_sim, tls.forces, verts);
2111 break;
2113 gather_data_mesh(vert_normals, verts, forces);
2114 scale_translations(forces, factors);
2115 apply_forces(cloth_sim, tls.forces, verts);
2116 break;
2118 expand_length_constraints(cloth_sim, verts, factors);
2119 break;
2122
2123 gather_data_mesh(positions_eval, verts, tls.positions),
2125 forces);
2126 scale_translations(forces, factors);
2127 apply_forces(cloth_sim, tls.forces, verts);
2128 break;
2130 apply_scale_filter(*ss.filter_cache, verts, factors, tls);
2131 break;
2132 }
2133}
2134
2135static void apply_filter_forces_grids(const Depsgraph &depsgraph,
2136 const Span<int> face_sets,
2137 const ClothFilterType filter_type,
2138 const float filter_strength,
2139 const float3 &gravity,
2140 const bke::pbvh::GridsNode &node,
2141 Object &object,
2142 FilterLocalData &tls)
2143{
2144 const SculptSession &ss = *object.sculpt;
2145 SimulationData &cloth_sim = *ss.filter_cache->cloth_sim;
2146 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
2147 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
2148
2149 const Span<int> grids = node.grids();
2150 const int grid_verts_num = grids.size() * key.grid_area;
2151
2152 tls.factors.resize(grid_verts_num);
2153 const MutableSpan<float> factors = tls.factors;
2154 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
2155 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
2156 auto_mask::calc_grids_factors(depsgraph, object, automasking, node, grids, factors);
2157
2159 for (const int i : grids.index_range()) {
2161 subdiv_ccg, face_sets, grids[i], ss.filter_cache->active_face_set))
2162 {
2163 factors.slice(i * key.grid_area, key.grid_area).fill(0.0f);
2164 }
2165 }
2166 }
2167
2168 scale_factors(factors, filter_strength);
2169
2170 const Span<int> verts = calc_vert_indices_grids(key, grids, tls.vert_indices);
2171
2172 tls.forces.resize(verts.size());
2173 const MutableSpan<float3> forces = tls.forces;
2174 if (!math::is_zero(gravity)) {
2175 forces.fill(gravity);
2176 apply_forces(cloth_sim, forces, verts);
2177 }
2178
2179 switch (filter_type) {
2181 calc_gravity_forces(factors, *ss.filter_cache, forces);
2182 apply_forces(cloth_sim, tls.forces, verts);
2183 break;
2185 gather_grids_normals(subdiv_ccg, grids, forces);
2186 scale_translations(forces, factors);
2187 apply_forces(cloth_sim, tls.forces, verts);
2188 break;
2190 expand_length_constraints(cloth_sim, verts, factors);
2191 break;
2194
2195 gather_grids_positions(subdiv_ccg, grids, tls.positions),
2197 forces);
2198 scale_translations(forces, factors);
2199 apply_forces(cloth_sim, tls.forces, verts);
2200 break;
2202 apply_scale_filter(*ss.filter_cache, verts, factors, tls);
2203 break;
2204 }
2205}
2206
2207static void apply_filter_forces_bmesh(const Depsgraph &depsgraph,
2208 const ClothFilterType filter_type,
2209 const float filter_strength,
2210 const float3 &gravity,
2212 Object &object,
2213 FilterLocalData &tls)
2214{
2215 const SculptSession &ss = *object.sculpt;
2216 SimulationData &cloth_sim = *ss.filter_cache->cloth_sim;
2217 const BMesh &bm = *ss.bm;
2218
2220
2221 tls.factors.resize(verts.size());
2222 const MutableSpan<float> factors = tls.factors;
2224 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
2225 auto_mask::calc_vert_factors(depsgraph, object, automasking, node, verts, factors);
2226
2228 const int face_set_offset = CustomData_get_offset_named(
2229 &bm.pdata, CD_PROP_INT32, ".sculpt_face_set");
2230 int i = 0;
2231 for (const BMVert *vert : verts) {
2232 if (!face_set::vert_has_face_set(face_set_offset, *vert, ss.filter_cache->active_face_set)) {
2233 factors[i] = 0.0f;
2234 }
2235 i++;
2236 }
2237 }
2238
2239 scale_factors(factors, filter_strength);
2240
2241 const Span<int> vert_indices = calc_vert_indices_bmesh(verts, tls.vert_indices);
2242
2243 tls.forces.resize(verts.size());
2244 const MutableSpan<float3> forces = tls.forces;
2245 if (!math::is_zero(gravity)) {
2246 forces.fill(gravity);
2247 apply_forces(cloth_sim, forces, vert_indices);
2248 }
2249
2250 switch (filter_type) {
2252 calc_gravity_forces(factors, *ss.filter_cache, forces);
2253 apply_forces(cloth_sim, tls.forces, vert_indices);
2254 break;
2256 gather_bmesh_normals(verts, forces);
2257 scale_translations(forces, factors);
2258 apply_forces(cloth_sim, tls.forces, vert_indices);
2259 break;
2261 expand_length_constraints(cloth_sim, vert_indices, factors);
2262 break;
2265
2268 forces);
2269 scale_translations(forces, factors);
2270 apply_forces(cloth_sim, tls.forces, vert_indices);
2271 break;
2273 apply_scale_filter(*ss.filter_cache, vert_indices, factors, tls);
2274 break;
2275 }
2276}
2277
2279 wmOperator *op,
2280 const wmEvent *event)
2281{
2282 Object &object = *CTX_data_active_object(C);
2284 SculptSession &ss = *object.sculpt;
2285 const Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
2286 const ClothFilterType filter_type = ClothFilterType(RNA_enum_get(op->ptr, "type"));
2287 float filter_strength = RNA_float_get(op->ptr, "strength");
2288
2289 if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
2290 MEM_delete(ss.filter_cache);
2291 ss.filter_cache = nullptr;
2292 undo::push_end(object);
2294 return OPERATOR_FINISHED;
2295 }
2296
2297 if (event->type != MOUSEMOVE) {
2299 }
2300
2301 const float len = event->prev_press_xy[0] - event->xy[0];
2302 filter_strength = filter_strength * -len * 0.001f * UI_SCALE_FAC;
2303
2305
2307
2309
2310 const IndexMask &node_mask = ss.filter_cache->node_mask;
2311
2312 if (auto_mask::is_enabled(sd, object, nullptr) && ss.filter_cache->automasking &&
2314 {
2315 ss.filter_cache->automasking->calc_cavity_factor(*depsgraph, object, node_mask);
2316 }
2317
2318 float3 gravity(0.0f);
2319 if (sd.gravity_object) {
2320 gravity = sd.gravity_object->object_to_world().ptr()[2];
2321 }
2322 else {
2323 gravity[2] = -1.0f;
2324 }
2325 gravity *= sd.gravity_factor * filter_strength;
2326
2327 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
2328
2330 switch (pbvh.type()) {
2331 case bke::pbvh::Type::Mesh: {
2332 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(*depsgraph, object);
2333 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(*depsgraph, object);
2334 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
2335 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
2336 const MeshAttributeData attribute_data(mesh);
2338 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2339 FilterLocalData &tls = all_tls.local();
2341 filter_type,
2342 filter_strength,
2343 gravity,
2344 positions_eval,
2345 vert_normals,
2346 vert_to_face_map,
2347 attribute_data,
2348 nodes[i],
2349 object,
2350 tls);
2351 bke::pbvh::update_node_bounds_mesh(positions_eval, nodes[i]);
2352 });
2353 break;
2354 }
2356 const Mesh &base_mesh = *static_cast<const Mesh *>(object.data);
2357 const bke::AttributeAccessor attributes = base_mesh.attributes();
2358 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set",
2360 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
2361 MutableSpan<float3> positions = subdiv_ccg.positions;
2363 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2364 FilterLocalData &tls = all_tls.local();
2366 *depsgraph, face_sets, filter_type, filter_strength, gravity, nodes[i], object, tls);
2367 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
2368 });
2369 break;
2370 }
2373 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2374 FilterLocalData &tls = all_tls.local();
2376 *depsgraph, filter_type, filter_strength, gravity, nodes[i], object, tls);
2378 });
2379 break;
2380 }
2381 }
2382 pbvh.tag_positions_changed(node_mask);
2384
2385 /* Activate all nodes. */
2386 sim_activate_nodes(object, *ss.filter_cache->cloth_sim, node_mask);
2387
2388 /* Update and write the simulation to the nodes. */
2389 do_simulation_step(*depsgraph, sd, object, *ss.filter_cache->cloth_sim, node_mask);
2390
2393}
2394
2396 wmOperator *op,
2397 const wmEvent *event)
2398{
2399 const Scene &scene = *CTX_data_scene(C);
2402 const Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
2403 SculptSession &ss = *ob.sculpt;
2404
2405 const View3D *v3d = CTX_wm_view3d(C);
2406 const Base *base = CTX_data_active_base(C);
2407 if (!BKE_base_is_visible(v3d, base)) {
2408 return OPERATOR_CANCELLED;
2409 }
2410
2411 const ClothFilterType filter_type = ClothFilterType(RNA_enum_get(op->ptr, "type"));
2412
2413 /* Update the active vertex */
2414 float2 mval_fl{float(event->mval[0]), float(event->mval[1])};
2416 cursor_geometry_info_update(C, &cgi, mval_fl, false);
2417
2418 /* Needs mask data to be available as it is used when solving the constraints. */
2420
2422 return OPERATOR_CANCELLED;
2423 }
2424
2425 undo::push_begin(scene, ob, op);
2427 ob,
2428 sd,
2430 mval_fl,
2431 RNA_float_get(op->ptr, "area_normal_radius"),
2432 RNA_float_get(op->ptr, "strength"));
2433
2434 if (auto_mask::is_enabled(sd, ob, nullptr)) {
2436 }
2437
2438 const float cloth_mass = RNA_float_get(op->ptr, "cloth_mass");
2439 const float cloth_damping = RNA_float_get(op->ptr, "cloth_damping");
2440 const bool use_collisions = RNA_boolean_get(op->ptr, "use_collisions");
2442 *depsgraph,
2443 ob,
2444 cloth_mass,
2445 cloth_damping,
2446 0.0f,
2447 use_collisions,
2449
2451
2452 float3 origin(0);
2454 sd, ob, ss.filter_cache->node_mask, *ss.filter_cache->cloth_sim, origin, FLT_MAX);
2455
2456 const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets");
2457 if (use_face_sets) {
2459 }
2460 else {
2462 }
2463
2464 const int force_axis = RNA_enum_get(op->ptr, "force_axis");
2465 ss.filter_cache->enabled_axis[0] = force_axis & CLOTH_FILTER_FORCE_X;
2466 ss.filter_cache->enabled_axis[1] = force_axis & CLOTH_FILTER_FORCE_Y;
2467 ss.filter_cache->enabled_axis[2] = force_axis & CLOTH_FILTER_FORCE_Z;
2468
2470
2473}
2474
2476{
2477 ot->name = "Filter Cloth";
2478 ot->idname = "SCULPT_OT_cloth_filter";
2479 ot->description = "Applies a cloth simulation deformation to the entire mesh";
2480
2483 ot->poll = SCULPT_mode_poll;
2484
2485 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2486
2488
2489 ot->prop = RNA_def_enum(ot->srna,
2490 "type",
2493 "Filter Type",
2494 "Operation that is going to be applied to the mesh");
2496 RNA_def_enum_flag(ot->srna,
2497 "force_axis",
2500 "Force Axis",
2501 "Apply the force in the selected axis");
2502 RNA_def_enum(ot->srna,
2503 "orientation",
2506 "Orientation",
2507 "Orientation of the axis to limit the filter force");
2508 RNA_def_float(ot->srna,
2509 "cloth_mass",
2510 1.0f,
2511 0.0f,
2512 2.0f,
2513 "Cloth Mass",
2514 "Mass of each simulation particle",
2515 0.0f,
2516 1.0f);
2517 RNA_def_float(ot->srna,
2518 "cloth_damping",
2519 0.0f,
2520 0.0f,
2521 1.0f,
2522 "Cloth Damping",
2523 "How much the applied forces are propagated through the cloth",
2524 0.0f,
2525 1.0f);
2526 ot->prop = RNA_def_boolean(ot->srna,
2527 "use_face_sets",
2528 false,
2529 "Use Face Sets",
2530 "Apply the filter only to the Face Set under the cursor");
2531 ot->prop = RNA_def_boolean(ot->srna,
2532 "use_collisions",
2533 false,
2534 "Use Collisions",
2535 "Collide with other collider objects in the scene");
2536}
2537
2538} // namespace blender::ed::sculpt_paint::cloth
float BKE_brush_curve_strength(eBrushCurvePreset preset, const CurveMapping *cumap, float distance, float brush_radius)
Definition brush.cc:1510
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:344
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:641
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2657
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
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)
@ BVH_RAYCAST_WATERTIGHT
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
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
@ KM_RELEASE
Definition WM_types.hh:309
@ 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:237
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:559
Span< NodeT > nodes() const
int nodes_num() const
Definition pbvh.cc:514
void flush_bounds_to_parents()
Definition pbvh.cc:1122
void deform(MutableSpan< float3 > translations, Span< int > verts) const
Definition sculpt.cc:7443
void foreach_index(Fn &&fn) const
static 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:2912
IndexMask search_nodes(const Tree &pbvh, IndexMaskMemory &memory, FunctionRef< bool(const Node &)> filter_fn)
Definition pbvh.cc:2579
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2544
void update_node_bounds_bmesh(BMeshNode &node)
Definition pbvh.cc:1110
void update_node_bounds_mesh(Span< float3 > positions, MeshNode &node)
Definition pbvh.cc:1090
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2435
void update_node_bounds_grids(int grid_area, Span< float3 > positions, GridsNode &node)
Definition pbvh.cc:1099
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2416
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:253
int active_face_set_get(const Object &object)
Definition sculpt.cc:197
void cache_init(bContext *C, Object &ob, const Sculpt &sd, undo::Type undo_type, const float mval_fl[2], float area_normal_radius, float start_strength)
void zero_disabled_axis_components(const filter::Cache &filter_cache, MutableSpan< float3 > vectors)
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:6807
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:2410
void scatter_data_bmesh(Span< T > node_data, const Set< BMVert *, 0 > &verts, MutableSpan< T > dst)
Definition sculpt.cc:6445
void gather_bmesh_positions(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > positions)
Definition sculpt.cc:6351
void calc_brush_strength_factors(const StrokeCache &cache, const Brush &brush, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7167
void gather_data_grids(const SubdivCCG &subdiv_ccg, Span< T > src, Span< int > grids, MutableSpan< T > node_data)
Definition sculpt.cc:6389
void vert_random_access_ensure(Object &object)
Definition sculpt.cc:142
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:7140
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:7596
void gather_bmesh_normals(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > normals)
Definition sculpt.cc:6369
Vector< BMVert *, 64 > BMeshNeighborVerts
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7089
void filter_region_clip_factors(const SculptSession &ss, Span< float3 > vert_positions, Span< int > verts, MutableSpan< float > factors)
Definition sculpt.cc:6956
void gather_data_bmesh(Span< T > src, const Set< BMVert *, 0 > &verts, MutableSpan< T > node_data)
Definition sculpt.cc:6405
void scale_translations(MutableSpan< float3 > translations, Span< float > factors)
Definition sculpt.cc:7476
bool report_if_shape_key_is_locked(const Object &ob, ReportList *reports)
Definition sculpt.cc:128
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7493
void clip_and_lock_translations(const Sculpt &sd, const SculptSession &ss, Span< float3 > positions, Span< int > verts, MutableSpan< float3 > translations)
Definition sculpt.cc:7316
bool cursor_geometry_info_update(bContext *C, CursorGeometryInfo *out, const float2 &mval, const bool use_sampled_normal)
Definition sculpt.cc:4662
void flush_update_done(const bContext *C, Object &ob, const UpdateType update_type)
Definition sculpt.cc:5129
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6419
void calc_brush_distances(const SculptSession &ss, Span< float3 > vert_positions, Span< int > vert, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:7039
void calc_brush_plane(const Depsgraph &depsgraph, const Brush &brush, Object &ob, const IndexMask &node_mask, float3 &r_area_no, float3 &r_area_co)
Definition sculpt.cc:2891
Span< BMVert * > vert_neighbors_get_bmesh(BMVert &vert, BMeshNeighborVerts &r_neighbors)
Definition sculpt.cc:388
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6379
void calc_brush_texture_factors(const SculptSession &ss, const Brush &brush, Span< float3 > vert_positions, Span< int > vert, MutableSpan< float > factors)
Definition sculpt.cc:7176
void flush_update_step(const bContext *C, const UpdateType update_type)
Definition sculpt.cc:5081
void calc_front_face(const float3 &view_normal, Span< float3 > normals, MutableSpan< float > factors)
Definition sculpt.cc:6898
void gather_grids_normals(const SubdivCCG &subdiv_ccg, Span< int > grids, MutableSpan< float3 > normals)
Definition sculpt.cc:6362
void translations_from_offset_and_factors(const float3 &offset, Span< float > factors, MutableSpan< float3 > r_translations)
Definition sculpt.cc:7512
void scatter_data_grids(const SubdivCCG &subdiv_ccg, Span< T > node_data, Span< int > grids, MutableSpan< T > dst)
Definition sculpt.cc:6429
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
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:543
bool SCULPT_mode_poll(bContext *C)
Definition sculpt.cc:3660
int SCULPT_vertex_count_get(const Object &object)
Definition sculpt.cc:152
#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:437
blender::ed::sculpt_paint::filter::Cache * filter_cache
Definition BKE_paint.hh:438
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:415
blender::float3 active_vert_position(const Depsgraph &depsgraph, const Object &object) const
Definition paint.cc:2263
std::optional< PersistentMultiresData > persistent_multires_data()
Definition paint.cc:2302
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:754
short val
Definition WM_types.hh:756
int mval[2]
Definition WM_types.hh:760
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:4225