diff options
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_cloth.h | 28 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/cloth.c | 417 | ||||
-rw-r--r-- | source/blender/physics/intern/BPH_mass_spring.cpp | 35 | ||||
-rw-r--r-- | source/blender/physics/intern/implicit.h | 5 | ||||
-rw-r--r-- | source/blender/physics/intern/implicit_blender.c | 138 |
5 files changed, 495 insertions, 128 deletions
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index a099ae46d78..baf60397504 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -133,11 +133,17 @@ ClothVertex; typedef struct ClothSpring { int ij; /* Pij from the paper, one end of the spring. */ int kl; /* Pkl from the paper, one end of the spring. */ - int mn; - float restlen; /* The original length of the spring. */ - int type; /* types defined in BKE_cloth.h ("springType") */ - int flags; /* defined in BKE_cloth.h, e.g. deactivated due to tearing */ - float stiffness; /* stiffness factor from the vertex groups */ + int mn; /* For hair springs: third vertex index; For bending springs: edge index; */ + int *pa; /* Array of vert indices for poly a (for bending springs). */ + int *pb; /* Array of vert indices for poly b (for bending springs). */ + int la; /* Length of *pa. */ + int lb; /* Length of *pb. */ + float restlen; /* The original length of the spring. */ + float restang; /* The original angle of the bending springs. */ + int type; /* Types defined in BKE_cloth.h ("springType"). */ + int flags; /* Defined in BKE_cloth.h, e.g. deactivated due to tearing. */ + float lin_stiffness; /* Linear stiffness factor from the vertex groups. */ + float ang_stiffness; /* Angular stiffness factor from the vertex groups. */ float editrestlen; /* angular bending spring target and derivatives */ @@ -186,12 +192,12 @@ typedef enum { /* Spring types as defined in the paper.*/ typedef enum { - CLOTH_SPRING_TYPE_STRUCTURAL = (1 << 1), - CLOTH_SPRING_TYPE_SHEAR = (1 << 2), - CLOTH_SPRING_TYPE_BENDING = (1 << 3), - CLOTH_SPRING_TYPE_GOAL = (1 << 4), - CLOTH_SPRING_TYPE_SEWING = (1 << 5), - CLOTH_SPRING_TYPE_BENDING_ANG = (1 << 6), + CLOTH_SPRING_TYPE_STRUCTURAL = (1 << 1), + CLOTH_SPRING_TYPE_SHEAR = (1 << 2), + CLOTH_SPRING_TYPE_BENDING = (1 << 3), + CLOTH_SPRING_TYPE_GOAL = (1 << 4), + CLOTH_SPRING_TYPE_SEWING = (1 << 5), + CLOTH_SPRING_TYPE_BENDING_HAIR = (1 << 6), } CLOTH_SPRING_TYPES; /* SPRING FLAGS */ diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 54236785509..ce723d4a7f2 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -68,6 +68,12 @@ static void cloth_update_spring_lengths( ClothModifierData *clmd, Mesh *mesh ); static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh ); static void cloth_apply_vgroup ( ClothModifierData *clmd, Mesh *mesh ); +typedef struct BendSpringRef { + int index; + int polys; + ClothSpring *spring; +} BendSpringRef; + /****************************************************************************** * * External interface called by modifier.c clothModifier functions. @@ -536,6 +542,9 @@ void cloth_free_modifier(ClothModifierData *clmd ) while (search) { ClothSpring *spring = search->link; + MEM_SAFE_FREE(spring->pa); + MEM_SAFE_FREE(spring->pb); + MEM_freeN ( spring ); search = search->next; } @@ -602,6 +611,9 @@ void cloth_free_modifier_extern(ClothModifierData *clmd ) while (search) { ClothSpring *spring = search->link; + MEM_SAFE_FREE(spring->pa); + MEM_SAFE_FREE(spring->pb); + MEM_freeN ( spring ); search = search->next; } @@ -961,13 +973,16 @@ static void cloth_free_edgelist(LinkNodePair *edgelist, unsigned int mvert_num) } } -static void cloth_free_errorsprings(Cloth *cloth, LinkNodePair *edgelist) +static void cloth_free_errorsprings(Cloth *cloth, LinkNodePair *edgelist, BendSpringRef *spring_ref) { if ( cloth->springs != NULL ) { LinkNode *search = cloth->springs; while (search) { ClothSpring *spring = search->link; + MEM_SAFE_FREE(spring->pa); + MEM_SAFE_FREE(spring->pb); + MEM_freeN ( spring ); search = search->next; } @@ -978,12 +993,49 @@ static void cloth_free_errorsprings(Cloth *cloth, LinkNodePair *edgelist) cloth_free_edgelist(edgelist, cloth->mvert_num); + MEM_SAFE_FREE(spring_ref); + if (cloth->edgeset) { BLI_edgeset_free(cloth->edgeset); cloth->edgeset = NULL; } } +BLI_INLINE void cloth_bend_poly_dir(ClothVertex *verts, int i, int j, int *inds, int len, float r_dir[3]) +{ + float cent[3] = {0}; + float fact = 1.0f / len; + + for (int x = 0; x < len; x++) { + madd_v3_v3fl(cent, verts[inds[x]].xrest, fact); + } + + normal_tri_v3(r_dir, verts[i].xrest, verts[j].xrest, cent); +} + +static float cloth_spring_angle(ClothVertex *verts, int i, int j, int *i_a, int *i_b, int len_a, int len_b) +{ + float dir_a[3], dir_b[3]; + float tmp[3], vec_e[3]; + float sin, cos; + + /* Poly vectors. */ + cloth_bend_poly_dir(verts, j, i, i_a, len_a, dir_a); + cloth_bend_poly_dir(verts, i, j, i_b, len_b, dir_b); + + /* Edge vector. */ + sub_v3_v3v3(vec_e, verts[i].xrest, verts[j].xrest); + normalize_v3(vec_e); + + /* Compute angle. */ + cos = dot_v3v3(dir_a, dir_b); + + cross_v3_v3v3(tmp, dir_a, dir_b); + sin = dot_v3v3(tmp, vec_e); + + return atan2f(sin, cos); +} + static void cloth_hair_update_bending_targets(ClothModifierData *clmd) { Cloth *cloth = clmd->clothObject; @@ -1008,7 +1060,7 @@ static void cloth_hair_update_bending_targets(ClothModifierData *clmd) ClothHairData *hair_ij, *hair_kl; bool is_root = spring->kl != prev_mn; - if (spring->type != CLOTH_SPRING_TYPE_BENDING_ANG) { + if (spring->type != CLOTH_SPRING_TYPE_BENDING_HAIR) { continue; } @@ -1083,7 +1135,7 @@ static void cloth_hair_update_bending_rest_targets(ClothModifierData *clmd) ClothHairData *hair_ij, *hair_kl; bool is_root = spring->kl != prev_mn; - if (spring->type != CLOTH_SPRING_TYPE_BENDING_ANG) { + if (spring->type != CLOTH_SPRING_TYPE_BENDING_HAIR) { continue; } @@ -1123,18 +1175,24 @@ static void cloth_update_springs( ClothModifierData *clmd ) while (search) { ClothSpring *spring = search->link; - spring->stiffness = 0.0f; + spring->lin_stiffness = 0.0f; + + if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) { + if (spring->type & CLOTH_SPRING_TYPE_BENDING) { + spring->ang_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; + } + } - if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) { - spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f; + if (spring->type & CLOTH_SPRING_TYPE_STRUCTURAL) { + spring->lin_stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f; } - else if (spring->type == CLOTH_SPRING_TYPE_SHEAR) { - spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f; + else if (spring->type & CLOTH_SPRING_TYPE_SHEAR) { + spring->lin_stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f; } else if (spring->type == CLOTH_SPRING_TYPE_BENDING) { - spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; + spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; } - else if (spring->type == CLOTH_SPRING_TYPE_BENDING_ANG) { + else if (spring->type == CLOTH_SPRING_TYPE_BENDING_HAIR) { ClothVertex *v1 = &cloth->verts[spring->ij]; ClothVertex *v2 = &cloth->verts[spring->kl]; if (clmd->hairdata) { @@ -1142,7 +1200,7 @@ static void cloth_update_springs( ClothModifierData *clmd ) v1->bend_stiff = clmd->hairdata[spring->ij].bending_stiffness; v2->bend_stiff = clmd->hairdata[spring->kl].bending_stiffness; } - spring->stiffness = (v1->bend_stiff + v2->bend_stiff) / 2.0f; + spring->lin_stiffness = (v1->bend_stiff + v2->bend_stiff) / 2.0f; } else if (spring->type == CLOTH_SPRING_TYPE_GOAL) { /* Warning: Appending NEW goal springs does not work because implicit solver would need reset! */ @@ -1197,16 +1255,23 @@ static void cloth_update_spring_lengths( ClothModifierData *clmd, Mesh *mesh ) while (search) { 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_SEWING) { + if (spring->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SHEAR | CLOTH_SPRING_TYPE_BENDING)) { shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl); - else + } + else { shrink_factor = 1.0f; + } spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor; + + if (spring->type & CLOTH_SPRING_TYPE_BENDING) { + spring->restang = cloth_spring_angle(cloth->verts, spring->ij, spring->kl, + spring->pa, spring->pb, spring->la, spring->lb); + } } - if ( spring->type == CLOTH_SPRING_TYPE_STRUCTURAL ) { + if (spring->type & CLOTH_SPRING_TYPE_STRUCTURAL) { clmd->sim_parms->avg_spring_len += spring->restlen; cloth->verts[spring->ij].avg_spring_len += spring->restlen; cloth->verts[spring->kl].avg_spring_len += spring->restlen; @@ -1216,12 +1281,14 @@ static void cloth_update_spring_lengths( ClothModifierData *clmd, Mesh *mesh ) search = search->next; } - if (struct_springs > 0) + if (struct_springs > 0) { clmd->sim_parms->avg_spring_len /= struct_springs; + } for (i = 0; i < mvert_num; i++) { - if (cloth->verts[i].spring_count > 0) + if (cloth->verts[i].spring_count > 0) { cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count); + } } } @@ -1260,12 +1327,103 @@ void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3] mul_m3_m3m3(mat, rot, mat); } +/* Add a shear and a bend spring between two verts within a poly. */ +static bool cloth_add_shear_bend_spring(ClothModifierData *clmd, LinkNodePair *edgelist, + const MLoop *mloop, const MPoly *mpoly, int i, int j, int k) +{ + Cloth *cloth = clmd->clothObject; + ClothSpring *spring; + const MLoop *tmp_loop; + float shrink_factor; + int x, y; + + /* Combined shear/bend properties. */ + spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring"); + + if (!spring) { + return false; + } + + spring_verts_ordered_set(spring, + mloop[mpoly[i].loopstart + j].v, + mloop[mpoly[i].loopstart + k].v); + + 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->type |= CLOTH_SPRING_TYPE_SHEAR; + spring->lin_stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f; + + if (edgelist) { + BLI_linklist_append(&edgelist[spring->ij], spring); + BLI_linklist_append(&edgelist[spring->kl], spring); + } + + /* Bending specific properties. */ + if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) { + spring->type |= CLOTH_SPRING_TYPE_BENDING; + + spring->la = k - j + 1; + spring->lb = mpoly[i].totloop - k + j + 1; + + spring->pa = MEM_mallocN(sizeof(*spring->pa) * spring->la, "spring poly"); + if (!spring->pa) { + return false; + } + + spring->pb = MEM_mallocN(sizeof(*spring->pb) * spring->lb, "spring poly"); + if (!spring->pb) { + return false; + } + + tmp_loop = mloop + mpoly[i].loopstart; + + for (x = 0; x < spring->la; x++) { + spring->pa[x] = tmp_loop[j + x].v; + } + + for (x = 0; x <= j; x++) { + spring->pb[x] = tmp_loop[x].v; + } + + for (y = k; y < mpoly[i].totloop; x++, y++) { + spring->pb[x] = tmp_loop[y].v; + } + + spring->mn = -1; + + spring->restang = cloth_spring_angle(cloth->verts, spring->ij, spring->kl, + spring->pa, spring->pb, spring->la, spring->lb); + + spring->ang_stiffness = (cloth->verts[spring->ij].bend_stiff + cloth->verts[spring->kl].bend_stiff) / 2.0f; + } + + BLI_linklist_prepend(&cloth->springs, spring); + + return true; +} + +BLI_INLINE bool cloth_bend_set_poly_vert_array(int **poly, int len, const MLoop *mloop) +{ + int *p = MEM_mallocN(sizeof(int) * len, "spring poly"); + + if (!p) { + return false; + } + + for (int i = 0; i < len; i++, mloop++) { + p[i] = mloop->v; + } + + *poly = p; + + return true; +} + static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh ) { Cloth *cloth = clmd->clothObject; ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL; unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0, struct_springs_real = 0; - unsigned int i = 0; unsigned int mvert_num = (unsigned int)mesh->totvert; unsigned int numedges = (unsigned int)mesh->totedge; unsigned int numpolys = (unsigned int)mesh->totpoly; @@ -1274,9 +1432,10 @@ static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh ) const MPoly *mpoly = mesh->mpoly; const MLoop *mloop = mesh->mloop; int index2 = 0; // our second vertex index - LinkNodePair *edgelist; + LinkNodePair *edgelist = NULL; EdgeSet *edgeset = NULL; LinkNode *search = NULL, *search2 = NULL; + BendSpringRef *spring_ref = NULL; // error handling if ( numedges==0 ) @@ -1290,13 +1449,23 @@ static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh ) cloth->springs = NULL; cloth->edgeset = NULL; - edgelist = MEM_callocN(sizeof(*edgelist) * mvert_num, "cloth_edgelist_alloc" ); + if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) { + spring_ref = MEM_callocN(sizeof(*spring_ref) * numedges, "temp bend spring reference"); - if (!edgelist) - return 0; + if (!spring_ref) { + return 0; + } + } + else { + edgelist = MEM_callocN(sizeof(*edgelist) * mvert_num, "cloth_edgelist_alloc" ); + + if (!edgelist) { + return 0; + } + } - // structural springs - for ( i = 0; i < numedges; i++ ) { + /* Structural springs. */ + for (int i = 0; i < numedges; i++) { spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if ( spring ) { @@ -1304,13 +1473,13 @@ static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh ) if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW && medge[i].flag & ME_LOOSEEDGE) { // handle sewing (loose edges will be pulled together) spring->restlen = 0.0f; - spring->stiffness = 1.0f; + spring->lin_stiffness = 1.0f; spring->type = CLOTH_SPRING_TYPE_SEWING; } else { 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->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f; + spring->lin_stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f; spring->type = CLOTH_SPRING_TYPE_STRUCTURAL; clmd->sim_parms->avg_spring_len += spring->restlen; @@ -1325,9 +1494,13 @@ static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh ) struct_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); + + if (spring_ref) { + spring_ref[i].spring = spring; + } } else { - cloth_free_errorsprings(cloth, edgelist); + cloth_free_errorsprings(cloth, edgelist, spring_ref); return 0; } } @@ -1335,86 +1508,147 @@ static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh ) if (struct_springs_real > 0) clmd->sim_parms->avg_spring_len /= struct_springs_real; - for (i = 0; i < mvert_num; i++) { + for (int i = 0; i < mvert_num; i++) { if (cloth->verts[i].spring_count > 0) cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count); } - // shear springs - for (i = 0; i < numpolys; i++) { - /* triangle faces already have shear springs due to structural geometry */ - if (mpoly[i].totloop == 4) { - int j; + edgeset = BLI_edgeset_new_ex(__func__, numedges); + cloth->edgeset = edgeset; + + if (numpolys) { + for (int i = 0; i < numpolys; i++) { + /* Shear springs. */ + /* Triangle faces already have shear springs due to structural geometry. */ + if (mpoly[i].totloop > 3) { + for (int j = 1; j < mpoly[i].totloop - 1; j++) { + if (j > 1) { + if (cloth_add_shear_bend_spring(clmd, edgelist, mloop, mpoly, i, 0, j)) { + shear_springs++; + + if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) { + bend_springs++; + } + } + else { + cloth_free_errorsprings(cloth, edgelist, spring_ref); + return 0; + } + } - for (j = 0; j != 2; j++) { - spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring"); + for (int k = j + 2; k < mpoly[i].totloop; k++) { + if (cloth_add_shear_bend_spring(clmd, edgelist, mloop, mpoly, i, j, k)) { + shear_springs++; - if (!spring) { - cloth_free_errorsprings(cloth, edgelist); - return 0; + if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) { + bend_springs++; + } + } + else { + cloth_free_errorsprings(cloth, edgelist, spring_ref); + return 0; + } + } } + } - spring_verts_ordered_set( - spring, - mloop[mpoly[i].loopstart + (j + 0)].v, - mloop[mpoly[i].loopstart + (j + 2)].v); + /* Angular bending springs along struct springs. */ + if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) { + const MLoop *ml = mloop + mpoly[i].loopstart; - 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->type = CLOTH_SPRING_TYPE_SHEAR; - spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f; + for (int j = 0; j < mpoly[i].totloop; j++, ml++) { + BendSpringRef *curr_ref = &spring_ref[ml->e]; + curr_ref->polys++; + + /* First poly found for this edge, store poly index. */ + if (curr_ref->polys == 1) { + curr_ref->index = i; + } + /* Second poly found for this egde, add bending data. */ + else if (curr_ref->polys == 2) { + spring = curr_ref->spring; + + spring->type |= CLOTH_SPRING_TYPE_BENDING; + + spring->la = mpoly[curr_ref->index].totloop; + spring->lb = mpoly[i].totloop; + + if (!cloth_bend_set_poly_vert_array(&spring->pa, spring->la, &mloop[mpoly[curr_ref->index].loopstart]) || + !cloth_bend_set_poly_vert_array(&spring->pb, spring->lb, &mloop[mpoly[i].loopstart])) + { + cloth_free_errorsprings(cloth, edgelist, spring_ref); + return 0; + } + + spring->mn = ml->e; - BLI_linklist_append(&edgelist[spring->ij], spring); - BLI_linklist_append(&edgelist[spring->kl], spring); + spring->restang = cloth_spring_angle(cloth->verts, spring->ij, spring->kl, + spring->pa, spring->pb, spring->la, spring->lb); - shear_springs++; + spring->ang_stiffness = (cloth->verts[spring->ij].bend_stiff + cloth->verts[spring->kl].bend_stiff) / 2.0f; - BLI_linklist_prepend(&cloth->springs, spring); + bend_springs++; + } + /* Third poly found for this egde, remove bending data. */ + else if (curr_ref->polys == 3) { + spring = curr_ref->spring; + + spring->type &= ~CLOTH_SPRING_TYPE_BENDING; + MEM_freeN(spring->pa); + MEM_freeN(spring->pb); + spring->pa = NULL; + spring->pb = NULL; + + bend_springs--; + } + } } } - } - edgeset = BLI_edgeset_new_ex(__func__, numedges); - cloth->edgeset = edgeset; + /* Linear bending springs. */ + if (clmd->sim_parms->bending_model == CLOTH_BENDING_LINEAR) { + search2 = cloth->springs; - if (numpolys) { - // bending springs - search2 = cloth->springs; - for ( i = struct_springs; i < struct_springs+shear_springs; i++ ) { - if ( !search2 ) - break; + for (int i = struct_springs; i < struct_springs+shear_springs; i++) { + if (!search2) { + break; + } - tspring2 = search2->link; - search = edgelist[tspring2->kl].list; - while ( search ) { - tspring = search->link; - index2 = ( ( tspring->ij==tspring2->kl ) ? ( tspring->kl ) : ( tspring->ij ) ); + tspring2 = search2->link; + search = edgelist[tspring2->kl].list; + + while (search) { + tspring = search->link; + index2 = ((tspring->ij == tspring2->kl) ? (tspring->kl) : (tspring->ij)); + + /* Check for existing spring. */ + /* Check also if startpoint is equal to endpoint. */ + if ((index2 != tspring2->ij) && + !BLI_edgeset_haskey(edgeset, tspring2->ij, index2)) + { + spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring"); + + if (!spring) { + cloth_free_errorsprings(cloth, edgelist, spring_ref); + return 0; + } - // check for existing spring - // check also if startpoint is equal to endpoint - if ((index2 != tspring2->ij) && - !BLI_edgeset_haskey(edgeset, tspring2->ij, index2)) - { - spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); + spring_verts_ordered_set(spring, tspring2->ij, index2); + 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->type = CLOTH_SPRING_TYPE_BENDING; + spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; + BLI_edgeset_insert(edgeset, spring->ij, spring->kl); + bend_springs++; - if (!spring) { - cloth_free_errorsprings(cloth, edgelist); - return 0; + BLI_linklist_prepend(&cloth->springs, spring); } - spring_verts_ordered_set(spring, tspring2->ij, index2); - 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->type = CLOTH_SPRING_TYPE_BENDING; - spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; - BLI_edgeset_insert(edgeset, spring->ij, spring->kl); - bend_springs++; - - BLI_linklist_prepend ( &cloth->springs, spring ); + search = search->next; } - search = search->next; + + search2 = search2->next; } - search2 = search2->next; } } else if (struct_springs > 2) { @@ -1429,7 +1663,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh ) spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if (!spring) { - cloth_free_errorsprings(cloth, edgelist); + cloth_free_errorsprings(cloth, edgelist, spring_ref); return 0; } @@ -1437,8 +1671,8 @@ static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh ) spring->kl = tspring->ij; spring->mn = tspring->kl; spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); - spring->type = CLOTH_SPRING_TYPE_BENDING_ANG; - spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; + spring->type = CLOTH_SPRING_TYPE_BENDING_HAIR; + spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); @@ -1466,7 +1700,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh ) spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if (!spring) { - cloth_free_errorsprings(cloth, edgelist); + cloth_free_errorsprings(cloth, edgelist, spring_ref); return 0; } @@ -1474,7 +1708,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh ) spring->kl = tspring->kl; spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_BENDING; - spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; + spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); @@ -1491,17 +1725,18 @@ static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh ) /* note: the edges may already exist so run reinsert */ /* insert other near springs in edgeset AFTER bending springs are calculated (for selfcolls) */ - for (i = 0; i < numedges; i++) { /* struct springs */ + for (int i = 0; i < numedges; i++) { /* struct springs */ BLI_edgeset_add(edgeset, medge[i].v1, medge[i].v2); } - for (i = 0; i < numpolys; i++) { /* edge springs */ + for (int i = 0; i < numpolys; i++) { /* edge springs */ if (mpoly[i].totloop == 4) { BLI_edgeset_add(edgeset, mloop[mpoly[i].loopstart + 0].v, mloop[mpoly[i].loopstart + 2].v); BLI_edgeset_add(edgeset, mloop[mpoly[i].loopstart + 1].v, mloop[mpoly[i].loopstart + 3].v); } } + MEM_SAFE_FREE(spring_ref); cloth->numsprings = struct_springs + shear_springs + bend_springs; diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp index 668e40e71cc..6ea2eeca6f8 100644 --- a/source/blender/physics/intern/BPH_mass_spring.cpp +++ b/source/blender/physics/intern/BPH_mass_spring.cpp @@ -67,7 +67,7 @@ static int cloth_count_nondiag_blocks(Cloth *cloth) for (link = cloth->springs; link; link = link->next) { ClothSpring *spring = (ClothSpring *)link->link; switch (spring->type) { - case CLOTH_SPRING_TYPE_BENDING_ANG: + case CLOTH_SPRING_TYPE_BENDING_HAIR: /* angular bending combines 3 vertices */ nondiag += 3; break; @@ -346,14 +346,29 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s) s->flags &= ~CLOTH_SPRING_FLAG_NEEDED; - // calculate force of structural + shear springs - if ((s->type & CLOTH_SPRING_TYPE_STRUCTURAL) || (s->type & CLOTH_SPRING_TYPE_SEWING)) { + /* Calculate force of bending springs. */ + if (s->type & CLOTH_SPRING_TYPE_BENDING) { +#ifdef CLOTH_FORCE_SPRING_BEND + float k, scaling; + + s->flags |= CLOTH_SPRING_FLAG_NEEDED; + + scaling = parms->bending + s->ang_stiffness * fabsf(parms->max_bend - parms->bending); + k = scaling * s->restlen * 0.1f; /* Multiplying by 0.1, just to scale the forces to more reasonable values. */ + + BPH_mass_spring_force_spring_angular(data, s->ij, s->kl, s->pa, s->pb, s->la, s->lb, + s->restang, k, parms->bending_damping); +#endif + } + + /* Calculate force of structural + shear springs. */ + if (s->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SEWING)) { #ifdef CLOTH_FORCE_SPRING_STRUCTURAL float k_tension, scaling_tension; s->flags |= CLOTH_SPRING_FLAG_NEEDED; - scaling_tension = parms->tension + s->stiffness * fabsf(parms->max_tension - parms->tension); + scaling_tension = parms->tension + s->lin_stiffness * fabsf(parms->max_tension - parms->tension); k_tension = scaling_tension / (parms->avg_spring_len + FLT_EPSILON); if (s->type & CLOTH_SPRING_TYPE_SEWING) { @@ -365,7 +380,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s) } else { float k_compression, scaling_compression; - scaling_compression = parms->compression + s->stiffness * fabsf(parms->max_compression - parms->compression); + scaling_compression = parms->compression + s->lin_stiffness * fabsf(parms->max_compression - parms->compression); k_compression = scaling_compression / (parms->avg_spring_len + FLT_EPSILON); BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, @@ -381,7 +396,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s) s->flags |= CLOTH_SPRING_FLAG_NEEDED; - scaling = parms->shear + s->stiffness * fabsf(parms->max_shear - parms->shear); + scaling = parms->shear + s->lin_stiffness * fabsf(parms->max_shear - parms->shear); k = scaling / (parms->avg_spring_len + FLT_EPSILON); BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->shear_damp, @@ -394,7 +409,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s) s->flags |= CLOTH_SPRING_FLAG_NEEDED; - scaling = parms->bending + s->stiffness * fabsf(parms->max_bend - parms->bending); + scaling = parms->bending + s->lin_stiffness * fabsf(parms->max_bend - parms->bending); kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON)); // Fix for [#45084] for cloth stiffness must have cb proportional to kb @@ -403,7 +418,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s) BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb); #endif } - else if (s->type & CLOTH_SPRING_TYPE_BENDING_ANG) { + else if (s->type & CLOTH_SPRING_TYPE_BENDING_HAIR) { #ifdef CLOTH_FORCE_SPRING_BEND float kb, cb, scaling; @@ -413,14 +428,14 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s) * this is crap, but needed due to cloth/hair mixing ... * max_bend factor is not even used for hair, so ... */ - scaling = s->stiffness * parms->bending; + scaling = s->lin_stiffness * parms->bending; kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON)); // Fix for [#45084] for cloth stiffness must have cb proportional to kb cb = kb * parms->bending_damping; /* XXX assuming same restlen for ij and jk segments here, this can be done correctly for hair later */ - BPH_mass_spring_force_spring_bending_angular(data, s->ij, s->kl, s->mn, s->target, kb, cb); + BPH_mass_spring_force_spring_bending_hair(data, s->ij, s->kl, s->mn, s->target, kb, cb); #if 0 { diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h index ffe9dbbec04..f99812a8aa9 100644 --- a/source/blender/physics/intern/implicit.h +++ b/source/blender/physics/intern/implicit.h @@ -118,10 +118,13 @@ bool BPH_mass_spring_force_spring_linear(struct Implicit_Data *data, int i, int float stiffness_tension, float damping_tension, float stiffness_compression, float damping_compression, bool resist_compress, bool new_compress, float clamp_force); +/* Angular spring force between two polygons */ +bool BPH_mass_spring_force_spring_angular(struct Implicit_Data *data, int i, int j, int *i_a, int *i_b, int len_a, int len_b, + float restang, float stiffness, float damping); /* Bending force, forming a triangle at the base of two structural springs */ bool BPH_mass_spring_force_spring_bending(struct Implicit_Data *data, int i, int j, float restlen, float kb, float cb); /* Angular bending force based on local target vectors */ -bool BPH_mass_spring_force_spring_bending_angular(struct Implicit_Data *data, int i, int j, int k, +bool BPH_mass_spring_force_spring_bending_hair(struct Implicit_Data *data, int i, int j, int k, const float target[3], float stiffness, float damping); /* Global goal spring */ bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data, int i, const float goal_x[3], const float goal_v[3], diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c index 677e566ff39..0d897893ff5 100644 --- a/source/blender/physics/intern/implicit_blender.c +++ b/source/blender/physics/intern/implicit_blender.c @@ -1664,6 +1664,114 @@ bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, flo } } +BLI_INLINE void poly_avg(lfVector *data, int *inds, int len, float r_avg[3]) +{ + float fact = 1.0f / (float)len; + + zero_v3(r_avg); + + for (int i = 0; i < len; i++) { + madd_v3_v3fl(r_avg, data[inds[i]], fact); + } +} + +BLI_INLINE void poly_norm(lfVector *data, int i, int j, int *inds, int len, float r_dir[3]) +{ + float mid[3]; + + poly_avg(data, inds, len, mid); + + normal_tri_v3(r_dir, data[i], data[j], mid); +} + +BLI_INLINE void edge_avg(lfVector *data, int i, int j, float r_avg[3]) +{ + r_avg[0] = (data[i][0] + data[j][0]) * 0.5f; + r_avg[1] = (data[i][1] + data[j][1]) * 0.5f; + r_avg[2] = (data[i][2] + data[j][2]) * 0.5f; +} + +BLI_INLINE void edge_norm(lfVector *data, int i, int j, float r_dir[3]) +{ + sub_v3_v3v3(r_dir, data[i], data[j]); + normalize_v3(r_dir); +} + +BLI_INLINE float bend_angle(float dir_a[3], float dir_b[3], float dir_e[3]) +{ + float cos, sin; + float tmp[3]; + + cos = dot_v3v3(dir_a, dir_b); + + cross_v3_v3v3(tmp, dir_a, dir_b); + sin = dot_v3v3(tmp, dir_e); + + return atan2f(sin, cos); +} + +BLI_INLINE void spring_angle(Implicit_Data *data, int i, int j, int *i_a, int *i_b, int len_a, int len_b, + float r_dir_a[3], float r_dir_b[3], + float *r_angle, float r_vel_a[3], float r_vel_b[3]) +{ + float dir_e[3], vel_e[3]; + + poly_norm(data->X, j, i, i_a, len_a, r_dir_a); + poly_norm(data->X, i, j, i_b, len_b, r_dir_b); + + edge_norm(data->X, i, j, dir_e); + + *r_angle = bend_angle(r_dir_a, r_dir_b, dir_e); + + poly_avg(data->V, i_a, len_a, r_vel_a); + poly_avg(data->V, i_b, len_b, r_vel_b); + + edge_avg(data->V, i, j, vel_e); + + sub_v3_v3(r_vel_a, vel_e); + sub_v3_v3(r_vel_b, vel_e); +} + +/* Angular springs roughly based on the bending model proposed by Baraff and Witkin in "Large Steps in Cloth Simulation". */ +bool BPH_mass_spring_force_spring_angular(Implicit_Data *data, int i, int j, int *i_a, int *i_b, int len_a, int len_b, + float restang, float stiffness, float damping) +{ + float angle, dir_a[3], dir_b[3], vel_a[3], vel_b[3]; + float f_a[3], f_b[3], f_e[3]; + float force; + int x; + + spring_angle(data, i, j, i_a, i_b, len_a, len_b, + dir_a, dir_b, &angle, vel_a, vel_b); + + /* spring force */ + force = stiffness * (angle - restang); + + /* damping force */ + force += -damping * (dot_v3v3(vel_a, dir_a) + dot_v3v3(vel_b, dir_b)); + + mul_v3_v3fl(f_a, dir_a, force / len_a); + mul_v3_v3fl(f_b, dir_b, force / len_b); + + for (x = 0; x < len_a; x++) { + add_v3_v3(data->F[i_a[x]], f_a); + } + + for (x = 0; x < len_b; x++) { + add_v3_v3(data->F[i_b[x]], f_b); + } + + mul_v3_v3fl(f_a, dir_a, force * 0.5f); + mul_v3_v3fl(f_b, dir_b, force * 0.5f); + + add_v3_v3v3(f_e, f_a, f_b); + + sub_v3_v3(data->F[i], f_e); + sub_v3_v3(data->F[j], f_e); + + return true; +} + /* Jacobian of a direction vector. * Basically the part of the differential orthogonal to the direction, * inversely proportional to the length of the edge. @@ -1687,7 +1795,7 @@ BLI_INLINE void spring_grad_dir(Implicit_Data *data, int i, int j, float edge[3] } } -BLI_INLINE void spring_angbend_forces(Implicit_Data *data, int i, int j, int k, +BLI_INLINE void spring_hairbend_forces(Implicit_Data *data, int i, int j, int k, const float goal[3], float stiffness, float damping, int q, const float dx[3], const float dv[3], @@ -1736,7 +1844,7 @@ BLI_INLINE void spring_angbend_forces(Implicit_Data *data, int i, int j, int k, } /* Finite Differences method for estimating the jacobian of the force */ -BLI_INLINE void spring_angbend_estimate_dfdx(Implicit_Data *data, int i, int j, int k, +BLI_INLINE void spring_hairbend_estimate_dfdx(Implicit_Data *data, int i, int j, int k, const float goal[3], float stiffness, float damping, int q, float dfdx[3][3]) @@ -1755,11 +1863,11 @@ BLI_INLINE void spring_angbend_estimate_dfdx(Implicit_Data *data, int i, int j, /* XXX TODO offset targets to account for position dependency */ for (a = 0; a < 3; ++a) { - spring_angbend_forces(data, i, j, k, goal, stiffness, damping, + spring_hairbend_forces(data, i, j, k, goal, stiffness, damping, q, dvec_pos[a], dvec_null[a], f); copy_v3_v3(dfdx[a], f); - spring_angbend_forces(data, i, j, k, goal, stiffness, damping, + spring_hairbend_forces(data, i, j, k, goal, stiffness, damping, q, dvec_neg[a], dvec_null[a], f); sub_v3_v3(dfdx[a], f); @@ -1770,7 +1878,7 @@ BLI_INLINE void spring_angbend_estimate_dfdx(Implicit_Data *data, int i, int j, } /* Finite Differences method for estimating the jacobian of the force */ -BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data, int i, int j, int k, +BLI_INLINE void spring_hairbend_estimate_dfdv(Implicit_Data *data, int i, int j, int k, const float goal[3], float stiffness, float damping, int q, float dfdv[3][3]) @@ -1789,11 +1897,11 @@ BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data, int i, int j, /* XXX TODO offset targets to account for position dependency */ for (a = 0; a < 3; ++a) { - spring_angbend_forces(data, i, j, k, goal, stiffness, damping, + spring_hairbend_forces(data, i, j, k, goal, stiffness, damping, q, dvec_null[a], dvec_pos[a], f); copy_v3_v3(dfdv[a], f); - spring_angbend_forces(data, i, j, k, goal, stiffness, damping, + spring_hairbend_forces(data, i, j, k, goal, stiffness, damping, q, dvec_null[a], dvec_neg[a], f); sub_v3_v3(dfdv[a], f); @@ -1806,7 +1914,7 @@ BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data, int i, int j, /* Angular spring that pulls the vertex toward the local target * See "Artistic Simulation of Curly Hair" (Pixar technical memo #12-03a) */ -bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, int j, int k, +bool BPH_mass_spring_force_spring_bending_hair(Implicit_Data *data, int i, int j, int k, const float target[3], float stiffness, float damping) { float goal[3]; @@ -1822,18 +1930,18 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in world_to_root_v3(data, j, goal, target); - spring_angbend_forces(data, i, j, k, goal, stiffness, damping, k, vecnull, vecnull, fk); + spring_hairbend_forces(data, i, j, k, goal, stiffness, damping, k, vecnull, vecnull, fk); negate_v3_v3(fj, fk); /* counterforce */ - spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, i, dfk_dxi); - spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, j, dfk_dxj); - spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, k, dfk_dxk); + spring_hairbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, i, dfk_dxi); + spring_hairbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, j, dfk_dxj); + spring_hairbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, k, dfk_dxk); copy_m3_m3(dfj_dxi, dfk_dxi); negate_m3(dfj_dxi); copy_m3_m3(dfj_dxj, dfk_dxj); negate_m3(dfj_dxj); - spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, i, dfk_dvi); - spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, j, dfk_dvj); - spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, k, dfk_dvk); + spring_hairbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, i, dfk_dvi); + spring_hairbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, j, dfk_dvj); + spring_hairbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, k, dfk_dvk); copy_m3_m3(dfj_dvi, dfk_dvi); negate_m3(dfj_dvi); copy_m3_m3(dfj_dvj, dfk_dvj); negate_m3(dfj_dvj); |