diff options
-rw-r--r-- | release/scripts/startup/bl_ui/properties_physics_cloth.py | 41 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_cloth.h | 6 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/cloth.c | 172 | ||||
-rw-r--r-- | source/blender/blenloader/intern/versioning_280.c | 14 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_cloth_types.h | 16 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_cloth.c | 170 | ||||
-rw-r--r-- | source/blender/physics/intern/BPH_mass_spring.cpp | 43 |
7 files changed, 454 insertions, 8 deletions
diff --git a/release/scripts/startup/bl_ui/properties_physics_cloth.py b/release/scripts/startup/bl_ui/properties_physics_cloth.py index d5ac140dc98..cd7e99f255c 100644 --- a/release/scripts/startup/bl_ui/properties_physics_cloth.py +++ b/release/scripts/startup/bl_ui/properties_physics_cloth.py @@ -160,6 +160,46 @@ class PHYSICS_PT_cloth_damping(PhysicButtonsPanel, Panel): col = flow.column() col.prop(cloth, "bending_damping", text="Bending") +class PHYSICS_PT_cloth_internal_springs(PhysicButtonsPanel, Panel): + bl_label = "Internal Springs" + 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_internal_springs", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + cloth = context.cloth.settings + md = context.cloth + ob = context.object + + layout.active = cloth.use_internal_springs 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, "internal_spring_max_length", text="Max Spring Creation Length") + col = flow.column() + col.prop(cloth, "internal_spring_max_diversion", text="Max Creation Diversion") + col = flow.column() + col.prop(cloth, "internal_spring_normal_check", text="Check Surface Normals") + col = flow.column() + col.prop(cloth, "internal_tension_stiffness", text="Tension") + col = flow.column() + col.prop(cloth, "internal_compression_stiffness", text="Compression") + + col = flow.column() + col.prop_search(cloth, "vertex_group_intern", ob, "vertex_groups", text="Vertex Group") + col = flow.column() + col.prop(cloth, "internal_tension_stiffness_max", text="Max Tension") + col = flow.column() + col.prop(cloth, "internal_compression_stiffness_max", text="Max Compression") class PHYSICS_PT_cloth_pressure(PhysicButtonsPanel, Panel): bl_label = "Pressure" @@ -422,6 +462,7 @@ classes = ( PHYSICS_PT_cloth_physical_properties, PHYSICS_PT_cloth_stiffness, PHYSICS_PT_cloth_damping, + PHYSICS_PT_cloth_internal_springs, PHYSICS_PT_cloth_pressure, PHYSICS_PT_cloth_cache, PHYSICS_PT_cloth_shape, diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index d59a81c1baf..17de53be42a 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -115,6 +115,7 @@ typedef struct ClothVertex { float shear_stiff; int spring_count; /* how many springs attached? */ float shrink_factor; /* how much to shrink this cloth */ + float internal_stiff; /* internal spring stiffness scaling */ float pressure_factor; /* how much pressure should affect this vertex */ } ClothVertex; @@ -198,8 +199,12 @@ typedef enum { CLOTH_SIMSETTINGS_FLAG_PRESSURE = (1 << 5), /** Use the user defined target volume. */ CLOTH_SIMSETTINGS_FLAG_PRESSURE_VOL = (1 << 6), + /** True if internal spring generation is enabled. */ + CLOTH_SIMSETTINGS_FLAG_INTERNAL_SPRINGS = (1 << 7), /** DEPRECATED, for versioning only. */ CLOTH_SIMSETTINGS_FLAG_SCALING = (1 << 8), + /** Require internal springs to be created between points with opposite normals. */ + CLOTH_SIMSETTINGS_FLAG_INTERNAL_SPRINGS_NORMAL = (1 << 9), /** Edit cache in edit-mode. */ CLOTH_SIMSETTINGS_FLAG_CCACHE_EDIT = (1 << 12), /** Don't allow spring compression. */ @@ -230,6 +235,7 @@ typedef enum { CLOTH_SPRING_TYPE_GOAL = (1 << 4), CLOTH_SPRING_TYPE_SEWING = (1 << 5), CLOTH_SPRING_TYPE_BENDING_HAIR = (1 << 6), + CLOTH_SPRING_TYPE_INTERNAL = (1 << 7), } CLOTH_SPRING_TYPES; /* SPRING FLAGS */ diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index d80fae29cc8..c26800aefba 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -31,6 +31,7 @@ #include "BLI_utildefines.h" #include "BLI_math.h" +#include "BLI_rand.h" #include "BLI_edgehash.h" #include "BLI_linklist.h" @@ -130,6 +131,16 @@ void cloth_init(ClothModifierData *clmd) clmd->sim_parms->eff_force_scale = 1000.0; clmd->sim_parms->eff_wind_scale = 250.0; + /* Internal spring settings */ + clmd->sim_parms->internal_spring_max_length = 0.0f; + clmd->sim_parms->internal_spring_max_diversion = M_PI / 4.0f; + clmd->sim_parms->internal_tension = 15.0f; + clmd->sim_parms->max_internal_tension = 15.0f; + clmd->sim_parms->internal_compression = 15.0f; + clmd->sim_parms->max_internal_compression = 15.0f; + clmd->sim_parms->vgroup_intern = 0; + clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_INTERNAL_SPRINGS_NORMAL; + /* Pressure settings */ clmd->sim_parms->uniform_pressure_force = 0.0f; clmd->sim_parms->target_volume = 0.0f; @@ -654,7 +665,7 @@ int cloth_uses_vgroup(ClothModifierData *clmd) (clmd->coll_parms->vgroup_selfcol > 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)); + (clmd->sim_parms->vgroup_intern > 0) || (clmd->sim_parms->vgroup_mass > 0)); } /** @@ -729,8 +740,14 @@ static void cloth_apply_vgroup(ClothModifierData *clmd, Mesh *mesh) verts->shrink_factor = dvert->dw[j].weight; } + if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_intern - 1)) { + /* Used to define the stiffness weight on the internal spring connected to this vertex. + */ + verts->internal_stiff = 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 */ + /* Used to define how much the pressure settings should affect the given vertex. */ verts->pressure_factor = dvert->dw[j].weight; } } @@ -1144,6 +1161,11 @@ static void cloth_update_springs(ClothModifierData *clmd) cloth->verts[spring->ij].bend_stiff) / 2.0f; } + else if (spring->type & CLOTH_SPRING_TYPE_INTERNAL) { + spring->lin_stiffness = (cloth->verts[spring->kl].internal_stiff + + cloth->verts[spring->ij].internal_stiff) / + 2.0f; + } else if (spring->type == CLOTH_SPRING_TYPE_BENDING_HAIR) { ClothVertex *v1 = &cloth->verts[spring->ij]; ClothVertex *v2 = &cloth->verts[spring->kl]; @@ -1208,8 +1230,8 @@ static void cloth_update_spring_lengths(ClothModifierData *clmd, Mesh *mesh) ClothSpring *spring = search->link; if (spring->type != CLOTH_SPRING_TYPE_SEWING) { - if (spring->type & - (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SHEAR | CLOTH_SPRING_TYPE_BENDING)) { + if (spring->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SHEAR | + CLOTH_SPRING_TYPE_BENDING | CLOTH_SPRING_TYPE_INTERNAL)) { shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl); } else { @@ -1385,6 +1407,85 @@ BLI_INLINE bool cloth_bend_set_poly_vert_array(int **poly, int len, const MLoop return true; } +static bool find_internal_spring_target_vertex(BVHTreeFromMesh *treedata, + unsigned int v_idx, + RNG *rng, + float max_length, + float max_diversion, + bool check_normal, + unsigned int *r_tar_v_idx) +{ + float co[3], no[3], new_co[3]; + float radius; + + copy_v3_v3(co, treedata->vert[v_idx].co); + normal_short_to_float_v3(no, treedata->vert[v_idx].no); + negate_v3(no); + + float vec_len = sin(max_diversion); + float offset[3]; + + offset[0] = 0.5f - BLI_rng_get_float(rng); + offset[1] = 0.5f - BLI_rng_get_float(rng); + offset[2] = 0.5f - BLI_rng_get_float(rng); + + normalize_v3(offset); + mul_v3_fl(offset, vec_len); + add_v3_v3(no, offset); + normalize_v3(no); + + /* Nudge the start point so we do not hit it with the ray. */ + copy_v3_v3(new_co, no); + mul_v3_fl(new_co, FLT_EPSILON); + add_v3_v3(new_co, co); + + radius = 0.0f; + if (max_length == 0.0f) { + max_length = FLT_MAX; + } + + BVHTreeRayHit rayhit = {0}; + rayhit.index = -1; + rayhit.dist = max_length; + + BLI_bvhtree_ray_cast( + treedata->tree, new_co, no, radius, &rayhit, treedata->raycast_callback, treedata); + + unsigned int vert_idx = -1; + const MLoop *mloop = treedata->loop; + const MLoopTri *lt = NULL; + + if (rayhit.index != -1 && rayhit.dist <= max_length) { + if (check_normal && dot_v3v3(rayhit.no, no) < 0.0f) { + /* We hit a point that points in the same direction as our starting point. */ + return false; + } + + float min_len = FLT_MAX; + lt = &treedata->looptri[rayhit.index]; + + for (int i = 0; i < 3; i++) { + unsigned int tmp_vert_idx = mloop[lt->tri[i]].v; + if (tmp_vert_idx == v_idx) { + /* We managed to hit ourselves. */ + return false; + } + + float len = len_v3v3(co, rayhit.co); + if (len < min_len) { + min_len = len; + vert_idx = tmp_vert_idx; + } + } + + *r_tar_v_idx = vert_idx; + return true; + } + else { + return false; + } +} + static int cloth_build_springs(ClothModifierData *clmd, Mesh *mesh) { Cloth *cloth = clmd->clothObject; @@ -1431,6 +1532,69 @@ static int cloth_build_springs(ClothModifierData *clmd, Mesh *mesh) } } + bool use_internal_springs = (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_INTERNAL_SPRINGS); + + if (use_internal_springs) { + BVHTreeFromMesh treedata = {NULL}; + unsigned int tar_v_idx; + BLI_bitmap *verts_used = NULL; + RNG *rng; + + verts_used = BLI_BITMAP_NEW(mvert_num * mvert_num, __func__); + BKE_bvhtree_from_mesh_get(&treedata, mesh, BVHTREE_FROM_LOOPTRI, 2); + rng = BLI_rng_new_srandom(0); + + for (int i = 0; i < mvert_num; i++) { + if (find_internal_spring_target_vertex( + &treedata, + i, + rng, + clmd->sim_parms->internal_spring_max_length, + clmd->sim_parms->internal_spring_max_diversion, + (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_INTERNAL_SPRINGS_NORMAL), + &tar_v_idx)) { + if (BLI_BITMAP_TEST_BOOL(verts_used, i * mvert_num + tar_v_idx)) { + continue; + } + + BLI_BITMAP_ENABLE(verts_used, i * mvert_num + tar_v_idx); + BLI_BITMAP_ENABLE(verts_used, tar_v_idx * mvert_num + i); + + spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring"); + + if (spring) { + spring_verts_ordered_set(spring, i, tar_v_idx); + + shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl); + spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, + cloth->verts[spring->ij].xrest) * + shrink_factor; + spring->lin_stiffness = (cloth->verts[spring->kl].internal_stiff + + cloth->verts[spring->ij].internal_stiff) / + 2.0f; + spring->type = CLOTH_SPRING_TYPE_INTERNAL; + + spring->flags = 0; + + BLI_linklist_prepend(&cloth->springs, spring); + + if (spring_ref) { + spring_ref[i].spring = spring; + } + } + else { + cloth_free_errorsprings(cloth, edgelist, spring_ref); + MEM_freeN(verts_used); + free_bvhtree_from_mesh(&treedata); + return 0; + } + } + } + MEM_freeN(verts_used); + free_bvhtree_from_mesh(&treedata); + BLI_rng_free(rng); + } + clmd->sim_parms->avg_spring_len = 0.0f; for (int i = 0; i < mvert_num; i++) { cloth->verts[i].avg_spring_len = 0.0f; diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 6c8b14ad5c7..5c7fda67ff0 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -4268,5 +4268,19 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) { /* Versioning code until next subversion bump goes here. */ + /* Cloth internal springs */ + 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->internal_tension = 15.0f; + clmd->sim_parms->max_internal_tension = 15.0f; + clmd->sim_parms->internal_compression = 15.0f; + clmd->sim_parms->max_internal_compression = 15.0f; + clmd->sim_parms->internal_spring_max_diversion = M_PI / 4.0f; + } + } + } } } diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h index aca29fe1bdd..8f3a26cf9c0 100644 --- a/source/blender/makesdna/DNA_cloth_types.h +++ b/source/blender/makesdna/DNA_cloth_types.h @@ -119,7 +119,6 @@ typedef struct ClothSimSettings { float bending_damping; /** Size of voxel grid cells for continuum dynamics. */ float voxel_cell_size; - char _pad[4]; /** Number of time steps per frame. */ int stepsPerFrame; @@ -145,7 +144,6 @@ typedef struct ClothSimSettings { short presets; short reset; - char _pad0[4]; struct EffectorWeights *effector_weights; short bending_model; @@ -161,6 +159,20 @@ typedef struct ClothSimSettings { float compression_damp; /** Mechanical damping of shear springs. */ float shear_damp; + + /** The maximum lenght an internal spring can have during creation. */ + float internal_spring_max_length; + /** How much the interal spring can diverge from the vertex normal during creation. */ + float internal_spring_max_diversion; + /** Vertex group for scaling structural stiffness. */ + short vgroup_intern; + char _pad1[2]; + float internal_tension; + float internal_compression; + float max_internal_tension; + float max_internal_compression; + char _pad0[4]; + } ClothSimSettings; typedef struct ClothCollSettings { diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c index 9f6f15b8379..c000e1059e6 100644 --- a/source/blender/makesrna/intern/rna_cloth.c +++ b/source/blender/makesrna/intern/rna_cloth.c @@ -29,6 +29,8 @@ #include "rna_internal.h" +#include "BLI_math.h" + #include "BKE_cloth.h" #include "BKE_modifier.h" @@ -201,6 +203,54 @@ static void rna_ClothSettings_shrink_max_set(struct PointerRNA *ptr, float value settings->shrink_max = value; } +static void rna_ClothSettings_internal_tension_set(struct PointerRNA *ptr, float value) +{ + ClothSimSettings *settings = (ClothSimSettings *)ptr->data; + + settings->internal_tension = value; + + /* check for max clipping */ + if (value > settings->max_internal_tension) { + settings->max_internal_tension = value; + } +} + +static void rna_ClothSettings_max_internal_tension_set(struct PointerRNA *ptr, float value) +{ + ClothSimSettings *settings = (ClothSimSettings *)ptr->data; + + /* check for clipping */ + if (value < settings->internal_tension) { + value = settings->internal_tension; + } + + settings->max_internal_tension = value; +} + +static void rna_ClothSettings_internal_compression_set(struct PointerRNA *ptr, float value) +{ + ClothSimSettings *settings = (ClothSimSettings *)ptr->data; + + settings->internal_compression = value; + + /* check for max clipping */ + if (value > settings->max_internal_compression) { + settings->max_internal_compression = value; + } +} + +static void rna_ClothSettings_max_internal_compression_set(struct PointerRNA *ptr, float value) +{ + ClothSimSettings *settings = (ClothSimSettings *)ptr->data; + + /* check for clipping */ + if (value < settings->internal_compression) { + value = settings->internal_compression; + } + + settings->max_internal_compression = value; +} + static void rna_ClothSettings_mass_vgroup_get(PointerRNA *ptr, char *value) { ClothSimSettings *sim = (ClothSimSettings *)ptr->data; @@ -291,6 +341,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_internal_vgroup_get(PointerRNA *ptr, char *value) +{ + ClothSimSettings *sim = (ClothSimSettings *)ptr->data; + rna_object_vgroup_name_index_get(ptr, value, sim->vgroup_intern); +} + +static int rna_ClothSettings_internal_vgroup_length(PointerRNA *ptr) +{ + ClothSimSettings *sim = (ClothSimSettings *)ptr->data; + return rna_object_vgroup_name_index_length(ptr, sim->vgroup_intern); +} + +static void rna_ClothSettings_internal_vgroup_set(PointerRNA *ptr, const char *value) +{ + ClothSimSettings *sim = (ClothSimSettings *)ptr->data; + rna_object_vgroup_name_index_set(ptr, value, &sim->vgroup_intern); +} + static void rna_ClothSettings_pressure_vgroup_get(PointerRNA *ptr, char *value) { ClothSimSettings *sim = (ClothSimSettings *)ptr->data; @@ -393,6 +461,18 @@ static char *rna_ClothCollisionSettings_path(PointerRNA *ptr) } } +static int rna_ClothSettings_internal_editable(struct PointerRNA *ptr, const char **r_info) +{ + ClothSimSettings *sim = (ClothSimSettings *)ptr->data; + + if (sim && (sim->bending_model == CLOTH_BENDING_LINEAR)) { + *r_info = "Only available with angular bending springs."; + return 0; + } + + return sim ? PROP_EDITABLE : 0; +} + #else static void rna_def_cloth_solver_result(BlenderRNA *brna) @@ -794,6 +874,96 @@ 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); + prop = RNA_def_property(srna, "use_internal_springs", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", CLOTH_SIMSETTINGS_FLAG_INTERNAL_SPRINGS); + RNA_def_property_ui_text(prop, + "Create Internal Springs", + "Simulate an internal volume structure by creating springs connecting " + "the opposite sides of the mesh"); + RNA_def_property_update(prop, 0, "rna_cloth_update"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + + prop = RNA_def_property(srna, "internal_spring_normal_check", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, NULL, "flags", CLOTH_SIMSETTINGS_FLAG_INTERNAL_SPRINGS_NORMAL); + RNA_def_property_ui_text(prop, + "Check Internal Spring Normals", + "Require the points the internal springs connect to have opposite " + "normal directions"); + RNA_def_property_editable_func(prop, "rna_ClothSettings_internal_editable"); + RNA_def_property_update(prop, 0, "rna_cloth_update"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + + prop = RNA_def_property(srna, "internal_spring_max_length", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "internal_spring_max_length"); + RNA_def_property_range(prop, 0.0f, 1000.0f); + RNA_def_property_ui_text( + prop, + "Internal Spring Max Length", + "The maximum length an internal spring can have during creation. If the distance between " + "internal points is greater than this, no internal spring will be created between these " + "points. " + "A length of zero means that there is no length limit"); + RNA_def_property_editable_func(prop, "rna_ClothSettings_internal_editable"); + RNA_def_property_update(prop, 0, "rna_cloth_update"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + + prop = RNA_def_property(srna, "internal_spring_max_diversion", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "internal_spring_max_diversion"); + RNA_def_property_range(prop, 0.0f, M_PI / 4.0f); + RNA_def_property_ui_text(prop, + "Internal Spring Max Diversion", + "How much the rays used to connect the internal points can diverge " + "from the vertex normal"); + RNA_def_property_editable_func(prop, "rna_ClothSettings_internal_editable"); + RNA_def_property_update(prop, 0, "rna_cloth_update"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + + prop = RNA_def_property(srna, "internal_tension_stiffness", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "internal_tension"); + RNA_def_property_range(prop, 0.0f, 10000.0f); + RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_internal_tension_set", NULL); + RNA_def_property_ui_text(prop, "Tension Stiffness", "How much the material resists stretching"); + RNA_def_property_editable_func(prop, "rna_ClothSettings_internal_editable"); + RNA_def_property_update(prop, 0, "rna_cloth_update"); + + prop = RNA_def_property(srna, "internal_tension_stiffness_max", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "max_internal_tension"); + RNA_def_property_range(prop, 0.0f, 10000.0f); + RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_max_internal_tension_set", NULL); + RNA_def_property_ui_text(prop, "Tension Stiffness Maximum", "Maximum tension stiffness value"); + RNA_def_property_editable_func(prop, "rna_ClothSettings_internal_editable"); + RNA_def_property_update(prop, 0, "rna_cloth_update"); + + prop = RNA_def_property(srna, "internal_compression_stiffness", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "internal_compression"); + RNA_def_property_range(prop, 0.0f, 10000.0f); + RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_internal_compression_set", NULL); + RNA_def_property_ui_text( + prop, "Compression Stiffness", "How much the material resists compression"); + RNA_def_property_editable_func(prop, "rna_ClothSettings_internal_editable"); + RNA_def_property_update(prop, 0, "rna_cloth_update"); + + prop = RNA_def_property(srna, "internal_compression_stiffness_max", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "max_internal_compression"); + RNA_def_property_range(prop, 0.0f, 10000.0f); + RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_max_internal_compression_set", NULL); + RNA_def_property_ui_text( + prop, "Compression Stiffness Maximum", "Maximum compression stiffness value"); + RNA_def_property_editable_func(prop, "rna_ClothSettings_internal_editable"); + RNA_def_property_update(prop, 0, "rna_cloth_update"); + + prop = RNA_def_property(srna, "vertex_group_intern", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, + "rna_ClothSettings_internal_vgroup_get", + "rna_ClothSettings_internal_vgroup_length", + "rna_ClothSettings_internal_vgroup_set"); + RNA_def_property_ui_text(prop, + "Internal Springs Vertex Group", + "Vertex group for fine control over the internal spring stiffness"); + RNA_def_property_editable_func(prop, "rna_ClothSettings_internal_editable"); + RNA_def_property_update(prop, 0, "rna_cloth_update"); + /* Pressure */ prop = RNA_def_property(srna, "use_pressure", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp index 7521efa5cbd..999cefde104 100644 --- a/source/blender/physics/intern/BPH_mass_spring.cpp +++ b/source/blender/physics/intern/BPH_mass_spring.cpp @@ -427,7 +427,8 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s) } /* Calculate force of structural + shear springs. */ - if (s->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SEWING)) { + if (s->type & + (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SEWING | CLOTH_SPRING_TYPE_INTERNAL)) { #ifdef CLOTH_FORCE_SPRING_STRUCTURAL float k_tension, scaling_tension; @@ -453,7 +454,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s) false, parms->max_sewing); } - else { + else if (s->type & CLOTH_SPRING_TYPE_STRUCTURAL) { float k_compression, scaling_compression; scaling_compression = parms->compression + s->lin_stiffness * fabsf(parms->max_compression - parms->compression); @@ -471,6 +472,44 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s) using_angular, 0.0f); } + else { + /* CLOTH_SPRING_TYPE_INTERNAL */ + BLI_assert(s->type & CLOTH_SPRING_TYPE_INTERNAL); + + scaling_tension = parms->internal_tension + + s->lin_stiffness * + fabsf(parms->max_internal_tension - parms->internal_tension); + k_tension = scaling_tension / (parms->avg_spring_len + FLT_EPSILON); + float scaling_compression = parms->internal_compression + + s->lin_stiffness * fabsf(parms->max_internal_compression - + parms->internal_compression); + float k_compression = scaling_compression / (parms->avg_spring_len + FLT_EPSILON); + + float k_tension_damp = parms->tension_damp; + float k_compression_damp = parms->compression_damp; + + if (k_tension == 0.0f) { + /* No damping so it behaves as if no tension spring was there at all. */ + k_tension_damp = 0.0f; + } + + if (k_compression == 0.0f) { + /* No damping so it behaves as if no compression spring was there at all. */ + k_compression_damp = 0.0f; + } + + BPH_mass_spring_force_spring_linear(data, + s->ij, + s->kl, + s->restlen, + k_tension, + k_tension_damp, + k_compression, + k_compression_damp, + resist_compress, + using_angular, + 0.0f); + } #endif } else if (s->type & CLOTH_SPRING_TYPE_SHEAR) { |