Sculpt: Cloth brush Pin Simulation Boundary property

The cloth brush has a defined simulated area with a falloff. In the falloff
area (the area between the dashed white circle and the exterior white
circle), simulation properties change in order to fade out the
simulation deformation effects towards the boundary.
With some brushes and stroke types (like anchored strokes with pinching
or grabbing with full strength), it is possible to apply more force than
what the boundary falloff can compensate, so the simulation breaks when
this happens.
This option pins the falloff area with softbody constraints, This
produces a much better deformation falloff and it is no longer possible
to move the vertices near the simulation boundary, so the simulation
won't break no matter the strength of the forces applied inside the
simulated areas.
This is an option as it is particularly useful for some brushes to add
localized details, but for brushes that are supposed to deform the
entire mesh (like the grab brush in D8424), this can add unwanted
softbody constraints that affect the simulation result.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D8435
This commit is contained in:
Pablo Dobarro 2020-07-31 01:12:06 +02:00
parent 6faa765af8
commit bf65820782
4 changed files with 47 additions and 22 deletions

View File

@ -656,6 +656,7 @@ def brush_settings(layout, context, brush, popover=False):
layout.separator()
layout.prop(brush, "cloth_sim_limit")
layout.prop(brush, "cloth_sim_falloff")
layout.prop(brush, "use_cloth_pin_simulation_boundary")
layout.separator()
layout.prop(brush, "cloth_deform_type")
layout.prop(brush, "cloth_force_falloff_type")

View File

@ -100,6 +100,28 @@
#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])
{
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
@ -210,6 +232,9 @@ static void do_cloth_brush_build_constraints_task_cb_ex(
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
@ -264,32 +289,21 @@ static void do_cloth_brush_build_constraints_task_cb_ex(
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 (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);
}
}
}
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 (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;
}
static void cloth_brush_apply_force_to_vertex(SculptSession *UNUSED(ss),
SculptClothSimulation *cloth_sim,
const float force[3],

View File

@ -726,6 +726,7 @@ typedef enum eBrushFlags2 {
BRUSH_MULTIPLANE_SCRAPE_PLANES_PREVIEW = (1 << 1),
BRUSH_POSE_IK_ANCHORED = (1 << 2),
BRUSH_USE_CONNECTED_ONLY = (1 << 3),
BRUSH_CLOTH_PIN_SIMULATION_BOUNDARY = (1 << 4),
} eBrushFlags2;
typedef enum {

View File

@ -2793,6 +2793,15 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Connected Only", "Affect only topologically connected elements");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "use_cloth_pin_simulation_boundary", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag2", BRUSH_CLOTH_PIN_SIMULATION_BOUNDARY);
RNA_def_property_ui_text(
prop,
"Pin Simulation Boundary",
"Lock the position of the vertices in the simulation falloff area to avoid artifacts and "
"create a softer transitionwith with unnafected areas");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "invert_to_scrape_fill", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_INVERT_TO_SCRAPE_FILL);
RNA_def_property_ui_text(prop,