Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/cloth.c')
-rw-r--r--source/blender/blenkernel/intern/cloth.c308
1 files changed, 251 insertions, 57 deletions
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index e1b5dd6d39d..765986cc82b 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -47,16 +47,9 @@
#include "BKE_modifier.h"
#include "BKE_pointcache.h"
-// #include "PIL_time.h" /* timing for debug prints */
+#include "BPH_mass_spring.h"
-/* Our available solvers. */
-// 255 is the magic reserved number, so NEVER try to put 255 solvers in here!
-// 254 = MAX!
-static CM_SOLVER_DEF solvers [] =
-{
- { "Implicit", CM_IMPLICIT, implicit_init, implicit_solver, implicit_free },
- // { "Implicit C++", CM_IMPLICITCPP, implicitcpp_init, implicitcpp_solver, implicitcpp_free },
-};
+// #include "PIL_time.h" /* timing for debug prints */
/* ********** cloth engine ******* */
/* Prototypes for internal functions.
@@ -68,7 +61,6 @@ static void cloth_update_springs( ClothModifierData *clmd );
static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm );
static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm );
-
/******************************************************************************
*
* External interface called by modifier.c clothModifier functions.
@@ -89,6 +81,7 @@ void cloth_init(ClothModifierData *clmd )
clmd->sim_parms->structural = 15.0;
clmd->sim_parms->shear = 15.0;
clmd->sim_parms->bending = 0.5;
+ clmd->sim_parms->bending_damping = 0.5;
clmd->sim_parms->Cdis = 5.0;
clmd->sim_parms->Cvi = 1.0;
clmd->sim_parms->mass = 0.3f;
@@ -130,6 +123,8 @@ void cloth_init(ClothModifierData *clmd )
clmd->sim_parms->goalfrict = 0.0f;
clmd->sim_parms->velocity_smooth = 0.0f;
+ clmd->sim_parms->voxel_cell_size = 0.1f;
+
if (!clmd->sim_parms->effector_weights)
clmd->sim_parms->effector_weights = BKE_add_effector_weights(NULL);
@@ -343,7 +338,7 @@ static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
return 0;
}
- implicit_set_positions(clmd);
+ BKE_cloth_solver_set_positions(clmd);
clmd->clothObject->last_frame= MINFRAME-1;
}
@@ -385,8 +380,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
// TIMEIT_START(cloth_step)
/* call the solver. */
- if (solvers [clmd->sim_parms->solver_type].solver)
- ret = solvers[clmd->sim_parms->solver_type].solver(ob, framenr, clmd, effectors);
+ ret = BPH_cloth_solve(ob, framenr, clmd, effectors);
// TIMEIT_END(cloth_step)
@@ -531,7 +525,7 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe);
if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED) {
- implicit_set_positions(clmd);
+ BKE_cloth_solver_set_positions(clmd);
cloth_to_object (ob, clmd, vertexCos);
BKE_ptcache_validate(cache, framenr);
@@ -544,7 +538,7 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
return;
}
else if (cache_result==PTCACHE_READ_OLD) {
- implicit_set_positions(clmd);
+ BKE_cloth_solver_set_positions(clmd);
}
if (framenr!=clmd->clothObject->last_frame+1)
@@ -581,10 +575,7 @@ void cloth_free_modifier(ClothModifierData *clmd )
if ( cloth ) {
- // If our solver provides a free function, call it
- if ( solvers [clmd->sim_parms->solver_type].free ) {
- solvers [clmd->sim_parms->solver_type].free ( clmd );
- }
+ BPH_cloth_solver_free(clmd);
// Free the verts.
if ( cloth->verts != NULL )
@@ -650,10 +641,7 @@ void cloth_free_modifier_extern(ClothModifierData *clmd )
if (G.debug_value > 0)
printf("cloth_free_modifier_extern in\n");
- // If our solver provides a free function, call it
- if ( solvers [clmd->sim_parms->solver_type].free ) {
- solvers [clmd->sim_parms->solver_type].free ( clmd );
- }
+ BPH_cloth_solver_free(clmd);
// Free the verts.
if ( cloth->verts != NULL )
@@ -931,12 +919,10 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
}
// init our solver
- if ( solvers [clmd->sim_parms->solver_type].init ) {
- solvers [clmd->sim_parms->solver_type].init ( ob, clmd );
- }
+ BPH_cloth_solver_init(ob, clmd);
if (!first)
- implicit_set_positions(clmd);
+ BKE_cloth_solver_set_positions(clmd);
clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel) );
@@ -1068,6 +1054,135 @@ static void cloth_free_errorsprings(Cloth *cloth, LinkNode **edgelist)
}
}
+static void cloth_hair_update_bending_targets(ClothModifierData *clmd)
+{
+ Cloth *cloth = clmd->clothObject;
+ LinkNode *search = NULL;
+ float hair_frame[3][3], dir_old[3], dir_new[3];
+ int prev_mn; /* to find hair chains */
+
+ if (!clmd->hairdata)
+ return;
+
+ /* XXX Note: we need to propagate frames from the root up,
+ * but structural hair springs are stored in reverse order.
+ * The bending springs however are then inserted in the same
+ * order as vertices again ...
+ * This messy situation can be resolved when solver data is
+ * generated directly from a dedicated hair system.
+ */
+
+ prev_mn = -1;
+ for (search = cloth->springs; search; search = search->next) {
+ ClothSpring *spring = search->link;
+ ClothHairData *hair_ij, *hair_kl;
+ bool is_root = spring->kl != prev_mn;
+
+ if (spring->type != CLOTH_SPRING_TYPE_BENDING_ANG) {
+ continue;
+ }
+
+ hair_ij = &clmd->hairdata[spring->ij];
+ hair_kl = &clmd->hairdata[spring->kl];
+ if (is_root) {
+ /* initial hair frame from root orientation */
+ copy_m3_m3(hair_frame, hair_ij->rot);
+ /* surface normal is the initial direction,
+ * parallel transport then keeps it aligned to the hair direction
+ */
+ copy_v3_v3(dir_new, hair_frame[2]);
+ }
+
+ copy_v3_v3(dir_old, dir_new);
+ sub_v3_v3v3(dir_new, cloth->verts[spring->mn].x, cloth->verts[spring->kl].x);
+ normalize_v3(dir_new);
+
+#if 0
+ if (clmd->debug_data && (spring->ij == 0 || spring->ij == 1)) {
+ float a[3], b[3];
+
+ copy_v3_v3(a, cloth->verts[spring->kl].x);
+// BKE_sim_debug_data_add_dot(clmd->debug_data, cloth_vert ? cloth_vert->x : key->co, 1, 1, 0, "frames", 8246, p, k);
+
+ mul_v3_v3fl(b, hair_frame[0], clmd->sim_parms->avg_spring_len);
+ BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 1, 0, 0, "frames", 8247, spring->kl, spring->mn);
+
+ mul_v3_v3fl(b, hair_frame[1], clmd->sim_parms->avg_spring_len);
+ BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 0, 1, 0, "frames", 8248, spring->kl, spring->mn);
+
+ mul_v3_v3fl(b, hair_frame[2], clmd->sim_parms->avg_spring_len);
+ BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 0, 0, 1, "frames", 8249, spring->kl, spring->mn);
+ }
+#endif
+
+ /* get local targets for kl/mn vertices by putting rest targets into the current frame,
+ * then multiply with the rest length to get the actual goals
+ */
+
+ mul_v3_m3v3(spring->target, hair_frame, hair_kl->rest_target);
+ mul_v3_fl(spring->target, spring->restlen);
+
+ /* move frame to next hair segment */
+ cloth_parallel_transport_hair_frame(hair_frame, dir_old, dir_new);
+
+ prev_mn = spring->mn;
+ }
+}
+
+static void cloth_hair_update_bending_rest_targets(ClothModifierData *clmd)
+{
+ Cloth *cloth = clmd->clothObject;
+ LinkNode *search = NULL;
+ float hair_frame[3][3], dir_old[3], dir_new[3];
+ int prev_mn; /* to find hair roots */
+
+ if (!clmd->hairdata)
+ return;
+
+ /* XXX Note: we need to propagate frames from the root up,
+ * but structural hair springs are stored in reverse order.
+ * The bending springs however are then inserted in the same
+ * order as vertices again ...
+ * This messy situation can be resolved when solver data is
+ * generated directly from a dedicated hair system.
+ */
+
+ prev_mn = -1;
+ for (search = cloth->springs; search; search = search->next) {
+ ClothSpring *spring = search->link;
+ ClothHairData *hair_ij, *hair_kl;
+ bool is_root = spring->kl != prev_mn;
+
+ if (spring->type != CLOTH_SPRING_TYPE_BENDING_ANG) {
+ continue;
+ }
+
+ hair_ij = &clmd->hairdata[spring->ij];
+ hair_kl = &clmd->hairdata[spring->kl];
+ if (is_root) {
+ /* initial hair frame from root orientation */
+ copy_m3_m3(hair_frame, hair_ij->rot);
+ /* surface normal is the initial direction,
+ * parallel transport then keeps it aligned to the hair direction
+ */
+ copy_v3_v3(dir_new, hair_frame[2]);
+ }
+
+ copy_v3_v3(dir_old, dir_new);
+ sub_v3_v3v3(dir_new, cloth->verts[spring->mn].xrest, cloth->verts[spring->kl].xrest);
+ normalize_v3(dir_new);
+
+ /* dir expressed in the hair frame defines the rest target direction */
+ copy_v3_v3(hair_kl->rest_target, dir_new);
+ mul_transposed_m3_v3(hair_frame, hair_kl->rest_target);
+
+ /* move frame to next hair segment */
+ cloth_parallel_transport_hair_frame(hair_frame, dir_old, dir_new);
+
+ prev_mn = spring->mn;
+ }
+}
+
/* update stiffness if vertex group values are changing from frame to frame */
static void cloth_update_springs( ClothModifierData *clmd )
{
@@ -1089,6 +1204,16 @@ static void cloth_update_springs( ClothModifierData *clmd )
else if (spring->type == CLOTH_SPRING_TYPE_BENDING) {
spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
}
+ else if (spring->type == CLOTH_SPRING_TYPE_BENDING_ANG) {
+ ClothVertex *v1 = &cloth->verts[spring->ij];
+ ClothVertex *v2 = &cloth->verts[spring->kl];
+ if (clmd->hairdata) {
+ /* copy extra hair data to generic cloth vertices */
+ 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;
+ }
else if (spring->type == CLOTH_SPRING_TYPE_GOAL) {
/* Warning: Appending NEW goal springs does not work because implicit solver would need reset! */
@@ -1105,8 +1230,43 @@ static void cloth_update_springs( ClothModifierData *clmd )
search = search->next;
}
+
+ cloth_hair_update_bending_targets(clmd);
+}
+BLI_INLINE void cross_identity_v3(float r[3][3], const float v[3])
+{
+ zero_m3(r);
+ r[0][1] = v[2];
+ r[0][2] = -v[1];
+ r[1][0] = -v[2];
+ r[1][2] = v[0];
+ r[2][0] = v[1];
+ r[2][1] = -v[0];
+}
+BLI_INLINE void madd_m3_m3fl(float r[3][3], float m[3][3], float f)
+{
+ r[0][0] += m[0][0] * f;
+ r[0][1] += m[0][1] * f;
+ r[0][2] += m[0][2] * f;
+ r[1][0] += m[1][0] * f;
+ r[1][1] += m[1][1] * f;
+ r[1][2] += m[1][2] * f;
+ r[2][0] += m[2][0] * f;
+ r[2][1] += m[2][1] * f;
+ r[2][2] += m[2][2] * f;
+}
+
+void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3], const float dir_new[3])
+{
+ float rot[3][3];
+
+ /* rotation between segments */
+ rotation_between_vecs_to_mat3(rot, dir_old, dir_new);
+
+ /* rotate the frame */
+ mul_m3_m3m3(mat, rot, mat);
}
static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
@@ -1283,40 +1443,74 @@ 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 = tspring2->ij;
+ 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;
+ 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;
}
+
+ cloth_hair_update_bending_rest_targets(clmd);
}
/* note: the edges may already exist so run reinsert */