Fix T30941: Add cloth air pressure simulation

This adds some basic simulation of internal air pressure inside of
closed cloth mesh objects.

Reviewed By: Jacques Lucke

Differential Revision: http://developer.blender.org/D5473
This commit is contained in:
Sebastian Parborg 2019-11-27 14:56:16 +01:00
parent eb798de101
commit f6cefbef22
Notes: blender-bot 2023-02-14 13:47:37 +01:00
Referenced by issue #30941, Blender cloth simulator air pressure enhancement
14 changed files with 242 additions and 10 deletions

View File

@ -161,6 +161,42 @@ class PHYSICS_PT_cloth_damping(PhysicButtonsPanel, Panel):
col.prop(cloth, "bending_damping", text="Bending")
class PHYSICS_PT_cloth_pressure(PhysicButtonsPanel, Panel):
bl_label = "Pressure"
bl_parent_id = 'PHYSICS_PT_cloth_physical_properties'
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
def draw_header(self, context):
cloth = context.cloth.settings
self.layout.active = cloth_panel_enabled(context.cloth)
self.layout.prop(cloth, "use_pressure", text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = True
cloth = context.cloth.settings
md = context.cloth
layout.active = cloth.use_pressure and cloth_panel_enabled(md)
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
col = flow.column()
col.prop(cloth, "uniform_pressure_force")
col = flow.column()
col.prop(cloth, "use_pressure_volume", text="Custom volume")
col = flow.column()
col.active = cloth.use_pressure_volume
col.prop(cloth, "target_volume")
col = flow.column()
col.prop(cloth, "pressure_factor", text="Factor")
class PHYSICS_PT_cloth_cache(PhysicButtonsPanel, Panel):
bl_label = "Cache"
bl_parent_id = 'PHYSICS_PT_cloth'
@ -382,6 +418,7 @@ classes = (
PHYSICS_PT_cloth_physical_properties,
PHYSICS_PT_cloth_stiffness,
PHYSICS_PT_cloth_damping,
PHYSICS_PT_cloth_pressure,
PHYSICS_PT_cloth_cache,
PHYSICS_PT_cloth_shape,
PHYSICS_PT_cloth_collision,

View File

@ -87,7 +87,8 @@ typedef struct Cloth {
struct MVertTri *tri;
struct Implicit_Data *implicit; /* our implicit solver connects to this pointer */
struct EdgeSet *edgeset; /* used for selfcollisions */
int last_frame, pad4;
int last_frame;
float initial_mesh_volume; /* Initial volume of the mesh. Used for pressure */
} Cloth;
/**
@ -192,6 +193,10 @@ typedef enum {
CLOTH_SIMSETTINGS_FLAG_GOAL = (1 << 3),
/** True if tearing is enabled. */
CLOTH_SIMSETTINGS_FLAG_TEARING = (1 << 4),
/** True if pressure sim is enabled. */
CLOTH_SIMSETTINGS_FLAG_PRESSURE = (1 << 5),
/** Use the user defined target volume. */
CLOTH_SIMSETTINGS_FLAG_PRESSURE_VOL = (1 << 6),
/** DEPRECATED, for versioning only. */
CLOTH_SIMSETTINGS_FLAG_SCALING = (1 << 8),
/** Edit cache in edit-mode. */

View File

@ -130,6 +130,11 @@ void cloth_init(ClothModifierData *clmd)
clmd->sim_parms->eff_force_scale = 1000.0;
clmd->sim_parms->eff_wind_scale = 250.0;
/* Pressure settings */
clmd->sim_parms->uniform_pressure_force = 0.0f;
clmd->sim_parms->target_volume = 0.0f;
clmd->sim_parms->pressure_factor = 1.0f;
// also from softbodies
clmd->sim_parms->maxgoal = 1.0f;
clmd->sim_parms->mingoal = 0.0f;
@ -291,6 +296,12 @@ static int do_init_cloth(Object *ob, ClothModifierData *clmd, Mesh *result, int
BKE_cloth_solver_set_positions(clmd);
ClothSimSettings *parms = clmd->sim_parms;
if (parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE &&
!(parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE_VOL)) {
BKE_cloth_solver_set_volume(clmd);
}
clmd->clothObject->last_frame = MINFRAME - 1;
clmd->sim_parms->dt = 1.0f / clmd->sim_parms->stepsPerFrame;
}
@ -1742,6 +1753,6 @@ static int cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
return 1;
} /* cloth_build_springs */
/***************************************************************************************
* SPRING NETWORK GPU_BATCH_BUILDING IMPLEMENTATION END
***************************************************************************************/
/***************************************************************************************
* SPRING NETWORK GPU_BATCH_BUILDING IMPLEMENTATION END
***************************************************************************************/

View File

@ -2392,9 +2392,7 @@ static float mesh_calc_poly_volume_centroid(const MPoly *mpoly,
/* Calculate the 6x volume of the tetrahedron formed by the 3 vertices
* of the triangle and the origin as the fourth vertex */
float v_cross[3];
cross_v3_v3v3(v_cross, v_pivot, v_step1);
const float tetra_volume = dot_v3v3(v_cross, v_step2);
const float tetra_volume = volume_tri_tetrahedron_signed_v3_6x(v_pivot, v_step1, v_step2);
total_volume += tetra_volume;
/* Calculate the centroid of the tetrahedron formed by the 3 vertices

View File

@ -92,6 +92,9 @@ float volume_tetrahedron_signed_v3(const float v1[3],
const float v3[3],
const float v4[3]);
float volume_tri_tetrahedron_signed_v3_6x(const float v1[3], const float v2[3], const float v3[3]);
float volume_tri_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3]);
bool is_edge_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]);

View File

@ -300,6 +300,25 @@ float volume_tetrahedron_signed_v3(const float v1[3],
return determinant_m3_array(m) / 6.0f;
}
/**
* The volume from a triangle that is made into a tetrahedron.
* This uses a simplified formula where the tip of the tetrahedron is in the world origin.
* Using this method, the total volume of a closed triangle mesh can be calculated.
* Note that you need to divide the result by 6 to get the actual volume.
*/
float volume_tri_tetrahedron_signed_v3_6x(const float v1[3], const float v2[3], const float v3[3])
{
float v_cross[3];
cross_v3_v3v3(v_cross, v1, v2);
float tetra_volume = dot_v3v3(v_cross, v3);
return tetra_volume;
}
float volume_tri_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3])
{
return volume_tri_tetrahedron_signed_v3_6x(v1, v2, v3) / 6.0f;
}
/********************************* Distance **********************************/
/* distance p to line v1-v2

View File

@ -3977,5 +3977,15 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
br->pose_smooth_iterations = 4;
}
}
/* Cloth pressure */
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Cloth) {
ClothModifierData *clmd = (ClothModifierData *)md;
clmd->sim_parms->pressure_factor = 1;
}
}
}
}
}

