Add cloth pressure vertex group and unlock cloth shrink values range

Introduced a way to specify cloth pressure force influence with a vertex
group. This will allow users to only have pressure affect certain parts
of the mesh.

In addition to this, the "shrink factor" is now also unlocked to allow
negative values and thus allowing the cloth mesh to grow as well.

Reviewed By: Jaques Lucke

Differential Revision: http://developer.blender.org/D6347
This commit is contained in:
2019-12-04 11:24:46 +01:00
parent b3f388dca9
commit 541d0fdba6
8 changed files with 146 additions and 55 deletions

View File

@@ -178,6 +178,7 @@ class PHYSICS_PT_cloth_pressure(PhysicButtonsPanel, Panel):
cloth = context.cloth.settings
md = context.cloth
ob = context.object
layout.active = cloth.use_pressure and cloth_panel_enabled(md)
@@ -196,6 +197,9 @@ class PHYSICS_PT_cloth_pressure(PhysicButtonsPanel, Panel):
col = flow.column()
col.prop(cloth, "pressure_factor", text="Factor")
col = flow.column()
col.prop_search(cloth, "vertex_group_pressure", ob, "vertex_groups", text="Vertex Group")
class PHYSICS_PT_cloth_cache(PhysicButtonsPanel, Panel):
bl_label = "Cache"

View File

