diff options
author | Sebastian Parborg <darkdefende@gmail.com> | 2019-11-27 16:56:16 +0300 |
---|---|---|
committer | Sebastian Parborg <darkdefende@gmail.com> | 2019-11-27 17:01:15 +0300 |
commit | f6cefbef22c8c6583b4927c179dabac3eb57aa22 (patch) | |
tree | 96785e2ee93f34bb14975a53bc2a4e003ee3fb59 | |
parent | eb798de101ac7946e2d719e763ad1f0fd3e26acd (diff) |
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
-rw-r--r-- | release/scripts/startup/bl_ui/properties_physics_cloth.py | 37 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_cloth.h | 7 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/cloth.c | 17 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh_evaluate.c | 4 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_math_geom.h | 3 | ||||
-rw-r--r-- | source/blender/blenlib/intern/math_geom.c | 19 | ||||
-rw-r--r-- | source/blender/blenloader/intern/versioning_280.c | 10 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_parametrizer.c | 5 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_cloth_types.h | 11 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_cloth.c | 40 | ||||
-rw-r--r-- | source/blender/physics/BPH_mass_spring.h | 1 | ||||
-rw-r--r-- | source/blender/physics/intern/BPH_mass_spring.cpp | 69 | ||||
-rw-r--r-- | source/blender/physics/intern/implicit.h | 5 | ||||
-rw-r--r-- | source/blender/physics/intern/implicit_blender.c | 24 |
14 files changed, 242 insertions, 10 deletions
diff --git a/release/scripts/startup/bl_ui/properties_physics_cloth.py b/release/scripts/startup/bl_ui/properties_physics_cloth.py index 3e87c9cd0c0..1921521669e 100644 --- a/release/scripts/startup/bl_ui/properties_physics_cloth.py +++ b/release/scripts/startup/bl_ui/properties_physics_cloth.py @@ -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, diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index 01f94c39215..0543021afef 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -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. */ diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 463cbd4f378..2be312bc4d9 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -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 + ***************************************************************************************/ diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 2b3051b766a..7b655b2d8fc 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -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 diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index eec5d214473..4f8810d50e1 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -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]); diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 27715ed49b5..ba2a8605dec 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -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 diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 8a3ec61bbc8..0cb68cfd7fe 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -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; + } + } + } } } diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c index bb96b4ba10c..e4d73c2b229 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.c +++ b/source/blender/editors/uvedit/uvedit_parametrizer.c @@ -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); diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h index 9cedd8f0ebf..5653e8a0450 100644 --- a/source/blender/makesdna/DNA_cloth_types.h +++ b/source/blender/makesdna/DNA_cloth_types.h @@ -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 */ diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c index e1a06a76235..cf48ed549e6 100644 --- a/source/blender/makesrna/intern/rna_cloth.c +++ b/source/blender/makesrna/intern/rna_cloth.c @@ -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 */ diff --git a/source/blender/physics/BPH_mass_spring.h b/source/blender/physics/BPH_mass_spring.h index c0ceff4d8cf..5a8c78812a4 100644 --- a/source/blender/physics/BPH_mass_spring.h +++ b/source/blender/physics/BPH_mass_spring.h @@ -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 } diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp index c057e74b72b..259eed88756 100644 --- a/source/blender/physics/intern/BPH_mass_spring.cpp +++ b/source/blender/physics/intern/BPH_mass_spring.cpp @@ -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) { diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h index 32416fa01ab..82a3f61e1e1 100644 --- a/source/blender/physics/intern/implicit.h +++ b/source/blender/physics/intern/implicit.h @@ -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; diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c index d8b3f647591..fa093f482f7 100644 --- a/source/blender/physics/intern/implicit_blender.c +++ b/source/blender/physics/intern/implicit_blender.c @@ -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, |