diff options
author | Sebastian Parborg <darkdefende@gmail.com> | 2019-12-09 21:10:55 +0300 |
---|---|---|
committer | Sebastian Parborg <darkdefende@gmail.com> | 2019-12-09 21:18:10 +0300 |
commit | 62ef59aa0cca736b09192b67cc924180d9c2f9f9 (patch) | |
tree | f0f76383b9536a5186abe0072b1a535e587cef22 /source/blender/blenkernel/intern | |
parent | e77fdc62b75a3b96e4c3ca5c2fc4025d8091ff99 (diff) |
Add the ability to create internal springs to the cloth sim
This can be used to make closed surfaces behave more like a soft body.
Reviewed By: Jacques Lucke
Differential Revision: http://developer.blender.org/D5788
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r-- | source/blender/blenkernel/intern/cloth.c | 172 |
1 files changed, 168 insertions, 4 deletions
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; |