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:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2008-04-10 15:39:20 +0400
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2008-04-10 15:39:20 +0400
commit1fe5302cce8de1bad875ad29a3fcff06d0c59654 (patch)
tree7ad40e8f9ee90d0c16185cf4dcb06ee025765b58 /source/blender/blenkernel/intern/softbody.c
parent36288dabb8e39910b81dc09067db9065cc3004b9 (diff)
Point Cache Refactoring
======================= Caching and Baking: - The point cache is now cleared on DAG_object_flush_update(), and not cleared for time dependency graph updates. - There is now a Bake button instead of Protect. Also cache start and end frames were added to softbody and particles. - The cloth autoprotect feature was removed. - The Ctrl+B menu now also bakes cloth and particles next to softbody and fluids. Additionally there are now frree bake and free cache menu entries. - The point cache api has been changed. There is now a PTCacheID struct for each point cache type that can be filled and then used to call the point cache functions. - PointCache struct was added to DNA and is automatically allocated for each physics type. - Soft body now supports Bake Editing just like cloth. - Tried to make the systems deal consistently with time ipo's and offsets. Still not sure it all works correct, but too complicated to solve completely now. Library Linking: - Added some more warnings to prevent editing settings on library linked objects. - Linked objects now read from the cache located next to the original library file, and never write to it. This restores old behavior for softbodies. For local simulation the mesh and not the object should be linked. - Dupligroups and proxies can't create local point caches at the moment, how to implement that I'm not sure. We probably need a proxy point cache for that to work (ugh). Physics UI: - Renamed deflection panel to collision for consistency and reorganized the buttons. Also removed some softbody collision buttons from the softbody panel that were duplicated in this panel for cloth. - Tweaked field panel buttons to not jump around when changing options. - Tabbing e.g. Soft Body Collision into the Soft Body panel, it now only shows Collision to make the panel names readable. - I tried to make enabled/disabling physics more consistent, since all three system did things different. Now the two modifier buttons to enable the modifier for the viewport and rendering are also duplicated in the physics panels. Toggling the Soft Body and Cloth buttons now both remove their modifiers. - Fixed modifier error drawing glitch. Particles: - Particles are now recalculated more often than before. Previously it did partial updates based on the changes, but that doesn't work well with DAG_object_flush_update() .. - Fixed memory leak loading keyed particle system. Now keys are not written to file anymore but always created after loading. - Make particle threads work with autothreads. Continue Physics: - The timeline play now has a Continue Physics option in the playback menu, which keeps the simulations going without writing them to the cache. - This doesn't always work that well, some changes are not immediately updated, but this can be improved later. Still it's fun to get a feel for the physics. Todo: - Point cache can get out of sync with and undo and changing a file without saving it. - Change the point cache file format to store a version (so old point cache files can be either converted or at least ignored), and to do correct endian conversion. - Menu item and/or buttons for Ctrl+B. - A system("rm ..") was changed to remove() since the former is very slow for clearing point caches. These system() calls were already giving trouble in a bug in the tracker, but really most use of this system("") should be changed and tested. - The Soft Body Collision and Clot Collision panel titles don't mention there's point cache settings there too, doing that makes them unreadable with the default panel setup.. but may need to make the names longer anyway.
Diffstat (limited to 'source/blender/blenkernel/intern/softbody.c')
-rw-r--r--source/blender/blenkernel/intern/softbody.c732
1 files changed, 392 insertions, 340 deletions
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index df6b0d37867..c7440f39a0c 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -3219,105 +3219,66 @@ static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts,
}
}
-void softbody_clear_cache(Object *ob, float framenr)
+void sbWriteCache(Object *ob, int framenr)
{
- SoftBody *sb = ob->soft;
- ModifierData *md = ob->modifiers.first;
- int stack_index = -1;
- int a;
-
- if(sb==NULL) 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;
- }
- }
- }
-
- BKE_ptcache_id_clear((ID *)ob, PTCACHE_CLEAR_ALL, framenr, stack_index);
-}
-static void softbody_write_cache(Object *ob, float framenr)
-{
- FILE *fp = NULL;
- SoftBody *sb = ob->soft;
+ SoftBody *sb= ob->soft;
BodyPoint *bp;
- ModifierData *md = ob->modifiers.first;
- int stack_index = -1;
+ PTCacheID pid;
+ PTCacheFile *pf;
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;
+ if(sb->totpoint == 0)
+ return;
+ BKE_ptcache_id_from_softbody(&pid, ob, sb);
+ pf= BKE_ptcache_file_open(&pid, PTCACHE_FILE_WRITE, framenr);
+ if(!pf)
+ return;
+
for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++)
- fwrite(&bp->pos, sizeof(float), 3, fp);
-/*write velocities too */
+ BKE_ptcache_file_write_floats(pf, bp->pos, 3);
+
for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++)
- fwrite(&bp->vec, sizeof(float), 3, fp);
-
- fclose(fp);
+ BKE_ptcache_file_write_floats(pf, bp->vec, 3);
+
+ BKE_ptcache_file_close(pf);
}
+
static int softbody_read_cache(Object *ob, float framenr)
{
- FILE *fp = NULL;
- SoftBody *sb = ob->soft;
+ 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;
+ PTCacheID pid;
+ PTCacheFile *pf;
+ int a;
+ if(sb->totpoint == 0)
+ return 0;
+
+ BKE_ptcache_id_from_softbody(&pid, ob, sb);
+ pf= BKE_ptcache_file_open(&pid, PTCACHE_FILE_READ, framenr);
+ if(!pf)
+ return 0;
- 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;
- }
+ for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) {
+ if(!BKE_ptcache_file_read_floats(pf, bp->pos, 3)) {
+ BKE_ptcache_file_close(pf);
+ return 0;
}
}
- 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;
- }
- /*read velocities too !*/
- for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++){
- if(fread(&bp->vec, sizeof(float), 3, fp) != 3) {
- ret = 0;
- break;
- }
- }
- fclose(fp);
+ for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) {
+ if(!BKE_ptcache_file_read_floats(pf, bp->vec, 3)) {
+ BKE_ptcache_file_close(pf);
+ return 0;
+ }
}
- return ret;
+ BKE_ptcache_file_close(pf);
+
+ return 1;
}
+
/* +++ ************ maintaining scratch *************** */
void sb_new_scratch(SoftBody *sb)
{
@@ -3376,6 +3337,9 @@ SoftBody *sbNew(void)
/*todo backward file compat should set sb->shearstiff = 1.0f while reading old files*/
sb->shearstiff = 1.0f;
sb->solverflags |= SBSO_OLDERR;
+
+ sb->pointcache = BKE_ptcache_add();
+
return sb;
}
@@ -3383,14 +3347,19 @@ SoftBody *sbNew(void)
void sbFree(SoftBody *sb)
{
free_softbody_intern(sb);
+ BKE_ptcache_free(sb->pointcache);
MEM_freeN(sb);
}
+void sbFreeSimulation(SoftBody *sb)
+{
+ free_softbody_intern(sb);
+}
/* makes totally fresh start situation */
void sbObjectToSoftbody(Object *ob)
{
- ob->softflag |= OB_SB_REDO;
+ //ob->softflag |= OB_SB_REDO;
free_softbody_intern(ob->soft);
}
@@ -3414,323 +3383,406 @@ void sbSetInterruptCallBack(int (*f)(void))
SB_localInterruptCallBack = f;
}
-
-/* simulates one step. framenr is in frames */
-void sbObjectStep(Object *ob, float framenr, float (*vertexCos)[3], int numVerts)
+static void softbody_update_positions(Object *ob, SoftBody *sb, float (*vertexCos)[3], int numVerts)
{
- ParticleSystemModifierData *psmd=0;
- ParticleData *pa=0;
- SoftBody *sb;
+ ParticleSystemModifierData *psmd= NULL;
+ ParticleData *pa= NULL;
HairKey *key= NULL;
BodyPoint *bp;
+ float hairmat[4][4];
int a;
- float dtime,ctime,forcetime;
+
+ /* update the vertex locations */
+ if(sb->particles) {
+ psmd= psys_get_modifier(ob,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 */
+ 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);
+ }
+}
+
+static void softbody_reset(Object *ob, SoftBody *sb, float (*vertexCos)[3], int numVerts)
+{
+ ParticleSystemModifierData *psmd= NULL;
+ HairKey *key= NULL;
+ ParticleData *pa= NULL;
+ BodyPoint *bp;
float hairmat[4][4];
+ int a;
- /* 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 */
- /* remake softbody if: */
- if( (ob->softflag & OB_SB_REDO) || /* signal after weightpainting */
- (ob->soft==NULL) || /* just to be nice we allow full init */
- (ob->soft->bpoint==NULL) || /* after reading new file, or acceptable as signal to refresh */
- (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 */
- {
- if(ob->soft && ob->soft->bpoint) /* don't clear on file load */
- softbody_clear_cache(ob, framenr);
+ if(sb->particles) {
+ psmd= psys_get_modifier(ob, sb->particles);
+ pa= sb->particles->particles;
+ key= pa->hair;
- if(ob->soft->particles){
- particles_to_softbody(ob);
+ psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat);
+ }
+
+ for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) {
+ 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*/
}
- else switch(ob->type) {
+ VECCOPY(bp->origS, bp->pos);
+ VECCOPY(bp->origE, bp->pos);
+ VECCOPY(bp->origT, bp->pos);
+ bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0f;
+
+ /* the bp->prev*'s are for rolling back from a canceled try to propagate in time
+ adaptive step size algo in a nutshell:
+ 1. set sheduled time step to new dtime
+ 2. try to advance the sheduled time step, beeing optimistic execute it
+ 3. check for success
+ 3.a we 're fine continue, may be we can increase sheduled time again ?? if so, do so!
+ 3.b we did exceed error limit --> roll back, shorten the sheduled time and try again at 2.
+ 4. check if we did reach dtime
+ 4.a nope we need to do some more at 2.
+ 4.b yup we're done
+ */
+
+ VECCOPY(bp->prevpos, bp->pos);
+ VECCOPY(bp->prevvec, bp->vec);
+ VECCOPY(bp->prevdx, bp->vec);
+ VECCOPY(bp->prevdv, bp->vec);
+ }
+
+ /* make a nice clean scratch struc */
+ free_scratch(sb); /* clear if any */
+ sb_new_scratch(sb); /* make a new */
+ sb->scratch->needstobuildcollider=1;
+
+ if((sb->particles)==0) {
+ /* copy some info to scratch */
+ switch(ob->type) {
case OB_MESH:
- mesh_to_softbody(ob);
+ if (ob->softflag & OB_SB_FACECOLL) mesh_faces_to_scratch(ob);
break;
case OB_LATTICE:
- lattice_to_softbody(ob);
break;
case OB_CURVE:
case OB_SURF:
- curve_surf_to_softbody(ob);
break;
default:
- renew_softbody(ob, numVerts, 0);
break;
}
-
- /* still need to update to correct vertex locations, happens on next step */
- ob->softflag |= OB_SB_RESET;
- ob->softflag &= ~OB_SB_REDO;
}
+}
- sb= ob->soft;
+static void softbody_step(Object *ob, SoftBody *sb, float dtime)
+{
+ /* the simulator */
+ float forcetime;
+ double sct,sst=PIL_check_seconds_timer();
+ ccd_update_deflector_hache(ob,sb->scratch->colliderhash);
- /* still no points? go away */
- if(sb->totpoint==0) return;
+ if(sb->scratch->needstobuildcollider){
+ if (query_external_colliders(ob)){
+ ccd_build_deflector_hache(ob,sb->scratch->colliderhash);
+ }
+ sb->scratch->needstobuildcollider=0;
+ }
+
+ if (sb->solver_ID < 2) {
+ /* special case of 2nd order Runge-Kutta type AKA Heun */
+ int mid_flags=0;
+ float err = 0;
+ float forcetimemax = 1.0f;
+ float forcetimemin = 0.001f;
+ float timedone =0.0; /* how far did we get without violating error condition */
+ /* loops = counter for emergency brake
+ * we don't want to lock up the system if physics fail
+ */
+ int loops =0 ;
+ SoftHeunTol = sb->rklimit; /* humm .. this should be calculated from sb parameters and sizes */
+ if (sb->minloops > 0) forcetimemax = 1.0f / sb->minloops;
+
+ if (sb->maxloops > 0) forcetimemin = 1.0f / sb->maxloops;
+
+ if(sb->solver_ID>0) mid_flags |= MID_PRESERVE;
+
+ //forcetime = dtime; /* hope for integrating in one step */
+ forcetime =forcetimemax; /* hope for integrating in one step */
+ while ( (ABS(timedone) < ABS(dtime)) && (loops < 2000) )
+ {
+ /* set goals in time */
+ interpolate_exciter(ob,200,(int)(200.0*(timedone/dtime)));
+
+ sb->scratch->flag &= ~SBF_DOFUZZY;
+ /* do predictive euler step */
+ softbody_calc_forces(ob, forcetime,timedone/dtime,0);
+ softbody_apply_forces(ob, forcetime, 1, NULL,mid_flags);
- if(sb->particles){
- psmd=psys_get_modifier(ob,sb->particles);
- pa=sb->particles->particles;
- }
- /* checking time: */
+ /* crop new slope values to do averaged slope step */
+ softbody_calc_forces(ob, forcetime,timedone/dtime,0);
+ softbody_apply_forces(ob, forcetime, 2, &err,mid_flags);
- ctime= bsystem_time(ob, framenr, 0.0);
+ softbody_apply_goalsnap(ob);
+
+ if (err > SoftHeunTol) { /* error needs to be scaled to some quantity */
+
+ if (forcetime > forcetimemin){
+ forcetime = MAX2(forcetime / 2.0f,forcetimemin);
+ softbody_restore_prev_step(ob);
+ //printf("down,");
+ }
+ else {
+ timedone += forcetime;
+ }
+ }
+ else {
+ float newtime = forcetime * 1.1f; /* hope for 1.1 times better conditions in next step */
+
+ if (sb->scratch->flag & SBF_DOFUZZY){
+ //if (err > SoftHeunTol/(2.0f*sb->fuzzyness)) { /* stay with this stepsize unless err really small */
+ newtime = forcetime;
+ //}
+ }
+ else {
+ if (err > SoftHeunTol/2.0f) { /* stay with this stepsize unless err really small */
+ newtime = forcetime;
+ }
+ }
+ timedone += forcetime;
+ newtime=MIN2(forcetimemax,MAX2(newtime,forcetimemin));
+ //if (newtime > forcetime) printf("up,");
+ if (forcetime > 0.0)
+ forcetime = MIN2(dtime - timedone,newtime);
+ else
+ forcetime = MAX2(dtime - timedone,newtime);
+ }
+ loops++;
+ if(sb->solverflags & SBSO_MONITOR ){
+ sct=PIL_check_seconds_timer();
+ if (sct-sst > 0.5f) printf("%3.0f%% \r",100.0f*timedone);
+ }
+ /* ask for user break */
+ if (SB_localInterruptCallBack && SB_localInterruptCallBack()) break;
- if (ob->softflag&OB_SB_RESET) {
- dtime = 0.0;
- } else {
- dtime= ctime - sb->ctime;
+ }
+ /* move snapped to final position */
+ interpolate_exciter(ob, 2, 2);
+ softbody_apply_goalsnap(ob);
+
+ // if(G.f & G_DEBUG){
+ if(sb->solverflags & SBSO_MONITOR ){
+ if (loops > HEUNWARNLIMIT) /* monitor high loop counts */
+ printf("\r needed %d steps/frame ",loops);
+ }
+
}
+ else if (sb->solver_ID == 2)
+ {/* do semi "fake" implicit euler */
+ //removed
+ }/*SOLVER SELECT*/
+ else if (sb->solver_ID == 4)
+ {
+ /* do semi "fake" implicit euler */
+ }/*SOLVER SELECT*/
+ else if (sb->solver_ID == 3){
+ /* do "stupid" semi "fake" implicit euler */
+ //removed
- if(softbody_read_cache(ob, framenr)) {
- if(sb->particles==0)
- softbody_to_object(ob, vertexCos, numVerts, sb->local);
- sb->ctime = ctime;
- return;
+ }/*SOLVER SELECT*/
+ else{
+ printf("softbody no valid solver ID!");
+ }/*SOLVER SELECT*/
+ if(sb->plastic){ apply_spring_memory(ob);}
+
+ if(sb->solverflags & SBSO_MONITOR ){
+ sct=PIL_check_seconds_timer();
+ if (sct-sst > 0.5f) printf(" solver time %f %s \r",sct-sst,ob->id.name);
}
+}
- /* the simulator */
+/* simulates one step. framenr is in frames */
+void sbObjectStep(Object *ob, float cfra, float (*vertexCos)[3], int numVerts)
+{
+ ParticleSystemModifierData *psmd=0;
+ ParticleData *pa=0;
+ SoftBody *sb= ob->soft;
+ PointCache *cache;
+ PTCacheID pid;
+ float dtime, timescale;
+ int framedelta, framenr, startframe, endframe;
- /* update the vertex locations */
- if (dtime!=0.0) {
- if(sb->particles) {
- pa=sb->particles->particles;
- key = pa->hair;
+ cache= sb->pointcache;
- psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat);
- }
+ framenr= (int)cfra;
+ framedelta= framenr - cache->simframe;
- 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 */
- if(sb->particles) {
- if(key == pa->hair + pa->totkey) {
- pa++;
- key = pa->hair;
+ BKE_ptcache_id_from_softbody(&pid, ob, sb);
+ BKE_ptcache_id_time(&pid, framenr, &startframe, &endframe, &timescale);
- psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat);
- }
- VECCOPY(bp->origE, key->co);
- Mat4MulVecfl(hairmat,bp->origE);
+ /* check for changes in mesh, should only happen in case the mesh
+ * structure changes during an animation */
+ if(sb->bpoint && numVerts != sb->totpoint) {
+ cache->flag &= ~PTCACHE_SIMULATION_VALID;
+ cache->simframe= 0;
- 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);
- }
+ return;
}
- if((ob->softflag&OB_SB_RESET) || /* got a reset signal */
- (dtime<0.0) || /* back in time */
- (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);
- }
+ /* clamp frame ranges */
+ if(framenr < startframe) {
+ cache->flag &= ~PTCACHE_SIMULATION_VALID;
+ cache->simframe= 0;
- for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) {
- if(sb->particles) {
- if(key == pa->hair + pa->totkey) {
- pa++;
- key = pa->hair;
+ return;
+ }
+ else if(framenr > endframe) {
+ framenr = endframe;
+ }
- 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);
- bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0f;
-
- /* the bp->prev*'s are for rolling back from a canceled try to propagate in time
- adaptive step size algo in a nutshell:
- 1. set sheduled time step to new dtime
- 2. try to advance the sheduled time step, beeing optimistic execute it
- 3. check for success
- 3.a we 're fine continue, may be we can increase sheduled time again ?? if so, do so!
- 3.b we did exceed error limit --> roll back, shorten the sheduled time and try again at 2.
- 4. check if we did reach dtime
- 4.a nope we need to do some more at 2.
- 4.b yup we're done
- */
+ /* verify if we need to create the softbody data */
+ if(sb->bpoint == NULL ||
+ ((ob->softflag & OB_SB_EDGES) && !ob->soft->bspring && object_has_edges(ob))) {
- VECCOPY(bp->prevpos, bp->pos);
- VECCOPY(bp->prevvec, bp->vec);
- VECCOPY(bp->prevdx, bp->vec);
- VECCOPY(bp->prevdv, bp->vec);
+ if(sb->particles){
+ particles_to_softbody(ob);
}
- /* make a nice clean scratch struc */
- free_scratch(sb); /* clear if any */
- sb_new_scratch(sb); /* make a new */
- sb->scratch->needstobuildcollider=1;
-
- if((sb->particles)==0) {
- /* copy some info to scratch */
+ else {
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;
+ case OB_MESH:
+ mesh_to_softbody(ob);
+ break;
+ case OB_LATTICE:
+ lattice_to_softbody(ob);
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ curve_surf_to_softbody(ob);
+ break;
+ default:
+ renew_softbody(ob, numVerts, 0);
+ break;
}
}
- ob->softflag &= ~OB_SB_RESET;
+ softbody_update_positions(ob, sb, vertexCos, numVerts);
+ softbody_reset(ob, sb, vertexCos, numVerts);
}
- else if(dtime>0.0) {
- double sct,sst=PIL_check_seconds_timer();
- ccd_update_deflector_hache(ob,sb->scratch->colliderhash);
+ /* continue physics special case */
+ if(BKE_ptcache_get_continue_physics()) {
+ cache->flag &= ~PTCACHE_SIMULATION_VALID;
+ cache->simframe= 0;
- if(sb->scratch->needstobuildcollider){
- if (query_external_colliders(ob)){
- ccd_build_deflector_hache(ob,sb->scratch->colliderhash);
- }
- sb->scratch->needstobuildcollider=0;
- }
+ /* do simulation */
+ dtime = timescale;
+ softbody_update_positions(ob, sb, vertexCos, numVerts);
+ softbody_step(ob, sb, dtime);
- if (sb->solver_ID < 2) {
- /* special case of 2nd order Runge-Kutta type AKA Heun */
- int mid_flags=0;
- float err = 0;
- float forcetimemax = 1.0f;
- float forcetimemin = 0.001f;
- float timedone =0.0; /* how far did we get without violating error condition */
- /* loops = counter for emergency brake
- * we don't want to lock up the system if physics fail
- */
- int loops =0 ;
- SoftHeunTol = sb->rklimit; /* humm .. this should be calculated from sb parameters and sizes */
- if (sb->minloops > 0) forcetimemax = 1.0f / sb->minloops;
-
- if (sb->maxloops > 0) forcetimemin = 1.0f / sb->maxloops;
+ if(sb->particles==0)
+ softbody_to_object(ob, vertexCos, numVerts, 0);
- if(sb->solver_ID>0) mid_flags |= MID_PRESERVE;
-
- //forcetime = dtime; /* hope for integrating in one step */
- forcetime =forcetimemax; /* hope for integrating in one step */
- while ( (ABS(timedone) < ABS(dtime)) && (loops < 2000) )
- {
- /* set goals in time */
- interpolate_exciter(ob,200,(int)(200.0*(timedone/dtime)));
-
- sb->scratch->flag &= ~SBF_DOFUZZY;
- /* do predictive euler step */
- softbody_calc_forces(ob, forcetime,timedone/dtime,0);
- softbody_apply_forces(ob, forcetime, 1, NULL,mid_flags);
+ return;
+ }
+ /* still no points? go away */
+ if(sb->totpoint==0) return;
- /* crop new slope values to do averaged slope step */
- softbody_calc_forces(ob, forcetime,timedone/dtime,0);
- softbody_apply_forces(ob, forcetime, 2, &err,mid_flags);
+ if(sb->particles){
+ psmd= psys_get_modifier(ob, sb->particles);
+ pa= sb->particles->particles;
+ }
- softbody_apply_goalsnap(ob);
-
- if (err > SoftHeunTol) { /* error needs to be scaled to some quantity */
-
- if (forcetime > forcetimemin){
- forcetime = MAX2(forcetime / 2.0f,forcetimemin);
- softbody_restore_prev_step(ob);
- //printf("down,");
- }
- else {
- timedone += forcetime;
- }
- }
- else {
- float newtime = forcetime * 1.1f; /* hope for 1.1 times better conditions in next step */
-
- if (sb->scratch->flag & SBF_DOFUZZY){
- //if (err > SoftHeunTol/(2.0f*sb->fuzzyness)) { /* stay with this stepsize unless err really small */
- newtime = forcetime;
- //}
- }
- else {
- if (err > SoftHeunTol/2.0f) { /* stay with this stepsize unless err really small */
- newtime = forcetime;
- }
- }
- timedone += forcetime;
- newtime=MIN2(forcetimemax,MAX2(newtime,forcetimemin));
- //if (newtime > forcetime) printf("up,");
- if (forcetime > 0.0)
- forcetime = MIN2(dtime - timedone,newtime);
- else
- forcetime = MAX2(dtime - timedone,newtime);
- }
- loops++;
- if(sb->solverflags & SBSO_MONITOR ){
- sct=PIL_check_seconds_timer();
- if (sct-sst > 0.5f) printf("%3.0f%% \r",100.0f*timedone);
- }
- /* ask for user break */
- if (SB_localInterruptCallBack && SB_localInterruptCallBack()) break;
+ /* try to read from cache */
+ if(softbody_read_cache(ob, framenr)) {
+ if(sb->particles==0)
+ softbody_to_object(ob, vertexCos, numVerts, sb->local);
- }
- /* move snapped to final position */
- interpolate_exciter(ob, 2, 2);
- softbody_apply_goalsnap(ob);
-
- // if(G.f & G_DEBUG){
- if(sb->solverflags & SBSO_MONITOR ){
- if (loops > HEUNWARNLIMIT) /* monitor high loop counts */
- printf("\r needed %d steps/frame ",loops);
- }
-
- }
- else if (sb->solver_ID == 2)
- {/* do semi "fake" implicit euler */
- //removed
- }/*SOLVER SELECT*/
- else if (sb->solver_ID == 4)
- {
- /* do semi "fake" implicit euler */
- }/*SOLVER SELECT*/
- else if (sb->solver_ID == 3){
- /* do "stupid" semi "fake" implicit euler */
- //removed
+ cache->flag |= PTCACHE_SIMULATION_VALID;
+ cache->simframe= framenr;
- }/*SOLVER SELECT*/
- else{
- printf("softbody no valid solver ID!");
- }/*SOLVER SELECT*/
- if(sb->plastic){ apply_spring_memory(ob);}
+ return;
+ }
+ else if(ob->id.lib || (cache->flag & PTCACHE_BAKED)) {
+ /* if baked and nothing in cache, do nothing */
+ if(cache->flag & PTCACHE_SIMULATION_VALID) {
+ cache->flag &= ~PTCACHE_SIMULATION_VALID;
+ cache->simframe= 0;
+ }
- if(sb->solverflags & SBSO_MONITOR ){
- sct=PIL_check_seconds_timer();
- if (sct-sst > 0.5f) printf(" solver time %f %s \r",sct-sst,ob->id.name);
- }
+ return;
}
- if(sb->particles==0)
- softbody_to_object(ob, vertexCos, numVerts, 0);
- sb->ctime= ctime;
+ if(framenr == startframe) {
+ /* first frame, no simulation to do, just set the positions */
+ softbody_update_positions(ob, sb, vertexCos, numVerts);
+
+ cache->flag |= PTCACHE_SIMULATION_VALID;
+ cache->simframe= framenr;
+
+ /* don't write cache on first frame, but on second frame write
+ * cache for frame 1 and 2 */
+ }
+ else if(framedelta == 1) {
+ /* if on second frame, write cache for first frame */
+ if(framenr == startframe+1)
+ sbWriteCache(ob, startframe);
+
+ softbody_update_positions(ob, sb, vertexCos, numVerts);
+
+ /* do simulation */
+ cache->flag |= PTCACHE_SIMULATION_VALID;
+ cache->simframe= framenr;
+
+ /* checking time: */
+ dtime = framedelta*timescale;
- softbody_write_cache(ob, framenr);
+ softbody_step(ob, sb, dtime);
+
+ if(sb->particles==0)
+ softbody_to_object(ob, vertexCos, numVerts, 0);
+
+ sbWriteCache(ob, framenr);
+ }
+ else {
+ /* time step backwards or too large forward - do nothing */
+ if(cache->flag & PTCACHE_SIMULATION_VALID) {
+ cache->flag &= ~PTCACHE_SIMULATION_VALID;
+ cache->simframe= 0;
+ }
+ }
}