static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr) { PointCache *cache; cache= clmd->point_cache; /* initialize simulation data if it didn't exist already */ if(clmd->clothObject == NULL) { if(!cloth_from_object(ob, clmd, result, framenr, 1)) { BKE_ptcache_invalidate(cache); return 0; } if(clmd->clothObject == NULL) { BKE_ptcache_invalidate(cache); return 0; } implicit_set_positions(clmd); clmd->clothObject->last_frame= MINFRAME-1; } return 1; }
static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr) { PointCache *cache; cache= clmd->point_cache; /* initialize simulation data if it didn't exist already */ if(clmd->clothObject == NULL) { if(!cloth_from_object(ob, clmd, result, framenr, 1)) { cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; return 0; } if(clmd->clothObject == NULL) { cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; return 0; } implicit_set_positions(clmd); } return 1; }
static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float UNUSED(framenr), int first) { int i = 0; MVert *mvert = NULL; ClothVertex *verts = NULL; float (*shapekey_rest)[3]= NULL; float tnull[3] = {0,0,0}; Cloth *cloth = NULL; float maxdist = 0; // If we have a clothObject, free it. if ( clmd->clothObject != NULL ) { cloth_free_modifier ( clmd ); if(G.rt > 0) printf("cloth_free_modifier cloth_from_object\n"); } // Allocate a new cloth object. clmd->clothObject = MEM_callocN ( sizeof ( Cloth ), "cloth" ); if ( clmd->clothObject ) { clmd->clothObject->old_solver_type = 255; // clmd->clothObject->old_collision_type = 255; cloth = clmd->clothObject; clmd->clothObject->edgehash = NULL; } else if ( !clmd->clothObject ) { modifier_setError ( & ( clmd->modifier ), "Out of memory on allocating clmd->clothObject." ); return 0; } // mesh input objects need DerivedMesh if ( !dm ) return 0; cloth_from_mesh ( clmd, dm ); // create springs clmd->clothObject->springs = NULL; clmd->clothObject->numsprings = -1; if( clmd->sim_parms->shapekey_rest ) shapekey_rest = dm->getVertDataArray ( dm, CD_CLOTH_ORCO ); mvert = dm->getVertArray ( dm ); verts = clmd->clothObject->verts; // set initial values for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ ) { if(first) { copy_v3_v3( verts->x, mvert[i].co ); mul_m4_v3( ob->obmat, verts->x ); if( shapekey_rest ) { verts->xrest= shapekey_rest[i]; mul_m4_v3( ob->obmat, verts->xrest ); } else verts->xrest = verts->x; } /* no GUI interface yet */ verts->mass = clmd->sim_parms->mass; verts->impulse_count = 0; if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) verts->goal= clmd->sim_parms->defgoal; else verts->goal= 0.0f; verts->flags = 0; copy_v3_v3 ( verts->xold, verts->x ); copy_v3_v3 ( verts->xconst, verts->x ); copy_v3_v3 ( verts->txold, verts->x ); copy_v3_v3 ( verts->tx, verts->x ); mul_v3_fl( verts->v, 0.0f ); verts->impulse_count = 0; copy_v3_v3 ( verts->impulse, tnull ); } // apply / set vertex groups // has to be happen before springs are build! cloth_apply_vgroup (clmd, dm); if ( !cloth_build_springs ( clmd, dm ) ) { cloth_free_modifier ( clmd ); modifier_setError ( & ( clmd->modifier ), "Can't build springs." ); printf("cloth_free_modifier cloth_build_springs\n"); return 0; } for ( i = 0; i < dm->getNumVerts(dm); i++) { if((!(cloth->verts[i].flags & CLOTH_VERT_FLAG_PINNED)) && (cloth->verts[i].goal > ALMOST_ZERO)) { cloth_add_spring (clmd, i, i, 0.0, CLOTH_SPRING_TYPE_GOAL); } } // init our solver if ( solvers [clmd->sim_parms->solver_type].init ) { solvers [clmd->sim_parms->solver_type].init ( ob, clmd ); } if(!first) implicit_set_positions(clmd); clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel) ); for(i = 0; i < dm->getNumVerts(dm); i++) { maxdist = MAX2(maxdist, clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len*2.0f)); } clmd->clothObject->bvhselftree = bvhselftree_build_from_cloth ( clmd, maxdist ); return 1; }
/************************************************ * clothModifier_do - main simulation function ************************************************/ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, DerivedMesh *dm, float (*vertexCos)[3]) { PointCache *cache; PTCacheID pid; float timescale; int framenr, startframe, endframe; int cache_result; clmd->scene= scene; /* nice to pass on later :) */ framenr= (int)scene->r.cfra; cache= clmd->point_cache; BKE_ptcache_id_from_cloth(&pid, ob, clmd); 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)) { clmd->sim_parms->reset = 0; cache->flag |= PTCACHE_OUTDATED; BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); BKE_ptcache_validate(cache, 0); cache->last_exact= 0; cache->flag &= ~PTCACHE_REDO_NEEDED; return; } // 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(BKE_ptcache_get_continue_physics() || ((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); return; } else if(framenr > endframe) { framenr= endframe; } /* initialize simulation data if it didn't exist already */ if(!do_init_cloth(ob, clmd, dm, framenr)) return; if((framenr == startframe) && (clmd->sim_parms->preroll == 0)) { BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); do_init_cloth(ob, clmd, dm, framenr); BKE_ptcache_validate(cache, framenr); cache->flag &= ~PTCACHE_REDO_NEEDED; clmd->clothObject->last_frame= framenr; return; } /* try to read from cache */ 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); cloth_to_object (ob, clmd, vertexCos); BKE_ptcache_validate(cache, framenr); if(cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED) BKE_ptcache_write(&pid, framenr); clmd->clothObject->last_frame= framenr; return; } else if(cache_result==PTCACHE_READ_OLD) { implicit_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 */ BKE_ptcache_invalidate(cache); return; } if(framenr!=clmd->clothObject->last_frame+1) return; /* if on second frame, write cache for first frame */ if(cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) BKE_ptcache_write(&pid, startframe); clmd->sim_parms->timescale *= framenr - cache->simframe; /* do simulation */ BKE_ptcache_validate(cache, framenr); if(!do_step_cloth(ob, clmd, dm, framenr)) { BKE_ptcache_invalidate(cache); } else BKE_ptcache_write(&pid, framenr); cloth_to_object (ob, clmd, vertexCos); clmd->clothObject->last_frame= framenr; }
/************************************************ * clothModifier_do - main simulation function ************************************************/ DerivedMesh *clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc) { DerivedMesh *result; PointCache *cache; PTCacheID pid; float timescale; int framedelta, framenr, startframe, endframe; int cache_result; clmd->scene= scene; /* nice to pass on later :) */ framenr= (int)scene->r.cfra; cache= clmd->point_cache; result = CDDM_copy(dm); BKE_ptcache_id_from_cloth(&pid, ob, clmd); BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, ×cale); clmd->sim_parms->timescale= timescale; if(!result) { cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; cache->last_exact= 0; return dm; } /* verify we still have the same number of vertices, if not do nothing. * note that this should only happen if the number of vertices changes * during an animation due to a preceding modifier, this should not * happen because of object changes! */ if(clmd->clothObject) { if(result->getNumVerts(result) != clmd->clothObject->numverts) { cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; cache->last_exact= 0; return result; } } // unused in the moment, calculated seperately in implicit.c clmd->sim_parms->dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame; /* handle continuous simulation with the play button */ if(BKE_ptcache_get_continue_physics()) { cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; cache->last_exact= 0; /* do simulation */ if(!do_init_cloth(ob, clmd, result, framenr)) return result; do_step_cloth(ob, clmd, result, framenr); cloth_to_object(ob, clmd, result); return result; } /* simulation is only active during a specific period */ if(framenr < startframe) { cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; cache->last_exact= 0; return result; } else if(framenr > endframe) { framenr= endframe; } if(cache->flag & PTCACHE_SIMULATION_VALID) framedelta= framenr - cache->simframe; else framedelta= -1; /* initialize simulation data if it didn't exist already */ if(!do_init_cloth(ob, clmd, result, framenr)) return result; if(framenr == startframe) { BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); do_init_cloth(ob, clmd, result, framenr); cache->simframe= framenr; cache->flag |= PTCACHE_SIMULATION_VALID; cache->flag &= ~PTCACHE_REDO_NEEDED; return result; } /* try to read from cache */ cache_result = BKE_ptcache_read_cache(&pid, (float)framenr, scene->r.frs_sec); if(cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED) { implicit_set_positions(clmd); cloth_to_object (ob, clmd, result); cache->simframe= framenr; cache->flag |= PTCACHE_SIMULATION_VALID; if(cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED) BKE_ptcache_write_cache(&pid, framenr); return result; } else if(cache_result==PTCACHE_READ_OLD) { implicit_set_positions(clmd); cache->flag |= PTCACHE_SIMULATION_VALID; } else if(ob->id.lib || (cache->flag & PTCACHE_BAKED)) { /* if baked and nothing in cache, do nothing */ cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; cache->last_exact= 0; return result; } /* if on second frame, write cache for first frame */ if(cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) BKE_ptcache_write_cache(&pid, startframe); clmd->sim_parms->timescale *= framenr - cache->simframe; /* do simulation */ cache->flag |= PTCACHE_SIMULATION_VALID; cache->simframe= framenr; if(!do_step_cloth(ob, clmd, result, framenr)) { cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; cache->last_exact= 0; } else BKE_ptcache_write_cache(&pid, framenr); cloth_to_object (ob, clmd, result); return result; }