Cloth: Implement angular bending springs

This implements angular bending springs for cloth simulation. This also
adds shearing springs for n-gons.

This angular spring implementation does not include Jacobian matrices,
as the springs can exist between polygons of different vertex counts,
rendering their relationships asymmetrical, and thus impossible to solve
with the current implementation. This means that the bending component
is solved explicitly. However, this is usually not a big problem, as
bending springs contribute less to instability than structural springs.

The the old linear bending model can still be used, and is the default for
existing files, to keep compatibility. However, the new angular bending
model is the default for any new simulation.

This commit makes small breaking changes, in that shearing springs are
now created on n-gons (also in linear bending mode), while n-gons were
previously ignored.

Reviewed By: brecht

Differential Revision: http://developer.blender.org/D3662
This commit is contained in:
Luca Rood 2016-12-05 21:39:29 -02:00
parent e3d31b8dfb
commit b6f0f8a5b5
6 changed files with 505 additions and 138 deletions

@ -1 +1 @@
Subproject commit 371960484a38fc64e0a2635170a41a0d8ab2f6bd
Subproject commit 6c3a46dc113de870a03191e4c0685238b0823acd

View File

@ -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 */

View File

@ -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 (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) {
spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.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;
}
}
else if (spring->type == CLOTH_SPRING_TYPE_SHEAR) {
spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_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->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" );
// structural springs
for ( i = 0; i < numedges; i++ ) {
if (!edgelist) {
return 0;
}
}
/* 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;
for (j = 0; j != 2; j++) {
spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
if (!spring) {
cloth_free_errorsprings(cloth, edgelist);
return 0;
}
spring_verts_ordered_set(
spring,
mloop[mpoly[i].loopstart + (j + 0)].v,
mloop[mpoly[i].loopstart + (j + 2)].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->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f;
BLI_linklist_append(&edgelist[spring->ij], spring);
BLI_linklist_append(&edgelist[spring->kl], spring);
shear_springs++;
BLI_linklist_prepend(&cloth->springs, spring);
}
}
}
edgeset = BLI_edgeset_new_ex(__func__, numedges);
cloth->edgeset = edgeset;
if (numpolys) {
// bending springs
search2 = cloth->springs;
for ( i = struct_springs; i < struct_springs+shear_springs; i++ ) {
if ( !search2 )
break;
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++;
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);
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, 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++;
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++;
BLI_linklist_prepend ( &cloth->springs, spring );
if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
bend_springs++;
}
}
else {
cloth_free_errorsprings(cloth, edgelist, spring_ref);
return 0;
}
}
}
search = search->next;
}
search2 = search2->next;
/* Angular bending springs along struct springs. */
if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
const MLoop *ml = mloop + mpoly[i].loopstart;
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;
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;
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--;
}
}
}
}
/* Linear bending springs. */
if (clmd->sim_parms->bending_model == CLOTH_BENDING_LINEAR) {
search2 = cloth->springs;
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));
/* 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;
}
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++;
BLI_linklist_prepend(&cloth->springs, spring);
}
search = search->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;

View File

@ -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
{

View File

@ -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],

View File

@ -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);