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.c352
1 files changed, 262 insertions, 90 deletions
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index aacf02555d4..3b3fe323f2b 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,13 +81,13 @@ 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;
clmd->sim_parms->stepsPerFrame = 5;
clmd->sim_parms->flags = 0;
clmd->sim_parms->solver_type = 0;
- clmd->sim_parms->preroll = 0;
clmd->sim_parms->maxspringlen = 10;
clmd->sim_parms->vgroup_mass = 0;
clmd->sim_parms->vgroup_shrink = 0;
@@ -130,6 +122,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 +337,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 +379,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)
@@ -469,10 +462,7 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
clmd->sim_parms->timescale= timescale;
- if (clmd->sim_parms->reset ||
- (framenr == (startframe - clmd->sim_parms->preroll) && clmd->sim_parms->preroll != 0) ||
- (clmd->clothObject && dm->getNumVerts(dm) != clmd->clothObject->numverts))
- {
+ if (clmd->sim_parms->reset || (clmd->clothObject && dm->getNumVerts(dm) != clmd->clothObject->numverts)) {
clmd->sim_parms->reset = 0;
cache->flag |= PTCACHE_OUTDATED;
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
@@ -484,22 +474,6 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
// unused in the moment, calculated separately in implicit.c
clmd->sim_parms->dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame;
- /* handle continuous simulation with the play button */
- if ((clmd->sim_parms->preroll > 0) && (framenr > startframe - clmd->sim_parms->preroll) && (framenr < startframe)) {
- BKE_ptcache_invalidate(cache);
-
- /* do simulation */
- if (!do_init_cloth(ob, clmd, dm, framenr))
- return;
-
- do_step_cloth(ob, clmd, dm, framenr);
- cloth_to_object(ob, clmd, vertexCos);
-
- clmd->clothObject->last_frame= framenr;
-
- return;
- }
-
/* simulation is only active during a specific period */
if (framenr < startframe) {
BKE_ptcache_invalidate(cache);
@@ -513,7 +487,7 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
if (!do_init_cloth(ob, clmd, dm, framenr))
return;
- if ((framenr == startframe) && (clmd->sim_parms->preroll == 0)) {
+ if (framenr == startframe) {
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
do_init_cloth(ob, clmd, dm, framenr);
BKE_ptcache_validate(cache, framenr);
@@ -526,7 +500,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);
@@ -539,7 +513,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);
}
else if ( /*ob->id.lib ||*/ (cache->flag & PTCACHE_BAKED)) { /* 2.4x disabled lib, but this can be used in some cases, testing further - campbell */
/* if baked and nothing in cache, do nothing */
@@ -581,10 +555,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 +621,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 )
@@ -789,7 +757,7 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
// Kicking goal factor to simplify things...who uses that anyway?
// ABS ( clmd->sim_parms->maxgoal - clmd->sim_parms->mingoal );
- verts->goal = powf(verts->goal, 4.0f);
+ verts->goal = pow4f(verts->goal);
if ( verts->goal >= SOFTGOALSNAP )
verts->flags |= CLOTH_VERT_FLAG_PINNED;
}
@@ -812,17 +780,15 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
}
}
- if (clmd->sim_parms->vgroup_shrink > 0 )
- {
- if ( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink-1))
- {
- verts->shrink_factor = clmd->sim_parms->shrink_min*(1.0f-dvert->dw[j].weight)+clmd->sim_parms->shrink_max*dvert->dw [j].weight; // linear interpolation between min and max shrink factor based on weight
+ if (clmd->sim_parms->vgroup_shrink > 0) {
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) {
+ /* linear interpolation between min and max shrink factor based on weight */
+ verts->shrink_factor = clmd->sim_parms->shrink_min * (1.0f - dvert->dw[j].weight) + clmd->sim_parms->shrink_max * dvert->dw [j].weight;
+ }
+ }
+ else {
+ verts->shrink_factor = clmd->sim_parms->shrink_min;
}
- }
- else {
- verts->shrink_factor = clmd->sim_parms->shrink_min;
- }
-
}
}
}
@@ -931,12 +897,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 +1032,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 +1182,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 +1208,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 +1421,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 (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 );
+ }
+
+ 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 (!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->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 );
}
-
- 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 */