View File

@ -2048,14 +2048,13 @@ static float p_collapse_cost(PEdge *edge, PEdge *pair)
float *co2 = e->next->next->vert->co;
if ((e->face != oldf1) && (e->face != oldf2)) {
float tetrav2[3], tetrav3[3], c[3];
float tetrav2[3], tetrav3[3];
/* tetrahedron volume = (1/3!)*|a.(b x c)| */
sub_v3_v3v3(tetrav2, co1, oldv->co);
sub_v3_v3v3(tetrav3, co2, oldv->co);
cross_v3_v3v3(c, tetrav2, tetrav3);
volumecost += fabsf(volume_tri_tetrahedron_signed_v3(tetrav2, tetrav3, edgevec));
volumecost += fabsf(dot_v3v3(edgevec, c) / 6.0f);
# if 0
shapecost += dot_v3v3(co1, keepv->co);

View File

@ -98,6 +98,17 @@ typedef struct ClothSimSettings {
/** Max amount to shrink cloth by 0.0f (no shrink) - 1.0f (shrink to nothing). */
float shrink_max;
/* Air pressure */
/* The uniform pressure that is constanty applied to the mesh. Can be negative */
float uniform_pressure_force;
/* User set volume. This is the volume the mesh wants to expand to (the equilibrium volume). */
float target_volume;
/* The scaling factor to apply to the actual pressure.
pressure=( (current_volume/target_volume) - 1 + uniform_pressure_force) *
pressure_factor */
float pressure_factor;
char _pad7[4];
/* XXX various hair stuff
* should really be separate, this struct is a horrible mess already
*/

View File

@ -774,6 +774,46 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_cloth_update");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
/* Pressure */
prop = RNA_def_property(srna, "use_pressure", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", CLOTH_SIMSETTINGS_FLAG_PRESSURE);
RNA_def_property_ui_text(prop, "Use Pressure", "Simulate pressure inside a closed cloth mesh");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, 0, "rna_cloth_update");
prop = RNA_def_property(srna, "use_pressure_volume", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", CLOTH_SIMSETTINGS_FLAG_PRESSURE_VOL);
RNA_def_property_ui_text(
prop, "Use Custom Volume", "Use the Volume parameter as the initial volume");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, 0, "rna_cloth_update");
prop = RNA_def_property(srna, "uniform_pressure_force", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "uniform_pressure_force");
RNA_def_property_range(prop, -10000.0f, 10000.0f);
RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_ui_text(
prop,
"Pressure",
"The uniform pressure that is constanty applied to the mesh. Can be negative");
RNA_def_property_update(prop, 0, "rna_cloth_update");
prop = RNA_def_property(srna, "target_volume", PROP_FLOAT, PROP_NONE);
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_update(prop, 0, "rna_cloth_update");
prop = RNA_def_property(srna, "pressure_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "pressure_factor");
RNA_def_property_range(prop, 0.0f, 10000.0f);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Pressure Scale", "Air pressure scaling factor");
RNA_def_property_update(prop, 0, "rna_cloth_update");
/* unused */
/* unused still */

View File

@ -53,6 +53,7 @@ int BPH_cloth_solve(struct Depsgraph *depsgraph,
struct ClothModifierData *clmd,
struct ListBase *effectors);
void BKE_cloth_solver_set_positions(struct ClothModifierData *clmd);
void BKE_cloth_solver_set_volume(ClothModifierData *clmd);
#ifdef __cplusplus
}

View File

@ -74,6 +74,25 @@ static int cloth_count_nondiag_blocks(Cloth *cloth)
return nondiag;
}
static float cloth_calc_volume(ClothModifierData *clmd)
{
/* calc 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]);
}
/* We need to divide by 6 to get the actual volume */
vol = vol / 6.0f;
return vol;
}
int BPH_cloth_solver_init(Object *UNUSED(ob), ClothModifierData *clmd)
{
Cloth *cloth = clmd->clothObject;
@ -127,6 +146,13 @@ void BKE_cloth_solver_set_positions(ClothModifierData *clmd)
}
}
void BKE_cloth_solver_set_volume(ClothModifierData *clmd)
{
Cloth *cloth = clmd->clothObject;
cloth->initial_mesh_volume = cloth_calc_volume(clmd);
}
static bool collision_response(ClothModifierData *clmd,
CollisionModifierData *collmd,
CollPair *collpair,
@ -526,6 +552,7 @@ static void cloth_calc_force(
{
/* Collect forces and derivatives: F, dFdX, dFdV */
Cloth *cloth = clmd->clothObject;
ClothSimSettings *parms = clmd->sim_parms;
Implicit_Data *data = cloth->implicit;
unsigned int i = 0;
float drag = clmd->sim_parms->Cvi * 0.01f; /* viscosity of air scaled in percent */
@ -570,6 +597,48 @@ static void cloth_calc_force(
#ifdef CLOTH_FORCE_DRAG
BPH_mass_spring_force_drag(data, drag);
#endif
/* handle pressure forces */
if (parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE) {
/* The difference in pressure between the inside and outside of the mesh.*/
float pressure_difference = 0.0f;
float init_vol;
if (parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE_VOL) {
init_vol = clmd->sim_parms->target_volume;
}
else {
init_vol = cloth->initial_mesh_volume;
}
/* Check if we need to calculate the volume of the mesh. */
if (init_vol > 1E-6f) {
float f;
float vol = cloth_calc_volume(clmd);
/* Calculate an artifical maximum value for cloth pressure. */
f = fabs(clmd->sim_parms->uniform_pressure_force) + 200.0f;
/* Clamp the cloth pressure to the calculated maximum value. */
if (vol * f < init_vol) {
pressure_difference = f;
}
else {
/* If the volume is the same don't apply any pressure. */
pressure_difference = (init_vol / vol) - 1;
}
}
pressure_difference += clmd->sim_parms->uniform_pressure_force;
pressure_difference *= clmd->sim_parms->pressure_factor;
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);
}
}
}
/* handle external forces like wind */
if (effectors) {

View File

@ -182,6 +182,11 @@ bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data,
float stiffness,
float damping);
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);
/* ======== Hair Volumetric Forces ======== */
struct HairGrid;

