1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2020 Blender Foundation.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup edsculpt
22 */
23
24 #include "MEM_guardedalloc.h"
25
26 #include "BLI_blenlib.h"
27 #include "BLI_dial_2d.h"
28 #include "BLI_edgehash.h"
29 #include "BLI_gsqueue.h"
30 #include "BLI_hash.h"
31 #include "BLI_math.h"
32 #include "BLI_task.h"
33 #include "BLI_utildefines.h"
34
35 #include "BLT_translation.h"
36
37 #include "DNA_brush_types.h"
38 #include "DNA_customdata_types.h"
39 #include "DNA_mesh_types.h"
40 #include "DNA_meshdata_types.h"
41 #include "DNA_node_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_scene_types.h"
44
45 #include "BKE_brush.h"
46 #include "BKE_bvhutils.h"
47 #include "BKE_ccg.h"
48 #include "BKE_collision.h"
49 #include "BKE_colortools.h"
50 #include "BKE_context.h"
51 #include "BKE_image.h"
52 #include "BKE_kelvinlet.h"
53 #include "BKE_key.h"
54 #include "BKE_lib_id.h"
55 #include "BKE_main.h"
56 #include "BKE_mesh.h"
57 #include "BKE_mesh_mapping.h"
58 #include "BKE_mesh_mirror.h"
59 #include "BKE_modifier.h"
60 #include "BKE_multires.h"
61 #include "BKE_node.h"
62 #include "BKE_object.h"
63 #include "BKE_paint.h"
64 #include "BKE_particle.h"
65 #include "BKE_pbvh.h"
66 #include "BKE_pointcache.h"
67 #include "BKE_report.h"
68 #include "BKE_scene.h"
69 #include "BKE_screen.h"
70 #include "BKE_subdiv_ccg.h"
71 #include "BKE_subsurf.h"
72
73 #include "DEG_depsgraph.h"
74 #include "DEG_depsgraph_query.h"
75
76 #include "WM_api.h"
77 #include "WM_message.h"
78 #include "WM_toolsystem.h"
79 #include "WM_types.h"
80
81 #include "ED_object.h"
82 #include "ED_screen.h"
83 #include "ED_sculpt.h"
84 #include "ED_view3d.h"
85 #include "paint_intern.h"
86 #include "sculpt_intern.h"
87
88 #include "RNA_access.h"
89 #include "RNA_define.h"
90
91 #include "GPU_immediate.h"
92 #include "GPU_immediate_util.h"
93 #include "GPU_matrix.h"
94 #include "GPU_state.h"
95
96 #include "UI_interface.h"
97 #include "UI_resources.h"
98
99 #include "bmesh.h"
100 #include "bmesh_tools.h"
101
102 #include <math.h>
103 #include <stdlib.h>
104 #include <string.h>
105
cloth_brush_simulation_location_get(SculptSession * ss,const Brush * brush,float r_location[3])106 static void cloth_brush_simulation_location_get(SculptSession *ss,
107 const Brush *brush,
108 float r_location[3])
109 {
110 if (!ss->cache || !brush) {
111 zero_v3(r_location);
112 return;
113 }
114
115 if (brush->cloth_simulation_area_type == BRUSH_CLOTH_SIMULATION_AREA_LOCAL) {
116 copy_v3_v3(r_location, ss->cache->initial_location);
117 return;
118 }
119 copy_v3_v3(r_location, ss->cache->location);
120 }
121
cloth_brush_simulation_falloff_get(const Brush * brush,const float radius,const float location[3],const float co[3])122 static float cloth_brush_simulation_falloff_get(const Brush *brush,
123 const float radius,
124 const float location[3],
125 const float co[3])
126 {
127 if (brush->sculpt_tool != SCULPT_TOOL_CLOTH) {
128 /* All brushes that are not the cloth brush do not use simulation areas. */
129 return 1.0f;
130 }
131
132 /* Global simulation does not have any falloff as the entire mesh is being simulated. */
133 if (brush->cloth_simulation_area_type == BRUSH_CLOTH_SIMULATION_AREA_GLOBAL) {
134 return 1.0f;
135 }
136
137 const float distance = len_v3v3(location, co);
138 const float limit = radius + (radius * brush->cloth_sim_limit);
139 const float falloff = radius + (radius * brush->cloth_sim_limit * brush->cloth_sim_falloff);
140
141 if (distance > limit) {
142 /* Outiside the limits. */
143 return 0.0f;
144 }
145 if (distance < falloff) {
146 /* Before the falloff area. */
147 return 1.0f;
148 }
149 /* Do a smoothstep transition inside the falloff area. */
150 float p = 1.0f - ((distance - falloff) / (limit - falloff));
151 return 3.0f * p * p - 2.0f * p * p * p;
152 }
153
154 #define CLOTH_LENGTH_CONSTRAINTS_BLOCK 100000
155 #define CLOTH_SIMULATION_ITERATIONS 5
156
157 #define CLOTH_SOLVER_DISPLACEMENT_FACTOR 0.6f
158 #define CLOTH_MAX_CONSTRAINTS_PER_VERTEX 1024
159 #define CLOTH_SIMULATION_TIME_STEP 0.01f
160 #define CLOTH_DEFORMATION_SNAKEHOOK_STRENGTH 0.35f
161 #define CLOTH_DEFORMATION_TARGET_STRENGTH 0.01f
162 #define CLOTH_DEFORMATION_GRAB_STRENGTH 0.1f
163
cloth_brush_sim_has_length_constraint(SculptClothSimulation * cloth_sim,const int v1,const int v2)164 static bool cloth_brush_sim_has_length_constraint(SculptClothSimulation *cloth_sim,
165 const int v1,
166 const int v2)
167 {
168 return BLI_edgeset_haskey(cloth_sim->created_length_constraints, v1, v2);
169 }
170
cloth_brush_reallocate_constraints(SculptClothSimulation * cloth_sim)171 static void cloth_brush_reallocate_constraints(SculptClothSimulation *cloth_sim)
172 {
173 if (cloth_sim->tot_length_constraints >= cloth_sim->capacity_length_constraints) {
174 cloth_sim->capacity_length_constraints += CLOTH_LENGTH_CONSTRAINTS_BLOCK;
175 cloth_sim->length_constraints = MEM_reallocN_id(cloth_sim->length_constraints,
176 cloth_sim->capacity_length_constraints *
177 sizeof(SculptClothLengthConstraint),
178 "length constraints");
179 }
180 }
181
cloth_brush_add_length_constraint(SculptSession * ss,SculptClothSimulation * cloth_sim,const int node_index,const int v1,const int v2,const bool use_persistent)182 static void cloth_brush_add_length_constraint(SculptSession *ss,
183 SculptClothSimulation *cloth_sim,
184 const int node_index,
185 const int v1,
186 const int v2,
187 const bool use_persistent)
188 {
189 SculptClothLengthConstraint *length_constraint =
190 &cloth_sim->length_constraints[cloth_sim->tot_length_constraints];
191
192 length_constraint->elem_index_a = v1;
193 length_constraint->elem_index_b = v2;
194
195 length_constraint->node = node_index;
196
197 length_constraint->elem_position_a = cloth_sim->pos[v1];
198 length_constraint->elem_position_b = cloth_sim->pos[v2];
199
200 length_constraint->type = SCULPT_CLOTH_CONSTRAINT_STRUCTURAL;
201
202 if (use_persistent) {
203 length_constraint->length = len_v3v3(SCULPT_vertex_persistent_co_get(ss, v1),
204 SCULPT_vertex_persistent_co_get(ss, v2));
205 }
206 else {
207 length_constraint->length = len_v3v3(SCULPT_vertex_co_get(ss, v1),
208 SCULPT_vertex_co_get(ss, v2));
209 }
210 length_constraint->strength = 1.0f;
211
212 cloth_sim->tot_length_constraints++;
213
214 /* Reallocation if the array capacity is exceeded. */
215 cloth_brush_reallocate_constraints(cloth_sim);
216
217 /* Add the constraint to the GSet to avoid creating it again. */
218 BLI_edgeset_add(cloth_sim->created_length_constraints, v1, v2);
219 }
220
cloth_brush_add_softbody_constraint(SculptClothSimulation * cloth_sim,const int node_index,const int v,const float strength)221 static void cloth_brush_add_softbody_constraint(SculptClothSimulation *cloth_sim,
222 const int node_index,
223 const int v,
224 const float strength)
225 {
226 SculptClothLengthConstraint *length_constraint =
227 &cloth_sim->length_constraints[cloth_sim->tot_length_constraints];
228
229 length_constraint->elem_index_a = v;
230 length_constraint->elem_index_b = v;
231
232 length_constraint->node = node_index;
233
234 length_constraint->elem_position_a = cloth_sim->pos[v];
235 length_constraint->elem_position_b = cloth_sim->softbody_pos[v];
236
237 length_constraint->type = SCULPT_CLOTH_CONSTRAINT_SOFTBODY;
238
239 length_constraint->length = 0.0f;
240 length_constraint->strength = strength;
241
242 cloth_sim->tot_length_constraints++;
243
244 /* Reallocation if the array capacity is exceeded. */
245 cloth_brush_reallocate_constraints(cloth_sim);
246 }
247
cloth_brush_add_pin_constraint(SculptClothSimulation * cloth_sim,const int node_index,const int v,const float strength)248 static void cloth_brush_add_pin_constraint(SculptClothSimulation *cloth_sim,
249 const int node_index,
250 const int v,
251 const float strength)
252 {
253 SculptClothLengthConstraint *length_constraint =
254 &cloth_sim->length_constraints[cloth_sim->tot_length_constraints];
255
256 length_constraint->elem_index_a = v;
257 length_constraint->elem_index_b = v;
258
259 length_constraint->node = node_index;
260
261 length_constraint->elem_position_a = cloth_sim->pos[v];
262 length_constraint->elem_position_b = cloth_sim->init_pos[v];
263
264 length_constraint->type = SCULPT_CLOTH_CONSTRAINT_PIN;
265
266 length_constraint->length = 0.0f;
267 length_constraint->strength = strength;
268
269 cloth_sim->tot_length_constraints++;
270
271 /* Reallocation if the array capacity is exceeded. */
272 cloth_brush_reallocate_constraints(cloth_sim);
273 }
274
cloth_brush_add_deformation_constraint(SculptClothSimulation * cloth_sim,const int node_index,const int v,const float strength)275 static void cloth_brush_add_deformation_constraint(SculptClothSimulation *cloth_sim,
276 const int node_index,
277 const int v,
278 const float strength)
279 {
280 SculptClothLengthConstraint *length_constraint =
281 &cloth_sim->length_constraints[cloth_sim->tot_length_constraints];
282
283 length_constraint->elem_index_a = v;
284 length_constraint->elem_index_b = v;
285
286 length_constraint->node = node_index;
287
288 length_constraint->type = SCULPT_CLOTH_CONSTRAINT_DEFORMATION;
289
290 length_constraint->elem_position_a = cloth_sim->pos[v];
291 length_constraint->elem_position_b = cloth_sim->deformation_pos[v];
292
293 length_constraint->length = 0.0f;
294 length_constraint->strength = strength;
295
296 cloth_sim->tot_length_constraints++;
297
298 /* Reallocation if the array capacity is exceeded. */
299 cloth_brush_reallocate_constraints(cloth_sim);
300 }
301
do_cloth_brush_build_constraints_task_cb_ex(void * __restrict userdata,const int n,const TaskParallelTLS * __restrict UNUSED (tls))302 static void do_cloth_brush_build_constraints_task_cb_ex(
303 void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
304 {
305 SculptThreadedTaskData *data = userdata;
306 SculptSession *ss = data->ob->sculpt;
307 const Brush *brush = data->brush;
308 PBVHNode *node = data->nodes[n];
309
310 const int node_index = POINTER_AS_INT(BLI_ghash_lookup(data->cloth_sim->node_state_index, node));
311 if (data->cloth_sim->node_state[node_index] != SCULPT_CLOTH_NODE_UNINITIALIZED) {
312 /* The simulation already contains constraints for this node. */
313 return;
314 }
315
316 PBVHVertexIter vd;
317
318 const bool pin_simulation_boundary = ss->cache != NULL && brush != NULL &&
319 brush->flag2 & BRUSH_CLOTH_PIN_SIMULATION_BOUNDARY &&
320 brush->cloth_simulation_area_type !=
321 BRUSH_CLOTH_SIMULATION_AREA_DYNAMIC;
322
323 const bool use_persistent = brush != NULL && brush->flag & BRUSH_PERSISTENT;
324
325 /* Brush can be NULL in tools that use the solver without relying of constraints with deformation
326 * positions. */
327 const bool cloth_is_deform_brush = ss->cache != NULL && brush != NULL &&
328 SCULPT_is_cloth_deform_brush(brush);
329 float radius_squared = 0.0f;
330 if (cloth_is_deform_brush) {
331 radius_squared = ss->cache->initial_radius * ss->cache->initial_radius;
332 }
333
334 /* Only limit the contraint creation to a radius when the simulation is local. */
335 const float cloth_sim_radius_squared = brush->cloth_simulation_area_type ==
336 BRUSH_CLOTH_SIMULATION_AREA_LOCAL ?
337 data->cloth_sim_radius * data->cloth_sim_radius :
338 FLT_MAX;
339
340 BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
341 {
342 const float len_squared = len_squared_v3v3(vd.co, data->cloth_sim_initial_location);
343 if (len_squared < cloth_sim_radius_squared) {
344
345 SculptVertexNeighborIter ni;
346 int build_indices[CLOTH_MAX_CONSTRAINTS_PER_VERTEX];
347 int tot_indices = 0;
348 build_indices[tot_indices] = vd.index;
349 tot_indices++;
350 SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
351 build_indices[tot_indices] = ni.index;
352 tot_indices++;
353 }
354 SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
355
356 if (data->cloth_sim->softbody_strength > 0.0f) {
357 cloth_brush_add_softbody_constraint(data->cloth_sim, node_index, vd.index, 1.0f);
358 }
359
360 /* As we don't know the order of the neighbor vertices, we create all possible combinations
361 * between the neighbor and the original vertex as length constraints. */
362 /* This results on a pattern that contains structural, shear and bending constraints for all
363 * vertices, but constraints are repeated taking more memory than necessary. */
364
365 for (int c_i = 0; c_i < tot_indices; c_i++) {
366 for (int c_j = 0; c_j < tot_indices; c_j++) {
367 if (c_i != c_j && !cloth_brush_sim_has_length_constraint(
368 data->cloth_sim, build_indices[c_i], build_indices[c_j])) {
369 cloth_brush_add_length_constraint(ss,
370 data->cloth_sim,
371 node_index,
372 build_indices[c_i],
373 build_indices[c_j],
374 use_persistent);
375 }
376 }
377 }
378 }
379
380 if (brush && brush->sculpt_tool == SCULPT_TOOL_CLOTH) {
381 /* The cloth brush works by applying forces in most of its modes, but some of them require
382 * deformation coordinates to make the simulation stable. */
383 if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB && len_squared < radius_squared) {
384 /* When the grab brush brush is used as part of the cloth brush, deformation constraints
385 * are created with different strengths and only inside the radius of the brush. */
386 const float fade = BKE_brush_curve_strength(brush, sqrtf(len_squared), ss->cache->radius);
387 cloth_brush_add_deformation_constraint(
388 data->cloth_sim, node_index, vd.index, fade * CLOTH_DEFORMATION_GRAB_STRENGTH);
389 }
390 else if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_SNAKE_HOOK) {
391 /* Cloth Snake Hook creates deformation constraint with fixed strength because the strength
392 * is controlled per iteration using cloth_sim->deformation_strength. */
393 cloth_brush_add_deformation_constraint(
394 data->cloth_sim, node_index, vd.index, CLOTH_DEFORMATION_SNAKEHOOK_STRENGTH);
395 }
396 }
397 else if (data->cloth_sim->deformation_pos) {
398 /* Any other tool that target the cloth simulation handle the falloff in
399 * their own code when modifying the deformation coordinates of the simulation, so
400 * deformation constraints are created with a fixed strength for all vertices. */
401 cloth_brush_add_deformation_constraint(
402 data->cloth_sim, node_index, vd.index, CLOTH_DEFORMATION_TARGET_STRENGTH);
403 }
404
405 if (pin_simulation_boundary) {
406 const float sim_falloff = cloth_brush_simulation_falloff_get(
407 brush, ss->cache->initial_radius, ss->cache->location, vd.co);
408 /* Vertex is inside the area of the simulation without any falloff applied. */
409 if (sim_falloff < 1.0f) {
410 /* Create constraints with more strength the closer the vertex is to the simulation
411 * boundary. */
412 cloth_brush_add_pin_constraint(data->cloth_sim, node_index, vd.index, 1.0f - sim_falloff);
413 }
414 }
415 }
416 BKE_pbvh_vertex_iter_end;
417 }
418
cloth_brush_apply_force_to_vertex(SculptSession * UNUSED (ss),SculptClothSimulation * cloth_sim,const float force[3],const int vertex_index)419 static void cloth_brush_apply_force_to_vertex(SculptSession *UNUSED(ss),
420 SculptClothSimulation *cloth_sim,
421 const float force[3],
422 const int vertex_index)
423 {
424 madd_v3_v3fl(cloth_sim->acceleration[vertex_index], force, 1.0f / cloth_sim->mass);
425 }
426
do_cloth_brush_apply_forces_task_cb_ex(void * __restrict userdata,const int n,const TaskParallelTLS * __restrict tls)427 static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
428 const int n,
429 const TaskParallelTLS *__restrict tls)
430 {
431 SculptThreadedTaskData *data = userdata;
432 SculptSession *ss = data->ob->sculpt;
433 const Brush *brush = data->brush;
434 SculptClothSimulation *cloth_sim = ss->cache->cloth_sim;
435 const float *offset = data->offset;
436 const float *grab_delta = data->grab_delta;
437 float(*imat)[4] = data->mat;
438
439 const bool use_falloff_plane = !SCULPT_is_cloth_deform_brush(brush) &&
440 brush->cloth_force_falloff_type ==
441 BRUSH_CLOTH_FORCE_FALLOFF_PLANE;
442
443 PBVHVertexIter vd;
444 const float bstrength = ss->cache->bstrength;
445
446 SculptBrushTest test;
447 SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
448 ss, &test, data->brush->falloff_shape);
449 const int thread_id = BLI_task_parallel_thread_id(tls);
450
451 /* For Pich Perpendicular Deform Type. */
452 float x_object_space[3];
453 float z_object_space[3];
454 if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_PINCH_PERPENDICULAR) {
455 normalize_v3_v3(x_object_space, imat[0]);
456 normalize_v3_v3(z_object_space, imat[2]);
457 }
458
459 /* For Plane Force Falloff. */
460 float deform_plane[4];
461 float plane_normal[3];
462 if (use_falloff_plane) {
463 normalize_v3_v3(plane_normal, grab_delta);
464 plane_from_point_normal_v3(deform_plane, data->area_co, plane_normal);
465 }
466
467 /* Gravity */
468 float gravity[3] = {0.0f};
469 if (ss->cache->supports_gravity) {
470 madd_v3_v3fl(gravity, ss->cache->gravity_direction, -data->sd->gravity_factor);
471 }
472
473 /* Original data for deform brushes. */
474 SculptOrigVertData orig_data;
475 if (SCULPT_is_cloth_deform_brush(brush)) {
476 SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
477 }
478
479 BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
480 {
481 float force[3];
482 float sim_location[3];
483 cloth_brush_simulation_location_get(ss, brush, sim_location);
484 const float sim_factor = cloth_brush_simulation_falloff_get(
485 brush, ss->cache->radius, sim_location, cloth_sim->init_pos[vd.index]);
486
487 float current_vertex_location[3];
488 if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) {
489 SCULPT_orig_vert_data_update(&orig_data, &vd);
490 copy_v3_v3(current_vertex_location, orig_data.co);
491 }
492 else {
493 copy_v3_v3(current_vertex_location, vd.co);
494 }
495
496 /* Apply gravity in the entire simulation area. */
497 float vertex_gravity[3];
498 mul_v3_v3fl(vertex_gravity, gravity, sim_factor);
499 cloth_brush_apply_force_to_vertex(ss, ss->cache->cloth_sim, vertex_gravity, vd.index);
500
501 /* When using the plane falloff mode the falloff is not constrained by the brush radius. */
502 if (sculpt_brush_test_sq_fn(&test, current_vertex_location) || use_falloff_plane) {
503
504 float dist = sqrtf(test.dist);
505
506 if (use_falloff_plane) {
507 dist = dist_to_plane_v3(vd.co, deform_plane);
508 }
509
510 const float fade = sim_factor * bstrength *
511 SCULPT_brush_strength_factor(ss,
512 brush,
513 current_vertex_location,
514 dist,
515 vd.no,
516 vd.fno,
517 vd.mask ? *vd.mask : 0.0f,
518 vd.index,
519 thread_id);
520
521 float brush_disp[3];
522 float normal[3];
523 if (vd.no) {
524 normal_short_to_float_v3(normal, vd.no);
525 }
526 else {
527 copy_v3_v3(normal, vd.fno);
528 }
529
530 switch (brush->cloth_deform_type) {
531 case BRUSH_CLOTH_DEFORM_DRAG:
532 sub_v3_v3v3(brush_disp, ss->cache->location, ss->cache->last_location);
533 normalize_v3(brush_disp);
534 mul_v3_v3fl(force, brush_disp, fade);
535 break;
536 case BRUSH_CLOTH_DEFORM_PUSH:
537 /* Invert the fade to push inwards. */
538 mul_v3_v3fl(force, offset, -fade);
539 break;
540 case BRUSH_CLOTH_DEFORM_GRAB:
541 madd_v3_v3v3fl(cloth_sim->deformation_pos[vd.index],
542 orig_data.co,
543 ss->cache->grab_delta_symmetry,
544 fade);
545 zero_v3(force);
546 break;
547 case BRUSH_CLOTH_DEFORM_SNAKE_HOOK:
548 copy_v3_v3(cloth_sim->deformation_pos[vd.index], cloth_sim->pos[vd.index]);
549 madd_v3_v3fl(cloth_sim->deformation_pos[vd.index], ss->cache->grab_delta_symmetry, fade);
550 cloth_sim->deformation_strength[vd.index] = fade;
551 zero_v3(force);
552 break;
553 case BRUSH_CLOTH_DEFORM_PINCH_POINT:
554 if (use_falloff_plane) {
555 float distance = dist_signed_to_plane_v3(vd.co, deform_plane);
556 copy_v3_v3(brush_disp, plane_normal);
557 mul_v3_fl(brush_disp, -distance);
558 }
559 else {
560 sub_v3_v3v3(brush_disp, ss->cache->location, vd.co);
561 }
562 normalize_v3(brush_disp);
563 mul_v3_v3fl(force, brush_disp, fade);
564 break;
565 case BRUSH_CLOTH_DEFORM_PINCH_PERPENDICULAR: {
566 float disp_center[3];
567 float x_disp[3];
568 float z_disp[3];
569 sub_v3_v3v3(disp_center, ss->cache->location, vd.co);
570 normalize_v3(disp_center);
571 mul_v3_v3fl(x_disp, x_object_space, dot_v3v3(disp_center, x_object_space));
572 mul_v3_v3fl(z_disp, z_object_space, dot_v3v3(disp_center, z_object_space));
573 add_v3_v3v3(disp_center, x_disp, z_disp);
574 mul_v3_v3fl(force, disp_center, fade);
575 } break;
576 case BRUSH_CLOTH_DEFORM_INFLATE:
577 mul_v3_v3fl(force, normal, fade);
578 break;
579 case BRUSH_CLOTH_DEFORM_EXPAND:
580 cloth_sim->length_constraint_tweak[vd.index] += fade * 0.1f;
581 zero_v3(force);
582 break;
583 }
584
585 cloth_brush_apply_force_to_vertex(ss, ss->cache->cloth_sim, force, vd.index);
586 }
587 }
588 BKE_pbvh_vertex_iter_end;
589 }
590
cloth_brush_collider_cache_create(Depsgraph * depsgraph)591 static ListBase *cloth_brush_collider_cache_create(Depsgraph *depsgraph)
592 {
593 ListBase *cache = NULL;
594 DEG_OBJECT_ITER_BEGIN (depsgraph,
595 ob,
596 DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_VISIBLE |
597 DEG_ITER_OBJECT_FLAG_DUPLI) {
598 CollisionModifierData *cmd = (CollisionModifierData *)BKE_modifiers_findby_type(
599 ob, eModifierType_Collision);
600 if (cmd && cmd->bvhtree) {
601 if (cache == NULL) {
602 cache = MEM_callocN(sizeof(ListBase), "ColliderCache array");
603 }
604
605 ColliderCache *col = MEM_callocN(sizeof(ColliderCache), "ColliderCache");
606 col->ob = ob;
607 col->collmd = cmd;
608 collision_move_object(cmd, 1.0, 0.0, true);
609 BLI_addtail(cache, col);
610 }
611 }
612 DEG_OBJECT_ITER_END;
613 return cache;
614 }
615
616 typedef struct ClothBrushCollision {
617 CollisionModifierData *col_data;
618 struct IsectRayPrecalc isect_precalc;
619 } ClothBrushCollision;
620
cloth_brush_collision_cb(void * userdata,int index,const BVHTreeRay * ray,BVHTreeRayHit * hit)621 static void cloth_brush_collision_cb(void *userdata,
622 int index,
623 const BVHTreeRay *ray,
624 BVHTreeRayHit *hit)
625 {
626 ClothBrushCollision *col = (ClothBrushCollision *)userdata;
627 CollisionModifierData *col_data = col->col_data;
628 MVertTri *verttri = &col_data->tri[index];
629 MVert *mverts = col_data->x;
630 float *tri[3], no[3], co[3];
631
632 tri[0] = mverts[verttri->tri[0]].co;
633 tri[1] = mverts[verttri->tri[1]].co;
634 tri[2] = mverts[verttri->tri[2]].co;
635 float dist = 0.0f;
636
637 bool tri_hit = isect_ray_tri_watertight_v3(
638 ray->origin, &col->isect_precalc, UNPACK3(tri), &dist, NULL);
639 normal_tri_v3(no, UNPACK3(tri));
640 madd_v3_v3v3fl(co, ray->origin, ray->direction, dist);
641
642 if (tri_hit && dist < hit->dist) {
643 hit->index = index;
644 hit->dist = dist;
645
646 copy_v3_v3(hit->co, co);
647 copy_v3_v3(hit->no, no);
648 }
649 }
650
cloth_brush_solve_collision(Object * object,SculptClothSimulation * cloth_sim,const int i)651 static void cloth_brush_solve_collision(Object *object,
652 SculptClothSimulation *cloth_sim,
653 const int i)
654 {
655 const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
656
657 ColliderCache *collider_cache;
658 BVHTreeRayHit hit;
659
660 float obmat_inv[4][4];
661 invert_m4_m4(obmat_inv, object->obmat);
662
663 for (collider_cache = cloth_sim->collider_list->first; collider_cache;
664 collider_cache = collider_cache->next) {
665 float ray_start[3], ray_normal[3];
666 float pos_world_space[3], prev_pos_world_space[3];
667
668 mul_v3_m4v3(pos_world_space, object->obmat, cloth_sim->pos[i]);
669 mul_v3_m4v3(prev_pos_world_space, object->obmat, cloth_sim->last_iteration_pos[i]);
670 sub_v3_v3v3(ray_normal, pos_world_space, prev_pos_world_space);
671 copy_v3_v3(ray_start, prev_pos_world_space);
672 hit.index = -1;
673 hit.dist = len_v3(ray_normal);
674 normalize_v3(ray_normal);
675
676 ClothBrushCollision col;
677 CollisionModifierData *collmd = collider_cache->collmd;
678 col.col_data = collmd;
679 isect_ray_tri_watertight_v3_precalc(&col.isect_precalc, ray_normal);
680
681 BLI_bvhtree_ray_cast_ex(collmd->bvhtree,
682 ray_start,
683 ray_normal,
684 0.3f,
685 &hit,
686 cloth_brush_collision_cb,
687 &col,
688 raycast_flag);
689
690 if (hit.index != -1) {
691
692 float collision_disp[3];
693 float movement_disp[3];
694 mul_v3_v3fl(collision_disp, hit.no, 0.005f);
695 sub_v3_v3v3(movement_disp, pos_world_space, prev_pos_world_space);
696 float friction_plane[4];
697 float pos_on_friction_plane[3];
698 plane_from_point_normal_v3(friction_plane, hit.co, hit.no);
699 closest_to_plane_v3(pos_on_friction_plane, friction_plane, pos_world_space);
700 sub_v3_v3v3(movement_disp, pos_on_friction_plane, hit.co);
701
702 /* TODO(pablodp606): This can be exposed in a brush/filter property as friction. */
703 mul_v3_fl(movement_disp, 0.35f);
704
705 copy_v3_v3(cloth_sim->pos[i], hit.co);
706 add_v3_v3(cloth_sim->pos[i], movement_disp);
707 add_v3_v3(cloth_sim->pos[i], collision_disp);
708 mul_v3_m4v3(cloth_sim->pos[i], obmat_inv, cloth_sim->pos[i]);
709 }
710 }
711 }
712
do_cloth_brush_solve_simulation_task_cb_ex(void * __restrict userdata,const int n,const TaskParallelTLS * __restrict UNUSED (tls))713 static void do_cloth_brush_solve_simulation_task_cb_ex(
714 void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
715 {
716 SculptThreadedTaskData *data = userdata;
717 SculptSession *ss = data->ob->sculpt;
718 const Brush *brush = data->brush;
719
720 PBVHNode *node = data->nodes[n];
721 PBVHVertexIter vd;
722 SculptClothSimulation *cloth_sim = data->cloth_sim;
723 const float time_step = data->cloth_time_step;
724
725 const int node_index = POINTER_AS_INT(BLI_ghash_lookup(data->cloth_sim->node_state_index, node));
726 if (data->cloth_sim->node_state[node_index] != SCULPT_CLOTH_NODE_ACTIVE) {
727 return;
728 }
729
730 AutomaskingCache *automasking = SCULPT_automasking_active_cache_get(ss);
731
732 BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
733 {
734 float sim_location[3];
735 cloth_brush_simulation_location_get(ss, brush, sim_location);
736 const float sim_factor =
737 ss->cache ? cloth_brush_simulation_falloff_get(
738 brush, ss->cache->radius, sim_location, cloth_sim->init_pos[vd.index]) :
739 1.0f;
740 if (sim_factor > 0.0f) {
741 int i = vd.index;
742 float temp[3];
743 copy_v3_v3(temp, cloth_sim->pos[i]);
744
745 mul_v3_fl(cloth_sim->acceleration[i], time_step);
746
747 float pos_diff[3];
748 sub_v3_v3v3(pos_diff, cloth_sim->pos[i], cloth_sim->prev_pos[i]);
749 mul_v3_fl(pos_diff, (1.0f - cloth_sim->damping) * sim_factor);
750
751 const float mask_v = (1.0f - (vd.mask ? *vd.mask : 0.0f)) *
752 SCULPT_automasking_factor_get(automasking, ss, vd.index);
753
754 madd_v3_v3fl(cloth_sim->pos[i], pos_diff, mask_v);
755 madd_v3_v3fl(cloth_sim->pos[i], cloth_sim->acceleration[i], mask_v);
756
757 if (cloth_sim->collider_list != NULL) {
758 cloth_brush_solve_collision(data->ob, cloth_sim, i);
759 }
760
761 copy_v3_v3(cloth_sim->last_iteration_pos[i], cloth_sim->pos[i]);
762
763 copy_v3_v3(cloth_sim->prev_pos[i], temp);
764 copy_v3_v3(cloth_sim->last_iteration_pos[i], cloth_sim->pos[i]);
765 copy_v3_fl(cloth_sim->acceleration[i], 0.0f);
766
767 copy_v3_v3(vd.co, cloth_sim->pos[vd.index]);
768
769 if (vd.mvert) {
770 vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
771 }
772 }
773 }
774 BKE_pbvh_vertex_iter_end;
775
776 /* Disable the simulation on this node, it needs to be enabled again to continue. */
777 cloth_sim->node_state[node_index] = SCULPT_CLOTH_NODE_INACTIVE;
778 }
779
cloth_brush_satisfy_constraints(SculptSession * ss,Brush * brush,SculptClothSimulation * cloth_sim)780 static void cloth_brush_satisfy_constraints(SculptSession *ss,
781 Brush *brush,
782 SculptClothSimulation *cloth_sim)
783 {
784
785 AutomaskingCache *automasking = SCULPT_automasking_active_cache_get(ss);
786
787 for (int constraint_it = 0; constraint_it < CLOTH_SIMULATION_ITERATIONS; constraint_it++) {
788 for (int i = 0; i < cloth_sim->tot_length_constraints; i++) {
789 const SculptClothLengthConstraint *constraint = &cloth_sim->length_constraints[i];
790
791 if (cloth_sim->node_state[constraint->node] != SCULPT_CLOTH_NODE_ACTIVE) {
792 /* Skip all constraints that were created for inactive nodes. */
793 continue;
794 }
795
796 const int v1 = constraint->elem_index_a;
797 const int v2 = constraint->elem_index_b;
798
799 float v1_to_v2[3];
800 sub_v3_v3v3(v1_to_v2, constraint->elem_position_b, constraint->elem_position_a);
801 const float current_distance = len_v3(v1_to_v2);
802 float correction_vector[3];
803 float correction_vector_half[3];
804
805 const float constraint_distance = constraint->length +
806 (cloth_sim->length_constraint_tweak[v1] * 0.5f) +
807 (cloth_sim->length_constraint_tweak[v2] * 0.5f);
808
809 if (current_distance > 0.0f) {
810 mul_v3_v3fl(correction_vector,
811 v1_to_v2,
812 CLOTH_SOLVER_DISPLACEMENT_FACTOR *
813 (1.0f - (constraint_distance / current_distance)));
814 }
815 else {
816 mul_v3_v3fl(correction_vector, v1_to_v2, CLOTH_SOLVER_DISPLACEMENT_FACTOR);
817 }
818
819 mul_v3_v3fl(correction_vector_half, correction_vector, 0.5f);
820
821 const float mask_v1 = (1.0f - SCULPT_vertex_mask_get(ss, v1)) *
822 SCULPT_automasking_factor_get(automasking, ss, v1);
823 const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, v2)) *
824 SCULPT_automasking_factor_get(automasking, ss, v2);
825
826 float sim_location[3];
827 cloth_brush_simulation_location_get(ss, brush, sim_location);
828
829 const float sim_factor_v1 = ss->cache ?
830 cloth_brush_simulation_falloff_get(brush,
831 ss->cache->radius,
832 sim_location,
833 cloth_sim->init_pos[v1]) :
834 1.0f;
835 const float sim_factor_v2 = ss->cache ?
836 cloth_brush_simulation_falloff_get(brush,
837 ss->cache->radius,
838 sim_location,
839 cloth_sim->init_pos[v2]) :
840 1.0f;
841
842 float deformation_strength = 1.0f;
843 if (constraint->type == SCULPT_CLOTH_CONSTRAINT_DEFORMATION) {
844 deformation_strength = (cloth_sim->deformation_strength[v1] +
845 cloth_sim->deformation_strength[v2]) *
846 0.5f;
847 }
848
849 if (constraint->type == SCULPT_CLOTH_CONSTRAINT_SOFTBODY) {
850 const float softbody_plasticity = brush ? brush->cloth_constraint_softbody_strength : 0.0f;
851 madd_v3_v3fl(cloth_sim->pos[v1],
852 correction_vector_half,
853 1.0f * mask_v1 * sim_factor_v1 * constraint->strength * softbody_plasticity);
854 madd_v3_v3fl(cloth_sim->softbody_pos[v1],
855 correction_vector_half,
856 -1.0f * mask_v1 * sim_factor_v1 * constraint->strength *
857 (1.0f - softbody_plasticity));
858 }
859 else {
860 madd_v3_v3fl(cloth_sim->pos[v1],
861 correction_vector_half,
862 1.0f * mask_v1 * sim_factor_v1 * constraint->strength * deformation_strength);
863 if (v1 != v2) {
864 madd_v3_v3fl(cloth_sim->pos[v2],
865 correction_vector_half,
866 -1.0f * mask_v2 * sim_factor_v2 * constraint->strength *
867 deformation_strength);
868 }
869 }
870 }
871 }
872 }
873
SCULPT_cloth_brush_do_simulation_step(Sculpt * sd,Object * ob,SculptClothSimulation * cloth_sim,PBVHNode ** nodes,int totnode)874 void SCULPT_cloth_brush_do_simulation_step(
875 Sculpt *sd, Object *ob, SculptClothSimulation *cloth_sim, PBVHNode **nodes, int totnode)
876 {
877 SculptSession *ss = ob->sculpt;
878 Brush *brush = BKE_paint_brush(&sd->paint);
879
880 /* Update the constraints. */
881 cloth_brush_satisfy_constraints(ss, brush, cloth_sim);
882
883 /* Solve the simulation and write the final step to the mesh. */
884 SculptThreadedTaskData solve_simulation_data = {
885 .sd = sd,
886 .ob = ob,
887 .brush = brush,
888 .nodes = nodes,
889 .cloth_time_step = CLOTH_SIMULATION_TIME_STEP,
890 .cloth_sim = cloth_sim,
891 };
892
893 TaskParallelSettings settings;
894 BKE_pbvh_parallel_range_settings(&settings, true, totnode);
895 BLI_task_parallel_range(
896 0, totnode, &solve_simulation_data, do_cloth_brush_solve_simulation_task_cb_ex, &settings);
897 }
898
cloth_brush_apply_brush_foces(Sculpt * sd,Object * ob,PBVHNode ** nodes,int totnode)899 static void cloth_brush_apply_brush_foces(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
900 {
901 SculptSession *ss = ob->sculpt;
902 Brush *brush = BKE_paint_brush(&sd->paint);
903
904 float grab_delta[3];
905 float mat[4][4];
906 float area_no[3];
907 float area_co[3];
908 float imat[4][4];
909 float offset[3];
910
911 SculptThreadedTaskData apply_forces_data = {
912 .sd = sd,
913 .ob = ob,
914 .brush = brush,
915 .nodes = nodes,
916 .area_no = area_no,
917 .area_co = area_co,
918 .mat = imat,
919 };
920
921 BKE_curvemapping_init(brush->curve);
922
923 /* Init the grab delta. */
924 copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
925 normalize_v3(grab_delta);
926
927 apply_forces_data.grab_delta = grab_delta;
928
929 if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
930 return;
931 }
932
933 /* Calcuate push offset. */
934
935 if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_PUSH) {
936 mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
937 mul_v3_v3(offset, ss->cache->scale);
938 mul_v3_fl(offset, 2.0f);
939
940 apply_forces_data.offset = offset;
941 }
942
943 if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_PINCH_PERPENDICULAR ||
944 brush->cloth_force_falloff_type == BRUSH_CLOTH_FORCE_FALLOFF_PLANE) {
945 SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
946
947 /* Init stroke local space matrix. */
948 cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
949 mat[0][3] = 0.0f;
950 cross_v3_v3v3(mat[1], area_no, mat[0]);
951 mat[1][3] = 0.0f;
952 copy_v3_v3(mat[2], area_no);
953 mat[2][3] = 0.0f;
954 copy_v3_v3(mat[3], ss->cache->location);
955 mat[3][3] = 1.0f;
956 normalize_m4(mat);
957
958 apply_forces_data.area_co = area_co;
959 apply_forces_data.area_no = area_no;
960 apply_forces_data.mat = mat;
961
962 /* Update matrix for the cursor preview. */
963 if (ss->cache->mirror_symmetry_pass == 0) {
964 copy_m4_m4(ss->cache->stroke_local_mat, mat);
965 }
966 }
967
968 if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_SNAKE_HOOK) {
969 /* Set the deformation strength to 0. Snake hook will initialize the strength in the required
970 * area. */
971 const int totverts = SCULPT_vertex_count_get(ss);
972 for (int i = 0; i < totverts; i++) {
973 ss->cache->cloth_sim->deformation_strength[i] = 0.0f;
974 }
975 }
976
977 TaskParallelSettings settings;
978 BKE_pbvh_parallel_range_settings(&settings, true, totnode);
979 BLI_task_parallel_range(
980 0, totnode, &apply_forces_data, do_cloth_brush_apply_forces_task_cb_ex, &settings);
981 }
982
983 /* Allocates nodes state and initializes them to Uninitialized, so constraints can be created for
984 * them. */
cloth_sim_initialize_default_node_state(SculptSession * ss,SculptClothSimulation * cloth_sim)985 static void cloth_sim_initialize_default_node_state(SculptSession *ss,
986 SculptClothSimulation *cloth_sim)
987 {
988 PBVHNode **nodes;
989 int totnode;
990 BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
991
992 cloth_sim->node_state = MEM_malloc_arrayN(
993 totnode, sizeof(eSculptClothNodeSimState), "node sim state");
994 cloth_sim->node_state_index = BLI_ghash_ptr_new("node sim state indices");
995 for (int i = 0; i < totnode; i++) {
996 cloth_sim->node_state[i] = SCULPT_CLOTH_NODE_UNINITIALIZED;
997 BLI_ghash_insert(cloth_sim->node_state_index, nodes[i], POINTER_FROM_INT(i));
998 }
999 MEM_SAFE_FREE(nodes);
1000 }
1001
1002 /* Public functions. */
SCULPT_cloth_brush_simulation_create(SculptSession * ss,const float cloth_mass,const float cloth_damping,const float cloth_softbody_strength,const bool use_collisions,const bool needs_deform_coords)1003 SculptClothSimulation *SCULPT_cloth_brush_simulation_create(SculptSession *ss,
1004 const float cloth_mass,
1005 const float cloth_damping,
1006 const float cloth_softbody_strength,
1007 const bool use_collisions,
1008 const bool needs_deform_coords)
1009 {
1010 const int totverts = SCULPT_vertex_count_get(ss);
1011 SculptClothSimulation *cloth_sim;
1012
1013 cloth_sim = MEM_callocN(sizeof(SculptClothSimulation), "cloth constraints");
1014
1015 cloth_sim->length_constraints = MEM_callocN(sizeof(SculptClothLengthConstraint) *
1016 CLOTH_LENGTH_CONSTRAINTS_BLOCK,
1017 "cloth length constraints");
1018 cloth_sim->capacity_length_constraints = CLOTH_LENGTH_CONSTRAINTS_BLOCK;
1019
1020 cloth_sim->acceleration = MEM_calloc_arrayN(
1021 totverts, sizeof(float[3]), "cloth sim acceleration");
1022 cloth_sim->pos = MEM_calloc_arrayN(totverts, sizeof(float[3]), "cloth sim pos");
1023 cloth_sim->prev_pos = MEM_calloc_arrayN(totverts, sizeof(float[3]), "cloth sim prev pos");
1024 cloth_sim->last_iteration_pos = MEM_calloc_arrayN(
1025 totverts, sizeof(float[3]), "cloth sim last iteration pos");
1026 cloth_sim->init_pos = MEM_calloc_arrayN(totverts, sizeof(float[3]), "cloth sim init pos");
1027 cloth_sim->length_constraint_tweak = MEM_calloc_arrayN(
1028 totverts, sizeof(float), "cloth sim length tweak");
1029
1030 if (needs_deform_coords) {
1031 cloth_sim->deformation_pos = MEM_calloc_arrayN(
1032 totverts, sizeof(float[3]), "cloth sim deformation positions");
1033 cloth_sim->deformation_strength = MEM_calloc_arrayN(
1034 totverts, sizeof(float), "cloth sim deformation strength");
1035 }
1036
1037 if (cloth_softbody_strength > 0.0f) {
1038 cloth_sim->softbody_pos = MEM_calloc_arrayN(
1039 totverts, sizeof(float[3]), "cloth sim softbody pos");
1040 }
1041
1042 cloth_sim->mass = cloth_mass;
1043 cloth_sim->damping = cloth_damping;
1044 cloth_sim->softbody_strength = cloth_softbody_strength;
1045
1046 if (use_collisions) {
1047 cloth_sim->collider_list = cloth_brush_collider_cache_create(ss->depsgraph);
1048 }
1049
1050 cloth_sim_initialize_default_node_state(ss, cloth_sim);
1051
1052 return cloth_sim;
1053 }
1054
SCULPT_cloth_brush_ensure_nodes_constraints(Sculpt * sd,Object * ob,PBVHNode ** nodes,int totnode,SculptClothSimulation * cloth_sim,float initial_location[3],const float radius)1055 void SCULPT_cloth_brush_ensure_nodes_constraints(
1056 Sculpt *sd,
1057 Object *ob,
1058 PBVHNode **nodes,
1059 int totnode,
1060 SculptClothSimulation *cloth_sim,
1061 /* Cannot be const, because it is assigned to a non-const variable.
1062 * NOLINTNEXTLINE: readability-non-const-parameter. */
1063 float initial_location[3],
1064 const float radius)
1065 {
1066 Brush *brush = BKE_paint_brush(&sd->paint);
1067
1068 /* TODO: Multi-threaded needs to be disabled for this task until implementing the optimization of
1069 * storing the constraints per node. */
1070 /* Currently all constrains are added to the same global array which can't be accessed from
1071 * different threads. */
1072 TaskParallelSettings settings;
1073 BKE_pbvh_parallel_range_settings(&settings, false, totnode);
1074
1075 cloth_sim->created_length_constraints = BLI_edgeset_new("created length constraints");
1076
1077 SculptThreadedTaskData build_constraints_data = {
1078 .sd = sd,
1079 .ob = ob,
1080 .brush = brush,
1081 .nodes = nodes,
1082 .cloth_sim = cloth_sim,
1083 .cloth_sim_initial_location = initial_location,
1084 .cloth_sim_radius = radius,
1085 };
1086 BLI_task_parallel_range(
1087 0, totnode, &build_constraints_data, do_cloth_brush_build_constraints_task_cb_ex, &settings);
1088
1089 BLI_edgeset_free(cloth_sim->created_length_constraints);
1090 }
1091
SCULPT_cloth_brush_simulation_init(SculptSession * ss,SculptClothSimulation * cloth_sim)1092 void SCULPT_cloth_brush_simulation_init(SculptSession *ss, SculptClothSimulation *cloth_sim)
1093 {
1094 const int totverts = SCULPT_vertex_count_get(ss);
1095 const bool has_deformation_pos = cloth_sim->deformation_pos != NULL;
1096 const bool has_softbody_pos = cloth_sim->softbody_pos != NULL;
1097 for (int i = 0; i < totverts; i++) {
1098 copy_v3_v3(cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, i));
1099 copy_v3_v3(cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i));
1100 copy_v3_v3(cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i));
1101 if (has_deformation_pos) {
1102 copy_v3_v3(cloth_sim->deformation_pos[i], SCULPT_vertex_co_get(ss, i));
1103 cloth_sim->deformation_strength[i] = 1.0f;
1104 }
1105 if (has_softbody_pos) {
1106 copy_v3_v3(cloth_sim->softbody_pos[i], SCULPT_vertex_co_get(ss, i));
1107 }
1108 }
1109 }
1110
SCULPT_cloth_brush_store_simulation_state(SculptSession * ss,SculptClothSimulation * cloth_sim)1111 void SCULPT_cloth_brush_store_simulation_state(SculptSession *ss, SculptClothSimulation *cloth_sim)
1112 {
1113 const int totverts = SCULPT_vertex_count_get(ss);
1114 for (int i = 0; i < totverts; i++) {
1115 copy_v3_v3(cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i));
1116 }
1117 }
1118
SCULPT_cloth_sim_activate_nodes(SculptClothSimulation * cloth_sim,PBVHNode ** nodes,int totnode)1119 void SCULPT_cloth_sim_activate_nodes(SculptClothSimulation *cloth_sim,
1120 PBVHNode **nodes,
1121 int totnode)
1122 {
1123 /* Activate the nodes inside the simulation area. */
1124 for (int n = 0; n < totnode; n++) {
1125 const int node_index = POINTER_AS_INT(BLI_ghash_lookup(cloth_sim->node_state_index, nodes[n]));
1126 cloth_sim->node_state[node_index] = SCULPT_CLOTH_NODE_ACTIVE;
1127 }
1128 }
1129
sculpt_cloth_ensure_constraints_in_simulation_area(Sculpt * sd,Object * ob,PBVHNode ** nodes,int totnode)1130 static void sculpt_cloth_ensure_constraints_in_simulation_area(Sculpt *sd,
1131 Object *ob,
1132 PBVHNode **nodes,
1133 int totnode)
1134 {
1135 SculptSession *ss = ob->sculpt;
1136 Brush *brush = BKE_paint_brush(&sd->paint);
1137 const float radius = ss->cache->initial_radius;
1138 const float limit = radius + (radius * brush->cloth_sim_limit);
1139 float sim_location[3];
1140 cloth_brush_simulation_location_get(ss, brush, sim_location);
1141 SCULPT_cloth_brush_ensure_nodes_constraints(
1142 sd, ob, nodes, totnode, ss->cache->cloth_sim, sim_location, limit);
1143 }
1144
1145 /* Main Brush Function. */
SCULPT_do_cloth_brush(Sculpt * sd,Object * ob,PBVHNode ** nodes,int totnode)1146 void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
1147 {
1148 SculptSession *ss = ob->sculpt;
1149 Brush *brush = BKE_paint_brush(&sd->paint);
1150
1151 /* Brushes that use anchored strokes and restore the mesh can't rely on symmetry passes and steps
1152 * count as it is always the first step, so the simulation needs to be created when it does not
1153 * exist for this stroke. */
1154 if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache) || !ss->cache->cloth_sim) {
1155
1156 /* The simulation structure only needs to be created on the first symmetry pass. */
1157 if (SCULPT_stroke_is_first_brush_step(ss->cache) || !ss->cache->cloth_sim) {
1158 ss->cache->cloth_sim = SCULPT_cloth_brush_simulation_create(
1159 ss,
1160 brush->cloth_mass,
1161 brush->cloth_damping,
1162 brush->cloth_constraint_softbody_strength,
1163 (brush->flag2 & BRUSH_CLOTH_USE_COLLISION),
1164 SCULPT_is_cloth_deform_brush(brush));
1165 SCULPT_cloth_brush_simulation_init(ss, ss->cache->cloth_sim);
1166 }
1167
1168 if (brush->cloth_simulation_area_type == BRUSH_CLOTH_SIMULATION_AREA_LOCAL) {
1169 /* When using simulation a fixed local simulation area, constraints are created only using
1170 * the initial stroke position and initial radius (per symmetry pass) instead of per node.
1171 * This allows to skip unnecessary constraints that will never be simulated, making the
1172 * solver faster. When the simulation starts for a node, the node gets activated and all its
1173 * constraints are considered final. As the same node can be included inside the brush radius
1174 * from multiple symmetry passes, the cloth brush can't activate the node for simulation yet
1175 * as this will cause the ensure constraints function to skip the node in the next symmetry
1176 * passes. It needs to build the constraints here and skip simulating the first step, so all
1177 * passes can add their constraints to all affected nodes. */
1178 sculpt_cloth_ensure_constraints_in_simulation_area(sd, ob, nodes, totnode);
1179 }
1180 /* The first step of a symmetry pass is never simulated as deformation modes need valid delta
1181 * for brush tip alignement. */
1182 return;
1183 }
1184
1185 /* Ensure the constraints for the nodes. */
1186 sculpt_cloth_ensure_constraints_in_simulation_area(sd, ob, nodes, totnode);
1187
1188 /* Store the initial state in the simulation. */
1189 SCULPT_cloth_brush_store_simulation_state(ss, ss->cache->cloth_sim);
1190
1191 /* Enable the nodes that should be simulated. */
1192 SCULPT_cloth_sim_activate_nodes(ss->cache->cloth_sim, nodes, totnode);
1193
1194 /* Apply forces to the vertices. */
1195 cloth_brush_apply_brush_foces(sd, ob, nodes, totnode);
1196
1197 /* Update and write the simulation to the nodes. */
1198 SCULPT_cloth_brush_do_simulation_step(sd, ob, ss->cache->cloth_sim, nodes, totnode);
1199 }
1200
SCULPT_cloth_simulation_free(struct SculptClothSimulation * cloth_sim)1201 void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim)
1202 {
1203 MEM_SAFE_FREE(cloth_sim->pos);
1204 MEM_SAFE_FREE(cloth_sim->last_iteration_pos);
1205 MEM_SAFE_FREE(cloth_sim->prev_pos);
1206 MEM_SAFE_FREE(cloth_sim->acceleration);
1207 MEM_SAFE_FREE(cloth_sim->length_constraints);
1208 MEM_SAFE_FREE(cloth_sim->length_constraint_tweak);
1209 MEM_SAFE_FREE(cloth_sim->deformation_pos);
1210 MEM_SAFE_FREE(cloth_sim->softbody_pos);
1211 MEM_SAFE_FREE(cloth_sim->init_pos);
1212 MEM_SAFE_FREE(cloth_sim->deformation_strength);
1213 MEM_SAFE_FREE(cloth_sim->node_state);
1214 BLI_ghash_free(cloth_sim->node_state_index, NULL, NULL);
1215 if (cloth_sim->collider_list) {
1216 BKE_collider_cache_free(&cloth_sim->collider_list);
1217 }
1218 MEM_SAFE_FREE(cloth_sim);
1219 }
1220
1221 /* Cursor drawing function. */
SCULPT_cloth_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)1222 void SCULPT_cloth_simulation_limits_draw(const uint gpuattr,
1223 const Brush *brush,
1224 const float location[3],
1225 const float normal[3],
1226 const float rds,
1227 const float line_width,
1228 const float outline_col[3],
1229 const float alpha)
1230 {
1231 float cursor_trans[4][4], cursor_rot[4][4];
1232 const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
1233 float quat[4];
1234 unit_m4(cursor_trans);
1235 translate_m4(cursor_trans, location[0], location[1], location[2]);
1236 rotation_between_vecs_to_quat(quat, z_axis, normal);
1237 quat_to_mat4(cursor_rot, quat);
1238 GPU_matrix_push();
1239 GPU_matrix_mul(cursor_trans);
1240 GPU_matrix_mul(cursor_rot);
1241
1242 GPU_line_width(line_width);
1243 immUniformColor3fvAlpha(outline_col, alpha * 0.5f);
1244 imm_draw_circle_dashed_3d(
1245 gpuattr, 0, 0, rds + (rds * brush->cloth_sim_limit * brush->cloth_sim_falloff), 320);
1246 immUniformColor3fvAlpha(outline_col, alpha * 0.7f);
1247 imm_draw_circle_wire_3d(gpuattr, 0, 0, rds + rds * brush->cloth_sim_limit, 80);
1248 GPU_matrix_pop();
1249 }
1250
SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr,SculptSession * ss,const float outline_col[3],float outline_alpha)1251 void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr,
1252 SculptSession *ss,
1253 const float outline_col[3],
1254 float outline_alpha)
1255 {
1256 float local_mat_inv[4][4];
1257 invert_m4_m4(local_mat_inv, ss->cache->stroke_local_mat);
1258 GPU_matrix_mul(ss->cache->stroke_local_mat);
1259
1260 const float dist = ss->cache->radius;
1261 const float arrow_x = ss->cache->radius * 0.2f;
1262 const float arrow_y = ss->cache->radius * 0.1f;
1263
1264 immUniformColor3fvAlpha(outline_col, outline_alpha);
1265 GPU_line_width(2.0f);
1266 immBegin(GPU_PRIM_LINES, 2);
1267 immVertex3f(gpuattr, dist, 0.0f, 0.0f);
1268 immVertex3f(gpuattr, -dist, 0.0f, 0.0f);
1269 immEnd();
1270
1271 immBegin(GPU_PRIM_TRIS, 6);
1272 immVertex3f(gpuattr, dist, 0.0f, 0.0f);
1273 immVertex3f(gpuattr, dist - arrow_x, arrow_y, 0.0f);
1274 immVertex3f(gpuattr, dist - arrow_x, -arrow_y, 0.0f);
1275
1276 immVertex3f(gpuattr, -dist, 0.0f, 0.0f);
1277 immVertex3f(gpuattr, -dist + arrow_x, arrow_y, 0.0f);
1278 immVertex3f(gpuattr, -dist + arrow_x, -arrow_y, 0.0f);
1279
1280 immEnd();
1281 }
1282
1283 /* Cloth Filter. */
1284
1285 typedef enum eSculpClothFilterType {
1286 CLOTH_FILTER_GRAVITY,
1287 CLOTH_FILTER_INFLATE,
1288 CLOTH_FILTER_EXPAND,
1289 CLOTH_FILTER_PINCH,
1290 CLOTH_FILTER_SCALE,
1291 } eSculptClothFilterType;
1292
1293 static EnumPropertyItem prop_cloth_filter_type[] = {
1294 {CLOTH_FILTER_GRAVITY, "GRAVITY", 0, "Gravity", "Applies gravity to the simulation"},
1295 {CLOTH_FILTER_INFLATE, "INFLATE", 0, "Inflate", "Inflates the cloth"},
1296 {CLOTH_FILTER_EXPAND, "EXPAND", 0, "Expand", "Expands the cloth's dimensions"},
1297 {CLOTH_FILTER_PINCH, "PINCH", 0, "Pinch", "Pulls the cloth to the cursor's start position"},
1298 {CLOTH_FILTER_SCALE,
1299 "SCALE",
1300 0,
1301 "Scale",
1302 "Scales the mesh as a softbody using the origin of the object as scale"},
1303 {0, NULL, 0, NULL, NULL},
1304 };
1305
1306 static EnumPropertyItem prop_cloth_filter_orientation_items[] = {
1307 {SCULPT_FILTER_ORIENTATION_LOCAL,
1308 "LOCAL",
1309 0,
1310 "Local",
1311 "Use the local axis to limit the force and set the gravity direction"},
1312 {SCULPT_FILTER_ORIENTATION_WORLD,
1313 "WORLD",
1314 0,
1315 "World",
1316 "Use the global axis to limit the force and set the gravity direction"},
1317 {SCULPT_FILTER_ORIENTATION_VIEW,
1318 "VIEW",
1319 0,
1320 "View",
1321 "Use the view axis to limit the force and set the gravity direction"},
1322 {0, NULL, 0, NULL, NULL},
1323 };
1324
1325 typedef enum eClothFilterForceAxis {
1326 CLOTH_FILTER_FORCE_X = 1 << 0,
1327 CLOTH_FILTER_FORCE_Y = 1 << 1,
1328 CLOTH_FILTER_FORCE_Z = 1 << 2,
1329 } eClothFilterForceAxis;
1330
1331 static EnumPropertyItem prop_cloth_filter_force_axis_items[] = {
1332 {CLOTH_FILTER_FORCE_X, "X", 0, "X", "Apply force in the X axis"},
1333 {CLOTH_FILTER_FORCE_Y, "Y", 0, "Y", "Apply force in the Y axis"},
1334 {CLOTH_FILTER_FORCE_Z, "Z", 0, "Z", "Apply force in the Z axis"},
1335 {0, NULL, 0, NULL, NULL},
1336 };
1337
cloth_filter_is_deformation_filter(eSculptClothFilterType filter_type)1338 static bool cloth_filter_is_deformation_filter(eSculptClothFilterType filter_type)
1339 {
1340 return ELEM(filter_type, CLOTH_FILTER_SCALE);
1341 }
1342
cloth_filter_apply_displacement_to_deform_co(const int v_index,const float disp[3],FilterCache * filter_cache)1343 static void cloth_filter_apply_displacement_to_deform_co(const int v_index,
1344 const float disp[3],
1345 FilterCache *filter_cache)
1346 {
1347 float final_disp[3];
1348 copy_v3_v3(final_disp, disp);
1349 SCULPT_filter_zero_disabled_axis_components(final_disp, filter_cache);
1350 add_v3_v3v3(filter_cache->cloth_sim->deformation_pos[v_index],
1351 filter_cache->cloth_sim->init_pos[v_index],
1352 final_disp);
1353 }
1354
cloth_filter_apply_forces_to_vertices(const int v_index,const float force[3],const float gravity[3],FilterCache * filter_cache)1355 static void cloth_filter_apply_forces_to_vertices(const int v_index,
1356 const float force[3],
1357 const float gravity[3],
1358 FilterCache *filter_cache)
1359 {
1360 float final_force[3];
1361 copy_v3_v3(final_force, force);
1362 SCULPT_filter_zero_disabled_axis_components(final_force, filter_cache);
1363 add_v3_v3(final_force, gravity);
1364 cloth_brush_apply_force_to_vertex(NULL, filter_cache->cloth_sim, final_force, v_index);
1365 }
1366
cloth_filter_apply_forces_task_cb(void * __restrict userdata,const int i,const TaskParallelTLS * __restrict UNUSED (tls))1367 static void cloth_filter_apply_forces_task_cb(void *__restrict userdata,
1368 const int i,
1369 const TaskParallelTLS *__restrict UNUSED(tls))
1370 {
1371 SculptThreadedTaskData *data = userdata;
1372 Sculpt *sd = data->sd;
1373 SculptSession *ss = data->ob->sculpt;
1374 PBVHNode *node = data->nodes[i];
1375
1376 SculptClothSimulation *cloth_sim = ss->filter_cache->cloth_sim;
1377
1378 const eSculptClothFilterType filter_type = data->filter_type;
1379 const bool is_deformation_filter = cloth_filter_is_deformation_filter(filter_type);
1380
1381 float sculpt_gravity[3] = {0.0f};
1382 if (sd->gravity_object) {
1383 copy_v3_v3(sculpt_gravity, sd->gravity_object->obmat[2]);
1384 }
1385 else {
1386 sculpt_gravity[2] = -1.0f;
1387 }
1388 mul_v3_fl(sculpt_gravity, sd->gravity_factor * data->filter_strength);
1389
1390 PBVHVertexIter vd;
1391 BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
1392 {
1393 float fade = vd.mask ? *vd.mask : 0.0f;
1394 fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index);
1395 fade = 1.0f - fade;
1396 float force[3] = {0.0f, 0.0f, 0.0f};
1397 float disp[3], temp[3], transform[3][3];
1398
1399 if (ss->filter_cache->active_face_set != SCULPT_FACE_SET_NONE) {
1400 if (!SCULPT_vertex_has_face_set(ss, vd.index, ss->filter_cache->active_face_set)) {
1401 continue;
1402 }
1403 }
1404
1405 switch (filter_type) {
1406 case CLOTH_FILTER_GRAVITY:
1407 if (ss->filter_cache->orientation == SCULPT_FILTER_ORIENTATION_VIEW) {
1408 /* When using the view orientation apply gravity in the -Y axis, this way objects will
1409 * fall down instead of backwards. */
1410 force[1] = -data->filter_strength * fade;
1411 }
1412 else {
1413 force[2] = -data->filter_strength * fade;
1414 }
1415 SCULPT_filter_to_object_space(force, ss->filter_cache);
1416 break;
1417 case CLOTH_FILTER_INFLATE: {
1418 float normal[3];
1419 SCULPT_vertex_normal_get(ss, vd.index, normal);
1420 mul_v3_v3fl(force, normal, fade * data->filter_strength);
1421 } break;
1422 case CLOTH_FILTER_EXPAND:
1423 cloth_sim->length_constraint_tweak[vd.index] += fade * data->filter_strength * 0.01f;
1424 zero_v3(force);
1425 break;
1426 case CLOTH_FILTER_PINCH:
1427 sub_v3_v3v3(force, ss->filter_cache->cloth_sim_pinch_point, vd.co);
1428 normalize_v3(force);
1429 mul_v3_fl(force, fade * data->filter_strength);
1430 break;
1431 case CLOTH_FILTER_SCALE:
1432 unit_m3(transform);
1433 scale_m3_fl(transform, 1.0f + (fade * data->filter_strength));
1434 copy_v3_v3(temp, cloth_sim->init_pos[vd.index]);
1435 mul_m3_v3(transform, temp);
1436 sub_v3_v3v3(disp, temp, cloth_sim->init_pos[vd.index]);
1437 zero_v3(force);
1438
1439 break;
1440 }
1441
1442 if (is_deformation_filter) {
1443 cloth_filter_apply_displacement_to_deform_co(vd.index, disp, ss->filter_cache);
1444 }
1445 else {
1446 cloth_filter_apply_forces_to_vertices(vd.index, force, sculpt_gravity, ss->filter_cache);
1447 }
1448 }
1449 BKE_pbvh_vertex_iter_end;
1450
1451 BKE_pbvh_node_mark_update(node);
1452 }
1453
sculpt_cloth_filter_modal(bContext * C,wmOperator * op,const wmEvent * event)1454 static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
1455 {
1456 Object *ob = CTX_data_active_object(C);
1457 Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
1458 SculptSession *ss = ob->sculpt;
1459 Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
1460 int filter_type = RNA_enum_get(op->ptr, "type");
1461 float filter_strength = RNA_float_get(op->ptr, "strength");
1462
1463 if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
1464 SCULPT_filter_cache_free(ss);
1465 SCULPT_undo_push_end();
1466 SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
1467 return OPERATOR_FINISHED;
1468 }
1469
1470 if (event->type != MOUSEMOVE) {
1471 return OPERATOR_RUNNING_MODAL;
1472 }
1473
1474 const float len = event->prevclickx - event->x;
1475 filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC;
1476
1477 SCULPT_vertex_random_access_ensure(ss);
1478
1479 BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
1480
1481 const int totverts = SCULPT_vertex_count_get(ss);
1482
1483 for (int i = 0; i < totverts; i++) {
1484 copy_v3_v3(ss->filter_cache->cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i));
1485 }
1486
1487 SculptThreadedTaskData data = {
1488 .sd = sd,
1489 .ob = ob,
1490 .nodes = ss->filter_cache->nodes,
1491 .filter_type = filter_type,
1492 .filter_strength = filter_strength,
1493 };
1494
1495 TaskParallelSettings settings;
1496 BKE_pbvh_parallel_range_settings(&settings, true, ss->filter_cache->totnode);
1497 BLI_task_parallel_range(
1498 0, ss->filter_cache->totnode, &data, cloth_filter_apply_forces_task_cb, &settings);
1499
1500 /* Activate all nodes. */
1501 SCULPT_cloth_sim_activate_nodes(
1502 ss->filter_cache->cloth_sim, ss->filter_cache->nodes, ss->filter_cache->totnode);
1503
1504 /* Update and write the simulation to the nodes. */
1505 SCULPT_cloth_brush_do_simulation_step(
1506 sd, ob, ss->filter_cache->cloth_sim, ss->filter_cache->nodes, ss->filter_cache->totnode);
1507
1508 if (ss->deform_modifiers_active || ss->shapekey_active) {
1509 SCULPT_flush_stroke_deform(sd, ob, true);
1510 }
1511 SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
1512 return OPERATOR_RUNNING_MODAL;
1513 }
1514
sculpt_cloth_filter_invoke(bContext * C,wmOperator * op,const wmEvent * event)1515 static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1516 {
1517 Object *ob = CTX_data_active_object(C);
1518 Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
1519 Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
1520 SculptSession *ss = ob->sculpt;
1521
1522 const eSculptClothFilterType filter_type = RNA_enum_get(op->ptr, "type");
1523
1524 /* Update the active vertex */
1525 float mouse[2];
1526 SculptCursorGeometryInfo sgi;
1527 mouse[0] = event->mval[0];
1528 mouse[1] = event->mval[1];
1529 SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
1530
1531 SCULPT_vertex_random_access_ensure(ss);
1532
1533 /* Needs mask data to be available as it is used when solving the constraints. */
1534 BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
1535
1536 SCULPT_undo_push_begin("Cloth filter");
1537 SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS);
1538
1539 ss->filter_cache->automasking = SCULPT_automasking_cache_init(sd, NULL, ob);
1540
1541 const float cloth_mass = RNA_float_get(op->ptr, "cloth_mass");
1542 const float cloth_damping = RNA_float_get(op->ptr, "cloth_damping");
1543 const bool use_collisions = RNA_boolean_get(op->ptr, "use_collisions");
1544 ss->filter_cache->cloth_sim = SCULPT_cloth_brush_simulation_create(
1545 ss,
1546 cloth_mass,
1547 cloth_damping,
1548 0.0f,
1549 use_collisions,
1550 cloth_filter_is_deformation_filter(filter_type));
1551
1552 copy_v3_v3(ss->filter_cache->cloth_sim_pinch_point, SCULPT_active_vertex_co_get(ss));
1553
1554 SCULPT_cloth_brush_simulation_init(ss, ss->filter_cache->cloth_sim);
1555
1556 float origin[3] = {0.0f, 0.0f, 0.0f};
1557 SCULPT_cloth_brush_ensure_nodes_constraints(sd,
1558 ob,
1559 ss->filter_cache->nodes,
1560 ss->filter_cache->totnode,
1561 ss->filter_cache->cloth_sim,
1562 origin,
1563 FLT_MAX);
1564
1565 const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets");
1566 if (use_face_sets) {
1567 ss->filter_cache->active_face_set = SCULPT_active_face_set_get(ss);
1568 }
1569 else {
1570 ss->filter_cache->active_face_set = SCULPT_FACE_SET_NONE;
1571 }
1572
1573 const int force_axis = RNA_enum_get(op->ptr, "force_axis");
1574 ss->filter_cache->enabled_force_axis[0] = force_axis & CLOTH_FILTER_FORCE_X;
1575 ss->filter_cache->enabled_force_axis[1] = force_axis & CLOTH_FILTER_FORCE_Y;
1576 ss->filter_cache->enabled_force_axis[2] = force_axis & CLOTH_FILTER_FORCE_Z;
1577
1578 SculptFilterOrientation orientation = RNA_enum_get(op->ptr, "orientation");
1579 ss->filter_cache->orientation = orientation;
1580
1581 WM_event_add_modal_handler(C, op);
1582 return OPERATOR_RUNNING_MODAL;
1583 }
1584
SCULPT_OT_cloth_filter(struct wmOperatorType * ot)1585 void SCULPT_OT_cloth_filter(struct wmOperatorType *ot)
1586 {
1587 /* Identifiers. */
1588 ot->name = "Filter Cloth";
1589 ot->idname = "SCULPT_OT_cloth_filter";
1590 ot->description = "Applies a cloth simulation deformation to the entire mesh";
1591
1592 /* API callbacks. */
1593 ot->invoke = sculpt_cloth_filter_invoke;
1594 ot->modal = sculpt_cloth_filter_modal;
1595 ot->poll = SCULPT_mode_poll;
1596
1597 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1598
1599 /* RNA. */
1600 RNA_def_enum(ot->srna,
1601 "type",
1602 prop_cloth_filter_type,
1603 CLOTH_FILTER_GRAVITY,
1604 "Filter type",
1605 "Operation that is going to be applied to the mesh");
1606 RNA_def_float(
1607 ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter Strength", -10.0f, 10.0f);
1608 RNA_def_enum_flag(ot->srna,
1609 "force_axis",
1610 prop_cloth_filter_force_axis_items,
1611 CLOTH_FILTER_FORCE_X | CLOTH_FILTER_FORCE_Y | CLOTH_FILTER_FORCE_Z,
1612 "Force axis",
1613 "Apply the force in the selected axis");
1614 RNA_def_enum(ot->srna,
1615 "orientation",
1616 prop_cloth_filter_orientation_items,
1617 SCULPT_FILTER_ORIENTATION_LOCAL,
1618 "Orientation",
1619 "Orientation of the axis to limit the filter force");
1620 RNA_def_float(ot->srna,
1621 "cloth_mass",
1622 1.0f,
1623 0.0f,
1624 2.0f,
1625 "Cloth Mass",
1626 "Mass of each simulation particle",
1627 0.0f,
1628 1.0f);
1629 RNA_def_float(ot->srna,
1630 "cloth_damping",
1631 0.0f,
1632 0.0f,
1633 1.0f,
1634 "Cloth Damping",
1635 "How much the applied forces are propagated through the cloth",
1636 0.0f,
1637 1.0f);
1638 ot->prop = RNA_def_boolean(ot->srna,
1639 "use_face_sets",
1640 false,
1641 "Use Face Sets",
1642 "Apply the filter only to the Face Set under the cursor");
1643 ot->prop = RNA_def_boolean(ot->srna,
1644 "use_collisions",
1645 false,
1646 "Use Collisions",
1647 "Collide with other collider objects in the scene");
1648 }
1649