Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/sculpt_paint/sculpt_cloth.c')
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c425
1 files changed, 356 insertions, 69 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index b401ed6d889..4070822a0a8 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -43,7 +43,9 @@
#include "DNA_scene_types.h"
#include "BKE_brush.h"
+#include "BKE_bvhutils.h"
#include "BKE_ccg.h"
+#include "BKE_collision.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_image.h"
@@ -69,6 +71,7 @@
#include "BKE_subsurf.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "WM_api.h"
#include "WM_message.h"
@@ -85,7 +88,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
@@ -101,6 +103,33 @@
#include <stdlib.h>
#include <string.h>
+static float cloth_brush_simulation_falloff_get(const Brush *brush,
+ const float radius,
+ const float location[3],
+ const float co[3])
+{
+ /* Global simulation does not have any falloff as the entire mesh is being simulated. */
+ if (brush->cloth_simulation_area_type == BRUSH_CLOTH_SIMULATION_AREA_GLOBAL) {
+ return 1.0f;
+ }
+
+ const float distance = len_v3v3(location, co);
+ const float limit = radius + (radius * brush->cloth_sim_limit);
+ const float falloff = radius + (radius * brush->cloth_sim_limit * brush->cloth_sim_falloff);
+
+ if (distance > limit) {
+ /* Outiside the limits. */
+ return 0.0f;
+ }
+ if (distance < falloff) {
+ /* Before the falloff area. */
+ return 1.0f;
+ }
+ /* Do a smoothstep transition inside the falloff area. */
+ float p = 1.0f - ((distance - falloff) / (limit - falloff));
+ return 3.0f * p * p - 2.0f * p * p * p;
+}
+
#define CLOTH_LENGTH_CONSTRAINTS_BLOCK 100000
#define CLOTH_SIMULATION_ITERATIONS 5
#define CLOTH_MAX_CONSTRAINTS_PER_VERTEX 1024
@@ -113,19 +142,8 @@ static bool cloth_brush_sim_has_length_constraint(SculptClothSimulation *cloth_s
return BLI_edgeset_haskey(cloth_sim->created_length_constraints, v1, v2);
}
-static void cloth_brush_add_length_constraint(SculptSession *ss,
- SculptClothSimulation *cloth_sim,
- const int v1,
- const int v2)
+static void cloth_brush_reallocate_constraints(SculptClothSimulation *cloth_sim)
{
- cloth_sim->length_constraints[cloth_sim->tot_length_constraints].v1 = v1;
- cloth_sim->length_constraints[cloth_sim->tot_length_constraints].v2 = v2;
- cloth_sim->length_constraints[cloth_sim->tot_length_constraints].length = len_v3v3(
- SCULPT_vertex_co_get(ss, v1), SCULPT_vertex_co_get(ss, v2));
-
- cloth_sim->tot_length_constraints++;
-
- /* Reallocation if the array capacity is exceeded. */
if (cloth_sim->tot_length_constraints >= cloth_sim->capacity_length_constraints) {
cloth_sim->capacity_length_constraints += CLOTH_LENGTH_CONSTRAINTS_BLOCK;
cloth_sim->length_constraints = MEM_reallocN_id(cloth_sim->length_constraints,
@@ -133,23 +151,119 @@ static void cloth_brush_add_length_constraint(SculptSession *ss,
sizeof(SculptClothLengthConstraint),
"length constraints");
}
+}
+
+static void cloth_brush_add_length_constraint(SculptSession *ss,
+ SculptClothSimulation *cloth_sim,
+ const int v1,
+ const int v2,
+ const bool use_persistent)
+{
+ SculptClothLengthConstraint *length_constraint =
+ &cloth_sim->length_constraints[cloth_sim->tot_length_constraints];
+
+ length_constraint->elem_index_a = v1;
+ length_constraint->elem_index_b = v2;
+
+ length_constraint->elem_position_a = cloth_sim->pos[v1];
+ length_constraint->elem_position_b = cloth_sim->pos[v2];
+
+ if (use_persistent) {
+ length_constraint->length = len_v3v3(SCULPT_vertex_persistent_co_get(ss, v1),
+ SCULPT_vertex_persistent_co_get(ss, v2));
+ }
+ else {
+ length_constraint->length = len_v3v3(SCULPT_vertex_co_get(ss, v1),
+ SCULPT_vertex_co_get(ss, v2));
+ }
+ length_constraint->strength = 1.0f;
+
+ cloth_sim->tot_length_constraints++;
+
+ /* Reallocation if the array capacity is exceeded. */
+ cloth_brush_reallocate_constraints(cloth_sim);
/* Add the constraint to the GSet to avoid creating it again. */
BLI_edgeset_add(cloth_sim->created_length_constraints, v1, v2);
}
+static void cloth_brush_add_softbody_constraint(SculptClothSimulation *cloth_sim,
+ const int v,
+ const float strength)
+{
+ SculptClothLengthConstraint *length_constraint =
+ &cloth_sim->length_constraints[cloth_sim->tot_length_constraints];
+
+ length_constraint->elem_index_a = v;
+ length_constraint->elem_index_b = v;
+
+ length_constraint->elem_position_a = cloth_sim->pos[v];
+ length_constraint->elem_position_b = cloth_sim->init_pos[v];
+
+ length_constraint->length = 0.0f;
+ length_constraint->strength = strength;
+
+ cloth_sim->tot_length_constraints++;
+
+ /* Reallocation if the array capacity is exceeded. */
+ cloth_brush_reallocate_constraints(cloth_sim);
+}
+
+static void cloth_brush_add_deformation_constraint(SculptClothSimulation *cloth_sim,
+ const int v,
+ const float strength)
+{
+ SculptClothLengthConstraint *length_constraint =
+ &cloth_sim->length_constraints[cloth_sim->tot_length_constraints];
+
+ length_constraint->elem_index_a = v;
+ length_constraint->elem_index_b = v;
+
+ length_constraint->elem_position_a = cloth_sim->pos[v];
+ length_constraint->elem_position_b = cloth_sim->deformation_pos[v];
+
+ length_constraint->length = 0.0f;
+ length_constraint->strength = strength;
+
+ cloth_sim->tot_length_constraints++;
+
+ /* Reallocation if the array capacity is exceeded. */
+ cloth_brush_reallocate_constraints(cloth_sim);
+}
+
static void do_cloth_brush_build_constraints_task_cb_ex(
void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
PBVHVertexIter vd;
+ const bool pin_simulation_boundary = ss->cache != NULL && brush != NULL &&
+ brush->flag2 & BRUSH_CLOTH_PIN_SIMULATION_BOUNDARY;
+
+ const bool use_persistent = brush != NULL && brush->flag & BRUSH_PERSISTENT;
+
+ /* Brush can be NULL in tools that use the solver without relying of constraints with deformation
+ * positions. */
+ const bool cloth_is_deform_brush = ss->cache != NULL && brush != NULL &&
+ SCULPT_is_cloth_deform_brush(brush);
+ float radius_squared = 0.0f;
+ if (cloth_is_deform_brush) {
+ radius_squared = ss->cache->initial_radius * ss->cache->initial_radius;
+ }
+
+ /* Only limit the contraint creation to a radius when the simulation is local. */
+ const float cloth_sim_radius_squared = brush->cloth_simulation_area_type ==
+ BRUSH_CLOTH_SIMULATION_AREA_LOCAL ?
+ data->cloth_sim_radius * data->cloth_sim_radius :
+ FLT_MAX;
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (len_squared_v3v3(vd.co, data->cloth_sim_initial_location) <
- data->cloth_sim_radius * data->cloth_sim_radius) {
+ const float len_squared = len_squared_v3v3(vd.co, data->cloth_sim_initial_location);
+ if (len_squared < cloth_sim_radius_squared) {
SculptVertexNeighborIter ni;
int build_indices[CLOTH_MAX_CONSTRAINTS_PER_VERTEX];
@@ -162,6 +276,11 @@ static void do_cloth_brush_build_constraints_task_cb_ex(
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ if (brush->cloth_constraint_softbody_strength > 0.0f) {
+ cloth_brush_add_softbody_constraint(
+ data->cloth_sim, vd.index, brush->cloth_constraint_softbody_strength);
+ }
+
/* As we don't know the order of the neighbor vertices, we create all possible combinations
* between the neighbor and the original vertex as length constraints. */
/* This results on a pattern that contains structural, shear and bending constraints for all
@@ -172,35 +291,29 @@ static void do_cloth_brush_build_constraints_task_cb_ex(
if (c_i != c_j && !cloth_brush_sim_has_length_constraint(
data->cloth_sim, build_indices[c_i], build_indices[c_j])) {
cloth_brush_add_length_constraint(
- ss, data->cloth_sim, build_indices[c_i], build_indices[c_j]);
+ ss, data->cloth_sim, build_indices[c_i], build_indices[c_j], use_persistent);
}
}
}
}
- }
- BKE_pbvh_vertex_iter_end;
-}
-static float cloth_brush_simulation_falloff_get(const Brush *brush,
- const float radius,
- const float location[3],
- const float co[3])
-{
- const float distance = len_v3v3(location, co);
- const float limit = radius + (radius * brush->cloth_sim_limit);
- const float falloff = radius + (radius * brush->cloth_sim_limit * brush->cloth_sim_falloff);
+ if (cloth_is_deform_brush && len_squared < radius_squared) {
+ const float fade = BKE_brush_curve_strength(brush, sqrtf(len_squared), ss->cache->radius);
+ cloth_brush_add_deformation_constraint(data->cloth_sim, vd.index, fade);
+ }
- if (distance > limit) {
- /* Outiside the limits. */
- return 0.0f;
- }
- if (distance < falloff) {
- /* Before the falloff area. */
- return 1.0f;
+ if (pin_simulation_boundary) {
+ const float sim_falloff = cloth_brush_simulation_falloff_get(
+ brush, ss->cache->initial_radius, ss->cache->location, vd.co);
+ /* Vertex is inside the area of the simulation without any falloff aplied. */
+ if (sim_falloff < 1.0f) {
+ /* Create constraints with more strength the closer the vertex is to the simulation
+ * boundary. */
+ cloth_brush_add_softbody_constraint(data->cloth_sim, vd.index, 1.0f - sim_falloff);
+ }
+ }
}
- /* Do a smoothstep transition inside the falloff area. */
- float p = 1.0f - ((distance - falloff) / (limit - falloff));
- return 3.0f * p * p - 2.0f * p * p * p;
+ BKE_pbvh_vertex_iter_end;
}
static void cloth_brush_apply_force_to_vertex(SculptSession *UNUSED(ss),
@@ -323,9 +436,10 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(force, offset, -fade);
break;
case BRUSH_CLOTH_DEFORM_GRAB:
- /* Grab writes the positions in the simulation directly without applying forces. */
- madd_v3_v3v3fl(
- cloth_sim->pos[vd.index], orig_data.co, ss->cache->grab_delta_symmetry, fade);
+ madd_v3_v3v3fl(cloth_sim->deformation_pos[vd.index],
+ orig_data.co,
+ ss->cache->grab_delta_symmetry,
+ fade);
zero_v3(force);
break;
case BRUSH_CLOTH_DEFORM_PINCH_POINT:
@@ -366,9 +480,36 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
+static ListBase *cloth_brush_collider_cache_create(Depsgraph *depsgraph)
+{
+ ListBase *cache = NULL;
+ DEG_OBJECT_ITER_BEGIN (depsgraph,
+ ob,
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI) {
+ CollisionModifierData *cmd = (CollisionModifierData *)BKE_modifiers_findby_type(
+ ob, eModifierType_Collision);
+ if (cmd && cmd->bvhtree) {
+ if (cache == NULL) {
+ cache = MEM_callocN(sizeof(ListBase), "ColliderCache array");
+ }
+
+ ColliderCache *col = MEM_callocN(sizeof(ColliderCache), "ColliderCache");
+ col->ob = ob;
+ col->collmd = cmd;
+ collision_move_object(cmd, 1.0, 0.0, true);
+ BLI_addtail(cache, col);
+ }
+ }
+ DEG_OBJECT_ITER_END;
+ return cache;
+}
+
static SculptClothSimulation *cloth_brush_simulation_create(SculptSession *ss,
+ Brush *brush,
const float cloth_mass,
- const float cloth_damping)
+ const float cloth_damping,
+ const bool use_collisions)
{
const int totverts = SCULPT_vertex_count_get(ss);
SculptClothSimulation *cloth_sim;
@@ -380,19 +521,130 @@ static SculptClothSimulation *cloth_brush_simulation_create(SculptSession *ss,
"cloth length constraints");
cloth_sim->capacity_length_constraints = CLOTH_LENGTH_CONSTRAINTS_BLOCK;
- cloth_sim->acceleration = MEM_callocN(sizeof(float) * 3 * totverts, "cloth sim acceleration");
- cloth_sim->pos = MEM_callocN(sizeof(float) * 3 * totverts, "cloth sim pos");
- cloth_sim->prev_pos = MEM_callocN(sizeof(float) * 3 * totverts, "cloth sim prev pos");
- cloth_sim->init_pos = MEM_callocN(sizeof(float) * 3 * totverts, "cloth sim init pos");
- cloth_sim->length_constraint_tweak = MEM_callocN(sizeof(float) * totverts,
- "cloth sim length tweak");
+ cloth_sim->acceleration = MEM_calloc_arrayN(
+ totverts, sizeof(float[3]), "cloth sim acceleration");
+ cloth_sim->pos = MEM_calloc_arrayN(totverts, sizeof(float[3]), "cloth sim pos");
+ cloth_sim->prev_pos = MEM_calloc_arrayN(totverts, sizeof(float[3]), "cloth sim prev pos");
+ cloth_sim->last_iteration_pos = MEM_calloc_arrayN(
+ totverts, sizeof(float[3]), "cloth sim last iteration pos");
+ cloth_sim->init_pos = MEM_calloc_arrayN(totverts, sizeof(float[3]), "cloth sim init pos");
+ cloth_sim->length_constraint_tweak = MEM_calloc_arrayN(
+ totverts, sizeof(float), "cloth sim length tweak");
+
+ /* Brush can be NULL for tools that need the solver but don't rely on constraint to deformation
+ * positions. */
+ if (brush && SCULPT_is_cloth_deform_brush(brush)) {
+ cloth_sim->deformation_pos = MEM_calloc_arrayN(
+ totverts, sizeof(float[3]), "cloth sim deformation positions");
+ }
cloth_sim->mass = cloth_mass;
cloth_sim->damping = cloth_damping;
+ if (use_collisions) {
+ cloth_sim->collider_list = cloth_brush_collider_cache_create(ss->depsgraph);
+ }
+
return cloth_sim;
}
+typedef struct ClothBrushCollision {
+ CollisionModifierData *col_data;
+ struct IsectRayPrecalc isect_precalc;
+} ClothBrushCollision;
+
+static void cloth_brush_collision_cb(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
+{
+ ClothBrushCollision *col = (ClothBrushCollision *)userdata;
+ CollisionModifierData *col_data = col->col_data;
+ MVertTri *verttri = &col_data->tri[index];
+ MVert *mverts = col_data->x;
+ float *tri[3], no[3], co[3];
+
+ tri[0] = mverts[verttri->tri[0]].co;
+ tri[1] = mverts[verttri->tri[1]].co;
+ tri[2] = mverts[verttri->tri[2]].co;
+ float dist = 0.0f;
+
+ bool tri_hit = isect_ray_tri_watertight_v3(
+ ray->origin, &col->isect_precalc, UNPACK3(tri), &dist, NULL);
+ normal_tri_v3(no, UNPACK3(tri));
+ madd_v3_v3v3fl(co, ray->origin, ray->direction, dist);
+
+ if (tri_hit && dist < hit->dist) {
+ hit->index = index;
+ hit->dist = dist;
+
+ copy_v3_v3(hit->co, co);
+ copy_v3_v3(hit->no, no);
+ }
+}
+
+static void cloth_brush_solve_collision(Object *object,
+ SculptClothSimulation *cloth_sim,
+ const int i)
+{
+ const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
+
+ ColliderCache *collider_cache;
+ BVHTreeRayHit hit;
+
+ float obmat_inv[4][4];
+ invert_m4_m4(obmat_inv, object->obmat);
+
+ for (collider_cache = cloth_sim->collider_list->first; collider_cache;
+ collider_cache = collider_cache->next) {
+ float ray_start[3], ray_normal[3];
+ float pos_world_space[3], prev_pos_world_space[3];
+
+ mul_v3_m4v3(pos_world_space, object->obmat, cloth_sim->pos[i]);
+ mul_v3_m4v3(prev_pos_world_space, object->obmat, cloth_sim->last_iteration_pos[i]);
+ sub_v3_v3v3(ray_normal, pos_world_space, prev_pos_world_space);
+ copy_v3_v3(ray_start, prev_pos_world_space);
+ hit.index = -1;
+ hit.dist = len_v3(ray_normal);
+ normalize_v3(ray_normal);
+
+ ClothBrushCollision col;
+ CollisionModifierData *collmd = collider_cache->collmd;
+ col.col_data = collmd;
+ isect_ray_tri_watertight_v3_precalc(&col.isect_precalc, ray_normal);
+
+ BLI_bvhtree_ray_cast_ex(collmd->bvhtree,
+ ray_start,
+ ray_normal,
+ 0.3f,
+ &hit,
+ cloth_brush_collision_cb,
+ &col,
+ raycast_flag);
+
+ if (hit.index != -1) {
+
+ float collision_disp[3];
+ float movement_disp[3];
+ mul_v3_v3fl(collision_disp, hit.no, 0.005f);
+ sub_v3_v3v3(movement_disp, pos_world_space, prev_pos_world_space);
+ float friction_plane[4];
+ float pos_on_friction_plane[3];
+ plane_from_point_normal_v3(friction_plane, hit.co, hit.no);
+ closest_to_plane_v3(pos_on_friction_plane, friction_plane, pos_world_space);
+ sub_v3_v3v3(movement_disp, pos_on_friction_plane, hit.co);
+
+ /* TODO(pablodp606): This can be exposed in a brush/filter property as friction. */
+ mul_v3_fl(movement_disp, 0.35f);
+
+ copy_v3_v3(cloth_sim->pos[i], hit.co);
+ add_v3_v3(cloth_sim->pos[i], movement_disp);
+ add_v3_v3(cloth_sim->pos[i], collision_disp);
+ mul_v3_m4v3(cloth_sim->pos[i], obmat_inv, cloth_sim->pos[i]);
+ }
+ }
+}
+
static void do_cloth_brush_solve_simulation_task_cb_ex(
void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
{
@@ -423,14 +675,22 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
const float mask_v = (1.0f - (vd.mask ? *vd.mask : 0.0f)) *
SCULPT_automasking_factor_get(ss, vd.index);
+
madd_v3_v3fl(cloth_sim->pos[i], pos_diff, mask_v);
madd_v3_v3fl(cloth_sim->pos[i], cloth_sim->acceleration[i], mask_v);
- copy_v3_v3(cloth_sim->prev_pos[i], temp);
+ if (cloth_sim->collider_list != NULL) {
+ cloth_brush_solve_collision(data->ob, cloth_sim, i);
+ }
+
+ copy_v3_v3(cloth_sim->last_iteration_pos[i], cloth_sim->pos[i]);
+ copy_v3_v3(cloth_sim->prev_pos[i], temp);
+ copy_v3_v3(cloth_sim->last_iteration_pos[i], cloth_sim->pos[i]);
copy_v3_fl(cloth_sim->acceleration[i], 0.0f);
copy_v3_v3(vd.co, cloth_sim->pos[vd.index]);
+
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
@@ -484,11 +744,11 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
for (int i = 0; i < cloth_sim->tot_length_constraints; i++) {
const SculptClothLengthConstraint *constraint = &cloth_sim->length_constraints[i];
- const int v1 = constraint->v1;
- const int v2 = constraint->v2;
+ const int v1 = constraint->elem_index_a;
+ const int v2 = constraint->elem_index_b;
float v1_to_v2[3];
- sub_v3_v3v3(v1_to_v2, cloth_sim->pos[v2], cloth_sim->pos[v1]);
+ sub_v3_v3v3(v1_to_v2, constraint->elem_position_b, constraint->elem_position_a);
const float current_distance = len_v3(v1_to_v2);
float correction_vector[3];
float correction_vector_half[3];
@@ -524,8 +784,14 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
cloth_sim->init_pos[v2]) :
1.0f;
- madd_v3_v3fl(cloth_sim->pos[v1], correction_vector_half, 1.0f * mask_v1 * sim_factor_v1);
- madd_v3_v3fl(cloth_sim->pos[v2], correction_vector_half, -1.0f * mask_v2 * sim_factor_v2);
+ madd_v3_v3fl(cloth_sim->pos[v1],
+ correction_vector_half,
+ 1.0f * mask_v1 * sim_factor_v1 * constraint->strength);
+ if (v1 != v2) {
+ madd_v3_v3fl(cloth_sim->pos[v2],
+ correction_vector_half,
+ -1.0f * mask_v2 * sim_factor_v2 * constraint->strength);
+ }
}
}
}
@@ -577,7 +843,7 @@ static void cloth_brush_apply_brush_foces(Sculpt *sd, Object *ob, PBVHNode **nod
.mat = imat,
};
- BKE_curvemapping_initialize(brush->curve);
+ BKE_curvemapping_init(brush->curve);
/* Init the grab delta. */
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
@@ -648,11 +914,20 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
/* The simulation structure only needs to be created on the first symmetry pass. */
if (SCULPT_stroke_is_first_brush_step(ss->cache) || !ss->cache->cloth_sim) {
+ const bool is_cloth_deform_brush = SCULPT_is_cloth_deform_brush(brush);
ss->cache->cloth_sim = cloth_brush_simulation_create(
- ss, brush->cloth_mass, brush->cloth_damping);
+ ss,
+ brush,
+ brush->cloth_mass,
+ brush->cloth_damping,
+ (brush->flag2 & BRUSH_CLOTH_USE_COLLISION));
for (int i = 0; i < totverts; i++) {
- copy_v3_v3(ss->cache->cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i));
+ copy_v3_v3(ss->cache->cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, i));
copy_v3_v3(ss->cache->cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i));
+ copy_v3_v3(ss->cache->cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i));
+ if (is_cloth_deform_brush) {
+ copy_v3_v3(ss->cache->cloth_sim->deformation_pos[i], SCULPT_vertex_co_get(ss, i));
+ }
}
}
@@ -680,18 +955,22 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim)
{
MEM_SAFE_FREE(cloth_sim->pos);
+ MEM_SAFE_FREE(cloth_sim->last_iteration_pos);
MEM_SAFE_FREE(cloth_sim->prev_pos);
MEM_SAFE_FREE(cloth_sim->acceleration);
MEM_SAFE_FREE(cloth_sim->length_constraints);
MEM_SAFE_FREE(cloth_sim->length_constraint_tweak);
+ MEM_SAFE_FREE(cloth_sim->deformation_pos);
MEM_SAFE_FREE(cloth_sim->init_pos);
+ if (cloth_sim->collider_list) {
+ BKE_collider_cache_free(&cloth_sim->collider_list);
+ }
MEM_SAFE_FREE(cloth_sim);
}
/* Cursor drawing function. */
void SCULPT_cloth_simulation_limits_draw(const uint gpuattr,
const Brush *brush,
- const float obmat[4][4],
const float location[3],
const float normal[3],
const float rds,
@@ -700,12 +979,13 @@ void SCULPT_cloth_simulation_limits_draw(const uint gpuattr,
const float alpha)
{
float cursor_trans[4][4], cursor_rot[4][4];
- float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
+ const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
float quat[4];
- copy_m4_m4(cursor_trans, obmat);
+ unit_m4(cursor_trans);
translate_m4(cursor_trans, location[0], location[1], location[2]);
rotation_between_vecs_to_quat(quat, z_axis, normal);
quat_to_mat4(cursor_rot, quat);
+ GPU_matrix_push();
GPU_matrix_mul(cursor_trans);
GPU_matrix_mul(cursor_rot);
@@ -715,6 +995,7 @@ void SCULPT_cloth_simulation_limits_draw(const uint gpuattr,
gpuattr, 0, 0, rds + (rds * brush->cloth_sim_limit * brush->cloth_sim_falloff), 320);
immUniformColor3fvAlpha(outline_col, alpha * 0.7f);
imm_draw_circle_wire_3d(gpuattr, 0, 0, rds + rds * brush->cloth_sim_limit, 80);
+ GPU_matrix_pop();
}
void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr,
@@ -762,11 +1043,7 @@ static EnumPropertyItem prop_cloth_filter_type[] = {
{CLOTH_FILTER_GRAVITY, "GRAVITY", 0, "Gravity", "Applies gravity to the simulation"},
{CLOTH_FILTER_INFLATE, "INFLATE", 0, "Inflate", "Inflates the cloth"},
{CLOTH_FILTER_EXPAND, "EXPAND", 0, "Expand", "Expands the cloth's dimensions"},
- {CLOTH_FILTER_PINCH,
- "PINCH",
- 0,
- "Pinch",
- "Pinches the cloth to the point where the cursor was when the filter started"},
+ {CLOTH_FILTER_PINCH, "PINCH", 0, "Pinch", "Pulls the cloth to the cursor's start position"},
{0, NULL, 0, NULL, NULL},
};
@@ -856,11 +1133,12 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent
float len = event->prevclickx - event->mval[0];
filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC;
- SCULPT_vertex_random_access_init(ss);
+ SCULPT_vertex_random_access_ensure(ss);
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
const int totverts = SCULPT_vertex_count_get(ss);
+
for (int i = 0; i < totverts; i++) {
copy_v3_v3(ss->filter_cache->cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i));
}
@@ -892,7 +1170,7 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent
static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *ob = CTX_data_active_object(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = ob->sculpt;
@@ -903,7 +1181,7 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent
mouse[1] = event->mval[1];
SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
- SCULPT_vertex_random_access_init(ss);
+ SCULPT_vertex_random_access_ensure(ss);
/* Needs mask data to be available as it is used when solving the constraints. */
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
@@ -913,11 +1191,15 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent
const float cloth_mass = RNA_float_get(op->ptr, "cloth_mass");
const float cloth_damping = RNA_float_get(op->ptr, "cloth_damping");
- ss->filter_cache->cloth_sim = cloth_brush_simulation_create(ss, cloth_mass, cloth_damping);
+ const bool use_collisions = RNA_boolean_get(op->ptr, "use_collisions");
+ ss->filter_cache->cloth_sim = cloth_brush_simulation_create(
+ ss, NULL, cloth_mass, cloth_damping, use_collisions);
+
copy_v3_v3(ss->filter_cache->cloth_sim_pinch_point, SCULPT_active_vertex_co_get(ss));
const int totverts = SCULPT_vertex_count_get(ss);
for (int i = 0; i < totverts; i++) {
+ copy_v3_v3(ss->filter_cache->cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, i));
copy_v3_v3(ss->filter_cache->cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i));
copy_v3_v3(ss->filter_cache->cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i));
}
@@ -946,7 +1228,7 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent
void SCULPT_OT_cloth_filter(struct wmOperatorType *ot)
{
/* Identifiers. */
- ot->name = "Filter cloth";
+ ot->name = "Filter Cloth";
ot->idname = "SCULPT_OT_cloth_filter";
ot->description = "Applies a cloth simulation deformation to the entire mesh";
@@ -989,4 +1271,9 @@ void SCULPT_OT_cloth_filter(struct wmOperatorType *ot)
false,
"Use Face Sets",
"Apply the filter only to the Face Set under the cursor");
+ ot->prop = RNA_def_boolean(ot->srna,
+ "use_collisions",
+ false,
+ "Use Collisions",
+ "Collide with other collider objects in the scene");
}