@@ -113,8 +113,9 @@ typedef struct ClothVertex {
float struct_stiff;
float bend_stiff;
float shear_stiff;
int spring_count; /* how many springs attached? */
float shrink_factor; /* how much to shrink this cloth */
int spring_count; /* how many springs attached? */
float shrink_factor; /* how much to shrink this cloth */
float pressure_factor; /* how much pressure should affect this vertex */
} ClothVertex;
/**

View File

@@ -134,6 +134,7 @@ void cloth_init(ClothModifierData *clmd)
clmd->sim_parms->uniform_pressure_force = 0.0f;
clmd->sim_parms->target_volume = 0.0f;
clmd->sim_parms->pressure_factor = 1.0f;
clmd->sim_parms->vgroup_pressure = 0;
// also from softbodies
clmd->sim_parms->maxgoal = 1.0f;
@@ -651,8 +652,9 @@ int cloth_uses_vgroup(ClothModifierData *clmd)
{
return (((clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) &&
(clmd->coll_parms->vgroup_selfcol > 0)) ||
(clmd->sim_parms->vgroup_struct > 0) || (clmd->sim_parms->vgroup_bend > 0) ||
(clmd->sim_parms->vgroup_shrink > 0) || (clmd->sim_parms->vgroup_mass > 0));
(clmd->sim_parms->vgroup_pressure > 0) || (clmd->sim_parms->vgroup_struct > 0) ||
(clmd->sim_parms->vgroup_bend > 0) || (clmd->sim_parms->vgroup_shrink > 0) ||
(clmd->sim_parms->vgroup_mass > 0));
}
/**
@@ -660,27 +662,16 @@ int cloth_uses_vgroup(ClothModifierData *clmd)
*/
static void cloth_apply_vgroup(ClothModifierData *clmd, Mesh *mesh)
{
/* Can be optimized to do all groups in one loop. */
int i = 0;
int j = 0;
MDeformVert *dvert = NULL;
Cloth *clothObj = NULL;
int mvert_num;
/* float goalfac = 0; */ /* UNUSED */
ClothVertex *verts = NULL;
if (!clmd || !mesh) {
return;
}
clothObj = clmd->clothObject;
int mvert_num = mesh->totvert;
mvert_num = mesh->totvert;
verts = clothObj->verts;
ClothVertex *verts = clmd->clothObject->verts;
if (cloth_uses_vgroup(clmd)) {
for (i = 0; i < mvert_num; i++, verts++) {
for (int i = 0; i < mvert_num; i++, verts++) {
/* Reset Goal values to standard */
if (clmd->sim_parms->vgroup_mass > 0) {
@@ -697,9 +688,9 @@ static void cloth_apply_vgroup(ClothModifierData *clmd, Mesh *mesh)
verts->flags &= ~CLOTH_VERT_FLAG_PINNED;
verts->flags &= ~CLOTH_VERT_FLAG_NOSELFCOLL;
dvert = CustomData_get(&mesh->vdata, i, CD_MDEFORMVERT);
MDeformVert *dvert = CustomData_get(&mesh->vdata, i, CD_MDEFORMVERT);
if (dvert) {
for (j = 0; j < dvert->totweight; j++) {
for (int j = 0; j < dvert->totweight; j++) {
if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_mass - 1)) {
verts->goal = dvert->dw[j].weight;
@@ -726,19 +717,21 @@ static void cloth_apply_vgroup(ClothModifierData *clmd, Mesh *mesh)
verts->bend_stiff = dvert->dw[j].weight;
}
if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) {
if (dvert->dw[j].def_nr == (clmd->coll_parms->vgroup_selfcol - 1)) {
if (dvert->dw[j].weight > 0.0f) {
verts->flags |= CLOTH_VERT_FLAG_NOSELFCOLL;
}
if (dvert->dw[j].def_nr == (clmd->coll_parms->vgroup_selfcol - 1)) {
if (dvert->dw[j].weight > 0.0f) {
verts->flags |= CLOTH_VERT_FLAG_NOSELFCOLL;
}
}
if (clmd->sim_parms->vgroup_shrink > 0) {
if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) {
/* Used for linear interpolation between min and max
* shrink factor based on weight. */
verts->shrink_factor = dvert->dw[j].weight;
}
if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) {
/* Used for linear interpolation between min and max
* shrink factor based on weight. */
verts->shrink_factor = dvert->dw[j].weight;
}
if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_pressure - 1)) {
/* Used to define how much the pressure settings should affect the given vertex */
verts->pressure_factor = dvert->dw[j].weight;
}
}
}
@@ -750,10 +743,10 @@ static float cloth_shrink_factor(ClothModifierData *clmd, ClothVertex *verts, in
{
/* Linear interpolation between min and max shrink factor based on weight. */
float base = 1.0f - clmd->sim_parms->shrink_min;
float delta = clmd->sim_parms->shrink_min - clmd->sim_parms->shrink_max;
float shrink_factor_delta = clmd->sim_parms->shrink_min - clmd->sim_parms->shrink_max;
float k1 = base + delta * verts[i1].shrink_factor;
float k2 = base + delta * verts[i2].shrink_factor;
float k1 = base + shrink_factor_delta * verts[i1].shrink_factor;
float k2 = base + shrink_factor_delta * verts[i2].shrink_factor;
/* Use geometrical mean to average two factors since it behaves better
* for diagonals when a rectangle transforms into a trapezoid. */

View File

@@ -93,9 +93,11 @@ typedef struct ClothSimSettings {
float collider_friction;
/** Damp the velocity to speed up getting to the resting position. */
float vel_damping DNA_DEPRECATED;
/** Min amount to shrink cloth by 0.0f (no shrink) - 1.0f (shrink to nothing). */
/** Min amount to shrink cloth by 0.0f (no shrink), 1.0f (shrink to nothing), -1.0f (double the
* edge length). */
float shrink_min;
/** Max amount to shrink cloth by 0.0f (no shrink) - 1.0f (shrink to nothing). */
/** Max amount to shrink cloth by 0.0f (no shrink), 1.0f (shrink to nothing), -1.0f (double the
* edge length). */
float shrink_max;
/* Air pressure */
@@ -107,7 +109,8 @@ typedef struct ClothSimSettings {
pressure=( (current_volume/target_volume) - 1 + uniform_pressure_force) *
pressure_factor */
float pressure_factor;
char _pad7[4];
short vgroup_pressure;
char _pad7[2];
/* XXX various hair stuff
* should really be separate, this struct is a horrible mess already

View File

@@ -291,6 +291,24 @@ static void rna_ClothSettings_bend_vgroup_set(PointerRNA *ptr, const char *value
rna_object_vgroup_name_index_set(ptr, value, &sim->vgroup_bend);
}
static void rna_ClothSettings_pressure_vgroup_get(PointerRNA *ptr, char *value)
{
ClothSimSettings *sim = (ClothSimSettings *)ptr->data;
rna_object_vgroup_name_index_get(ptr, value, sim->vgroup_pressure);
}
static int rna_ClothSettings_pressure_vgroup_length(PointerRNA *ptr)
{
ClothSimSettings *sim = (ClothSimSettings *)ptr->data;
return rna_object_vgroup_name_index_length(ptr, sim->vgroup_pressure);
}
static void rna_ClothSettings_pressure_vgroup_set(PointerRNA *ptr, const char *value)
{
ClothSimSettings *sim = (ClothSimSettings *)ptr->data;
rna_object_vgroup_name_index_set(ptr, value, &sim->vgroup_pressure);
}
static void rna_CollSettings_selfcol_vgroup_get(PointerRNA *ptr, char *value)
{
ClothCollSettings *coll = (ClothCollSettings *)ptr->data;
@@ -595,14 +613,16 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "shrink_min", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "shrink_min");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_range(prop, -FLT_MAX, 1.0f);
RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.05f, 3);
RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_shrink_min_set", NULL);
RNA_def_property_ui_text(prop, "Shrink Factor", "Factor by which to shrink cloth");
RNA_def_property_update(prop, 0, "rna_cloth_update");
prop = RNA_def_property(srna, "shrink_max", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "shrink_max");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_range(prop, -FLT_MAX, 1.0f);
RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.05f, 3);
RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_shrink_max_set", NULL);
RNA_def_property_ui_text(prop, "Shrink Factor Max", "Max amount to shrink cloth by");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -803,8 +823,10 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "target_volume");
RNA_def_property_range(prop, 0.0f, 10000.0f);
RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_ui_text(
prop, "Target Volume", "The mesh volume where the inner/outer pressure will be the same");
RNA_def_property_ui_text(prop,
"Target Volume",
"The mesh volume where the inner/outer pressure will be the same. If "
"set to zero the volume will not contribute to the total pressure");
RNA_def_property_update(prop, 0, "rna_cloth_update");
prop = RNA_def_property(srna, "pressure_factor", PROP_FLOAT, PROP_NONE);
@@ -814,6 +836,19 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Pressure Scale", "Air pressure scaling factor");
RNA_def_property_update(prop, 0, "rna_cloth_update");
prop = RNA_def_property(srna, "vertex_group_pressure", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop,
"rna_ClothSettings_pressure_vgroup_get",
"rna_ClothSettings_pressure_vgroup_length",
"rna_ClothSettings_pressure_vgroup_set");
RNA_def_property_ui_text(
prop,
"Pressure Vertex Group",
"Vertex Group for where to apply pressure. Zero weight means no "
"pressure while a weight of one means full pressure. Faces with a vertex "
"that has zero weight will be excluded from the volume calculation");
RNA_def_property_update(prop, 0, "rna_cloth_update");
/* unused */
/* unused still */

View File

@@ -76,18 +76,39 @@ static int cloth_count_nondiag_blocks(Cloth *cloth)
static float cloth_calc_volume(ClothModifierData *clmd)
{
/* calc the (closed) cloth volume */
/* Calculate the (closed) cloth volume. */
Cloth *cloth = clmd->clothObject;
const MVertTri *tri = cloth->tri;
Implicit_Data *data = cloth->implicit;
float vol = 0;
for (unsigned int i = 0; i < cloth->tri_num; i++) {
const MVertTri *vt = &tri[i];
vol += BPH_tri_tetra_volume_signed_6x(data, vt->tri[0], vt->tri[1], vt->tri[2]);
}
if (clmd->sim_parms->vgroup_pressure > 0) {
for (unsigned int i = 0; i < cloth->tri_num; i++) {
bool skip_face = false;
/* We have custom vertex weights for pressure. */
const MVertTri *vt = &tri[i];
for (unsigned int j = 0; j < 3; j++) {
/* If any weight is zero, don't take this face into account for volume calculation. */
ClothVertex *verts = clmd->clothObject->verts;
/* We need to divide by 6 to get the actual volume */
if (verts[vt->tri[j]].pressure_factor == 0.0f) {
skip_face = true;
}
}
if (skip_face) {
continue;
}
vol += BPH_tri_tetra_volume_signed_6x(data, vt->tri[0], vt->tri[1], vt->tri[2]);
}
}
else {
for (unsigned int i = 0; i < cloth->tri_num; i++) {
const MVertTri *vt = &tri[i];
vol += BPH_tri_tetra_volume_signed_6x(data, vt->tri[0], vt->tri[1], vt->tri[2]);
}
}
/* We need to divide by 6 to get the actual volume. */
vol = vol / 6.0f;
return vol;
@@ -634,8 +655,38 @@ static void cloth_calc_force(
for (i = 0; i < cloth->tri_num; i++) {
const MVertTri *vt = &tri[i];
if (fabs(pressure_difference) > 1E-6f) {
BPH_mass_spring_force_pressure(
data, vt->tri[0], vt->tri[1], vt->tri[2], pressure_difference);
if (clmd->sim_parms->vgroup_pressure > 0) {
/* We have custom vertex weights for pressure. */
ClothVertex *verts = clmd->clothObject->verts;
int v1, v2, v3;
v1 = vt->tri[0];
v2 = vt->tri[1];
v3 = vt->tri[2];
float weights[3];
bool skip_face = false;
weights[0] = verts[v1].pressure_factor;
weights[1] = verts[v2].pressure_factor;
weights[2] = verts[v3].pressure_factor;
for (unsigned int j = 0; j < 3; j++) {
if (weights[j] == 0.0f) {
/* Exclude faces which has a zero weight vert. */
skip_face = true;
break;
}
}
if (skip_face) {
continue;
}
BPH_mass_spring_force_pressure(data, v1, v2, v3, pressure_difference, weights);
}
else {
float weights[3] = {1.0f, 1.0f, 1.0f};
BPH_mass_spring_force_pressure(
data, vt->tri[0], vt->tri[1], vt->tri[2], pressure_difference, weights);
}
}
}
}

View File

@@ -184,8 +184,12 @@ bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data,
float BPH_tri_tetra_volume_signed_6x(struct Implicit_Data *data, int v1, int v2, int v3);
void BPH_mass_spring_force_pressure(
struct Implicit_Data *data, int v1, int v2, int v3, float pressure_difference);
void BPH_mass_spring_force_pressure(struct Implicit_Data *data,
int v1,
int v2,
int v3,
float pressure_difference,
float weights[3]);
/* ======== Hair Volumetric Forces ======== */

View File

@@ -1489,7 +1489,7 @@ float BPH_tri_tetra_volume_signed_6x(Implicit_Data *data, int v1, int v2, int v3
}
void BPH_mass_spring_force_pressure(
Implicit_Data *data, int v1, int v2, int v3, float pressure_difference)
Implicit_Data *data, int v1, int v2, int v3, float pressure_difference, float weights[3])
{
float nor[3], area;
float factor;
@@ -1500,9 +1500,9 @@ void BPH_mass_spring_force_pressure(
factor = pressure_difference * area / 3.0f;
/* add pressure to each of the face verts */
madd_v3_v3fl(data->F[v1], nor, factor);
madd_v3_v3fl(data->F[v2], nor, factor);
madd_v3_v3fl(data->F[v3], nor, factor);
madd_v3_v3fl(data->F[v1], nor, factor * weights[0]);
madd_v3_v3fl(data->F[v2], nor, factor * weights[1]);
madd_v3_v3fl(data->F[v3], nor, factor * weights[2]);
}
static void edge_wind_vertex(const float dir[3],