diff options
author | Daniel Genrich <daniel.genrich@gmx.net> | 2008-07-03 00:28:49 +0400 |
---|---|---|
committer | Daniel Genrich <daniel.genrich@gmx.net> | 2008-07-03 00:28:49 +0400 |
commit | 8ca128414ddbe73bf31755df6cf19e5c70aba99c (patch) | |
tree | 4d7994a0b5a324b17a817c007d1711cc7cc167bd /source/blender/blenkernel | |
parent | b0958b6646b3b1fa8127f7620ce00e63ff82d0e7 (diff) |
Cloth collisions: Reorganized collision system to be more flexible for other parts of blender, so it can be more easily reused. Also slowed down friction impulse.
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/BKE_cloth.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/cloth.c | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/collision.c | 467 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/implicit.c | 13 |
4 files changed, 274 insertions, 212 deletions
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index 2e5da236a89..f3c13d3d820 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -208,7 +208,7 @@ typedef enum //////////////////////////////////////////////// // needed for implicit.c -int cloth_bvh_objcollision ( ClothModifierData * clmd, float step, float dt ); +int cloth_bvh_objcollision ( Object *ob, ClothModifierData * clmd, float step, float dt ); //////////////////////////////////////////////// diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 6034b85e20f..c7817b017ef 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -132,7 +132,7 @@ void cloth_init ( ClothModifierData *clmd ) clmd->coll_parms->self_friction = 5.0; clmd->coll_parms->friction = 5.0; - clmd->coll_parms->loop_count = 3; + clmd->coll_parms->loop_count = 2; clmd->coll_parms->epsilon = 0.015f; clmd->coll_parms->flags = CLOTH_COLLSETTINGS_FLAG_ENABLED; clmd->coll_parms->collision_list = NULL; @@ -471,7 +471,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul tend(); - /* printf ( "Cloth simulation time: %f\n", ( float ) tval() ); */ + // printf ( "%f\n", ( float ) tval() ); return ret; } diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 7f41ca033d3..26c5d186d87 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -541,7 +541,7 @@ int cloth_collision_response_static ( ClothModifierData *clmd, CollisionModifier { Normalize ( vrel_t_pre ); - impulse = 2.0 * magtangent / ( 1.0 + w1*w1 + w2*w2 + w3*w3 ); + impulse = magtangent / ( 1.0 + w1*w1 + w2*w2 + w3*w3 ); // 2.0 * VECADDMUL ( cloth1->verts[collpair->ap1].impulse, vrel_t_pre, w1 * impulse ); VECADDMUL ( cloth1->verts[collpair->ap2].impulse, vrel_t_pre, w2 * impulse ); VECADDMUL ( cloth1->verts[collpair->ap3].impulse, vrel_t_pre, w3 * impulse ); @@ -1291,52 +1291,223 @@ int cloth_collision_moving ( ClothModifierData *clmd, CollisionModifierData *col return 1; } -int cloth_bvh_objcollisions_do ( ClothModifierData * clmd, CollisionModifierData *collmd, float step, float dt ) -{ +int cloth_do_selfcollisions(ClothModifierData * clmd) +{ + int ret2 = 0, l; Cloth *cloth = clmd->clothObject; - BVHTree *cloth_bvh= ( BVHTree * ) cloth->bvhtree; - long i=0, j = 0, numfaces = 0, numverts = 0; - ClothVertex *verts = NULL; - CollPair *collisions = NULL, *collisions_index = NULL; - int ret = 0; - int result = 0; - float tnull[3] = {0,0,0}; - BVHTreeOverlap *overlap = NULL; - - - numfaces = clmd->clothObject->numfaces; - numverts = clmd->clothObject->numverts; - - verts = cloth->verts; + + if ( clmd->clothObject->bvhselftree ) + { + for(l = 0; l < clmd->coll_parms->self_loop_count; l++) + { + BVHTreeOverlap *overlap = NULL; + ClothVertex *verts = clmd->clothObject->verts; // needed for openMP + int k; + int ret = 0, result = 0; + + // search for overlapping collision pairs + overlap = BLI_bvhtree_overlap ( cloth->bvhselftree, cloth->bvhselftree, &result ); + +// #pragma omp parallel for private(k, i, j) schedule(static) + for ( k = 0; k < result; k++ ) + { + float temp[3]; + float length = 0; + float mindistance; + int i, j; + + i = overlap[k].indexA; + j = overlap[k].indexB; + + mindistance = clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len + cloth->verts[j].avg_spring_len ); + + if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) + { + if ( ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) + && ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) ) + { + continue; + } + } + + VECSUB ( temp, verts[i].tx, verts[j].tx ); + + if ( ( ABS ( temp[0] ) > mindistance ) || ( ABS ( temp[1] ) > mindistance ) || ( ABS ( temp[2] ) > mindistance ) ) continue; + + // check for adjacent points (i must be smaller j) + if ( BLI_edgehash_haskey ( cloth->edgehash, MIN2(i, j), MAX2(i, j) ) ) + { + continue; + } + + length = Normalize ( temp ); + + if ( length < mindistance ) + { + float correction = mindistance - length; + + if ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) + { + VecMulf ( temp, -correction ); + VECADD ( verts[j].tx, verts[j].tx, temp ); + } + else if ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) + { + VecMulf ( temp, correction ); + VECADD ( verts[i].tx, verts[i].tx, temp ); + } + else + { + VecMulf ( temp, -correction*0.5 ); + VECADD ( verts[j].tx, verts[j].tx, temp ); + + VECSUB ( verts[i].tx, verts[i].tx, temp ); + } + ret = 1; + ret2 += ret; + } + else + { + // check for approximated time collisions + } + } + + if ( overlap ) + MEM_freeN ( overlap ); + + if(!ret) + break; + + } + //////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////// + // SELFCOLLISIONS: update velocities + //////////////////////////////////////////////////////////// + if ( ret2 ) + { + int i; + ClothVertex *verts = clmd->clothObject->verts; // needed for openMP + + for ( i = 0; i < cloth->numverts; i++ ) + { + if ( ! ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) ) + { + VECSUB ( verts[i].tv, verts[i].tx, verts[i].txold ); + } + } + } + //////////////////////////////////////////////////////////// + } + return ret2; +} - if ( collmd->bvhtree ) +// return all collision objects in scene +// collision object will exclude self +CollisionModifierData **get_collisionobjects(Object *self, int *numcollobj) +{ + Base *base=NULL; + CollisionModifierData **objs = NULL; + Object *coll_ob = NULL; + CollisionModifierData *collmd = NULL; + int numobj = 0, maxobj = 100; + + objs = MEM_callocN(sizeof(CollisionModifierData *)*maxobj, "CollisionObjectsArray"); + // check all collision objects + for ( base = G.scene->base.first; base; base = base->next ) { - /* get pointer to bounding volume hierarchy */ - BVHTree *coll_bvh = collmd->bvhtree; + coll_ob = base->object; + collmd = ( CollisionModifierData * ) modifiers_findByType ( coll_ob, eModifierType_Collision ); + + if ( !collmd ) + { + if ( coll_ob->dup_group ) + { + GroupObject *go; + Group *group = coll_ob->dup_group; - /* move object to position (step) in time */ - collision_move_object ( collmd, step + dt, step ); + for ( go= group->gobject.first; go; go= go->next ) + { + coll_ob = go->ob; - /* search for overlapping collision pairs */ - overlap = BLI_bvhtree_overlap ( cloth_bvh, coll_bvh, &result ); + collmd = ( CollisionModifierData * ) modifiers_findByType ( coll_ob, eModifierType_Collision ); - collisions = ( CollPair* ) MEM_mallocN ( sizeof ( CollPair ) * result*4, "collision array" ); //*4 since cloth_collision_static can return more than 1 collision - collisions_index = collisions; + if ( !collmd ) + continue; - for ( i = 0; i < result; i++ ) - { - collisions_index = cloth_collision ( ( ModifierData * ) clmd, ( ModifierData * ) collmd, overlap+i, collisions_index ); - } + if(coll_ob == self) + continue; - if ( overlap ) - MEM_freeN ( overlap ); + if(numobj >= maxobj) + { + // realloc + int oldmax = maxobj; + CollisionModifierData **tmp; + maxobj *= 2; + tmp = MEM_callocN(sizeof(CollisionModifierData *)*maxobj, "CollisionObjectsArray"); + memcpy(tmp, objs, sizeof(CollisionModifierData *)*oldmax); + MEM_freeN(objs); + objs = tmp; + } + + objs[numobj] = collmd; + numobj++; + } + } + } + else + { + if(coll_ob == self) + continue; + + if(numobj >= maxobj) + { + // realloc + int oldmax = maxobj; + CollisionModifierData **tmp; + maxobj *= 2; + tmp = MEM_callocN(sizeof(CollisionModifierData *)*maxobj, "CollisionObjectsArray"); + memcpy(tmp, objs, sizeof(CollisionModifierData *)*oldmax); + MEM_freeN(objs); + objs = tmp; + + } + + objs[numobj] = collmd; + numobj++; + } } - else + *numcollobj = numobj; + return objs; +} + +void cloth_bvh_objcollisions_nearcheck ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair **collisions, CollPair **collisions_index, int numresult, BVHTreeOverlap *overlap) +{ + int i; + + *collisions = ( CollPair* ) MEM_mallocN ( sizeof ( CollPair ) * numresult * 4, "collision array" ); //*4 since cloth_collision_static can return more than 1 collision + *collisions_index = *collisions; + + for ( i = 0; i < numresult; i++ ) { - if ( G.rt > 0 ) - printf ( "cloth_bvh_objcollision: found a collision object with clothObject or collData NULL.\n" ); + *collisions_index = cloth_collision ( ( ModifierData * ) clmd, ( ModifierData * ) collmd, overlap+i, *collisions_index ); } +} +int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair *collisions, CollPair *collisions_index) +{ + Cloth *cloth = clmd->clothObject; + int i=0, j = 0, numfaces = 0, numverts = 0; + ClothVertex *verts = NULL; + int ret = 0; + int result = 0; + float tnull[3] = {0,0,0}; + + numfaces = clmd->clothObject->numfaces; + numverts = clmd->clothObject->numverts; + + verts = cloth->verts; + // process all collisions (calculate impulses, TODO: also repulses if distance too short) result = 1; for ( j = 0; j < 5; j++ ) // 5 is just a value that ensures convergence @@ -1363,48 +1534,22 @@ int cloth_bvh_objcollisions_do ( ClothModifierData * clmd, CollisionModifierData } } } -/* - result += cloth_collision_moving ( clmd, collmd, collisions, collisions_index ); - - // apply impulses in parallel - if ( result ) - { - for ( i = 0; i < numverts; i++ ) - { - // calculate "velocities" (just xnew = xold + v; no dt in v) - if ( verts[i].impulse_count ) - { - VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count ); - VECCOPY ( verts[i].impulse, tnull ); - verts[i].impulse_count = 0; - - ret++; - } - } - } -*/ } } - - if ( collisions ) MEM_freeN ( collisions ); - return ret; } // cloth - object collisions -int cloth_bvh_objcollision ( ClothModifierData * clmd, float step, float dt ) +int cloth_bvh_objcollision ( Object *ob, ClothModifierData * clmd, float step, float dt ) { - Base *base=NULL; - CollisionModifierData *collmd=NULL; Cloth *cloth=NULL; - Object *coll_ob=NULL; BVHTree *cloth_bvh=NULL; - long i=0, j = 0, k = 0, l = 0, numfaces = 0, numverts = 0; - int result = 0, rounds = 0; // result counts applied collisions; ic is for debug output; + long i=0, numfaces = 0, numverts = 0; + int rounds = 0; // result counts applied collisions; ic is for debug output; ClothVertex *verts = NULL; int ret = 0, ret2 = 0; - ClothModifierData *tclmd; - int collisions = 0; + CollisionModifierData **collobjs = NULL; + int numcollobj = 0; if ( ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ ) || ! ( ( ( Cloth * ) clmd->clothObject )->bvhtree ) ) { @@ -1424,54 +1569,61 @@ int cloth_bvh_objcollision ( ClothModifierData * clmd, float step, float dt ) // update cloth bvh bvhtree_update_from_cloth ( clmd, 1 ); // 0 means STATIC, 1 means MOVING (see later in this function) bvhselftree_update_from_cloth ( clmd, 0 ); // 0 means STATIC, 1 means MOVING (see later in this function) + + collobjs = get_collisionobjects(ob, &numcollobj); + + if(!collobjs) + return 0; do { - result = 0; + CollPair **collisions, **collisions_index; + ret2 = 0; + collisions = MEM_callocN(sizeof(CollPair *) *numcollobj , "CollPair"); + collisions_index = MEM_callocN(sizeof(CollPair *) *numcollobj , "CollPair"); + // check all collision objects - for ( base = G.scene->base.first; base; base = base->next ) + for(i = 0; i < numcollobj; i++) { - coll_ob = base->object; - collmd = ( CollisionModifierData * ) modifiers_findByType ( coll_ob, eModifierType_Collision ); - - if ( !collmd ) - { - if ( coll_ob->dup_group ) - { - GroupObject *go; - Group *group = coll_ob->dup_group; - - for ( go= group->gobject.first; go; go= go->next ) - { - coll_ob = go->ob; - - collmd = ( CollisionModifierData * ) modifiers_findByType ( coll_ob, eModifierType_Collision ); - - if ( !collmd ) - continue; - - tclmd = ( ClothModifierData * ) modifiers_findByType ( coll_ob, eModifierType_Cloth ); - if ( tclmd == clmd ) - continue; - - ret += cloth_bvh_objcollisions_do ( clmd, collmd, step, dt ); - ret2 += ret; - } - } - } - else + CollisionModifierData *collmd = collobjs[i]; + BVHTreeOverlap *overlap = NULL; + int result = 0; + + /* move object to position (step) in time */ + collision_move_object ( collmd, step + dt, step ); + + /* search for overlapping collision pairs */ + overlap = BLI_bvhtree_overlap ( cloth_bvh, collmd->bvhtree, &result ); + + // go to next object if no overlap is there + if(!result || !overlap) { - tclmd = ( ClothModifierData * ) modifiers_findByType ( coll_ob, eModifierType_Cloth ); - if ( tclmd == clmd ) - continue; - - ret += cloth_bvh_objcollisions_do ( clmd, collmd, step, dt ); - ret2 += ret; + if ( overlap ) + MEM_freeN ( overlap ); + continue; } + + /* check if collisions really happen (costly near check) */ + cloth_bvh_objcollisions_nearcheck ( clmd, collmd, &collisions[i], &collisions_index[i], result, overlap); + + // resolve nearby collisions + ret += cloth_bvh_objcollisions_resolve ( clmd, collmd, collisions[i], collisions_index[i]); + ret2 += ret; + + if ( overlap ) + MEM_freeN ( overlap ); } rounds++; + + for(i = 0; i < numcollobj; i++) + { + if ( collisions[i] ) MEM_freeN ( collisions[i] ); + } + + MEM_freeN(collisions); + MEM_freeN(collisions_index); //////////////////////////////////////////////////////////// // update positions @@ -1493,117 +1645,20 @@ int cloth_bvh_objcollision ( ClothModifierData * clmd, float step, float dt ) } //////////////////////////////////////////////////////////// - + //////////////////////////////////////////////////////////// // Test on *simple* selfcollisions //////////////////////////////////////////////////////////// if ( clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF ) { - for(l = 0; l < clmd->coll_parms->self_loop_count; l++) - { - // TODO: add coll quality rounds again - BVHTreeOverlap *overlap = NULL; - - collisions = 1; - verts = cloth->verts; // needed for openMP - - numfaces = clmd->clothObject->numfaces; - numverts = clmd->clothObject->numverts; - - verts = cloth->verts; - - if ( cloth->bvhselftree ) - { - // search for overlapping collision pairs - overlap = BLI_bvhtree_overlap ( cloth->bvhselftree, cloth->bvhselftree, &result ); - - // #pragma omp parallel for private(k, i, j) schedule(static) - for ( k = 0; k < result; k++ ) - { - float temp[3]; - float length = 0; - float mindistance; - - i = overlap[k].indexA; - j = overlap[k].indexB; - - mindistance = clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len + cloth->verts[j].avg_spring_len ); - - if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) - { - if ( ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) - && ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) ) - { - continue; - } - } - - VECSUB ( temp, verts[i].tx, verts[j].tx ); - - if ( ( ABS ( temp[0] ) > mindistance ) || ( ABS ( temp[1] ) > mindistance ) || ( ABS ( temp[2] ) > mindistance ) ) continue; - - // check for adjacent points (i must be smaller j) - if ( BLI_edgehash_haskey ( cloth->edgehash, MIN2(i, j), MAX2(i, j) ) ) - { - continue; - } - - length = Normalize ( temp ); - - if ( length < mindistance ) - { - float correction = mindistance - length; - - if ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) - { - VecMulf ( temp, -correction ); - VECADD ( verts[j].tx, verts[j].tx, temp ); - } - else if ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) - { - VecMulf ( temp, correction ); - VECADD ( verts[i].tx, verts[i].tx, temp ); - } - else - { - VecMulf ( temp, -correction*0.5 ); - VECADD ( verts[j].tx, verts[j].tx, temp ); - - VECSUB ( verts[i].tx, verts[i].tx, temp ); - } - ret = 1; - ret2 += ret; - } - else - { - // check for approximated time collisions - } - } - - if ( overlap ) - MEM_freeN ( overlap ); - - } - } - //////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////// - // SELFCOLLISIONS: update velocities - //////////////////////////////////////////////////////////// - if ( ret2 ) - { - for ( i = 0; i < cloth->numverts; i++ ) - { - if ( ! ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) ) - { - VECSUB ( verts[i].tv, verts[i].tx, verts[i].txold ); - } - } - } - //////////////////////////////////////////////////////////// + ret2 += cloth_do_selfcollisions(clmd); } + //////////////////////////////////////////////////////////// } while ( ret2 && ( clmd->coll_parms->loop_count>rounds ) ); + + if(collobjs) + + MEM_freeN(collobjs); return MIN2 ( ret, 1 ); } diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c index 808984aaa3c..297ac0b1530 100644 --- a/source/blender/blenkernel/intern/implicit.c +++ b/source/blender/blenkernel/intern/implicit.c @@ -1588,10 +1588,17 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase VECSUB(verts[i].tv, verts[i].tx, verts[i].txold); VECCOPY(verts[i].v, verts[i].tv); } - + // call collision function - result = cloth_bvh_objcollision(clmd, step + dt, dt); - + // TODO: check if "step" or "step+dt" is correct - dg + result = cloth_bvh_objcollision(ob, clmd, step, dt); + + // correct velocity again, just to be sure we had to change it due to adaptive collisions + for(i = 0; i < numverts; i++) + { + VECSUB(verts[i].tv, verts[i].tx, id->X[i]); + } + // copy corrected positions back to simulation for(i = 0; i < numverts; i++) { |