Blender V4.3
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_matrix.h"
15#include "BLI_math_matrix.hh"
16#include "BLI_math_rotation.h"
17#include "BLI_math_vector.hh"
18#include "BLI_utildefines.h"
19#include "BLI_vector.hh"
20
21#include "BLT_translation.hh"
22
23#include "DNA_brush_types.h"
25#include "DNA_object_types.h"
26#include "DNA_scene_types.h"
27
28#include "BKE_brush.hh"
29#include "BKE_bvhutils.hh"
30#include "BKE_ccg.hh"
31#include "BKE_collision.h"
32#include "BKE_context.hh"
33#include "BKE_layer.hh"
34#include "BKE_mesh.hh"
35#include "BKE_modifier.hh"
36#include "BKE_paint.hh"
37#include "BKE_pbvh_api.hh"
38#include "BKE_subdiv_ccg.hh"
39
41
42#include "WM_api.hh"
43#include "WM_types.hh"
44
45#include "ED_sculpt.hh"
46
47#include "brushes/types.hh"
48#include "mesh_brush_common.hh"
49#include "sculpt_automask.hh"
50#include "sculpt_face_set.hh"
51#include "sculpt_filter.hh"
52#include "sculpt_hide.hh"
53#include "sculpt_intern.hh"
54#include "sculpt_undo.hh"
55
56#include "RNA_access.hh"
57#include "RNA_define.hh"
58
59#include "GPU_immediate.hh"
60#include "GPU_immediate_util.hh"
61#include "GPU_matrix.hh"
62#include "GPU_state.hh"
63
64#include "UI_interface.hh"
65
66#include "bmesh.hh"
67
68#include <cmath>
69#include <cstdlib>
70#include <cstring>
71
73
75 const Span<int> grids,
76 Vector<int> &indices)
77{
78 const int grid_verts_num = grids.size() * key.grid_area;
79 indices.resize(grid_verts_num);
80 for (const int i : grids.index_range()) {
82 indices.as_mutable_span().slice(i * key.grid_area, key.grid_area),
83 grids[i] * key.grid_area);
84 }
85 return indices;
86}
87
89 Vector<int> &indices)
90{
91 indices.resize(verts.size());
92 int i = 0;
93 for (const BMVert *vert : verts) {
94 indices[i] = BM_elem_index_get(vert);
95 i++;
96 }
97 return indices;
98}
99
101 const BitGroupVector<> &grid_hidden,
102 const Span<int> grids,
103 Vector<int> &indices)
104{
105 if (grid_hidden.is_empty()) {
106 return calc_vert_indices_grids(key, grids, indices);
107 }
108 const int grid_verts_num = grids.size() * key.grid_area;
109 indices.reserve(grid_verts_num);
110 for (const int i : grids.index_range()) {
111 const int start = grids[i] * key.grid_area;
112 bits::foreach_0_index(grid_hidden[grids[i]],
113 [&](const int offset) { indices.append(start + offset); });
114 }
115 return indices;
116}
117
119 Vector<int> &indices)
120{
121 indices.reserve(verts.size());
122 for (const BMVert *vert : verts) {
123 if (!BM_elem_flag_test(vert, BM_ELEM_HIDDEN)) {
124 indices.append(BM_elem_index_get(vert));
125 }
126 }
127 return indices;
128}
129
130static void calc_vert_neighbor_indices_grids(const SubdivCCG &subdiv_ccg,
131 const Span<int> verts,
132 const MutableSpan<Vector<int>> neighbor_indices)
133{
134 BLI_assert(verts.size() == neighbor_indices.size());
135 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
136
137 for (const int i : verts.index_range()) {
138 SubdivCCGNeighbors neighbors;
140 subdiv_ccg, SubdivCCGCoord::from_index(key, verts[i]), false, neighbors);
141
142 neighbor_indices[i].clear();
143 for (const SubdivCCGCoord coord : neighbors.coords) {
144 neighbor_indices[i].append(coord.to_index(key));
145 }
146 }
147}
148
150 const Span<int> verts,
151 const MutableSpan<Vector<int>> neighbor_indices)
152{
153 BLI_assert(verts.size() == neighbor_indices.size());
154 Vector<BMVert *, 64> neighbors;
155
156 for (const int i : verts.index_range()) {
157 BMVert *vert = BM_vert_at_index(&const_cast<BMesh &>(bm), verts[i]);
158 neighbor_indices[i].clear();
159 for (const BMVert *neighbor : vert_neighbors_get_bmesh(*vert, neighbors)) {
160 neighbor_indices[i].append(BM_elem_index_get(neighbor));
161 }
162 }
163}
164
166{
167 if (!ss.cache || !brush) {
168 return float3(0);
169 }
171 return ss.cache->initial_location_symm;
172 }
173 return ss.cache->location_symm;
174}
175
177 const Brush &brush,
178 IndexMaskMemory &memory)
179{
180 const SculptSession &ss = *object.sculpt;
181 BLI_assert(ss.cache);
183 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
184
185 switch (brush.cloth_simulation_area_type) {
187 const float radius_squared = math::square(ss.cache->initial_radius *
188 (1.0 + brush.cloth_sim_limit));
189 return bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
190 return node_in_sphere(node, ss.cache->initial_location_symm, radius_squared, false);
191 });
192 }
194 return bke::pbvh::all_leaf_nodes(pbvh, memory);
196 const float radius_squared = math::square(ss.cache->radius * (1.0 + brush.cloth_sim_limit));
197 return bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
198 return node_in_sphere(node, ss.cache->location_symm, radius_squared, false);
199 });
200 }
201 }
202
204 return {};
205}
206
207bool is_cloth_deform_brush(const Brush &brush)
208{
211 /* All brushes that are not the cloth brush deform the simulation using softbody
212 * constraints instead of applying forces. */
215}
216
218 const float radius,
219 const float3 &location,
220 const float3 &co)
221{
223 /* All brushes that are not the cloth brush do not use simulation areas. */
224 return 1.0f;
225 }
226
227 /* Global simulation does not have any falloff as the entire mesh is being simulated. */
229 return 1.0f;
230 }
231
232 const float distance = math::distance(location, co);
233 const float limit = radius + (radius * brush.cloth_sim_limit);
234 const float falloff = radius + (radius * brush.cloth_sim_limit * brush.cloth_sim_falloff);
235
236 if (distance > limit) {
237 /* Outside the limits. */
238 return 0.0f;
239 }
240 if (distance < falloff) {
241 /* Before the falloff area. */
242 return 1.0f;
243 }
244 /* Do a smooth-step transition inside the falloff area. */
245 float p = 1.0f - ((distance - falloff) / (limit - falloff));
246 return 3.0f * p * p - 2.0f * p * p * p;
247}
248
250 const float radius,
251 const float3 &location,
252 const Span<float3> positions,
253 const MutableSpan<float> factors)
254{
255 BLI_assert(positions.size() == factors.size());
256
257 for (const int i : positions.index_range()) {
258 factors[i] *= cloth_brush_simulation_falloff_get(brush, radius, location, positions[i]);
259 }
260}
261
262#define CLOTH_LENGTH_CONSTRAINTS_BLOCK 100000
263#define CLOTH_SIMULATION_ITERATIONS 5
264
265#define CLOTH_SOLVER_DISPLACEMENT_FACTOR 0.6f
266#define CLOTH_MAX_CONSTRAINTS_PER_VERTEX 1024
267#define CLOTH_SIMULATION_TIME_STEP 0.01f
268#define CLOTH_DEFORMATION_SNAKEHOOK_STRENGTH 0.35f
269#define CLOTH_DEFORMATION_TARGET_STRENGTH 0.01f
270#define CLOTH_DEFORMATION_GRAB_STRENGTH 0.1f
271
273 const int node_index,
274 const int v1,
275 const int v2,
276 const Span<float3> init_positions)
277{
278 LengthConstraint length_constraint{};
279
280 length_constraint.elem_index_a = v1;
281 length_constraint.elem_index_b = v2;
282
283 length_constraint.node = node_index;
284
285 length_constraint.elem_position_a = cloth_sim.pos[v1];
286 length_constraint.elem_position_b = cloth_sim.pos[v2];
287
288 length_constraint.type = SCULPT_CLOTH_CONSTRAINT_STRUCTURAL;
289
290 length_constraint.length = math::distance(init_positions[v1], init_positions[v2]);
291 length_constraint.strength = 1.0f;
292
293 cloth_sim.length_constraints.append(length_constraint);
294}
295
297 const int node_index,
298 const int v,
299 const float strength)
300{
301 LengthConstraint length_constraint{};
302
303 length_constraint.elem_index_a = v;
304 length_constraint.elem_index_b = v;
305
306 length_constraint.node = node_index;
307
308 length_constraint.elem_position_a = cloth_sim.pos[v];
309 length_constraint.elem_position_b = cloth_sim.softbody_pos[v];
310
311 length_constraint.type = SCULPT_CLOTH_CONSTRAINT_SOFTBODY;
312
313 length_constraint.length = 0.0f;
314 length_constraint.strength = strength;
315
316 cloth_sim.length_constraints.append(length_constraint);
317}
318
320 const int node_index,
321 const int v,
322 const float strength)
323{
324 LengthConstraint length_constraint{};
325
326 length_constraint.elem_index_a = v;
327 length_constraint.elem_index_b = v;
328
329 length_constraint.node = node_index;
330
331 length_constraint.elem_position_a = cloth_sim.pos[v];
332 length_constraint.elem_position_b = cloth_sim.init_pos[v];
333
334 length_constraint.type = SCULPT_CLOTH_CONSTRAINT_PIN;
335
336 length_constraint.length = 0.0f;
337 length_constraint.strength = strength;
338
339 cloth_sim.length_constraints.append(length_constraint);
340}
341
343 const int node_index,
344 const int v,
345 const float strength)
346{
347 LengthConstraint length_constraint{};
348
349 length_constraint.elem_index_a = v;
350 length_constraint.elem_index_b = v;
351
352 length_constraint.node = node_index;
353
354 length_constraint.type = SCULPT_CLOTH_CONSTRAINT_DEFORMATION;
355
356 length_constraint.elem_position_a = cloth_sim.pos[v];
357 length_constraint.elem_position_b = cloth_sim.deformation_pos[v];
358
359 length_constraint.length = 0.0f;
360 length_constraint.strength = strength;
361
362 cloth_sim.length_constraints.append(length_constraint);
363}
364
365static void add_constraints_for_verts(const Object &object,
366 const Brush *brush,
367 const float3 &cloth_sim_initial_location,
368 const float cloth_sim_radius,
369 const Span<float3> init_positions,
370 const int node_index,
371 const Span<int> verts,
372 const Span<Vector<int>> vert_neighbors,
373 SimulationData &cloth_sim,
374 Set<OrderedEdge> &created_length_constraints)
375{
376 const SculptSession &ss = *object.sculpt;
377
378 const bool is_brush_has_stroke_cache = ss.cache != nullptr && brush != nullptr;
379 const bool pin_simulation_boundary = is_brush_has_stroke_cache &&
383
384 /* Brush can be nullptr in tools that use the solver without relying of constraints with
385 * deformation positions. */
386 const bool cloth_is_deform_brush = is_brush_has_stroke_cache && is_cloth_deform_brush(*brush);
387
388 const bool use_falloff_plane = brush->cloth_force_falloff_type ==
390 float radius_squared = 0.0f;
391 if (cloth_is_deform_brush) {
392 radius_squared = ss.cache->initial_radius * ss.cache->initial_radius;
393 }
394
395 /* Only limit the constraint creation to a radius when the simulation is local. */
396 const float cloth_sim_radius_squared = brush->cloth_simulation_area_type ==
398 cloth_sim_radius * cloth_sim_radius :
399 FLT_MAX;
400
401 for (const int i : verts.index_range()) {
402 const int vert = verts[i];
403 const float len_squared = math::distance_squared(init_positions[vert],
404 cloth_sim_initial_location);
405 if (len_squared < cloth_sim_radius_squared) {
406 if (cloth_sim.softbody_strength > 0.0f) {
407 cloth_brush_add_softbody_constraint(cloth_sim, node_index, vert, 1.0f);
408 }
409
410 const Span<int> neighbors = vert_neighbors[i];
411
412 /* As we don't know the order of the neighbor vertices, we create all possible combinations
413 * between the neighbor and the original vertex as length constraints. */
414 /* This results on a pattern that contains structural, shear and bending constraints for all
415 * vertices, but constraints are repeated taking more memory than necessary. */
416 for (const int neighbor : neighbors) {
417 if (created_length_constraints.add({vert, neighbor})) {
418 cloth_brush_add_length_constraint(cloth_sim, node_index, vert, neighbor, init_positions);
419 }
420 }
421 for (const int a : neighbors) {
422 for (const int b : neighbors) {
423 if (a != b) {
424 if (created_length_constraints.add({a, b})) {
425 cloth_brush_add_length_constraint(cloth_sim, node_index, a, b, init_positions);
426 }
427 }
428 }
429 }
430 }
431
432 if (is_brush_has_stroke_cache && brush->sculpt_brush_type == SCULPT_BRUSH_TYPE_CLOTH) {
433 /* The cloth brush works by applying forces in most of its modes, but some of them require
434 * deformation coordinates to make the simulation stable. */
436 if (use_falloff_plane) {
437 /* With plane falloff the strength of the constraints is set when applying the
438 * deformation forces. */
440 cloth_sim, node_index, vert, CLOTH_DEFORMATION_GRAB_STRENGTH);
441 }
442 else if (len_squared < radius_squared) {
443 /* With radial falloff deformation constraints are created with different strengths and
444 * only inside the radius of the brush. */
445 const float fade = BKE_brush_curve_strength(
446 brush, std::sqrt(len_squared), ss.cache->radius);
448 cloth_sim, node_index, vert, fade * CLOTH_DEFORMATION_GRAB_STRENGTH);
449 }
450 }
452 /* Cloth Snake Hook creates deformation constraint with fixed strength because the strength
453 * is controlled per iteration using cloth_sim.deformation_strength. */
455 cloth_sim, node_index, vert, CLOTH_DEFORMATION_SNAKEHOOK_STRENGTH);
456 }
457 }
458 else if (!cloth_sim.deformation_pos.is_empty()) {
459 /* Any other tool that target the cloth simulation handle the falloff in
460 * their own code when modifying the deformation coordinates of the simulation, so
461 * deformation constraints are created with a fixed strength for all vertices. */
463 cloth_sim, node_index, vert, CLOTH_DEFORMATION_TARGET_STRENGTH);
464 }
465
466 if (pin_simulation_boundary) {
467 const float sim_falloff = cloth_brush_simulation_falloff_get(
468 *brush, ss.cache->initial_radius, ss.cache->location_symm, init_positions[vert]);
469 /* Vertex is inside the area of the simulation without any falloff applied. */
470 if (sim_falloff < 1.0f) {
471 /* Create constraints with more strength the closer the vertex is to the simulation
472 * boundary. */
473 cloth_brush_add_pin_constraint(cloth_sim, node_index, vert, 1.0f - sim_falloff);
474 }
475 }
476 }
477}
478
480 Object &object,
481 const IndexMask &node_mask,
482 SimulationData &cloth_sim,
483 const float3 &initial_location,
484 const float radius)
485{
486 SculptSession &ss = *object.sculpt;
487 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
488 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
489
490 /* TODO: Multi-threaded needs to be disabled for this task until implementing the optimization of
491 * storing the constraints per node. */
492 /* Currently all constrains are added to the same global array which can't be accessed from
493 * different threads. */
494
495 IndexMaskMemory memory;
496 Set<OrderedEdge> created_length_constraints;
497 Vector<int> vert_indices;
498 Vector<Vector<int>> vert_neighbors;
499 switch (pbvh.type()) {
502 const IndexMask uninitialized_nodes = IndexMask::from_predicate(
503 node_mask, GrainSize(1024), memory, [&](const int i) {
504 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
505 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_UNINITIALIZED;
506 });
507 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
508 const OffsetIndices faces = mesh.faces();
509 const Span<int> corner_verts = mesh.corner_verts();
510 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
511 const bke::AttributeAccessor attributes = mesh.attributes();
512 const VArraySpan<bool> hide_vert = *attributes.lookup<bool>(".hide_vert",
514 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly",
516
517 Span<float3> init_positions;
518 VArraySpan<float3> persistent_position;
519 if (brush != nullptr && brush->flag & BRUSH_PERSISTENT) {
520 persistent_position = *attributes.lookup<float3>(".sculpt_persistent_co",
522 }
523 if (persistent_position.is_empty()) {
524 init_positions = cloth_sim.init_pos;
525 }
526 else {
527 init_positions = persistent_position;
528 }
529 uninitialized_nodes.foreach_index([&](const int i) {
530 const Span<int> verts = hide::node_visible_verts(nodes[i], hide_vert, vert_indices);
531 vert_neighbors.resize(verts.size());
533 faces, corner_verts, vert_to_face_map, hide_poly, verts, vert_neighbors);
535 brush,
536 initial_location,
537 radius,
538 init_positions,
539 cloth_sim.node_state_index.lookup(&nodes[i]),
540 verts,
541 vert_neighbors,
542 cloth_sim,
543 created_length_constraints);
544 });
545 break;
546 }
549 const IndexMask uninitialized_nodes = IndexMask::from_predicate(
550 node_mask, GrainSize(1024), memory, [&](const int i) {
551 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
552 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_UNINITIALIZED;
553 });
554 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
555 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
556 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
557 uninitialized_nodes.foreach_index([&](const int i) {
559 key, grid_hidden, nodes[i].grids(), vert_indices);
560 vert_neighbors.resize(verts.size());
561 calc_vert_neighbor_indices_grids(subdiv_ccg, verts, vert_neighbors);
563 brush,
564 initial_location,
565 radius,
566 cloth_sim.init_pos,
567 cloth_sim.node_state_index.lookup(&nodes[i]),
568 verts,
569 vert_neighbors,
570 cloth_sim,
571 created_length_constraints);
572 });
573 break;
574 }
577 const IndexMask uninitialized_nodes = IndexMask::from_predicate(
578 node_mask, GrainSize(1024), memory, [&](const int i) {
579 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
580 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_UNINITIALIZED;
581 });
582 BMesh &bm = *ss.bm;
585 uninitialized_nodes.foreach_index([&](const int i) {
586 const Set<BMVert *, 0> &bm_verts = BKE_pbvh_bmesh_node_unique_verts(&nodes[i]);
587 const Span<int> verts = calc_visible_vert_indices_bmesh(bm_verts, vert_indices);
588 vert_neighbors.resize(verts.size());
589 calc_vert_neighbor_indices_bmesh(bm, verts, vert_neighbors);
591 brush,
592 initial_location,
593 radius,
594 cloth_sim.init_pos,
595 cloth_sim.node_state_index.lookup(&nodes[i]),
596 verts,
597 vert_neighbors,
598 cloth_sim,
599 created_length_constraints);
600 });
601 break;
602 }
603 }
604}
605
607 const Span<float3> forces,
608 const Span<int> verts)
609{
610 const float mass_inv = math::rcp(cloth_sim.mass);
611 for (const int i : verts.index_range()) {
612 cloth_sim.acceleration[verts[i]] += forces[i] * mass_inv;
613 }
614}
615
617 const Span<int> verts,
618 const Span<float> factors)
619{
620 MutableSpan<float> length_constraint_tweak = cloth_sim.length_constraint_tweak;
621 for (const int i : verts.index_range()) {
622 length_constraint_tweak[verts[i]] += factors[i] * 0.01f;
623 }
624}
625
627 const float4 &plane,
628 const MutableSpan<float> distances)
629{
630 for (const int i : positions.index_range()) {
631 distances[i] = dist_to_plane_v3(positions[i], plane);
632 }
633}
634
636 const float min,
637 const float max)
638{
639 for (float &factor : factors) {
640 factor = std::clamp(factor, min, max);
641 }
642}
643
645 const Span<int> verts,
646 const MutableSpan<float> factors,
647 const bool use_falloff_plane,
648 const float3 &grab_delta_symmetry)
649{
650 for (const int i : verts.index_range()) {
651 cloth_sim.deformation_pos[verts[i]] = cloth_sim.init_pos[verts[i]] +
652 grab_delta_symmetry * factors[i];
653 }
654 if (use_falloff_plane) {
655 clamp_factors(factors, 0.0f, 1.0f);
657 }
658 else {
660 }
661}
662
664 const Span<int> verts,
665 const MutableSpan<float> factors,
666 const float3 &grab_delta_symmetry)
667{
668 for (const int i : verts.index_range()) {
669 const int vert = verts[i];
670 cloth_sim.deformation_pos[vert] = cloth_sim.pos[vert] + grab_delta_symmetry * factors[i];
671 }
673}
674
675BLI_NOINLINE static void calc_pinch_forces(const Span<float3> positions,
676 const float3 &location,
677 const MutableSpan<float3> forces)
678{
679 for (const int i : forces.index_range()) {
680 forces[i] = math::normalize(location - positions[i]);
681 }
682}
683
685 const float4 &plane,
686 const float3 &plane_normal,
687 const MutableSpan<float3> forces)
688{
689 for (const int i : positions.index_range()) {
690 const float distance = dist_signed_to_plane_v3(positions[i], plane);
691 forces[i] = math::normalize(plane_normal * -distance);
692 }
693}
694
696 const float4x4 &imat,
697 const float3 &location,
698 const MutableSpan<float3> forces)
699{
700 const float3 x_object_space = math::normalize(imat.x_axis());
701 const float3 z_object_space = math::normalize(imat.z_axis());
702 for (const int i : positions.index_range()) {
703 const float3 disp_center = math::normalize(location - positions[i]);
704 const float3 x_disp = x_object_space * math::dot(disp_center, x_object_space);
705 const float3 z_disp = z_object_space * math::dot(disp_center, z_object_space);
706 forces[i] = x_disp + z_disp;
707 }
708}
709
720
725
726static void calc_forces_mesh(const Depsgraph &depsgraph,
727 Object &ob,
728 const Brush &brush,
729 const float3 &offset,
730 const float4x4 &imat,
731 const float3 &sim_location,
732 const float3 &gravity,
733 const std::optional<FalloffPlane> &falloff_plane,
734 const MeshAttributeData &attribute_data,
735 const Span<float3> positions_eval,
736 const Span<float3> vert_normals,
737 const bke::pbvh::MeshNode &node,
738 LocalData &tls)
739{
740 SculptSession &ss = *ob.sculpt;
741 SimulationData &cloth_sim = *ss.cache->cloth_sim;
742 const StrokeCache &cache = *ss.cache;
743
744 const Span<int> verts = node.verts();
745 const MutableSpan positions = gather_data_mesh(positions_eval, verts, tls.positions);
746 const MutableSpan init_positions = gather_data_mesh(
747 cloth_sim.init_pos.as_span(), verts, tls.init_positions);
748 const Span<float3> current_positions = brush.cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB ?
749 init_positions :
750 positions;
751
752 tls.factors.resize(verts.size());
753 const MutableSpan<float> factors = tls.factors;
754 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
755 filter_region_clip_factors(ss, current_positions, factors);
756
757 calc_brush_simulation_falloff(brush, cache.radius, sim_location, positions, factors);
758
759 tls.translations.resize(verts.size());
760 const MutableSpan<float3> forces = tls.translations;
761
762 /* Apply gravity in the entire simulation area before brush distances are taken into account. */
763 if (!math::is_zero(gravity)) {
764 translations_from_offset_and_factors(gravity, factors, forces);
765 apply_forces(cloth_sim, forces, verts);
766 }
767
768 if (brush.flag & BRUSH_FRONTFACE) {
769 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
770 }
771
772 tls.distances.resize(verts.size());
773 const MutableSpan<float> distances = tls.distances;
774 if (falloff_plane) {
775 calc_distances_to_plane(current_positions, falloff_plane->plane, distances);
776 }
777 else {
779 ss, current_positions, eBrushFalloffShape(brush.falloff_shape), distances);
780 }
781 apply_hardness_to_distances(cache, distances);
782 calc_brush_strength_factors(cache, brush, distances, factors);
783
784 const auto_mask::Cache *automask = auto_mask::active_cache_get(ss);
785 auto_mask::calc_vert_factors(depsgraph, ob, automask, node, verts, factors);
786
787 calc_brush_texture_factors(ss, brush, current_positions, factors);
788
789 scale_factors(factors, cache.bstrength);
790
791 switch (brush.cloth_deform_type) {
794 math::normalize(cache.location_symm - cache.last_location_symm), factors, forces);
795 apply_forces(cloth_sim, forces, verts);
796 break;
798 translations_from_offset_and_factors(-offset, factors, forces);
799 apply_forces(cloth_sim, forces, verts);
800 break;
803 cloth_sim, verts, factors, falloff_plane.has_value(), cache.grab_delta_symm);
804 break;
806 apply_snake_hook_brush(cloth_sim, verts, factors, cache.grab_delta_symm);
807 break;
809 if (falloff_plane) {
810 calc_plane_pinch_forces(positions, falloff_plane->plane, falloff_plane->normal, forces);
811 }
812 else {
813 calc_pinch_forces(positions, cache.location_symm, forces);
814 }
815 scale_translations(forces, factors);
816 apply_forces(cloth_sim, forces, verts);
817 break;
819 calc_perpendicular_pinch_forces(positions, imat, cache.location_symm, forces);
820 scale_translations(forces, factors);
821 apply_forces(cloth_sim, forces, verts);
822 break;
823 }
825 gather_data_mesh(vert_normals, verts, forces);
826 scale_translations(forces, factors);
827 apply_forces(cloth_sim, forces, verts);
828 break;
830 expand_length_constraints(cloth_sim, verts, factors);
831 break;
832 }
833}
834
835static void calc_forces_grids(const Depsgraph &depsgraph,
836 Object &ob,
837 const Brush &brush,
838 const float3 &offset,
839 const float4x4 &imat,
840 const float3 &sim_location,
841 const float3 &gravity,
842 const std::optional<FalloffPlane> &falloff_plane,
843 const bke::pbvh::GridsNode &node,
844 LocalData &tls)
845{
846 SculptSession &ss = *ob.sculpt;
847 SimulationData &cloth_sim = *ss.cache->cloth_sim;
848 const StrokeCache &cache = *ss.cache;
849 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
850 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
851
852 const Span<int> grids = node.grids();
853 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
854 const MutableSpan init_positions = gather_data_grids(
855 subdiv_ccg, cloth_sim.init_pos.as_span(), grids, tls.init_positions);
856 const Span<float3> current_positions = brush.cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB ?
857 init_positions :
858 positions;
859
860 tls.factors.resize(positions.size());
861 const MutableSpan<float> factors = tls.factors;
862 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
863 filter_region_clip_factors(ss, current_positions, factors);
864
865 calc_brush_simulation_falloff(brush, cache.radius, sim_location, positions, factors);
866
867 const Span<int> verts = calc_vert_indices_grids(key, grids, tls.vert_indices);
868
869 tls.translations.resize(verts.size());
870 const MutableSpan<float3> forces = tls.translations;
871
872 /* Apply gravity in the entire simulation area before brush distances are taken into account. */
873 if (!math::is_zero(gravity)) {
874 translations_from_offset_and_factors(gravity, factors, forces);
875 apply_forces(cloth_sim, forces, verts);
876 }
877
878 if (brush.flag & BRUSH_FRONTFACE) {
879 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
880 }
881
882 tls.distances.resize(verts.size());
883 const MutableSpan<float> distances = tls.distances;
884 if (falloff_plane) {
885 calc_distances_to_plane(current_positions, falloff_plane->plane, distances);
886 }
887 else {
889 ss, current_positions, eBrushFalloffShape(brush.falloff_shape), distances);
890 }
891 apply_hardness_to_distances(cache, distances);
892 calc_brush_strength_factors(cache, brush, distances, factors);
893
894 const auto_mask::Cache *automask = auto_mask::active_cache_get(ss);
895 auto_mask::calc_grids_factors(depsgraph, ob, automask, node, grids, factors);
896
897 calc_brush_texture_factors(ss, brush, current_positions, factors);
898
899 scale_factors(factors, cache.bstrength);
900
901 switch (brush.cloth_deform_type) {
904 math::normalize(cache.location_symm - cache.last_location_symm), factors, forces);
905 apply_forces(cloth_sim, forces, verts);
906 break;
908 translations_from_offset_and_factors(-offset, factors, forces);
909 apply_forces(cloth_sim, forces, verts);
910 break;
913 cloth_sim, verts, factors, falloff_plane.has_value(), cache.grab_delta_symm);
914 break;
916 apply_snake_hook_brush(cloth_sim, verts, factors, cache.grab_delta_symm);
917 break;
919 if (falloff_plane) {
920 calc_plane_pinch_forces(positions, falloff_plane->plane, falloff_plane->normal, forces);
921 }
922 else {
923 calc_pinch_forces(positions, cache.location_symm, forces);
924 }
925 scale_translations(forces, factors);
926 apply_forces(cloth_sim, forces, verts);
927 break;
929 calc_perpendicular_pinch_forces(positions, imat, cache.location_symm, forces);
930 scale_translations(forces, factors);
931 apply_forces(cloth_sim, forces, verts);
932 break;
933 }
935 gather_grids_normals(subdiv_ccg, grids, forces);
936 scale_translations(forces, factors);
937 apply_forces(cloth_sim, forces, verts);
938 break;
940 expand_length_constraints(cloth_sim, verts, factors);
941 break;
942 }
943}
944
945static void calc_forces_bmesh(const Depsgraph &depsgraph,
946 Object &ob,
947 const Brush &brush,
948 const float3 &offset,
949 const float4x4 &imat,
950 const float3 &sim_location,
951 const float3 &gravity,
952 const std::optional<FalloffPlane> &falloff_plane,
954 LocalData &tls)
955{
956 SculptSession &ss = *ob.sculpt;
957 SimulationData &cloth_sim = *ss.cache->cloth_sim;
958 const StrokeCache &cache = *ss.cache;
959
960 const Set<BMVert *, 0> &bm_verts = BKE_pbvh_bmesh_node_unique_verts(&node);
962
963 const MutableSpan positions = gather_bmesh_positions(bm_verts, tls.positions);
964 const MutableSpan init_positions = gather_data_mesh(
965 cloth_sim.init_pos.as_span(), verts, tls.init_positions);
966 const Span<float3> current_positions = brush.cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB ?
967 init_positions :
968 positions;
969
970 tls.factors.resize(verts.size());
971 const MutableSpan<float> factors = tls.factors;
972 fill_factor_from_hide_and_mask(*ss.bm, bm_verts, factors);
973 filter_region_clip_factors(ss, current_positions, factors);
974
975 calc_brush_simulation_falloff(brush, cache.radius, sim_location, positions, factors);
976
977 tls.translations.resize(verts.size());
978 const MutableSpan<float3> forces = tls.translations;
979
980 /* Apply gravity in the entire simulation area before brush distances are taken into account. */
981 if (!math::is_zero(gravity)) {
982 translations_from_offset_and_factors(gravity, factors, forces);
983 apply_forces(cloth_sim, forces, verts);
984 }
985
986 if (brush.flag & BRUSH_FRONTFACE) {
987 calc_front_face(cache.view_normal_symm, bm_verts, factors);
988 }
989
990 tls.distances.resize(verts.size());
991 const MutableSpan<float> distances = tls.distances;
992 if (falloff_plane) {
993 calc_distances_to_plane(current_positions, falloff_plane->plane, distances);
994 }
995 else {
997 ss, current_positions, eBrushFalloffShape(brush.falloff_shape), distances);
998 }
999 apply_hardness_to_distances(cache, distances);
1000 calc_brush_strength_factors(cache, brush, distances, factors);
1001
1002 const auto_mask::Cache *automask = auto_mask::active_cache_get(ss);
1003 auto_mask::calc_vert_factors(depsgraph, ob, automask, node, bm_verts, factors);
1004
1005 calc_brush_texture_factors(ss, brush, current_positions, factors);
1006
1007 scale_factors(factors, cache.bstrength);
1008
1009 switch (brush.cloth_deform_type) {
1012 math::normalize(cache.location_symm - cache.last_location_symm), factors, forces);
1013 apply_forces(cloth_sim, forces, verts);
1014 break;
1016 translations_from_offset_and_factors(-offset, factors, forces);
1017 apply_forces(cloth_sim, forces, verts);
1018 break;
1021 cloth_sim, verts, factors, falloff_plane.has_value(), cache.grab_delta_symm);
1022 break;
1024 apply_snake_hook_brush(cloth_sim, verts, factors, cache.grab_delta_symm);
1025 break;
1027 if (falloff_plane) {
1028 calc_plane_pinch_forces(positions, falloff_plane->plane, falloff_plane->normal, forces);
1029 }
1030 else {
1031 calc_pinch_forces(positions, cache.location_symm, forces);
1032 }
1033 scale_translations(forces, factors);
1034 apply_forces(cloth_sim, forces, verts);
1035 break;
1037 calc_perpendicular_pinch_forces(positions, imat, cache.location_symm, forces);
1038 scale_translations(forces, factors);
1039 apply_forces(cloth_sim, forces, verts);
1040 break;
1041 }
1043 gather_bmesh_normals(bm_verts, forces);
1044 scale_translations(forces, factors);
1045 apply_forces(cloth_sim, forces, verts);
1046 break;
1048 expand_length_constraints(cloth_sim, verts, factors);
1049 break;
1050 }
1051}
1052
1054 const Depsgraph &depsgraph)
1055{
1057 DEGObjectIterSettings deg_iter_settings = {nullptr};
1058 deg_iter_settings.depsgraph = &const_cast<Depsgraph &>(depsgraph);
1061 DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, ob) {
1062 if (STREQ(object.id.name, ob->id.name)) {
1063 continue;
1064 }
1065
1068 if (!cmd) {
1069 continue;
1070 }
1071
1072 if (!cmd->bvhtree) {
1073 continue;
1074 }
1075
1077 col.ob = ob;
1078 col.collmd = cmd;
1079 collision_move_object(cmd, 1.0, 0.0, true);
1080 cache.append(col);
1081 }
1083 return cache;
1084}
1085
1090
1091static void cloth_brush_collision_cb(void *userdata,
1092 int index,
1093 const BVHTreeRay *ray,
1094 BVHTreeRayHit *hit)
1095{
1097 CollisionModifierData *col_data = col->col_data;
1098 const int3 vert_tri = col_data->vert_tris[index];
1099 float(*positions)[3] = col_data->x;
1100 float *tri[3], no[3], co[3];
1101
1102 tri[0] = positions[vert_tri[0]];
1103 tri[1] = positions[vert_tri[1]];
1104 tri[2] = positions[vert_tri[2]];
1105 float dist = 0.0f;
1106
1107 bool tri_hit = isect_ray_tri_watertight_v3(
1108 ray->origin, &col->isect_precalc, UNPACK3(tri), &dist, nullptr);
1109 normal_tri_v3(no, UNPACK3(tri));
1110 madd_v3_v3v3fl(co, ray->origin, ray->direction, dist);
1111
1112 if (tri_hit && dist < hit->dist) {
1113 hit->index = index;
1114 hit->dist = dist;
1115
1116 copy_v3_v3(hit->co, co);
1117 copy_v3_v3(hit->no, no);
1118 }
1119}
1120
1121static void cloth_brush_solve_collision(const Object &object,
1122 SimulationData &cloth_sim,
1123 const int i)
1124{
1125 const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
1126
1127 const float4x4 &object_to_world = object.object_to_world();
1128 const float4x4 &world_to_object = object.world_to_object();
1129
1130 for (const ColliderCache &collider_cache : cloth_sim.collider_list) {
1131 const float3 pos_world_space = math::transform_point(object_to_world, cloth_sim.pos[i]);
1132 const float3 prev_pos_world_space = math::transform_point(object_to_world,
1133 cloth_sim.last_iteration_pos[i]);
1134
1135 BVHTreeRayHit hit{};
1136 hit.index = -1;
1137
1138 const float3 ray_normal = math::normalize_and_get_length(
1139 pos_world_space - prev_pos_world_space, hit.dist);
1140
1142 CollisionModifierData *collmd = collider_cache.collmd;
1143 col.col_data = collmd;
1144 isect_ray_tri_watertight_v3_precalc(&col.isect_precalc, ray_normal);
1145
1147 prev_pos_world_space,
1148 ray_normal,
1149 0.3f,
1150 &hit,
1152 &col,
1153 raycast_flag);
1154
1155 if (hit.index == -1) {
1156 continue;
1157 }
1158
1159 const float3 collision_disp = float3(hit.no) * 0.005f;
1160
1161 float4 friction_plane;
1162 plane_from_point_normal_v3(friction_plane, hit.co, hit.no);
1163 float3 pos_on_friction_plane;
1164 closest_to_plane_v3(pos_on_friction_plane, friction_plane, pos_world_space);
1165 constexpr float friction_factor = 0.35f;
1166 const float3 movement_disp = (pos_on_friction_plane - float3(hit.co)) * friction_factor;
1167
1168 cloth_sim.pos[i] = math::transform_point(world_to_object,
1169 float3(hit.co) + movement_disp + collision_disp);
1170 }
1171}
1172
1174 const Brush *brush,
1175 const float3 &sim_location,
1176 const Span<int> verts,
1177 const MutableSpan<float> factors,
1178 LocalData &tls,
1179 SimulationData &cloth_sim)
1180{
1181 const SculptSession &ss = *object.sculpt;
1182
1183 tls.diffs.resize(verts.size());
1184 const MutableSpan<float3> pos_diff = tls.diffs;
1185 for (const int i : verts.index_range()) {
1186 pos_diff[i] = cloth_sim.pos[verts[i]] - cloth_sim.prev_pos[verts[i]];
1187 }
1188
1189 for (const int vert : verts) {
1190 cloth_sim.prev_pos[vert] = cloth_sim.pos[vert];
1191 }
1192
1193 for (const int i : verts.index_range()) {
1194 const int vert = verts[i];
1195 cloth_sim.pos[vert] += cloth_sim.acceleration[vert] * factors[i] * CLOTH_SIMULATION_TIME_STEP;
1196 }
1197
1198 scale_factors(factors, 1.0f - cloth_sim.damping);
1199 if (ss.cache) {
1200 const MutableSpan positions = gather_data_mesh(
1201 cloth_sim.init_pos.as_span(), verts, tls.positions);
1202 calc_brush_simulation_falloff(*brush, ss.cache->radius, sim_location, positions, factors);
1203 }
1204 scale_translations(pos_diff, factors);
1205
1206 for (const int i : verts.index_range()) {
1207 const int vert = verts[i];
1208 cloth_sim.pos[vert] += pos_diff[i];
1209 }
1210
1211 for (const int vert : verts) {
1212 cloth_brush_solve_collision(object, cloth_sim, vert);
1213 }
1214
1215 for (const int vert : verts) {
1216 cloth_sim.last_iteration_pos[vert] = cloth_sim.pos[vert];
1217 }
1218
1220}
1221
1222static void calc_constraint_factors(const Depsgraph &depsgraph,
1223 const Object &object,
1224 const Brush *brush,
1225 const float3 &sim_location,
1226 const Span<float3> init_positions,
1227 const MutableSpan<float> cloth_factors)
1228{
1229 const SculptSession &ss = *object.sculpt;
1230 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1231 IndexMaskMemory memory;
1232 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1233
1234 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
1235
1236 struct LocalData {
1239 };
1241 switch (pbvh.type()) {
1242 case bke::pbvh::Type::Mesh: {
1243 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1244 const MeshAttributeData attribute_data(mesh.attributes());
1246 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1247 LocalData &tls = all_tls.local();
1248 const Span<int> verts = nodes[i].verts();
1249 tls.factors.resize(verts.size());
1250 const MutableSpan<float> factors = tls.factors;
1252 attribute_data.hide_vert, attribute_data.mask, verts, factors);
1253 auto_mask::calc_vert_factors(depsgraph, object, automasking, nodes[i], verts, factors);
1254 if (ss.cache) {
1255 const MutableSpan positions = gather_data_mesh(init_positions, verts, tls.positions);
1257 *brush, ss.cache->radius, sim_location, positions, factors);
1258 }
1259 scatter_data_mesh(factors.as_span(), verts, cloth_factors);
1260 });
1261 break;
1262 }
1264 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1265 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1267 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1268 LocalData &tls = all_tls.local();
1269 const Span<int> grids = nodes[i].grids();
1270 const int grid_verts_num = grids.size() * key.grid_area;
1271 tls.factors.resize(grid_verts_num);
1272 const MutableSpan<float> factors = tls.factors;
1273 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
1274 auto_mask::calc_grids_factors(depsgraph, object, automasking, nodes[i], grids, factors);
1275 if (ss.cache) {
1276 const Span<float3> positions = gather_data_grids(
1277 subdiv_ccg, init_positions, grids, tls.positions);
1279 *brush, ss.cache->radius, sim_location, positions, factors);
1280 }
1281 scatter_data_grids(subdiv_ccg, factors.as_span(), grids, cloth_factors);
1282 });
1283 break;
1284 }
1286 const BMesh &bm = *ss.bm;
1288 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1289 LocalData &tls = all_tls.local();
1291 const_cast<bke::pbvh::BMeshNode *>(&nodes[i]));
1292 tls.factors.resize(verts.size());
1293 const MutableSpan<float> factors = tls.factors;
1295 auto_mask::calc_vert_factors(depsgraph, object, automasking, nodes[i], verts, factors);
1296 if (ss.cache) {
1297 const MutableSpan positions = gather_data_bmesh(init_positions, verts, tls.positions);
1299 *brush, ss.cache->radius, sim_location, positions, factors);
1300 }
1301 scatter_data_bmesh(factors.as_span(), verts, cloth_factors);
1302 });
1303 break;
1304 }
1305 }
1306}
1307
1308static void cloth_brush_satisfy_constraints(const Depsgraph &depsgraph,
1309 const Object &object,
1310 const Brush *brush,
1311 SimulationData &cloth_sim)
1312{
1313 const SculptSession &ss = *object.sculpt;
1314
1315 const float3 sim_location = cloth_brush_simulation_location_get(ss, brush);
1316
1317 /* Precalculate factors into an array since we need random access to specific vertex values. */
1318 Array<float> factors(SCULPT_vertex_count_get(object));
1319 calc_constraint_factors(depsgraph, object, brush, sim_location, cloth_sim.init_pos, factors);
1320
1321 for (int constraint_it = 0; constraint_it < CLOTH_SIMULATION_ITERATIONS; constraint_it++) {
1322 for (const LengthConstraint &constraint : cloth_sim.length_constraints) {
1323 if (cloth_sim.node_state[constraint.node] != SCULPT_CLOTH_NODE_ACTIVE) {
1324 /* Skip all constraints that were created for inactive nodes. */
1325 continue;
1326 }
1327
1328 const int v1 = constraint.elem_index_a;
1329 const int v2 = constraint.elem_index_b;
1330
1331 const float3 v1_to_v2 = float3(constraint.elem_position_b) -
1332 float3(constraint.elem_position_a);
1333 const float current_distance = math::length(v1_to_v2);
1334 float3 correction_vector;
1335
1336 const float constraint_distance = constraint.length +
1337 (cloth_sim.length_constraint_tweak[v1] * 0.5f) +
1338 (cloth_sim.length_constraint_tweak[v2] * 0.5f);
1339
1340 if (current_distance > 0.0f) {
1341 correction_vector = v1_to_v2 * CLOTH_SOLVER_DISPLACEMENT_FACTOR *
1342 (1.0f - (constraint_distance / current_distance));
1343 }
1344 else {
1345 correction_vector = v1_to_v2 * CLOTH_SOLVER_DISPLACEMENT_FACTOR;
1346 }
1347
1348 const float3 correction_vector_half = correction_vector * 0.5f;
1349
1350 const float factor_v1 = factors[v1];
1351 const float factor_v2 = factors[v2];
1352
1353 float deformation_strength = 1.0f;
1354 if (constraint.type == SCULPT_CLOTH_CONSTRAINT_DEFORMATION) {
1355 deformation_strength = (cloth_sim.deformation_strength[v1] +
1356 cloth_sim.deformation_strength[v2]) *
1357 0.5f;
1358 }
1359
1360 if (constraint.type == SCULPT_CLOTH_CONSTRAINT_SOFTBODY) {
1361 const float softbody_plasticity = brush ? brush->cloth_constraint_softbody_strength : 0.0f;
1362 cloth_sim.pos[v1] += correction_vector_half *
1363 (1.0f * factor_v1 * constraint.strength * softbody_plasticity);
1364 cloth_sim.softbody_pos[v1] += correction_vector_half * -1.0f * factor_v1 *
1365 constraint.strength * (1.0f - softbody_plasticity);
1366 }
1367 else {
1368 cloth_sim.pos[v1] += correction_vector_half * 1.0f * factor_v1 * constraint.strength *
1369 deformation_strength;
1370 if (v1 != v2) {
1371 cloth_sim.pos[v2] += correction_vector_half * -1.0f * factor_v2 * constraint.strength *
1372 deformation_strength;
1373 }
1374 }
1375 }
1376 }
1377}
1378
1379void do_simulation_step(const Depsgraph &depsgraph,
1380 const Sculpt &sd,
1381 Object &object,
1382 SimulationData &cloth_sim,
1383 const IndexMask &node_mask)
1384{
1385 SculptSession &ss = *object.sculpt;
1386 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1387 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1388
1389 /* Update the constraints. */
1390 cloth_brush_satisfy_constraints(depsgraph, object, brush, cloth_sim);
1391
1392 const float3 sim_location = cloth_brush_simulation_location_get(ss, brush);
1393
1394 IndexMaskMemory memory;
1396 switch (pbvh.type()) {
1397 case bke::pbvh::Type::Mesh: {
1399 const IndexMask active_nodes = IndexMask::from_predicate(
1400 node_mask, GrainSize(1024), memory, [&](const int i) {
1401 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1402 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_ACTIVE;
1403 });
1404 Mesh &mesh = *static_cast<Mesh *>(object.data);
1405 const MeshAttributeData attribute_data(mesh.attributes());
1406 const PositionDeformData position_data(depsgraph, object);
1407 active_nodes.foreach_index(GrainSize(1), [&](const int i) {
1408 LocalData &tls = all_tls.local();
1409 const Span<int> verts = nodes[i].verts();
1410
1411 tls.factors.resize(verts.size());
1412 const MutableSpan<float> factors = tls.factors;
1414 attribute_data.hide_vert, attribute_data.mask, verts, factors);
1415 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
1416 auto_mask::calc_vert_factors(depsgraph, object, automasking, nodes[i], verts, factors);
1417
1418 solve_verts_simulation(object, brush, sim_location, verts, factors, tls, cloth_sim);
1419
1420 tls.translations.resize(verts.size());
1421 const MutableSpan<float3> translations = tls.translations;
1422 for (const int i : verts.index_range()) {
1423 translations[i] = cloth_sim.pos[verts[i]] - position_data.eval[verts[i]];
1424 }
1425
1426 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
1427 position_data.deform(translations, verts);
1428
1429 cloth_sim.node_state[cloth_sim.node_state_index.lookup(&nodes[i])] =
1431 bke::pbvh::update_node_bounds_mesh(position_data.eval, nodes[i]);
1432 });
1433 break;
1434 }
1437 const IndexMask active_nodes = IndexMask::from_predicate(
1438 node_mask, GrainSize(1024), memory, [&](const int i) {
1439 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1440 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_ACTIVE;
1441 });
1442 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1443 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1444 const Span<float3> cloth_positions = cloth_sim.pos;
1445 MutableSpan<float3> positions = subdiv_ccg.positions;
1446 active_nodes.foreach_index(GrainSize(1), [&](const int i) {
1447 LocalData &tls = all_tls.local();
1448 const Span<int> grids = nodes[i].grids();
1449 const int grid_verts_num = grids.size() * key.grid_area;
1450
1451 tls.factors.resize(grid_verts_num);
1452 const MutableSpan<float> factors = tls.factors;
1453 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
1454 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
1455 auto_mask::calc_grids_factors(depsgraph, object, automasking, nodes[i], grids, factors);
1456
1457 const Span<int> verts = calc_vert_indices_grids(key, grids, tls.vert_indices);
1458 solve_verts_simulation(object, brush, sim_location, verts, factors, tls, cloth_sim);
1459
1460 for (const int grid : grids) {
1461 const IndexRange grid_range = bke::ccg::grid_range(key, grid);
1462 positions.slice(grid_range).copy_from(cloth_positions.slice(grid_range));
1463 }
1464
1465 cloth_sim.node_state[cloth_sim.node_state_index.lookup(&nodes[i])] =
1467 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
1468 });
1469 break;
1470 }
1473 const IndexMask active_nodes = IndexMask::from_predicate(
1474 node_mask, GrainSize(1024), memory, [&](const int i) {
1475 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1476 return cloth_sim.node_state[node_index] == SCULPT_CLOTH_NODE_ACTIVE;
1477 });
1478 BMesh &bm = *ss.bm;
1479 active_nodes.foreach_index(GrainSize(1), [&](const int i) {
1480 LocalData &tls = all_tls.local();
1482
1483 tls.factors.resize(verts.size());
1484 const MutableSpan<float> factors = tls.factors;
1486 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
1487 auto_mask::calc_vert_factors(depsgraph, object, automasking, nodes[i], verts, factors);
1488
1489 const Span<int> vert_indices = calc_vert_indices_bmesh(verts, tls.vert_indices);
1490 solve_verts_simulation(object, brush, sim_location, vert_indices, factors, tls, cloth_sim);
1491
1492 for (BMVert *vert : verts) {
1493 copy_v3_v3(vert->co, cloth_sim.pos[BM_elem_index_get(vert)]);
1494 }
1495
1496 cloth_sim.node_state[cloth_sim.node_state_index.lookup(&nodes[i])] =
1499 });
1500 break;
1501 }
1502 }
1503 pbvh.tag_positions_changed(node_mask);
1505}
1506
1507static void cloth_brush_apply_brush_foces(const Depsgraph &depsgraph,
1508 const Sculpt &sd,
1509 Object &ob,
1510 const IndexMask &node_mask)
1511{
1512 SculptSession &ss = *ob.sculpt;
1513 StrokeCache &cache = *ss.cache;
1514 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
1515
1516 float3 area_no;
1517 float3 area_co;
1518 float3 offset;
1519
1520 if (math::is_zero(cache.grab_delta_symm)) {
1521 return;
1522 }
1523
1524 float3 grab_delta = math::normalize(cache.grab_delta_symm);
1525
1526 /* Calculate push offset. */
1528 offset = cache.sculpt_normal_symm * cache.radius * cache.scale * 2.0f;
1529 }
1530
1534 {
1535 calc_brush_plane(depsgraph, brush, ob, node_mask, area_no, area_co);
1536
1537 /* Initialize stroke local space matrix. */
1538 mat.x_axis() = math::cross(area_no, cache.grab_delta_symm);
1539 mat.y_axis() = math::cross(area_no, mat.x_axis());
1540 mat.z_axis() = area_no;
1541 mat.location() = cache.location_symm;
1542 normalize_m4(mat.ptr());
1543
1544 /* Update matrix for the cursor preview. */
1545 if (cache.mirror_symmetry_pass == 0) {
1546 cache.stroke_local_mat = mat;
1547 }
1548 }
1549
1551 /* Set the deformation strength to 0. Brushes will initialize the strength in the required
1552 * area. */
1553 cache.cloth_sim->deformation_strength.fill(0.0f);
1554 }
1555
1556 const float3 sim_location = cloth_brush_simulation_location_get(ss, &brush);
1557
1558 /* Gravity */
1559 float3 gravity(0);
1560 if (cache.supports_gravity) {
1561 gravity += cache.gravity_direction_symm * -sd.gravity_factor;
1562 }
1563
1564 std::optional<FalloffPlane> falloff_plane;
1566 falloff_plane.emplace();
1567 falloff_plane->normal = math::normalize(grab_delta);
1568 plane_from_point_normal_v3(falloff_plane->plane, area_co, falloff_plane->normal);
1569 }
1570
1572
1574 switch (pbvh.type()) {
1575 case bke::pbvh::Type::Mesh: {
1576 const Mesh &mesh = *static_cast<Mesh *>(ob.data);
1577 const MeshAttributeData attribute_data(mesh.attributes());
1578 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(depsgraph, ob);
1579 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1581 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1582 LocalData &tls = all_tls.local();
1584 ob,
1585 brush,
1586 offset,
1587 mat,
1588 sim_location,
1589 gravity,
1590 falloff_plane,
1591 attribute_data,
1592 positions_eval,
1593 vert_normals,
1594 nodes[i],
1595 tls);
1596 });
1597 break;
1598 }
1601 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1602 LocalData &tls = all_tls.local();
1604 ob,
1605 brush,
1606 offset,
1607 mat,
1608 sim_location,
1609 gravity,
1610 falloff_plane,
1611 nodes[i],
1612 tls);
1613 });
1614 break;
1615 }
1618 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1619 LocalData &tls = all_tls.local();
1621 ob,
1622 brush,
1623 offset,
1624 mat,
1625 sim_location,
1626 gravity,
1627 falloff_plane,
1628 nodes[i],
1629 tls);
1630 });
1631 break;
1632 }
1633 }
1634}
1635
1636/* Allocates nodes state and initializes them to Uninitialized, so constraints can be created for
1637 * them. */
1639{
1640 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1641 IndexMaskMemory memory;
1642 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1644
1645 switch (pbvh.type()) {
1646 case bke::pbvh::Type::Mesh: {
1648 node_mask.foreach_index([&](const int i) { cloth_sim.node_state_index.add(&nodes[i], i); });
1649 break;
1650 }
1653 node_mask.foreach_index([&](const int i) { cloth_sim.node_state_index.add(&nodes[i], i); });
1654 break;
1655 }
1658 node_mask.foreach_index([&](const int i) { cloth_sim.node_state_index.add(&nodes[i], i); });
1659 break;
1660 }
1661 }
1662}
1663
1664static void copy_positions_to_array(const Depsgraph &depsgraph,
1665 const Object &object,
1666 MutableSpan<float3> positions)
1667{
1668 const SculptSession &ss = *object.sculpt;
1669 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1670 switch (pbvh.type()) {
1672 positions.copy_from(bke::pbvh::vert_positions_eval(depsgraph, object));
1673 break;
1675 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1676 positions.copy_from(subdiv_ccg.positions);
1677 break;
1678 }
1680 BM_mesh_vert_coords_get(ss.bm, positions);
1681 break;
1682 }
1683}
1684
1685static void copy_normals_to_array(const Depsgraph &depsgraph,
1686 const Object &object,
1687 MutableSpan<float3> normals)
1688{
1689 const SculptSession &ss = *object.sculpt;
1690 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1691 switch (pbvh.type()) {
1693 normals.copy_from(bke::pbvh::vert_normals_eval(depsgraph, object));
1694 break;
1696 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1697 normals.copy_from(subdiv_ccg.normals);
1698 break;
1699 }
1701 BM_mesh_vert_normals_get(ss.bm, normals);
1702 break;
1703 }
1704}
1705
1706std::unique_ptr<SimulationData> brush_simulation_create(const Depsgraph &depsgraph,
1707 Object &ob,
1708 const float cloth_mass,
1709 const float cloth_damping,
1710 const float cloth_softbody_strength,
1711 const bool use_collisions,
1712 const bool needs_deform_coords)
1713{
1714 const int totverts = SCULPT_vertex_count_get(ob);
1715 std::unique_ptr<SimulationData> cloth_sim = std::make_unique<SimulationData>();
1716
1717 cloth_sim->length_constraints.reserve(CLOTH_LENGTH_CONSTRAINTS_BLOCK);
1718
1719 cloth_sim->acceleration = Array<float3>(totverts, float3(0));
1720 cloth_sim->pos = Array<float3>(totverts, float3(0));
1721 cloth_sim->length_constraint_tweak = Array<float>(totverts, 0.0f);
1722
1723 cloth_sim->init_pos.reinitialize(totverts);
1724 copy_positions_to_array(depsgraph, ob, cloth_sim->init_pos);
1725
1726 cloth_sim->last_iteration_pos = cloth_sim->init_pos;
1727 cloth_sim->prev_pos = cloth_sim->init_pos;
1728
1729 cloth_sim->init_no.reinitialize(totverts);
1730 copy_normals_to_array(depsgraph, ob, cloth_sim->init_no);
1731
1732 if (needs_deform_coords) {
1733 cloth_sim->deformation_pos = cloth_sim->init_pos;
1734 cloth_sim->deformation_strength = Array<float>(totverts, 1.0f);
1735 }
1736
1737 if (cloth_softbody_strength > 0.0f) {
1738 cloth_sim->softbody_pos = cloth_sim->init_pos;
1739 }
1740
1741 cloth_sim->mass = cloth_mass;
1742 cloth_sim->damping = cloth_damping;
1743 cloth_sim->softbody_strength = cloth_softbody_strength;
1744
1745 if (use_collisions) {
1746 cloth_sim->collider_list = cloth_brush_collider_cache_create(ob, depsgraph);
1747 }
1748
1750
1751 return cloth_sim;
1752}
1753
1755 const Object &object,
1756 SimulationData &cloth_sim)
1757{
1758 copy_positions_to_array(depsgraph, object, cloth_sim.pos);
1759}
1760
1761void sim_activate_nodes(Object &object, SimulationData &cloth_sim, const IndexMask &node_mask)
1762{
1763 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1764
1765 /* Activate the nodes inside the simulation area. */
1766 switch (pbvh.type()) {
1767 case bke::pbvh::Type::Mesh: {
1769 node_mask.foreach_index([&](const int i) {
1770 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1771 cloth_sim.node_state[node_index] = SCULPT_CLOTH_NODE_ACTIVE;
1772 });
1773 break;
1774 }
1777 node_mask.foreach_index([&](const int i) {
1778 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1779 cloth_sim.node_state[node_index] = SCULPT_CLOTH_NODE_ACTIVE;
1780 });
1781 break;
1782 }
1785 node_mask.foreach_index([&](const int i) {
1786 const int node_index = cloth_sim.node_state_index.lookup(&nodes[i]);
1787 cloth_sim.node_state[node_index] = SCULPT_CLOTH_NODE_ACTIVE;
1788 });
1789 break;
1790 }
1791 }
1792}
1793
1795 Object &ob,
1796 const IndexMask &node_mask)
1797{
1798 SculptSession &ss = *ob.sculpt;
1799 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1800 const float radius = ss.cache->initial_radius;
1801 const float limit = radius + (radius * brush->cloth_sim_limit);
1802 const float3 sim_location = cloth_brush_simulation_location_get(ss, brush);
1803 ensure_nodes_constraints(sd, ob, node_mask, *ss.cache->cloth_sim, sim_location, limit);
1804}
1805
1806void do_cloth_brush(const Depsgraph &depsgraph,
1807 const Sculpt &sd,
1808 Object &ob,
1809 const IndexMask &node_mask)
1810{
1811 SculptSession &ss = *ob.sculpt;
1812 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1813
1814 /* Brushes that use anchored strokes and restore the mesh can't rely on symmetry passes and steps
1815 * count as it is always the first step, so the simulation needs to be created when it does not
1816 * exist for this stroke. */
1818
1819 /* The simulation structure only needs to be created on the first symmetry pass. */
1822 ob,
1823 brush->cloth_mass,
1824 brush->cloth_damping,
1827 is_cloth_deform_brush(*brush));
1828 }
1829
1831 /* When using simulation a fixed local simulation area, constraints are created only using
1832 * the initial stroke position and initial radius (per symmetry pass) instead of per node.
1833 * This allows to skip unnecessary constraints that will never be simulated, making the
1834 * solver faster. When the simulation starts for a node, the node gets activated and all its
1835 * constraints are considered final. As the same node can be included inside the brush radius
1836 * from multiple symmetry passes, the cloth brush can't activate the node for simulation yet
1837 * as this will cause the ensure constraints function to skip the node in the next symmetry
1838 * passes. It needs to build the constraints here and skip simulating the first step, so all
1839 * passes can add their constraints to all affected nodes. */
1841 }
1842 /* The first step of a symmetry pass is never simulated as deformation modes need valid delta
1843 * for brush tip alignment. */
1844 return;
1845 }
1846
1847 /* Ensure the constraints for the nodes. */
1849
1850 /* Store the initial state in the simulation. */
1852
1853 /* Enable the nodes that should be simulated. */
1854 sim_activate_nodes(ob, *ss.cache->cloth_sim, node_mask);
1855
1856 /* Apply forces to the vertices. */
1857 cloth_brush_apply_brush_foces(depsgraph, sd, ob, node_mask);
1858
1859 /* Update and write the simulation to the nodes. */
1860 do_simulation_step(depsgraph, sd, ob, *ss.cache->cloth_sim, node_mask);
1861}
1862
1864
1865void simulation_limits_draw(const uint gpuattr,
1866 const Brush &brush,
1867 const float location[3],
1868 const float normal[3],
1869 const float rds,
1870 const float line_width,
1871 const float outline_col[3],
1872 const float alpha)
1873{
1874 float cursor_trans[4][4], cursor_rot[4][4];
1875 const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
1876 float quat[4];
1877 unit_m4(cursor_trans);
1878 translate_m4(cursor_trans, location[0], location[1], location[2]);
1879 rotation_between_vecs_to_quat(quat, z_axis, normal);
1880 quat_to_mat4(cursor_rot, quat);
1882 GPU_matrix_mul(cursor_trans);
1883 GPU_matrix_mul(cursor_rot);
1884
1885 GPU_line_width(line_width);
1886 immUniformColor3fvAlpha(outline_col, alpha * 0.5f);
1888 gpuattr, 0, 0, rds + (rds * brush.cloth_sim_limit * brush.cloth_sim_falloff), 320);
1889 immUniformColor3fvAlpha(outline_col, alpha * 0.7f);
1890 imm_draw_circle_wire_3d(gpuattr, 0, 0, rds + rds * brush.cloth_sim_limit, 80);
1892}
1893
1895 SculptSession &ss,
1896 const float outline_col[3],
1897 float outline_alpha)
1898{
1899 float4x4 local_mat = ss.cache->stroke_local_mat;
1900
1902 add_v3_v3v3(local_mat[3], ss.cache->location, ss.cache->grab_delta);
1903 }
1904
1905 GPU_matrix_mul(local_mat.ptr());
1906
1907 const float dist = ss.cache->radius;
1908 const float arrow_x = ss.cache->radius * 0.2f;
1909 const float arrow_y = ss.cache->radius * 0.1f;
1910
1911 immUniformColor3fvAlpha(outline_col, outline_alpha);
1912 GPU_line_width(2.0f);
1914 immVertex3f(gpuattr, dist, 0.0f, 0.0f);
1915 immVertex3f(gpuattr, -dist, 0.0f, 0.0f);
1916 immEnd();
1917
1919 immVertex3f(gpuattr, dist, 0.0f, 0.0f);
1920 immVertex3f(gpuattr, dist - arrow_x, arrow_y, 0.0f);
1921 immVertex3f(gpuattr, dist - arrow_x, -arrow_y, 0.0f);
1922
1923 immVertex3f(gpuattr, -dist, 0.0f, 0.0f);
1924 immVertex3f(gpuattr, -dist + arrow_x, arrow_y, 0.0f);
1925 immVertex3f(gpuattr, -dist + arrow_x, -arrow_y, 0.0f);
1926
1927 immEnd();
1928}
1929
1930/* Cloth Filter. */
1931
1933 Gravity,
1934 Inflate,
1935 Expand,
1936 Pinch,
1937 Scale,
1938};
1939
1941 {int(ClothFilterType::Gravity), "GRAVITY", 0, "Gravity", "Applies gravity to the simulation"},
1942 {int(ClothFilterType::Inflate), "INFLATE", 0, "Inflate", "Inflates the cloth"},
1943 {int(ClothFilterType::Expand), "EXPAND", 0, "Expand", "Expands the cloth's dimensions"},
1945 "PINCH",
1946 0,
1947 "Pinch",
1948 "Pulls the cloth to the cursor's start position"},
1950 "SCALE",
1951 0,
1952 "Scale",
1953 "Scales the mesh as a soft body using the origin of the object as scale"},
1954 {0, nullptr, 0, nullptr, nullptr},
1955};
1956
1959 "LOCAL",
1960 0,
1961 "Local",
1962 "Use the local axis to limit the force and set the gravity direction"},
1964 "WORLD",
1965 0,
1966 "World",
1967 "Use the global axis to limit the force and set the gravity direction"},
1969 "VIEW",
1970 0,
1971 "View",
1972 "Use the view axis to limit the force and set the gravity direction"},
1973 {0, nullptr, 0, nullptr, nullptr},
1974};
1975
1981
1983 {CLOTH_FILTER_FORCE_X, "X", 0, "X", "Apply force in the X axis"},
1984 {CLOTH_FILTER_FORCE_Y, "Y", 0, "Y", "Apply force in the Y axis"},
1985 {CLOTH_FILTER_FORCE_Z, "Z", 0, "Z", "Apply force in the Z axis"},
1986 {0, nullptr, 0, nullptr, nullptr},
1987};
1988
1990{
1991 return ELEM(filter_type, ClothFilterType::Scale);
1992}
1993
1995 const filter::Cache &filter_cache,
1996 const MutableSpan<float3> forces)
1997{
1998 const float3x3 to_object_space = filter::to_object_space(filter_cache);
1999 for (const int i : forces.index_range()) {
2000 float3 force(0.0f);
2001 if (filter_cache.orientation == filter::FilterOrientation::View) {
2002 /* When using the view orientation apply gravity in the -Y axis, this way objects will
2003 * fall down instead of backwards. */
2004 force[1] = -factors[i];
2005 }
2006 else {
2007 force[2] = -factors[i];
2008 }
2009 forces[i] = to_object_space * force;
2010 }
2011}
2012
2020
2022 const Span<int> verts,
2023 const Span<float> factors,
2024 FilterLocalData &tls)
2025{
2026 const MutableSpan translations = gather_data_mesh(
2027 filter_cache.cloth_sim->init_pos.as_span(), verts, tls.forces);
2028 scale_translations(translations, factors);
2029 filter::zero_disabled_axis_components(filter_cache, translations);
2030 for (const int i : verts.index_range()) {
2031 filter_cache.cloth_sim->deformation_pos[verts[i]] =
2032 filter_cache.cloth_sim->init_pos[verts[i]] + translations[i];
2033 }
2034}
2035
2036static void apply_filter_forces_mesh(const Depsgraph &depsgraph,
2037 const ClothFilterType filter_type,
2038 const float filter_strength,
2039 const float3 &gravity,
2040 const Span<float3> positions_eval,
2041 const Span<float3> vert_normals,
2042 const GroupedSpan<int> vert_to_face_map,
2043 const MeshAttributeData &attribute_data,
2044 const bke::pbvh::MeshNode &node,
2045 Object &object,
2046 FilterLocalData &tls)
2047{
2048 const SculptSession &ss = *object.sculpt;
2049 SimulationData &cloth_sim = *ss.filter_cache->cloth_sim;
2050
2051 const Span<int> verts = node.verts();
2052
2053 tls.factors.resize(verts.size());
2054 const MutableSpan<float> factors = tls.factors;
2055 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
2056 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
2057 auto_mask::calc_vert_factors(depsgraph, object, automasking, node, verts, factors);
2058
2060 for (const int i : verts.index_range()) {
2061 const int vert = verts[i];
2063 vert_to_face_map, attribute_data.face_sets, vert, ss.filter_cache->active_face_set))
2064 {
2065 factors[i] = 0.0f;
2066 }
2067 }
2068 }
2069
2070 scale_factors(factors, filter_strength);
2071
2072 tls.forces.resize(verts.size());
2073 const MutableSpan<float3> forces = tls.forces;
2074 if (!math::is_zero(gravity)) {
2075 forces.fill(gravity);
2076 apply_forces(cloth_sim, forces, verts);
2077 }
2078
2079 switch (filter_type) {
2081 calc_gravity_forces(factors, *ss.filter_cache, forces);
2082 apply_forces(cloth_sim, tls.forces, verts);
2083 break;
2085 gather_data_mesh(vert_normals, verts, forces);
2086 scale_translations(forces, factors);
2087 apply_forces(cloth_sim, tls.forces, verts);
2088 break;
2090 expand_length_constraints(cloth_sim, verts, factors);
2091 break;
2094
2095 gather_data_mesh(positions_eval, verts, tls.positions),
2097 forces);
2098 scale_translations(forces, factors);
2099 apply_forces(cloth_sim, tls.forces, verts);
2100 break;
2102 apply_scale_filter(*ss.filter_cache, verts, factors, tls);
2103 break;
2104 }
2105}
2106
2107static void apply_filter_forces_grids(const Depsgraph &depsgraph,
2108 const Span<int> face_sets,
2109 const ClothFilterType filter_type,
2110 const float filter_strength,
2111 const float3 &gravity,
2112 const bke::pbvh::GridsNode &node,
2113 Object &object,
2114 FilterLocalData &tls)
2115{
2116 const SculptSession &ss = *object.sculpt;
2117 SimulationData &cloth_sim = *ss.filter_cache->cloth_sim;
2118 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
2119 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
2120
2121 const Span<int> grids = node.grids();
2122 const int grid_verts_num = grids.size() * key.grid_area;
2123
2124 tls.factors.resize(grid_verts_num);
2125 const MutableSpan<float> factors = tls.factors;
2126 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
2127 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
2128 auto_mask::calc_grids_factors(depsgraph, object, automasking, node, grids, factors);
2129
2131 for (const int i : grids.index_range()) {
2133 subdiv_ccg, face_sets, grids[i], ss.filter_cache->active_face_set))
2134 {
2135 factors.slice(i * key.grid_area, key.grid_area).fill(0.0f);
2136 }
2137 }
2138 }
2139
2140 scale_factors(factors, filter_strength);
2141
2142 const Span<int> verts = calc_vert_indices_grids(key, grids, tls.vert_indices);
2143
2144 tls.forces.resize(verts.size());
2145 const MutableSpan<float3> forces = tls.forces;
2146 if (!math::is_zero(gravity)) {
2147 forces.fill(gravity);
2148 apply_forces(cloth_sim, forces, verts);
2149 }
2150
2151 switch (filter_type) {
2153 calc_gravity_forces(factors, *ss.filter_cache, forces);
2154 apply_forces(cloth_sim, tls.forces, verts);
2155 break;
2157 gather_grids_normals(subdiv_ccg, grids, forces);
2158 scale_translations(forces, factors);
2159 apply_forces(cloth_sim, tls.forces, verts);
2160 break;
2162 expand_length_constraints(cloth_sim, verts, factors);
2163 break;
2166
2167 gather_grids_positions(subdiv_ccg, grids, tls.positions),
2169 forces);
2170 scale_translations(forces, factors);
2171 apply_forces(cloth_sim, tls.forces, verts);
2172 break;
2174 apply_scale_filter(*ss.filter_cache, verts, factors, tls);
2175 break;
2176 }
2177}
2178
2179static void apply_filter_forces_bmesh(const Depsgraph &depsgraph,
2180 const ClothFilterType filter_type,
2181 const float filter_strength,
2182 const float3 &gravity,
2184 Object &object,
2185 FilterLocalData &tls)
2186{
2187 const SculptSession &ss = *object.sculpt;
2188 SimulationData &cloth_sim = *ss.filter_cache->cloth_sim;
2189 const BMesh &bm = *ss.bm;
2190
2192
2193 tls.factors.resize(verts.size());
2194 const MutableSpan<float> factors = tls.factors;
2196 const auto_mask::Cache *automasking = auto_mask::active_cache_get(ss);
2197 auto_mask::calc_vert_factors(depsgraph, object, automasking, node, verts, factors);
2198
2200 const int face_set_offset = CustomData_get_offset_named(
2201 &bm.pdata, CD_PROP_INT32, ".sculpt_face_set");
2202 int i = 0;
2203 for (const BMVert *vert : verts) {
2204 if (!face_set::vert_has_face_set(face_set_offset, *vert, ss.filter_cache->active_face_set)) {
2205 factors[i] = 0.0f;
2206 }
2207 i++;
2208 }
2209 }
2210
2211 scale_factors(factors, filter_strength);
2212
2213 const Span<int> vert_indices = calc_vert_indices_bmesh(verts, tls.vert_indices);
2214
2215 tls.forces.resize(verts.size());
2216 const MutableSpan<float3> forces = tls.forces;
2217 if (!math::is_zero(gravity)) {
2218 forces.fill(gravity);
2219 apply_forces(cloth_sim, forces, vert_indices);
2220 }
2221
2222 switch (filter_type) {
2224 calc_gravity_forces(factors, *ss.filter_cache, forces);
2225 apply_forces(cloth_sim, tls.forces, vert_indices);
2226 break;
2228 gather_bmesh_normals(verts, forces);
2229 scale_translations(forces, factors);
2230 apply_forces(cloth_sim, tls.forces, vert_indices);
2231 break;
2233 expand_length_constraints(cloth_sim, vert_indices, factors);
2234 break;
2237
2240 forces);
2241 scale_translations(forces, factors);
2242 apply_forces(cloth_sim, tls.forces, vert_indices);
2243 break;
2245 apply_scale_filter(*ss.filter_cache, vert_indices, factors, tls);
2246 break;
2247 }
2248}
2249
2250static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
2251{
2252 Object &object = *CTX_data_active_object(C);
2253 Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
2254 SculptSession &ss = *object.sculpt;
2255 const Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
2256 const ClothFilterType filter_type = ClothFilterType(RNA_enum_get(op->ptr, "type"));
2257 float filter_strength = RNA_float_get(op->ptr, "strength");
2258
2259 if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
2260 MEM_delete(ss.filter_cache);
2261 ss.filter_cache = nullptr;
2262 undo::push_end(object);
2264 return OPERATOR_FINISHED;
2265 }
2266
2267 if (event->type != MOUSEMOVE) {
2269 }
2270
2271 const float len = event->prev_press_xy[0] - event->xy[0];
2272 filter_strength = filter_strength * -len * 0.001f * UI_SCALE_FAC;
2273
2275
2277
2279
2280 const IndexMask &node_mask = ss.filter_cache->node_mask;
2281
2282 float3 gravity(0.0f);
2283 if (sd.gravity_object) {
2284 gravity = sd.gravity_object->object_to_world().ptr()[2];
2285 }
2286 else {
2287 gravity[2] = -1.0f;
2288 }
2289 gravity *= sd.gravity_factor * filter_strength;
2290
2291 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
2292
2294 switch (pbvh.type()) {
2295 case bke::pbvh::Type::Mesh: {
2296 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(*depsgraph, object);
2297 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(*depsgraph, object);
2298 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
2299 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
2300 MeshAttributeData attribute_data(mesh.attributes());
2302 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2303 FilterLocalData &tls = all_tls.local();
2305 filter_type,
2306 filter_strength,
2307 gravity,
2308 positions_eval,
2309 vert_normals,
2310 vert_to_face_map,
2311 attribute_data,
2312 nodes[i],
2313 object,
2314 tls);
2315 bke::pbvh::update_node_bounds_mesh(positions_eval, nodes[i]);
2316 });
2317 break;
2318 }
2320 const Mesh &base_mesh = *static_cast<const Mesh *>(object.data);
2321 const bke::AttributeAccessor attributes = base_mesh.attributes();
2322 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set",
2324 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
2325 MutableSpan<float3> positions = subdiv_ccg.positions;
2327 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2328 FilterLocalData &tls = all_tls.local();
2330 *depsgraph, face_sets, filter_type, filter_strength, gravity, nodes[i], object, tls);
2331 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
2332 });
2333 break;
2334 }
2337 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2338 FilterLocalData &tls = all_tls.local();
2340 *depsgraph, filter_type, filter_strength, gravity, nodes[i], object, tls);
2342 });
2343 break;
2344 }
2345 }
2346 pbvh.tag_positions_changed(node_mask);
2348
2349 /* Activate all nodes. */
2350 sim_activate_nodes(object, *ss.filter_cache->cloth_sim, node_mask);
2351
2352 /* Update and write the simulation to the nodes. */
2353 do_simulation_step(*depsgraph, sd, object, *ss.filter_cache->cloth_sim, node_mask);
2354
2357}
2358
2360{
2361 const Scene &scene = *CTX_data_scene(C);
2364 const Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
2365 SculptSession &ss = *ob.sculpt;
2366
2367 const View3D *v3d = CTX_wm_view3d(C);
2368 const Base *base = CTX_data_active_base(C);
2369 if (!BKE_base_is_visible(v3d, base)) {
2370 return OPERATOR_CANCELLED;
2371 }
2372
2373 const ClothFilterType filter_type = ClothFilterType(RNA_enum_get(op->ptr, "type"));
2374
2375 /* Update the active vertex */
2376 float2 mval_fl{float(event->mval[0]), float(event->mval[1])};
2378 SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
2379
2380 /* Needs mask data to be available as it is used when solving the constraints. */
2382
2384 return OPERATOR_CANCELLED;
2385 }
2386
2387 undo::push_begin(scene, ob, op);
2389 ob,
2390 sd,
2392 mval_fl,
2393 RNA_float_get(op->ptr, "area_normal_radius"),
2394 RNA_float_get(op->ptr, "strength"));
2395
2397
2398 const float cloth_mass = RNA_float_get(op->ptr, "cloth_mass");
2399 const float cloth_damping = RNA_float_get(op->ptr, "cloth_damping");
2400 const bool use_collisions = RNA_boolean_get(op->ptr, "use_collisions");
2402 *depsgraph,
2403 ob,
2404 cloth_mass,
2405 cloth_damping,
2406 0.0f,
2407 use_collisions,
2409
2411
2412 float3 origin(0);
2414 sd, ob, ss.filter_cache->node_mask, *ss.filter_cache->cloth_sim, origin, FLT_MAX);
2415
2416 const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets");
2417 if (use_face_sets) {
2419 }
2420 else {
2422 }
2423
2424 const int force_axis = RNA_enum_get(op->ptr, "force_axis");
2425 ss.filter_cache->enabled_axis[0] = force_axis & CLOTH_FILTER_FORCE_X;
2426 ss.filter_cache->enabled_axis[1] = force_axis & CLOTH_FILTER_FORCE_Y;
2427 ss.filter_cache->enabled_axis[2] = force_axis & CLOTH_FILTER_FORCE_Z;
2428
2430
2433}
2434
2436{
2437 ot->name = "Filter Cloth";
2438 ot->idname = "SCULPT_OT_cloth_filter";
2439 ot->description = "Applies a cloth simulation deformation to the entire mesh";
2440
2444
2446
2448
2450 "type",
2453 "Filter Type",
2454 "Operation that is going to be applied to the mesh");
2457 "force_axis",
2460 "Force Axis",
2461 "Apply the force in the selected axis");
2463 "orientation",
2466 "Orientation",
2467 "Orientation of the axis to limit the filter force");
2469 "cloth_mass",
2470 1.0f,
2471 0.0f,
2472 2.0f,
2473 "Cloth Mass",
2474 "Mass of each simulation particle",
2475 0.0f,
2476 1.0f);
2478 "cloth_damping",
2479 0.0f,
2480 0.0f,
2481 1.0f,
2482 "Cloth Damping",
2483 "How much the applied forces are propagated through the cloth",
2484 0.0f,
2485 1.0f);
2487 "use_face_sets",
2488 false,
2489 "Use Face Sets",
2490 "Apply the filter only to the Face Set under the cursor");
2492 "use_collisions",
2493 false,
2494 "Use Collisions",
2495 "Collide with other collider objects in the scene");
2496}
2497
2498} // namespace blender::ed::sculpt_paint::cloth
float BKE_brush_curve_strength(eBrushCurvePreset preset, const CurveMapping *cumap, float distance, float brush_radius)
Definition brush.cc:1388
void collision_move_object(struct CollisionModifierData *collmd, float step, float prevstep, bool moving_bvh)
Definition collision.cc:60
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:341
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:654
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2601
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:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_NOINLINE
@ BVH_RAYCAST_WATERTIGHT
Definition BLI_kdopbvh.h:89
#define BVH_RAYCAST_DEFAULT
Definition BLI_kdopbvh.h:91
int BLI_bvhtree_ray_cast_ex(const BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata, int flag)
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition math_geom.cc:215
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:500
float dist_signed_to_plane_v3(const float p[3], const float plane[4])
Definition math_geom.cc:493
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:433
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:39
void unit_m4(float m[4][4])
Definition rct.c:1127
void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
void normalize_m4(float R[4][4]) ATTR_NONNULL()
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_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_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:161
Read Guarded memory(de)allocation.
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
@ KM_RELEASE
Definition WM_types.hh:285
@ BM_ELEM_HIDDEN
#define BM_elem_index_get(ele)
#define BM_elem_flag_test(ele, hflag)
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_vert_coords_get(BMesh *bm, MutableSpan< float3 > positions)
void BM_mesh_vert_normals_get(BMesh *bm, MutableSpan< float3 > normals)
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
#define BM_VERT
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
AttributeSet attributes
Span< T > as_span() const
Definition BLI_array.hh:232
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
bool is_empty() const
Definition BLI_array.hh:253
constexpr int64_t size() const
Definition BLI_span.hh:494
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:574
constexpr void fill(const T &value) const
Definition BLI_span.hh:518
constexpr Span< T > as_span() const
Definition BLI_span.hh:662
constexpr IndexRange index_range() const
Definition BLI_span.hh:671
constexpr void fill_indices(Span< IndexT > indices, const T &value) const
Definition BLI_span.hh:527
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr bool is_empty() const
Definition BLI_span.hh:261
void append(const T &value)
void resize(const int64_t new_size)
void tag_positions_changed(const IndexMask &node_mask)
Definition pbvh.cc:549
Span< NodeT > nodes() const
int nodes_num() const
Definition pbvh.cc:504
void deform(MutableSpan< float3 > translations, Span< int > verts) const
Definition sculpt.cc:7139
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
void foreach_index(Fn &&fn) const
local_group_size(16, 16) .push_constant(Type b
const Depsgraph * depsgraph
int len
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
static ushort indices[]
static float verts[][3]
uint col
ccl_device_inline float len_squared(const float2 a)
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:2846
IndexMask search_nodes(const Tree &pbvh, IndexMaskMemory &memory, FunctionRef< bool(const Node &)> filter_fn)
Definition pbvh.cc:2647
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2612
void update_node_bounds_bmesh(BMeshNode &node)
Definition pbvh.cc:1095
void update_node_bounds_mesh(Span< float3 > positions, MeshNode &node)
Definition pbvh.cc:1075
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2502
void update_node_bounds_grids(int grid_area, Span< float3 > positions, GridsNode &node)
Definition pbvh.cc:1084
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2482
void flush_bounds_to_parents(Tree &pbvh)
Definition pbvh.cc:1132
void calc_grids_factors(const Depsgraph &depsgraph, const Object &object, const Cache &cache, const bke::pbvh::GridsNode &node, Span< int > grids, MutableSpan< float > factors)
std::unique_ptr< Cache > cache_init(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob)
const Cache * active_cache_get(const SculptSession &ss)
void calc_vert_factors(const Depsgraph &depsgraph, const Object &object, const Cache &cache, const bke::pbvh::MeshNode &node, Span< int > verts, MutableSpan< float > factors)
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 Span< Vector< int > > vert_neighbors, SimulationData &cloth_sim, Set< OrderedEdge > &created_length_constraints)
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 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)
static void calc_vert_neighbor_indices_grids(const SubdivCCG &subdiv_ccg, const Span< int > verts, const MutableSpan< Vector< int > > neighbor_indices)
void do_cloth_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
static void calc_vert_neighbor_indices_bmesh(const BMesh &bm, const Span< int > verts, const MutableSpan< Vector< int > > neighbor_indices)
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 BLI_NOINLINE void apply_snake_hook_brush(SimulationData &cloth_sim, const Span< int > verts, const MutableSpan< float > factors, const float3 &grab_delta_symmetry)
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 int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
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)
static void cloth_brush_apply_brush_foces(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
static EnumPropertyItem prop_cloth_filter_orientation_items[]
static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static BLI_NOINLINE void fill_factor_from_hide_and_mask(const Mesh &mesh, const Span< int > face_indices, const MutableSpan< float > r_factors)
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:254
int active_face_set_get(const Object &object)
Definition sculpt.cc:198
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)
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:2326
void scatter_data_bmesh(Span< T > node_data, const Set< BMVert *, 0 > &verts, MutableSpan< T > dst)
Definition sculpt.cc:6148
void gather_bmesh_positions(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > positions)
Definition sculpt.cc:6054
void calc_brush_strength_factors(const StrokeCache &cache, const Brush &brush, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:6889
void gather_data_grids(const SubdivCCG &subdiv_ccg, Span< T > src, Span< int > grids, MutableSpan< T > node_data)
Definition sculpt.cc:6092
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:6862
void gather_bmesh_normals(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > normals)
Definition sculpt.cc:6072
void filter_region_clip_factors(const SculptSession &ss, Span< float3 > vert_positions, Span< int > verts, MutableSpan< float > factors)
Definition sculpt.cc:6639
void gather_data_bmesh(Span< T > src, const Set< BMVert *, 0 > &verts, MutableSpan< T > node_data)
Definition sculpt.cc:6108
void flush_update_done(const bContext *C, Object &ob, UpdateType update_type)
Definition sculpt.cc:5055
void calc_brush_distances(const SculptSession &ss, Span< float3 > vert_positions, Span< int > vert_indices, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:6722
void scale_translations(MutableSpan< float3 > translations, Span< float > factors)
Definition sculpt.cc:7210
void flush_update_step(bContext *C, UpdateType update_type)
Definition sculpt.cc:4960
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:7227
void clip_and_lock_translations(const Sculpt &sd, const SculptSession &ss, Span< float3 > positions, Span< int > verts, MutableSpan< float3 > translations)
Definition sculpt.cc:7022
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6122
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:2789
Span< BMVert * > vert_neighbors_get_bmesh(BMVert &vert, Vector< BMVert *, 64 > &r_neighbors)
Definition sculpt.cc:389
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6082
void calc_vert_neighbors(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face, Span< bool > hide_poly, Span< int > verts, MutableSpan< Vector< int > > result)
Definition sculpt.cc:7330
void calc_front_face(const float3 &view_normal, Span< float3 > normals, MutableSpan< float > factors)
Definition sculpt.cc:6581
void gather_grids_normals(const SubdivCCG &subdiv_ccg, Span< int > grids, MutableSpan< float3 > normals)
Definition sculpt.cc:6065
void translations_from_offset_and_factors(const float3 &offset, Span< float > factors, MutableSpan< float3 > r_translations)
Definition sculpt.cc:7246
void calc_brush_texture_factors(const SculptSession &ss, const Brush &brush, Span< float3 > vert_positions, Span< int > vert_indices, MutableSpan< float > factors)
Definition sculpt.cc:6898
void scatter_data_grids(const SubdivCCG &subdiv_ccg, Span< T > node_data, Span< int > grids, MutableSpan< T > dst)
Definition sculpt.cc:6132
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)
VecBase< float, 3 > float3
CCL_NAMESPACE_BEGIN ccl_device float fade(float t)
Definition noise.h:14
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:513
bool SCULPT_cursor_geometry_info_update(bContext *C, SculptCursorGeometryInfo *out, const float mval[2], bool use_sampled_normal)
Definition sculpt.cc:4580
void SCULPT_vertex_random_access_ensure(Object &object)
Definition sculpt.cc:144
bool SCULPT_mode_poll(bContext *C)
Definition sculpt.cc:3560
int SCULPT_vertex_count_get(const Object &object)
Definition sculpt.cc:153
bool SCULPT_stroke_is_first_brush_step(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:507
#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.c:32
#define FLT_MAX
Definition stdcycles.h:14
CustomData pdata
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 Object * ob
struct SculptSession * sculpt
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:427
blender::ed::sculpt_paint::filter::Cache * filter_cache
Definition BKE_paint.hh:428
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:405
blender::float3 active_vert_position(const Depsgraph &depsgraph, const Object &object) const
Definition paint.cc:2224
struct Object * gravity_object
float gravity_factor
static SubdivCCGCoord from_index(const CCGKey &key, int index)
blender::Vector< SubdivCCGCoord, 256 > 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
short val
Definition WM_types.hh:724
int mval[2]
Definition WM_types.hh:728
short type
Definition WM_types.hh:722
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
struct PointerRNA * ptr
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
@ MOUSEMOVE
@ LEFTMOUSE
wmOperatorType * ot
Definition wm_files.cc:4125