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:
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
|
@ -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,
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
***************************************************************************************/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue