diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index a7a837406ac..64910e5f1a9 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -272,8 +272,11 @@ typedef enum eSculptClothConstraintType { /* Constraint that references the position of a vertex and a position in deformation_pos which can be deformed by the tools. */ SCULPT_CLOTH_CONSTRAINT_DEFORMATION = 1, - /* Constarint that references the vertex position and its initial position. */ + /* Constarint that references the vertex position and a editable softbody position for + plasticity. */ SCULPT_CLOTH_CONSTRAINT_SOFTBODY = 2, + /* Constarint that references the vertex position and its initial position. */ + SCULPT_CLOTH_CONSTRAINT_PIN = 3, } eSculptClothConstraintType; typedef struct SculptClothLengthConstraint { @@ -314,10 +317,12 @@ typedef struct SculptClothSimulation { float mass; float damping; + float softbody_strength; float (*acceleration)[3]; float (*pos)[3]; float (*init_pos)[3]; + float (*softbody_pos)[3]; float (*prev_pos)[3]; float (*last_iteration_pos)[3]; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 39b675de3c0..c4c9db69dcd 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -5747,7 +5747,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe if (brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM) { if (!ss->cache->cloth_sim) { - ss->cache->cloth_sim = SCULPT_cloth_brush_simulation_create(ss, 1.0f, 0.0f, false, true); + ss->cache->cloth_sim = SCULPT_cloth_brush_simulation_create( + ss, 1.0f, 0.0f, 0.0f, false, true); SCULPT_cloth_brush_simulation_init(ss, ss->cache->cloth_sim); } SCULPT_cloth_brush_store_simulation_state(ss, ss->cache->cloth_sim); diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index 2bca5e2e1f0..84d156122f3 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -229,7 +229,7 @@ static void cloth_brush_add_softbody_constraint(SculptClothSimulation *cloth_sim length_constraint->node = node_index; length_constraint->elem_position_a = cloth_sim->pos[v]; - length_constraint->elem_position_b = cloth_sim->init_pos[v]; + length_constraint->elem_position_b = cloth_sim->softbody_pos[v]; length_constraint->type = SCULPT_CLOTH_CONSTRAINT_SOFTBODY; @@ -242,6 +242,33 @@ static void cloth_brush_add_softbody_constraint(SculptClothSimulation *cloth_sim cloth_brush_reallocate_constraints(cloth_sim); } +static void cloth_brush_add_pin_constraint(SculptClothSimulation *cloth_sim, + const int node_index, + 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->node = node_index; + + length_constraint->elem_position_a = cloth_sim->pos[v]; + length_constraint->elem_position_b = cloth_sim->init_pos[v]; + + length_constraint->type = SCULPT_CLOTH_CONSTRAINT_PIN; + + 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 node_index, const int v, @@ -323,9 +350,8 @@ 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, node_index, vd.index, brush->cloth_constraint_softbody_strength); + if (data->cloth_sim->softbody_strength > 0.0f) { + cloth_brush_add_softbody_constraint(data->cloth_sim, node_index, vd.index, 1.0f); } /* As we don't know the order of the neighbor vertices, we create all possible combinations @@ -379,8 +405,7 @@ static void do_cloth_brush_build_constraints_task_cb_ex( 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, node_index, vd.index, 1.0f - sim_falloff); + cloth_brush_add_pin_constraint(data->cloth_sim, node_index, vd.index, 1.0f - sim_falloff); } } } @@ -809,14 +834,26 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss, 0.5f; } - madd_v3_v3fl(cloth_sim->pos[v1], - correction_vector_half, - 1.0f * mask_v1 * sim_factor_v1 * constraint->strength * deformation_strength); - if (v1 != v2) { - madd_v3_v3fl(cloth_sim->pos[v2], + if (constraint->type == SCULPT_CLOTH_CONSTRAINT_SOFTBODY) { + const float softbody_plasticity = brush ? brush->cloth_constraint_softbody_strength : 0.0f; + madd_v3_v3fl(cloth_sim->pos[v1], correction_vector_half, - -1.0f * mask_v2 * sim_factor_v2 * constraint->strength * - deformation_strength); + 1.0f * mask_v1 * sim_factor_v1 * constraint->strength * softbody_plasticity); + madd_v3_v3fl(cloth_sim->softbody_pos[v1], + correction_vector_half, + -1.0f * mask_v1 * sim_factor_v1 * constraint->strength * + (1.0f - softbody_plasticity)); + } + else { + madd_v3_v3fl(cloth_sim->pos[v1], + correction_vector_half, + 1.0f * mask_v1 * sim_factor_v1 * constraint->strength * deformation_strength); + if (v1 != v2) { + madd_v3_v3fl(cloth_sim->pos[v2], + correction_vector_half, + -1.0f * mask_v2 * sim_factor_v2 * constraint->strength * + deformation_strength); + } } } } @@ -954,6 +991,7 @@ static void cloth_sim_initialize_default_node_state(SculptSession *ss, SculptClothSimulation *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) { @@ -984,8 +1022,14 @@ SculptClothSimulation *SCULPT_cloth_brush_simulation_create(SculptSession *ss, totverts, sizeof(float), "cloth sim deformation strength"); } + if (cloth_softbody_strength > 0.0f) { + cloth_sim->softbody_pos = MEM_calloc_arrayN( + totverts, sizeof(float[3]), "cloth sim softbody pos"); + } + cloth_sim->mass = cloth_mass; cloth_sim->damping = cloth_damping; + cloth_sim->softbody_strength = cloth_softbody_strength; if (use_collisions) { cloth_sim->collider_list = cloth_brush_collider_cache_create(ss->depsgraph); @@ -1037,6 +1081,7 @@ void SCULPT_cloth_brush_simulation_init(SculptSession *ss, SculptClothSimulation { const int totverts = SCULPT_vertex_count_get(ss); const bool has_deformation_pos = cloth_sim->deformation_pos != NULL; + const bool has_softbody_pos = cloth_sim->softbody_pos != NULL; for (int i = 0; i < totverts; i++) { copy_v3_v3(cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, i)); copy_v3_v3(cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i)); @@ -1045,6 +1090,9 @@ void SCULPT_cloth_brush_simulation_init(SculptSession *ss, SculptClothSimulation copy_v3_v3(cloth_sim->deformation_pos[i], SCULPT_vertex_co_get(ss, i)); cloth_sim->deformation_strength[i] = 1.0f; } + if (has_softbody_pos) { + copy_v3_v3(cloth_sim->softbody_pos[i], SCULPT_vertex_co_get(ss, i)); + } } } @@ -1086,6 +1134,7 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode ss, brush->cloth_mass, brush->cloth_damping, + brush->cloth_constraint_softbody_strength, (brush->flag2 & BRUSH_CLOTH_USE_COLLISION), SCULPT_is_cloth_deform_brush(brush)); SCULPT_cloth_brush_simulation_init(ss, ss->cache->cloth_sim); @@ -1121,6 +1170,7 @@ void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim) 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->softbody_pos); MEM_SAFE_FREE(cloth_sim->init_pos); MEM_SAFE_FREE(cloth_sim->deformation_strength); MEM_SAFE_FREE(cloth_sim->node_state); @@ -1455,6 +1505,7 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent ss, cloth_mass, cloth_damping, + 0.0f, use_collisions, cloth_filter_is_deformation_filter(filter_type)); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 84a47ab86ba..a690e426770 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -365,11 +365,13 @@ void SCULPT_do_cloth_brush(struct Sculpt *sd, void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim); -struct SculptClothSimulation *SCULPT_cloth_brush_simulation_create(struct SculptSession *ss, - const float cloth_mass, - const float cloth_damping, - const bool use_collisions, - const bool needs_deform_coords); +struct SculptClothSimulation *SCULPT_cloth_brush_simulation_create( + struct SculptSession *ss, + const float cloth_mass, + const float cloth_damping, + const float cloth_softbody_strength, + const bool use_collisions, + const bool needs_deform_coords); void SCULPT_cloth_brush_simulation_init(struct SculptSession *ss, struct SculptClothSimulation *cloth_sim); diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 35f5c4c37bc..70d613f8b21 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -2753,8 +2753,8 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( prop, - "Soft Body Influence", - "How much the simulation preserves the original shape, acting as a soft body"); + "Soft Body Plasticity", + "How much the cloth preserves the original shape, acting as a soft body"); RNA_def_property_update(prop, 0, "rna_Brush_update"); prop = RNA_def_property(srna, "hardness", PROP_FLOAT, PROP_FACTOR);