diff options
Diffstat (limited to 'source/blender/blenkernel/intern/cloth.c')
-rw-r--r-- | source/blender/blenkernel/intern/cloth.c | 352 |
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, ×cale); 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 */ |