diff options
Diffstat (limited to 'source/blender/blenkernel/intern/softbody.c')
-rw-r--r-- | source/blender/blenkernel/intern/softbody.c | 453 |
1 files changed, 293 insertions, 160 deletions
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 36d114cf023..bd9d1cb75ca 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -61,9 +61,11 @@ variables on the UI for now #include "DNA_curve_types.h" #include "DNA_object_types.h" #include "DNA_object_force.h" /* here is the softbody struct */ +#include "DNA_particle_types.h" #include "DNA_key_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" #include "DNA_lattice_types.h" #include "DNA_scene_types.h" @@ -75,9 +77,12 @@ variables on the UI for now #include "BKE_global.h" #include "BKE_key.h" #include "BKE_object.h" +#include "BKE_particle.h" #include "BKE_softbody.h" #include "BKE_utildefines.h" #include "BKE_DerivedMesh.h" +#include "BKE_pointcache.h" +#include "BKE_modifier.h" #include "BIF_editdeform.h" #include "BIF_graphics.h" @@ -90,18 +95,6 @@ static int (*SB_localInterruptCallBack)(void) = NULL; /* ********** soft body engine ******* */ - -typedef struct BodyPoint { - float origS[3], origE[3], origT[3], pos[3], vec[3], force[3]; - float goal; - float prevpos[3], prevvec[3], prevdx[3], prevdv[3]; /* used for Heun integration */ - int nofsprings; int *springs; - float choke; - float colball; - short flag; - char octantflag; -} BodyPoint; - typedef struct BodySpring { int v1, v2; float len, strength, cf; @@ -480,21 +473,31 @@ void ccd_build_deflector_hache(Object *vertexowner,GHash *hash) while (base) { /*Only proceed for mesh object in same layer */ if(base->object->type==OB_MESH && (base->lay & vertexowner->lay)) { + int particles=0; ob= base->object; - if((vertexowner) && (ob == vertexowner)){ - /* if vertexowner is given we don't want to check collision with owner object */ - base = base->next; - continue; + if((vertexowner) && (ob == vertexowner)) { + if(vertexowner->soft->particles){ + particles=1; + } + else { + /* if vertexowner is given we don't want to check collision with owner object */ + base = base->next; + continue; + } } /*+++ only with deflecting set */ if(ob->pd && ob->pd->deflect && BLI_ghash_lookup(hash, ob) == 0) { DerivedMesh *dm= NULL; - - if(ob->softflag & OB_SB_COLLFINAL) { /* so maybe someone wants overkill to collide with subsurfed */ - dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH); - } else { - dm = mesh_get_derived_deform(ob, CD_MASK_BAREMESH); + + if(particles) { + dm = psys_get_modifier(ob,psys_get_current(ob))->dm; + } + else { + if(ob->softflag & OB_SB_COLLFINAL) /* so maybe someone wants overkill to collide with subsurfed */ + dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH); + else + dm = mesh_get_derived_deform(ob, CD_MASK_BAREMESH); } if(dm){ @@ -852,10 +855,11 @@ static void renew_softbody(Object *ob, int totpoint, int totspring) { SoftBody *sb; int i; - + short softflag; if(ob->soft==NULL) ob->soft= sbNew(); else free_softbody_intern(ob->soft); sb= ob->soft; + softflag=ob->softflag; if(totpoint) { sb->totpoint= totpoint; @@ -869,8 +873,8 @@ static void renew_softbody(Object *ob, int totpoint, int totspring) for (i=0; i<totpoint; i++) { BodyPoint *bp = &sb->bpoint[i]; - if(ob->softflag & OB_SB_GOAL) { - bp->goal= ob->soft->defgoal; + if(softflag & OB_SB_GOAL) { + bp->goal= sb->defgoal; } else { bp->goal= 0.0f; @@ -900,7 +904,6 @@ static void free_softbody_baked(SoftBody *sb) sb->keys= NULL; sb->totkey= 0; - } static void free_scratch(SoftBody *sb) { @@ -1203,9 +1206,9 @@ int sb_detect_face_collisionCached(float face_v1[3],float face_v2[3],float face_ Crossf(d_nvect, edge2, edge1); Normalize(d_nvect); if ( - LineIntersectsTriangle(nv1, nv2, face_v1, face_v2, face_v3, &t) || - LineIntersectsTriangle(nv2, nv3, face_v1, face_v2, face_v3, &t) || - LineIntersectsTriangle(nv3, nv1, face_v1, face_v2, face_v3, &t) ){ + LineIntersectsTriangle(nv1, nv2, face_v1, face_v2, face_v3, &t, NULL) || + LineIntersectsTriangle(nv2, nv3, face_v1, face_v2, face_v3, &t, NULL) || + LineIntersectsTriangle(nv3, nv1, face_v1, face_v2, face_v3, &t, NULL) ){ Vec3PlusStVec(force,-1.0f,d_nvect); *damp=ob->pd->pdef_sbdamp; deflected = 2; @@ -1217,9 +1220,9 @@ int sb_detect_face_collisionCached(float face_v1[3],float face_v2[3],float face_ Crossf(d_nvect, edge2, edge1); Normalize(d_nvect); if ( - LineIntersectsTriangle(nv1, nv3, face_v1, face_v2, face_v3, &t) || - LineIntersectsTriangle(nv3, nv4, face_v1, face_v2, face_v3, &t) || - LineIntersectsTriangle(nv4, nv1, face_v1, face_v2, face_v3, &t) ){ + LineIntersectsTriangle(nv1, nv3, face_v1, face_v2, face_v3, &t, NULL) || + LineIntersectsTriangle(nv3, nv4, face_v1, face_v2, face_v3, &t, NULL) || + LineIntersectsTriangle(nv4, nv1, face_v1, face_v2, face_v3, &t, NULL) ){ Vec3PlusStVec(force,-1.0f,d_nvect); *damp=ob->pd->pdef_sbdamp; deflected = 2; @@ -1402,7 +1405,7 @@ int sb_detect_edge_collisionCached(float edge_v1[3],float edge_v2[3],float *damp Crossf(d_nvect, edge2, edge1); Normalize(d_nvect); - if ( LineIntersectsTriangle(edge_v1, edge_v2, nv1, nv2, nv3, &t)){ + if ( LineIntersectsTriangle(edge_v1, edge_v2, nv1, nv2, nv3, &t, NULL)){ float v1[3],v2[3]; float intrusiondepth,i1,i2; VECSUB(v1, edge_v1, nv2); @@ -1421,7 +1424,7 @@ int sb_detect_edge_collisionCached(float edge_v1[3],float edge_v2[3],float *damp Crossf(d_nvect, edge2, edge1); Normalize(d_nvect); - if (LineIntersectsTriangle( edge_v1, edge_v2,nv1, nv3, nv4, &t)){ + if (LineIntersectsTriangle( edge_v1, edge_v2,nv1, nv3, nv4, &t, NULL)){ float v1[3],v2[3]; float intrusiondepth,i1,i2; VECSUB(v1, edge_v1, nv4); @@ -1550,7 +1553,7 @@ int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3], float * Object *ob= NULL; GHash *hash; GHashIterator *ihash; - float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3],d_nvect[3], dv1[3],ve[3],avel[3], + float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3],d_nvect[3], dv1[3],ve[3],avel[3]={0.0,0.0,0.0}, vv1[3], vv2[3], vv3[3], vv4[3], coledge[3], mindistedge = 1000.0f, outerforceaccu[3],innerforceaccu[3], facedist,n_mag,force_mag_norm,minx,miny,minz,maxx,maxy,maxz, @@ -2953,6 +2956,103 @@ static void curve_surf_to_softbody(Object *ob) } +static void springs_from_particles(Object *ob) +{ + ParticleSystem *psys; + ParticleSystemModifierData *psmd=0; + ParticleData *pa=0; + HairKey *key=0; + SoftBody *sb; + BodyPoint *bp; + BodySpring *bs; + int a,k; + float hairmat[4][4]; + + psys= ob->soft->particles; + sb= ob->soft; + if(ob && sb && psys) { + psmd = psys_get_modifier(ob, psys); + + bp= sb->bpoint; + for(a=0, pa=psys->particles; a<psys->totpart; a++, pa++) { + for(k=0, key=pa->hair; k<pa->totkey; k++, bp++, key++) { + VECCOPY(bp->origS, key->co); + + psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); + + Mat4MulVecfl(hairmat, bp->origS); + } + } + + for(a=0, bs=sb->bspring; a<sb->totspring; a++, bs++) + bs->len= VecLenf(sb->bpoint[bs->v1].origS, sb->bpoint[bs->v2].origS); + } +} + +static void particles_to_softbody(Object *ob) +{ + SoftBody *sb; + BodyPoint *bp; + BodySpring *bs; + ParticleData *pa; + HairKey *key; + ParticleSystem *psys= ob->soft->particles; + float goalfac; + int a, k, curpoint; + int totpoint= psys_count_keys(psys); + int totedge= totpoint-psys->totpart; + + /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */ + renew_softbody(ob, totpoint, totedge); + + psys->particles->bpi = 0; + for(a=1, pa=psys->particles+1; a<psys->totpart; a++, pa++) + pa->bpi = (pa-1)->bpi + pa->totkey; + + /* we always make body points */ + sb= ob->soft; + bp= sb->bpoint; + bs= sb->bspring; + goalfac= ABS(sb->maxgoal - sb->mingoal); + + if((ob->softflag & OB_SB_GOAL)) { + for(a=0, pa=psys->particles; a<psys->totpart; a++, pa++) { + for(k=0, key=pa->hair; k<pa->totkey; k++,bp++,key++) { + if(k) { + bp->goal= key->weight; + bp->goal= sb->mingoal + bp->goal*goalfac; + bp->goal= (float)pow(bp->goal, 4.0f); + } + else{ + /* hair roots are allways fixed fully to goal */ + bp->goal= 1.0f; + } + } + } + } + + bp= sb->bpoint; + curpoint=0; + for(a=0, pa=psys->particles; a<psys->totpart; a++, curpoint++, pa++) { + for(k=0; k<pa->totkey-1; k++,bs++,curpoint++) { + bs->v1=curpoint; + bs->v2=curpoint+1; + bs->strength= 1.0; + bs->order=1; + } + } + + build_bps_springlist(ob); /* scan for springs attached to bodypoints ONCE */ + /* insert *other second order* springs if desired */ + if(sb->secondspring > 0.0000001f) { + add_2nd_order_springs(ob,sb->secondspring*10.0); /* exploits the the first run of build_bps_springlist(ob);*/ + build_bps_springlist(ob); /* yes we need to do it again*/ + } + springs_from_particles(ob); /* write the 'rest'-lenght of the springs */ + if(ob->softflag & OB_SB_SELF) + calculate_collision_balls(ob); +} + /* copies softbody result back in object */ static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts, int local) { @@ -2969,117 +3069,94 @@ static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts, } } -/* return 1 if succesfully baked and applied step */ -static int softbody_baked_step(Object *ob, float framenr, float (*vertexCos)[3], int numVerts) +void softbody_clear_cache(Object *ob, float framenr) { - SoftBody *sb= ob->soft; - SBVertex *key0, *key1, *key2, *key3; - BodyPoint *bp; - float data[4], sfra, efra, cfra, dfra, fac; /* start, end, current, delta */ - int ofs1, a; - - /* precondition check */ - if(sb==NULL || sb->keys==NULL || sb->totkey==0) return 0; - /* so we got keys, but no bodypoints... even without simul we need it for the bake */ - if(sb->bpoint==NULL) sb->bpoint= MEM_callocN( sb->totpoint*sizeof(BodyPoint), "bodypoint"); - - /* convert cfra time to system time */ - sfra= (float)sb->sfra; - cfra= bsystem_time(ob, framenr, 0.0); - efra= (float)sb->efra; - dfra= (float)sb->interval; + SoftBody *sb = ob->soft; + ModifierData *md = ob->modifiers.first; + int stack_index = -1; + int a; - /* offset in keys array */ - ofs1= (int)floor( (cfra-sfra)/dfra ); + if(sb==NULL) return; - if(ofs1 < 0) { - key0=key1=key2=key3= *sb->keys; - } - else if(ofs1 >= sb->totkey-1) { - key0=key1=key2=key3= *(sb->keys+sb->totkey-1); - } + if(sb->particles) + stack_index = modifiers_indexInObject(ob,(ModifierData*)psys_get_modifier(ob,sb->particles)); else { - key1= *(sb->keys+ofs1); - key2= *(sb->keys+ofs1+1); - - if(ofs1>0) key0= *(sb->keys+ofs1-1); - else key0= key1; - - if(ofs1<sb->totkey-2) key3= *(sb->keys+ofs1+2); - else key3= key2; - } - - sb->ctime= cfra; /* needed? */ - - /* timing */ - fac= ((cfra-sfra)/dfra) - (float)ofs1; - CLAMP(fac, 0.0, 1.0); - set_four_ipo(fac, data, KEY_BSPLINE); - if (key0&&key1&&key2&&key3) // may be null because we SHIFT_ESCAPED - for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++, key0++, key1++, key2++, key3++) { - bp->pos[0]= data[0]*key0->vec[0] + data[1]*key1->vec[0] + data[2]*key2->vec[0] + data[3]*key3->vec[0]; - bp->pos[1]= data[0]*key0->vec[1] + data[1]*key1->vec[1] + data[2]*key2->vec[1] + data[3]*key3->vec[1]; - bp->pos[2]= data[0]*key0->vec[2] + data[1]*key1->vec[2] + data[2]*key2->vec[2] + data[3]*key3->vec[2]; + for(a=0; md; md=md->next, a++) { + if(md->type == eModifierType_Softbody) { + stack_index = a; + break; + } + } } - - softbody_to_object(ob, vertexCos, numVerts, sb->local); - - return 1; -} -/* only gets called after succesfully doing softbody_step */ -/* already checked for OB_SB_BAKE flag */ -static void softbody_baked_add(Object *ob, float framenr) + BKE_ptcache_id_clear((ID *)ob, PTCACHE_CLEAR_ALL, framenr, stack_index); +} +static void softbody_write_cache(Object *ob, float framenr) { - SoftBody *sb= ob->soft; - SBVertex *key; + FILE *fp = NULL; + SoftBody *sb = ob->soft; BodyPoint *bp; - float sfra, efra, cfra, dfra, fac1; /* start, end, current, delta */ - int ofs1, a; - - /* convert cfra time to system time */ - sfra= (float)sb->sfra; - fac1= ob->sf; ob->sf= 0.0f; /* disable startframe */ - cfra= bsystem_time(ob, framenr, 0.0); - ob->sf= fac1; - efra= (float)sb->efra; - dfra= (float)sb->interval; - - if(sb->totkey==0) { - if(sb->sfra >= sb->efra) return; /* safety, UI or py setting allows */ - if(sb->interval<1) sb->interval= 1; /* just be sure */ - - sb->totkey= 1 + (int)(ceil( (efra-sfra)/dfra ) ); - sb->keys= MEM_callocN( sizeof(void *)*sb->totkey, "sb keys"); + ModifierData *md = ob->modifiers.first; + int stack_index = -1; + int a; + + if(sb->totpoint == 0) return; + + if(sb->particles) + stack_index = modifiers_indexInObject(ob,(ModifierData*)psys_get_modifier(ob,sb->particles)); + else { + for(a=0; md; md=md->next, a++) { + if(md->type == eModifierType_Softbody) { + stack_index = a; + break; + } + } } + + fp = BKE_ptcache_id_fopen((ID *)ob, 'w', framenr, stack_index); + if(!fp) return; + + for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) + fwrite(&bp->pos, sizeof(float), 3, fp); - /* inverse matrix might not be uptodate... */ - Mat4Invert(ob->imat, ob->obmat); - - /* now find out if we have to store a key */ - - /* offset in keys array */ - if(cfra>=(efra)) { - ofs1= sb->totkey-1; - fac1= 0.0; - } + fclose(fp); +} +static int softbody_read_cache(Object *ob, float framenr) +{ + FILE *fp = NULL; + SoftBody *sb = ob->soft; + BodyPoint *bp; + ModifierData *md = ob->modifiers.first; + int stack_index = -1; + int a, ret = 1; + + if(sb->totpoint == 0) return 0; + + if(sb->particles) + stack_index = modifiers_indexInObject(ob,(ModifierData*)psys_get_modifier(ob,sb->particles)); else { - ofs1= (int)floor( (cfra-sfra)/dfra ); - fac1= ((cfra-sfra)/dfra) - (float)ofs1; - } - if( fac1 < 1.0/dfra ) { - - key= *(sb->keys+ofs1); - if(key == NULL) { - *(sb->keys+ofs1)= key= MEM_mallocN(sb->totpoint*sizeof(SBVertex), "softbody key"); - - for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++, key++) { - VECCOPY(key->vec, bp->pos); - if(sb->local) - Mat4MulVecfl(ob->imat, key->vec); + for(a=0; md; md=md->next, a++) { + if(md->type == eModifierType_Softbody) { + stack_index = a; + break; } } } + + fp = BKE_ptcache_id_fopen((ID *)ob, 'r', framenr, stack_index); + if(!fp) + ret = 0; + else { + for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) + if(fread(&bp->pos, sizeof(float), 3, fp) != 3) { + ret = 0; + break; + } + + fclose(fp); + } + + return ret; } /* +++ ************ maintaining scratch *************** */ void sb_new_scratch(SoftBody *sb) @@ -3175,15 +3252,14 @@ void sbSetInterruptCallBack(int (*f)(void)) /* simulates one step. framenr is in frames */ void sbObjectStep(Object *ob, float framenr, float (*vertexCos)[3], int numVerts) { + ParticleSystemModifierData *psmd=0; + ParticleData *pa=0; SoftBody *sb; + HairKey *key= NULL; BodyPoint *bp; int a; float dtime,ctime,forcetime,err; - - /* baking works with global time */ - if(!(ob->softflag & OB_SB_BAKEDO) ) - if(softbody_baked_step(ob, framenr, vertexCos, numVerts) ) return; - + float hairmat[4][4]; /* This part only sets goals and springs, based on original mesh/curve/lattice data. Copying coordinates happens in next chunk by setting softbody flag OB_SB_RESET */ @@ -3194,7 +3270,13 @@ void sbObjectStep(Object *ob, float framenr, float (*vertexCos)[3], int numVerts (numVerts!=ob->soft->totpoint) || /* should never happen, just to be safe */ ((ob->softflag & OB_SB_EDGES) && !ob->soft->bspring && object_has_edges(ob))) /* happens when in UI edges was set */ { - switch(ob->type) { + if(ob->soft && ob->soft->bpoint) /* don't clear on file load */ + softbody_clear_cache(ob, framenr); + + if(ob->soft->particles){ + particles_to_softbody(ob); + } + else switch(ob->type) { case OB_MESH: mesh_to_softbody(ob); break; @@ -3220,6 +3302,10 @@ void sbObjectStep(Object *ob, float framenr, float (*vertexCos)[3], int numVerts /* still no points? go away */ if(sb->totpoint==0) return; + if(sb->particles){ + psmd=psys_get_modifier(ob,sb->particles); + pa=sb->particles->particles; + } /* checking time: */ @@ -3231,17 +3317,45 @@ void sbObjectStep(Object *ob, float framenr, float (*vertexCos)[3], int numVerts dtime= ctime - sb->ctime; } + if(softbody_read_cache(ob, framenr)) { + if(sb->particles==0) + softbody_to_object(ob, vertexCos, numVerts, sb->local); + sb->ctime = ctime; + return; + } + /* the simulator */ /* update the vertex locations */ if (dtime!=0.0) { + if(sb->particles) { + pa=sb->particles->particles; + key = pa->hair; + + psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); + } + for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) { /* store where goals are now */ VECCOPY(bp->origS, bp->origE); /* copy the position of the goals at desired end time */ - VECCOPY(bp->origE, vertexCos[a]); - /* vertexCos came from local world, go global */ - Mat4MulVecfl(ob->obmat, bp->origE); + if(sb->particles) { + if(key == pa->hair + pa->totkey) { + pa++; + key = pa->hair; + + psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); + } + VECCOPY(bp->origE, key->co); + Mat4MulVecfl(hairmat,bp->origE); + + key++; + } + else{ + VECCOPY(bp->origE, vertexCos[a]); + /* vertexCos came from local world, go global */ + Mat4MulVecfl(ob->obmat, bp->origE); + } /* just to be save give bp->origT a defined value will be calulated in interpolate_exciter()*/ VECCOPY(bp->origT, bp->origE); @@ -3253,9 +3367,29 @@ void sbObjectStep(Object *ob, float framenr, float (*vertexCos)[3], int numVerts (dtime>=9.9*G.scene->r.framelen) /* too far forward in time --> goals won't be accurate enough */ ) { + if(sb->particles) { + pa=sb->particles->particles; + key = pa->hair; + + psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); + } + for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) { - VECCOPY(bp->pos, vertexCos[a]); - Mat4MulVecfl(ob->obmat, bp->pos); /* yep, sofbody is global coords*/ + if(sb->particles) { + if(key == pa->hair + pa->totkey) { + pa++; + key = pa->hair; + + psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); + } + VECCOPY(bp->pos, key->co); + Mat4MulVecfl(hairmat, bp->pos); + key++; + } + else { + VECCOPY(bp->pos, vertexCos[a]); + Mat4MulVecfl(ob->obmat, bp->pos); /* yep, sofbody is global coords*/ + } VECCOPY(bp->origS, bp->pos); VECCOPY(bp->origE, bp->pos); VECCOPY(bp->origT, bp->pos); @@ -3283,23 +3417,22 @@ void sbObjectStep(Object *ob, float framenr, float (*vertexCos)[3], int numVerts sb_new_scratch(sb); /* make a new */ sb->scratch->needstobuildcollider=1; - - /* copy some info to scratch */ - switch(ob->type) { - case OB_MESH: - if (ob->softflag & OB_SB_FACECOLL) mesh_faces_to_scratch(ob); - break; - case OB_LATTICE: - break; - case OB_CURVE: - case OB_SURF: - break; - default: - break; + if((sb->particles)==0) { + /* copy some info to scratch */ + switch(ob->type) { + case OB_MESH: + if (ob->softflag & OB_SB_FACECOLL) mesh_faces_to_scratch(ob); + break; + case OB_LATTICE: + break; + case OB_CURVE: + case OB_SURF: + break; + default: + break; + } } - - ob->softflag &= ~OB_SB_RESET; } else if(dtime>0.0) { @@ -3411,10 +3544,10 @@ void sbObjectStep(Object *ob, float framenr, float (*vertexCos)[3], int numVerts } } - softbody_to_object(ob, vertexCos, numVerts, 0); + if(sb->particles==0) + softbody_to_object(ob, vertexCos, numVerts, 0); sb->ctime= ctime; - - if(ob->softflag & OB_SB_BAKEDO) softbody_baked_add(ob, framenr); + softbody_write_cache(ob, framenr); } |