View File

@ -1469,6 +1469,7 @@ void BPH_mass_spring_force_face_wind(
/* calculate face normal and area */
area = calc_nor_area_tri(nor, data->X[v1], data->X[v2], data->X[v3]);
/* The force is calculated and split up evenly for each of the three face verts */
factor = effector_scale * area / 3.0f;
world_to_root_v3(data, v1, win, winvec[v1]);
@ -1481,6 +1482,29 @@ void BPH_mass_spring_force_face_wind(
madd_v3_v3fl(data->F[v3], nor, factor * dot_v3v3(win, nor));
}
float BPH_tri_tetra_volume_signed_6x(Implicit_Data *data, int v1, int v2, int v3)
{
/* The result will be 6x the volume */
return volume_tri_tetrahedron_signed_v3_6x(data->X[v1], data->X[v2], data->X[v3]);
}
void BPH_mass_spring_force_pressure(
Implicit_Data *data, int v1, int v2, int v3, float pressure_difference)
{
float nor[3], area;
float factor;
/* calculate face normal and area */
area = calc_nor_area_tri(nor, data->X[v1], data->X[v2], data->X[v3]);
/* The force is calculated and split up evenly for each of the three face verts */
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);
}
static void edge_wind_vertex(const float dir[3],
float length,
float radius,