diff options
-rw-r--r-- | source/blender/blenkernel/BKE_cloth.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/cloth.c | 92 | ||||
-rw-r--r-- | source/blender/physics/intern/BPH_mass_spring.cpp | 14 | ||||
-rw-r--r-- | source/blender/physics/intern/implicit.h | 4 | ||||
-rw-r--r-- | source/blender/physics/intern/implicit_blender.c | 44 |
5 files changed, 125 insertions, 33 deletions
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index 571c0ec89a1..838388f428c 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -124,6 +124,7 @@ 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 matrix_index; /* needed for implicit solver (fast lookup) */ int type; /* types defined in BKE_cloth.h ("springType") */ @@ -175,7 +176,8 @@ typedef enum { 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_SEWING = (1 << 5), + CLOTH_SPRING_TYPE_BENDING_ANG = (1 << 6), } CLOTH_SPRING_TYPES; /* SPRING FLAGS */ diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 4132fc86608..1b3b668f524 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -1287,39 +1287,71 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) } } else if (struct_springs > 2) { - /* bending springs for hair strands */ - /* The current algorightm only goes through the edges in order of the mesh edges list */ - /* and makes springs between the outer vert of edges sharing a vertice. This works just */ - /* fine for hair, but not for user generated string meshes. This could/should be later */ - /* extended to work with non-ordered edges so that it can be used for general "rope */ - /* dynamics" without the need for the vertices or edges to be ordered through the length*/ - /* of the strands. -jahka */ - search = cloth->springs; - search2 = search->next; - while (search && search2) { - tspring = search->link; - tspring2 = search2->link; - - if (tspring->ij == tspring2->kl) { - spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); + if (G.debug_value != 1112) { + search = cloth->springs; + search2 = search->next; + while (search && search2) { + tspring = search->link; + tspring2 = search2->link; - if (!spring) { - cloth_free_errorsprings(cloth, edgelist); - return 0; + if (tspring->ij == tspring2->kl) { + spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); + + if (!spring) { + cloth_free_errorsprings(cloth, edgelist); + return 0; + } + + spring->ij = tspring->kl; + spring->kl = tspring->ij; + spring->mn = tspring2->ij; + 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; + bend_springs++; + + BLI_linklist_prepend ( &cloth->springs, spring ); } - - spring->ij = tspring2->ij; - 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; - bend_springs++; - - BLI_linklist_prepend ( &cloth->springs, spring ); + + search = search->next; + search2 = search2->next; + } + } + else { + /* bending springs for hair strands */ + /* The current algorightm only goes through the edges in order of the mesh edges list */ + /* and makes springs between the outer vert of edges sharing a vertice. This works just */ + /* fine for hair, but not for user generated string meshes. This could/should be later */ + /* extended to work with non-ordered edges so that it can be used for general "rope */ + /* dynamics" without the need for the vertices or edges to be ordered through the length*/ + /* of the strands. -jahka */ + search = cloth->springs; + search2 = search->next; + while (search && search2) { + tspring = search->link; + tspring2 = search2->link; + + if (tspring->ij == tspring2->kl) { + spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); + + if (!spring) { + cloth_free_errorsprings(cloth, edgelist); + return 0; + } + + spring->ij = tspring2->ij; + 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; + bend_springs++; + + BLI_linklist_prepend ( &cloth->springs, spring ); + } + + search = search->next; + search2 = search2->next; } - - search = search->next; - search2 = search2->next; } } diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp index db371997632..56de54e4192 100644 --- a/source/blender/physics/intern/BPH_mass_spring.cpp +++ b/source/blender/physics/intern/BPH_mass_spring.cpp @@ -373,7 +373,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, BPH_mass_spring_force_spring_goal(data, s->ij, s->matrix_index, goal_x, goal_v, k, parms->goalfrict * 0.01f, s->f, s->dfdx, s->dfdv); #endif } - else { /* calculate force of bending springs */ + else if (s->type & CLOTH_SPRING_TYPE_BENDING) { /* calculate force of bending springs */ #ifdef CLOTH_FORCE_SPRING_BEND float kb, cb, scaling; @@ -385,6 +385,18 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->matrix_index, s->restlen, kb, cb, s->f, s->dfdx, s->dfdv); #endif } + else if (s->type & CLOTH_SPRING_TYPE_BENDING_ANG) { +#ifdef CLOTH_FORCE_SPRING_BEND + float kb, cb, scaling; + + s->flags |= CLOTH_SPRING_FLAG_NEEDED; + + scaling = parms->bending + s->stiffness * fabsf(parms->max_bend - parms->bending); + cb = kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON)); + + BPH_mass_spring_force_spring_bending_angular(data, s->ij, s->kl, s->matrix_index, s->restlen, kb, cb, s->f, s->dfdx, s->dfdv); +#endif + } } static void hair_get_boundbox(ClothModifierData *clmd, float gmin[3], float gmax[3]) diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h index 3743152cc79..ea9a5b8211a 100644 --- a/source/blender/physics/intern/implicit.h +++ b/source/blender/physics/intern/implicit.h @@ -140,6 +140,10 @@ bool BPH_mass_spring_force_spring_linear(struct Implicit_Data *data, int i, int bool BPH_mass_spring_force_spring_bending(struct Implicit_Data *data, int i, int j, int spring_index, float restlen, float kb, float cb, float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]); +/* 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 spring_index, float restlen, + float stiffness, float damping, + float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]); /* Global goal spring */ bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data, int i, int spring_index, const float goal_x[3], const float goal_v[3], float stiffness, float damping, diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c index bad883d7af3..dd8cab6556f 100644 --- a/source/blender/physics/intern/implicit_blender.c +++ b/source/blender/physics/intern/implicit_blender.c @@ -1181,12 +1181,12 @@ int BPH_mass_spring_init_spring(Implicit_Data *data, int index, int v1, int v2) { int s = data->M[0].vcount + index; /* index from array start */ + /* tfm and S don't have spring entries (diagonal blocks only) */ init_fmatrix(data->bigI + s, v1, v2); init_fmatrix(data->M + s, v1, v2); init_fmatrix(data->dFdX + s, v1, v2); init_fmatrix(data->dFdV + s, v1, v2); init_fmatrix(data->A + s, v1, v2); -// init_fmatrix(data->S + s, v1, v2); // has no off-diagonal spring entries init_fmatrix(data->P + s, v1, v2); init_fmatrix(data->Pinv + s, v1, v2); @@ -1609,6 +1609,48 @@ bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, int } } +/* 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 spring_index, float restlen, + float stiffness, float damping, + float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]) +{ + float target[3], dist[3], extent[3], length, dir[3], vel[3]; + float f[3], dfdx[3][3], dfdv[3][3]; + + target[0] = 0.0f; + target[1] = 0.0f; + target[2] = restlen; + + // calculate elonglation +// spring_length(data, i, j, extent, dir, &length, vel); + sub_v3_v3v3(extent, data->X[j], data->X[i]); + sub_v3_v3v3(vel, data->V[j], data->V[i]); + length = len_v3(extent); + + sub_v3_v3v3(dist, target, extent); + mul_v3_v3fl(f, dist, stiffness); +// mul_v3_v3fl(f, dir, fbstar(length, restlen, kb, cb)); + + zero_m3(dfdx); + zero_m3(dfdv); + +// outerproduct(dfdx, dir, dir); +// mul_m3_fl(dfdx, fbstar_jacobi(length, restlen, kb, cb)); + + /* XXX damping not supported */ +// zero_m3(dfdv); + + apply_spring(data, i, j, spring_index, f, dfdx, dfdv); + + if (r_f) copy_v3_v3(r_f, f); + if (r_dfdx) copy_m3_m3(r_dfdx, dfdx); + if (r_dfdv) copy_m3_m3(r_dfdv, dfdv); + + return true; +} + bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, int i, int UNUSED(spring_index), const float goal_x[3], const float goal_v[3], float stiffness, float damping, float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]) |