diff options
Diffstat (limited to 'source/blender/blenkernel/intern/particle_system.c')
-rw-r--r-- | source/blender/blenkernel/intern/particle_system.c | 1151 |
1 files changed, 609 insertions, 542 deletions
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index b057976e3b5..a128cfaedf9 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -24,7 +24,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Raul Fernandez Hernandez (Farsthary), Stephen Swhitehorn. * * ***** END GPL LICENSE BLOCK ***** */ @@ -159,8 +159,7 @@ void psys_reset(ParticleSystem *psys, int mode) psys_free_path_cache(psys, psys->edit); /* reset point cache */ - psys->pointcache->flag &= ~PTCACHE_SIMULATION_VALID; - psys->pointcache->simframe= 0; + BKE_ptcache_invalidate(psys->pointcache); } static void realloc_particles(ParticleSimulationData *sim, int new_totpart) @@ -287,7 +286,7 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys) node: the allocated links - total derived mesh element count nodearray: the array of nodes aligned with the base mesh's elements, so - each original elements can reference its derived elements + each original elements can reference its derived elements */ Mesh *me= (Mesh*)ob->data; PARTICLE_P; @@ -512,18 +511,18 @@ static void distribute_particles_in_grid(DerivedMesh *dm, ParticleSystem *psys) static void hammersley_create(float *out, int n, int seed, float amount) { RNG *rng; - double p, t, offs[2]; - int k, kk; + double p, t, offs[2]; + int k, kk; rng = rng_new(31415926 + n + seed); offs[0]= rng_getDouble(rng) + amount; offs[1]= rng_getDouble(rng) + amount; rng_free(rng); - for (k = 0; k < n; k++) { - t = 0; - for (p = 0.5, kk = k; kk; p *= 0.5, kk >>= 1) - if (kk & 1) /* kk mod 2 = 1 */ + for (k = 0; k < n; k++) { + t = 0; + for (p = 0.5, kk = k; kk; p *= 0.5, kk >>= 1) + if (kk & 1) /* kk mod 2 = 1 */ t += p; out[2*k + 0]= fmod((double)k/(double)n + offs[0], 1.0); @@ -546,7 +545,7 @@ static void init_mv_jit(float *jit, int num, int seed2, float amount) rng = rng_new(31415926 + num + seed2); x= 0; - num2 = 2 * num; + num2 = 2 * num; for(i=0; i<num2; i+=2) { jit[i]= x + amount*rad1*(0.5f - rng_getFloat(rng)); @@ -618,6 +617,10 @@ static int binary_search_distribution(float *sum, int n, float value) return low; } +/* the max number if calls to rng_* funcs within psys_thread_distribute_particle + * be sure to keep up to date if this changes */ +#define PSYS_RND_DIST_SKIP 2 + /* note: this function must be thread safe, for from == PART_FROM_CHILD */ #define ONLY_WORKING_WITH_PA_VERTS 0 static void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, ChildParticle *cpa, int p) @@ -633,6 +636,7 @@ static void psys_thread_distribute_particle(ParticleThread *thread, ParticleData int cfrom= ctx->cfrom; int distr= ctx->distr; int i, intersect, tot; + int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */ if(from == PART_FROM_VERT) { /* TODO_PARTICLE - use original index */ @@ -670,6 +674,8 @@ static void psys_thread_distribute_particle(ParticleThread *thread, ParticleData case PART_DISTR_RAND: randu= rng_getFloat(thread->rng); randv= rng_getFloat(thread->rng); + rng_skip_tot -= 2; + psys_uv_to_w(randu, randv, mface->v4, pa->fuv); break; } @@ -752,6 +758,8 @@ static void psys_thread_distribute_particle(ParticleThread *thread, ParticleData randu= rng_getFloat(thread->rng); randv= rng_getFloat(thread->rng); + rng_skip_tot -= 2; + psys_uv_to_w(randu, randv, mf->v4, cpa->fuv); cpa->num = ctx->index[p]; @@ -860,6 +868,9 @@ static void psys_thread_distribute_particle(ParticleThread *thread, ParticleData cpa->parent=cpa->pa[0]; } } + + if(rng_skip_tot > 0) /* should never be below zero */ + rng_skip(thread->rng, rng_skip_tot); } static void *exec_distribution(void *data) @@ -876,12 +887,12 @@ static void *exec_distribution(void *data) for(p=0; p<totpart; p++, cpa++) { if(thread->ctx->skip) /* simplification skip */ - rng_skip(thread->rng, 5*thread->ctx->skip[p]); + rng_skip(thread->rng, PSYS_RND_DIST_SKIP * thread->ctx->skip[p]); if((p+thread->num) % thread->tot == 0) psys_thread_distribute_particle(thread, NULL, cpa, p); else /* thread skip */ - rng_skip(thread->rng, 5); + rng_skip(thread->rng, PSYS_RND_DIST_SKIP); } } else { @@ -2215,21 +2226,17 @@ static void set_keyed_keys(ParticleSimulationData *sim) void psys_make_temp_pointcache(Object *ob, ParticleSystem *psys) { PointCache *cache = psys->pointcache; - PTCacheID pid; - - if((cache->flag & PTCACHE_DISK_CACHE)==0 || cache->mem_cache.first) - return; - BKE_ptcache_id_from_particles(&pid, ob, psys); - - BKE_ptcache_disk_to_mem(&pid); + if(cache->flag & PTCACHE_DISK_CACHE && cache->mem_cache.first == NULL) { + PTCacheID pid; + BKE_ptcache_id_from_particles(&pid, ob, psys); + BKE_ptcache_disk_to_mem(&pid); + } } static void psys_clear_temp_pointcache(ParticleSystem *psys) { - if((psys->pointcache->flag & PTCACHE_DISK_CACHE)==0) - return; - - BKE_ptcache_free_mem(&psys->pointcache->mem_cache); + if(psys->pointcache->flag & PTCACHE_DISK_CACHE) + BKE_ptcache_free_mem(&psys->pointcache->mem_cache); } void psys_get_pointcache_start_end(Scene *scene, ParticleSystem *psys, int *sfra, int *efra) { @@ -2275,6 +2282,136 @@ static void psys_update_effectors(ParticleSimulationData *sim) precalc_guides(sim, sim->psys->effectors); } +/************************************************* + SPH fluid physics + + In theory, there could be unlimited implementation + of SPH simulators +**************************************************/ +void particle_fluidsim(ParticleSystem *psys, ParticleData *pa, ParticleSettings *part, ParticleSimulationData *sim, float dfra, float cfra, float mass){ +/**************************************************************************************************************** +* This code uses in some parts adapted algorithms from the pseduo code as outlined in the Research paper +* Titled: Particle-based Viscoelastic Fluid Simulation. +* Authors: Simon Clavet, Philippe Beaudoin and Pierre Poulin +* +* Website: http://www.iro.umontreal.ca/labs/infographie/papers/Clavet-2005-PVFS/ +* Presented at Siggraph, (2005) +* +*****************************************************************************************************************/ + KDTree *tree = psys->tree; + KDTreeNearest *ptn = NULL; + + SPHFluidSettings *fluid = part->fluid; + ParticleData *second_particle; + + float start[3], end[3], v[3]; + float temp[3]; + float q, radius, D; + float p, pnear, pressure_near, pressure; + float dtime = dfra * psys_get_timestep(sim); + float omega = fluid->viscosity_omega; + float beta = fluid->viscosity_omega; + float massfactor = 1.0f/mass; + int n, neighbours; + + + radius = fluid->radius; + + VECCOPY(start, pa->prev_state.co); + VECCOPY(end, pa->state.co); + + VECCOPY(v, pa->state.vel); + + neighbours = BLI_kdtree_range_search(tree, radius, start, NULL, &ptn); + + /* use ptn[n].co to store relative direction */ + for(n=1; n<neighbours; n++) { + sub_v3_v3(ptn[n].co, start); + normalize_v3(ptn[n].co); + } + + /* Viscosity - Algorithm 5 */ + if (omega > 0.f || beta > 0.f) { + float u, I; + + for(n=1; n<neighbours; n++) { + second_particle = psys->particles + ptn[n].index; + q = ptn[n].dist/radius; + + sub_v3_v3v3(temp, v, second_particle->prev_state.vel); + + u = dot_v3v3(ptn[n].co, temp); + + if (u > 0){ + I = dtime * ((1-q) * (omega * u + beta * u*u)) * 0.5f; + madd_v3_v3fl(v, ptn[n].co, -I * massfactor); + } + } + } + + /* Hooke's spring force */ + if (fluid->spring_k > 0.f) { + float D, L = fluid->rest_length; + for(n=1; n<neighbours; n++) { + /* L is a factor of radius */ + D = dtime * 10.f * fluid->spring_k * (1.f - L) * (L - ptn[n].dist/radius); + madd_v3_v3fl(v, ptn[n].co, -D * massfactor); + } + } + /* Update particle position */ + VECADDFAC(end, start, v, dtime); + + /* Double Density Relaxation - Algorithm 2 */ + p = 0; + pnear = 0; + for(n=1; n<neighbours; n++) { + q = ptn[n].dist/radius; + p += ((1-q)*(1-q)); + pnear += ((1-q)*(1-q)*(1-q)); + } + p *= part->mass; + pnear *= part->mass; + pressure = fluid->stiffness_k * (p - fluid->rest_density); + pressure_near = fluid->stiffness_knear * pnear; + + for(n=1; n<neighbours; n++) { + q = ptn[n].dist/radius; + + D = dtime * dtime * (pressure*(1-q) + pressure_near*(1-q)*(1-q))* 0.5f; + madd_v3_v3fl(end, ptn[n].co, -D * massfactor); + } + + /* Artificial buoyancy force in negative gravity direction */ + if (fluid->buoyancy >= 0.f && psys_uses_gravity(sim)) { + float B = -dtime * dtime * fluid->buoyancy * (p - fluid->rest_density) * 0.5f; + madd_v3_v3fl(end, sim->scene->physics_settings.gravity, -B * massfactor); + } + + /* apply final result and recalculate velocity */ + VECCOPY(pa->state.co, end); + sub_v3_v3v3(pa->state.vel, end, start); + mul_v3_fl(pa->state.vel, 1.f/dtime); + + if(ptn){ MEM_freeN(ptn); ptn=NULL;} +} + +static void apply_particle_fluidsim(ParticleSystem *psys, ParticleData *pa, ParticleSettings *part, ParticleSimulationData *sim, float dfra, float cfra){ + ParticleTarget *pt; +// float dtime = dfra*psys_get_timestep(sim); + float particle_mass = part->mass; + + particle_fluidsim(psys, pa, part, sim, dfra, cfra, particle_mass); + + /*----check other SPH systems (Multifluids) , each fluid has its own parameters---*/ + for(pt=sim->psys->targets.first; pt; pt=pt->next) { + ParticleSystem *epsys = psys_get_target_system(sim->ob, pt); + + if(epsys) + particle_fluidsim(epsys, pa, epsys->part, sim, dfra, cfra, particle_mass); + } + /*----------------------------------------------------------------*/ +} + /************************************************/ /* Newtonian physics */ /************************************************/ @@ -2720,6 +2857,12 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo VECCOPY(col.co1, pa->prev_state.co); VECCOPY(col.co2, pa->state.co); + + VECCOPY(col.ve1, pa->prev_state.vel); + VECCOPY(col.ve2, pa->state.vel); + mul_v3_fl(col.ve1, timestep * dfra); + mul_v3_fl(col.ve2, timestep * dfra); + col.t = 0.0f; /* override for boids */ @@ -2765,12 +2908,20 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo int through = (BLI_frand() < pd->pdef_perm) ? 1 : 0; float co[3]; /* point of collision */ float vec[3]; /* movement through collision */ - float t = hit.dist/col.ray_len; /* time of collision between this iteration */ - float dt = col.t + t * (1.0f - col.t); /* time of collision between frame change*/ - - interp_v3_v3v3(co, col.co1, col.co2, t); + float acc[3]; /* acceleration */ + + float x = hit.dist/col.ray_len; /* location of collision between this iteration */ + float le = len_v3(col.ve1)/col.ray_len; + float ac = len_v3(col.ve2)/col.ray_len - le; /* (taking acceleration into account) */ + float t = (-le + sqrt(le*le + 2*ac*x))/ac; /* time of collision between this iteration */ + float dt = col.t + x * (1.0f - col.t); /* time of collision between frame change*/ + float it = 1.0 - t; + + interp_v3_v3v3(co, col.co1, col.co2, x); VECSUB(vec, col.co2, col.co1); + VECSUB(acc, col.ve2, col.ve1); + mul_v3_fl(col.vel, 1.0f-col.t); /* particle dies in collision */ @@ -2790,7 +2941,7 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo deflections=max_deflections; } else { - float nor_vec[3], tan_vec[3], tan_vel[3], vel[3]; + float nor_vec[3], tan_vec[3], tan_vel[3]; float damp, frict; float inp, inp_v; @@ -2867,10 +3018,6 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo /* combine components together again */ VECADD(vec, nor_vec, tan_vec); - /* calculate velocity from collision vector */ - VECCOPY(vel, vec); - mul_v3_fl(vel, 1.0f/MAX2((timestep*dfra) * (1.0f - col.t), 0.00001)); - /* make sure we don't hit the current face again */ VECADDFAC(co, co, col.nor, (through ? -0.0001f : 0.0001f)); @@ -2878,21 +3025,25 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo BoidParticle *bpa = pa->boid; if(bpa->data.mode == eBoidMode_OnLand || co[2] <= boid_z) { co[2] = boid_z; - vel[2] = 0.0f; + vec[2] = 0.0f; } } - /* store state for reactors */ - //VECCOPY(reaction_state.co, co); - //interp_v3_v3v3(reaction_state.vel, pa->prev_state.vel, pa->state.vel, dt); - //interp_qt_qtqt(reaction_state.rot, pa->prev_state.rot, pa->state.rot, dt); - /* set coordinates for next iteration */ + + /* apply acceleration to final position, but make sure particle stays above surface */ + madd_v3_v3v3fl(acc, vec, acc, it); + ac = dot_v3v3(acc, col.nor); + if((!through && ac < 0.0f) || (through && ac > 0.0f)) + madd_v3_v3fl(acc, col.nor, -ac); + VECCOPY(col.co1, co); - VECADDFAC(col.co2, co, vec, 1.0f - t); - col.t = dt; + VECADDFAC(col.co2, co, acc, it); + + VECCOPY(col.ve1, vec); + VECCOPY(col.ve2, acc); - if(len_v3(vec) < 0.001 && len_v3(pa->state.vel) < 0.001) { + if(len_v3(vec) < 0.001 && len_v3v3(pa->state.co, pa->prev_state.co) < 0.001) { /* kill speed to stop slipping */ VECCOPY(pa->state.vel,zerovec); VECCOPY(pa->state.co, co); @@ -2902,10 +3053,14 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo } else { VECCOPY(pa->state.co, col.co2); + mul_v3_v3fl(pa->state.vel, acc, 1.0f/MAX2((timestep*dfra) * (1.0f - col.t), 0.00001)); + /* Stickness to surface */ normalize_v3(nor_vec); - VECADDFAC(pa->state.vel, vel, nor_vec, -pd->pdef_stickness); + madd_v3_v3fl(pa->state.vel, nor_vec, -pd->pdef_stickness); } + + col.t = dt; } deflections++; @@ -2920,66 +3075,18 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo /* Hair */ /************************************************/ /* check if path cache or children need updating and do it if needed */ -static void psys_update_path_cache(ParticleSimulationData *sim, float cfra) +void psys_update_path_cache(ParticleSimulationData *sim, float cfra) { ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; - ParticleEditSettings *pset = &sim->scene->toolsettings->particle; - int distr=0, alloc=0, skip=0; - - if((psys->part->childtype && psys->totchild != get_psys_tot_child(sim->scene, psys)) || psys->recalc&PSYS_RECALC_RESET) - alloc=1; - - if(alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (sim->ob && sim->ob->mode & OB_MODE_WEIGHT_PAINT))) - distr=1; - - if(distr){ - if(alloc) - realloc_particles(sim, sim->psys->totpart); - - if(get_psys_tot_child(sim->scene, psys)) { - /* don't generate children while computing the hair keys */ - if(!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) { - distribute_particles(sim, PART_FROM_CHILD); - - if(part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES && part->parents!=0.0) - psys_find_parents(sim); - } - } - else - psys_free_children(psys); - } - - if((part->type==PART_HAIR || psys->flag&PSYS_KEYED || psys->pointcache->flag & PTCACHE_BAKED)==0) - skip = 1; /* only hair, keyed and baked stuff can have paths */ - else if(part->ren_as != PART_DRAW_PATH && !(part->type==PART_HAIR && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR))) - skip = 1; /* particle visualization must be set as path */ - else if(!psys->renderdata) { - if(part->draw_as != PART_DRAW_REND) - skip = 1; /* draw visualization */ - else if(psys->pointcache->flag & PTCACHE_BAKING) - skip = 1; /* no need to cache paths while baking dynamics */ - else if(psys_in_edit_mode(sim->scene, psys)) { - if((pset->flag & PE_DRAW_PART)==0) - skip = 1; - else if(part->childtype==0 && (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED)==0) - skip = 1; /* in edit mode paths are needed for child particles and dynamic hair */ - } - } - - if(!skip) { + + /* only hair, keyed and baked stuff can have paths */ + if(part->type==PART_HAIR || psys->flag&PSYS_KEYED || psys->pointcache->mem_cache.first) { psys_cache_paths(sim, cfra); /* for render, child particle paths are computed on the fly */ - if(part->childtype) { - if(!psys->totchild) - skip = 1; - else if((psys->part->type == PART_HAIR && psys->flag & PSYS_HAIR_DONE)==0) - skip = 1; - - if(!skip) - psys_cache_child_paths(sim, cfra, 0); - } + if(part->childtype && psys->totchild) + psys_cache_child_paths(sim, cfra, 0); } else if(psys->pathcache) psys_free_path_cache(psys, NULL); @@ -3094,6 +3201,8 @@ static void do_hair_dynamics(ParticleSimulationData *sim) psys->hair_out_dm = clothModifier_do(psys->clmd, sim->scene, sim->ob, dm, 0, 0); psys->clmd->sim_parms->effector_weights = NULL; + + psys_free_path_cache(psys, NULL); } static void hair_step(ParticleSimulationData *sim, float cfra) { @@ -3123,8 +3232,8 @@ static void hair_step(ParticleSimulationData *sim, float cfra) if(psys->part->type==PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) do_hair_dynamics(sim); + /* following lines were removed r29079 but cause bug [#22811], see report for details */ psys_update_effectors(sim); - psys_update_path_cache(sim, cfra); psys->flag |= PSYS_HAIR_UPDATED; @@ -3184,15 +3293,11 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) { ParticleSystem *psys = sim->psys; ParticleSettings *part=psys->part; - KDTree *tree=0; - //IpoCurve *icu_esize=find_ipocurve(part->ipo,PART_EMIT_SIZE); // XXX old animation system -/* Material *ma=give_current_material(sim->ob, part->omat); */ BoidBrainData bbd; PARTICLE_P; float timestep; - int totpart; /* current time */ - float ctime, ipotime; // XXX old animation system + float ctime; /* frame & time changes */ float dfra, dtime, pa_dtime, pa_dfra=0.0; float birthtime, dietime; @@ -3200,200 +3305,186 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) /* where have we gone in time since last time */ dfra= cfra - psys->cfra; - totpart=psys->totpart; - timestep = psys_get_timestep(sim); dtime= dfra*timestep; ctime= cfra*timestep; - ipotime= cfra; // XXX old animation system - -#if 0 // XXX old animation system - if(part->flag&PART_ABS_TIME && part->ipo){ - calc_ipo(part->ipo, cfra); - execute_ipo((ID *)part, part->ipo); - } -#endif // XXX old animation system if(dfra<0.0){ - float *vg_size=0; - //if(part->type==PART_REACTOR) - // vg_size=psys_cache_vgroup(sim->psmd->dm,psys,PSYS_VG_SIZE); - LOOP_EXISTING_PARTICLES { - /* set correct ipo timing */ -#if 0 // XXX old animation system - if((part->flag&PART_ABS_TIME)==0 && part->ipo){ - ipotime=100.0f*(cfra-pa->time)/pa->lifetime; - calc_ipo(part->ipo, ipotime); - execute_ipo((ID *)part, part->ipo); - } -#endif // XXX old animation system pa->size = part->size; if(part->randsize > 0.0) pa->size *= 1.0f - part->randsize * PSYS_FRAND(p + 1); reset_particle(sim, pa, dtime, cfra); } - - if(vg_size) - MEM_freeN(vg_size); + return; } - else{ - BLI_srandom(31415926 + (int)cfra + psys->seed); - psys_update_effectors(sim); + BLI_srandom(31415926 + (int)cfra + psys->seed); + + psys_update_effectors(sim); - if(part->type != PART_HAIR) - sim->colliders = get_collider_cache(sim->scene, NULL); + if(part->type != PART_HAIR) + sim->colliders = get_collider_cache(sim->scene, NULL, NULL); - if(part->phystype==PART_PHYS_BOIDS){ - ParticleTarget *pt = psys->targets.first; - bbd.sim = sim; - bbd.part = part; - bbd.cfra = cfra; - bbd.dfra = dfra; - bbd.timestep = timestep; + if(part->phystype==PART_PHYS_BOIDS){ + ParticleTarget *pt = psys->targets.first; + bbd.sim = sim; + bbd.part = part; + bbd.cfra = cfra; + bbd.dfra = dfra; + bbd.timestep = timestep; - psys_update_particle_tree(psys, cfra); + psys_update_particle_tree(psys, cfra); - boids_precalc_rules(part, cfra); + boids_precalc_rules(part, cfra); - for(; pt; pt=pt->next) { - if(pt->ob) - psys_update_particle_tree(BLI_findlink(&pt->ob->particlesystem, pt->psys-1), cfra); - } + for(; pt; pt=pt->next) { + if(pt->ob) + psys_update_particle_tree(BLI_findlink(&pt->ob->particlesystem, pt->psys-1), cfra); + } + } + else if(part->phystype==PART_PHYS_FLUID){ + ParticleTarget *pt = psys->targets.first; + psys_update_particle_tree(psys, cfra); + + for(; pt; pt=pt->next) { /* Updating others systems particle tree for fluid-fluid interaction */ + if(pt->ob) psys_update_particle_tree(BLI_findlink(&pt->ob->particlesystem, pt->psys-1), cfra); } + } - /* main loop: calculate physics for all particles */ - LOOP_SHOWN_PARTICLES { - copy_particle_key(&pa->prev_state,&pa->state,1); - - /* set correct ipo timing */ -#if 0 // XXX old animation system - if((part->flag&PART_ABS_TIME)==0 && part->ipo){ - ipotime=100.0f*(cfra-pa->time)/pa->lifetime; - calc_ipo(part->ipo, ipotime); - execute_ipo((ID *)part, part->ipo); - } -#endif // XXX old animation system - //update_particle_settings(psys, part, &tpart, pa); + /* main loop: calculate physics for all particles */ + LOOP_SHOWN_PARTICLES { + copy_particle_key(&pa->prev_state,&pa->state,1); - pa->size = part->size; - if(part->randsize > 0.0) - pa->size *= 1.0f - part->randsize * PSYS_FRAND(p + 1); + pa->size = part->size; + if(part->randsize > 0.0) + pa->size *= 1.0f - part->randsize * PSYS_FRAND(p + 1); - ///* reactions can change birth time so they need to be checked first */ - //if(psys->reactevents.first && ELEM(pa->alive,PARS_DEAD,PARS_KILLED)==0) - // react_to_events(psys,p); + ///* reactions can change birth time so they need to be checked first */ + //if(psys->reactevents.first && ELEM(pa->alive,PARS_DEAD,PARS_KILLED)==0) + // react_to_events(psys,p); - birthtime = pa->time; - dietime = birthtime + pa->lifetime; + birthtime = pa->time; + dietime = birthtime + pa->lifetime; - pa_dfra = dfra; - pa_dtime = dtime; + pa_dfra = dfra; + pa_dtime = dtime; - if(dietime <= cfra && psys->cfra < dietime){ - /* particle dies some time between this and last step */ - pa_dfra = dietime - ((birthtime > psys->cfra) ? birthtime : psys->cfra); - pa_dtime = pa_dfra * timestep; - pa->alive = PARS_DYING; - } - else if(birthtime <= cfra && birthtime >= psys->cfra){ - /* particle is born some time between this and last step*/ - reset_particle(sim, pa, dtime, cfra); - pa->alive = PARS_ALIVE; - pa_dfra = cfra - birthtime; - pa_dtime = pa_dfra*timestep; - } - else if(dietime < cfra){ - /* nothing to be done when particle is dead */ - } + if(dietime <= cfra && psys->cfra < dietime){ + /* particle dies some time between this and last step */ + pa_dfra = dietime - ((birthtime > psys->cfra) ? birthtime : psys->cfra); + pa_dtime = pa_dfra * timestep; + pa->alive = PARS_DYING; + } + else if(birthtime <= cfra && birthtime >= psys->cfra){ + /* particle is born some time between this and last step*/ + reset_particle(sim, pa, dtime, cfra); + pa->alive = PARS_ALIVE; + pa_dfra = cfra - birthtime; + pa_dtime = pa_dfra*timestep; + } + else if(dietime < cfra){ + /* nothing to be done when particle is dead */ + } + + /* only reset unborn particles if they're shown or if the particle is born soon*/ + if(pa->alive==PARS_UNBORN + && (part->flag & PART_UNBORN || cfra + psys->pointcache->step > pa->time)) + reset_particle(sim, pa, dtime, cfra); + else if(part->phystype == PART_PHYS_NO) + reset_particle(sim, pa, dtime, cfra); + + if(dfra>0.0 && ELEM(pa->alive,PARS_ALIVE,PARS_DYING)){ + switch(part->phystype){ + case PART_PHYS_NEWTON: + /* do global forces & effectors */ + apply_particle_forces(sim, p, pa_dfra, cfra); + + /* deflection */ + if(sim->colliders) + deflect_particle(sim, p, pa_dfra, cfra); + + /* rotations */ + rotate_particle(part, pa, pa_dfra, timestep); + break; + case PART_PHYS_BOIDS: + { + bbd.goal_ob = NULL; + boid_brain(&bbd, p, pa); + if(pa->alive != PARS_DYING) { + boid_body(&bbd, pa); - /* only reset unborn particles if they're shown or if the particle is born soon*/ - if(pa->alive==PARS_UNBORN - && (part->flag & PART_UNBORN || cfra + psys->pointcache->step > pa->time)) - reset_particle(sim, pa, dtime, cfra); - else if(part->phystype == PART_PHYS_NO) - reset_particle(sim, pa, dtime, cfra); - - if(dfra>0.0 && ELEM(pa->alive,PARS_ALIVE,PARS_DYING)){ - switch(part->phystype){ - case PART_PHYS_NEWTON: - /* do global forces & effectors */ - apply_particle_forces(sim, p, pa_dfra, cfra); - /* deflection */ if(sim->colliders) deflect_particle(sim, p, pa_dfra, cfra); - - /* rotations */ - rotate_particle(part, pa, pa_dfra, timestep); - break; - case PART_PHYS_BOIDS: - { - bbd.goal_ob = NULL; - boid_brain(&bbd, p, pa); - if(pa->alive != PARS_DYING) { - boid_body(&bbd, pa); - - /* deflection */ - if(sim->colliders) - deflect_particle(sim, p, pa_dfra, cfra); - } - break; } + break; } + case PART_PHYS_FLUID: + { + /* do global forces & effectors */ + apply_particle_forces(sim, p, pa_dfra, cfra); + + /* do fluid sim */ + apply_particle_fluidsim(psys, pa, part, sim, pa_dfra, cfra); + + /* deflection */ + if(sim->colliders) + deflect_particle(sim, p, pa_dfra, cfra); + + /* rotations, SPH particles are not physical particles, just interpolation particles, thus rotation has not a direct sense for them */ + rotate_particle(part, pa, pa_dfra, timestep); + break; + } + } - if(pa->alive == PARS_DYING){ - //push_reaction(ob,psys,p,PART_EVENT_DEATH,&pa->state); - - pa->alive=PARS_DEAD; - pa->state.time=pa->dietime; - } - else - pa->state.time=cfra; + if(pa->alive == PARS_DYING){ + //push_reaction(ob,psys,p,PART_EVENT_DEATH,&pa->state); - //push_reaction(ob,psys,p,PART_EVENT_NEAR,&pa->state); + pa->alive=PARS_DEAD; + pa->state.time=pa->dietime; } - } + else + pa->state.time=cfra; - free_collider_cache(&sim->colliders); + //push_reaction(ob,psys,p,PART_EVENT_NEAR,&pa->state); + } } - if(tree) - BLI_kdtree_free(tree); -} + free_collider_cache(&sim->colliders); + if(psys->pathcache) + psys_free_path_cache(psys, NULL); +} +void psys_update_children(ParticleSimulationData *sim) +{ + if((sim->psys->part->type == PART_HAIR) && (sim->psys->flag & PSYS_HAIR_DONE)==0) + /* don't generate children while growing hair - waste of time */ + psys_free_children(sim->psys); + else if(sim->psys->part->childtype) { + if(sim->psys->totchild != get_psys_tot_child(sim->scene, sim->psys)) + distribute_particles(sim, PART_FROM_CHILD); + } + else + psys_free_children(sim->psys); +} /* updates cached particles' alive & other flags etc..*/ static void cached_step(ParticleSimulationData *sim, float cfra) { ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; - //IpoCurve *icu_esize = NULL; //=find_ipocurve(part->ipo,PART_EMIT_SIZE); // XXX old animation system -/* Material *ma = give_current_material(sim->ob,part->omat); */ PARTICLE_P; - float disp, birthtime, dietime, *vg_size= NULL; // XXX ipotime=cfra + float disp, birthtime, dietime; BLI_srandom(psys->seed); - if(part->from!=PART_FROM_PARTICLE) - vg_size= psys_cache_vgroup(sim->psmd->dm,psys,PSYS_VG_SIZE); - psys_update_effectors(sim); disp= (float)get_current_display_percentage(psys)/100.0f; LOOP_PARTICLES { -#if 0 // XXX old animation system - if((part->flag&PART_ABS_TIME)==0 && part->ipo){ - ipotime=100.0f*(cfra-pa->time)/pa->lifetime; - calc_ipo(part->ipo, ipotime); - execute_ipo((ID *)part, part->ipo); - } -#endif // XXX old animation system - //update_settings_with_particle(psys, part, pa); - pa->size = part->size; if(part->randsize > 0.0) pa->size *= 1.0f - part->randsize * PSYS_FRAND(p + 1); @@ -3409,12 +3500,10 @@ static void cached_step(ParticleSimulationData *sim, float cfra) if(part->flag & PART_UNBORN && (psys->pointcache->flag & PTCACHE_EXTERNAL) == 0) reset_particle(sim, pa, 0.0f, cfra); } - else if(dietime <= cfra){ + else if(dietime <= cfra) pa->alive = PARS_DEAD; - } - else{ + else pa->alive = PARS_ALIVE; - } if(psys->lattice){ end_latt_deform(psys->lattice); @@ -3426,114 +3515,8 @@ static void cached_step(ParticleSimulationData *sim, float cfra) else pa->flag &= ~PARS_NO_DISP; } - - /* make sure that children are up to date */ - if(psys->part->childtype && psys->totchild != get_psys_tot_child(sim->scene, psys)) { - realloc_particles(sim, psys->totpart); - distribute_particles(sim, PART_FROM_CHILD); - } - - psys_update_path_cache(sim, cfra); - - if(vg_size) - MEM_freeN(vg_size); -} - -static void psys_changed_type(ParticleSimulationData *sim) -{ - ParticleSettings *part = sim->psys->part; - PTCacheID pid; - - BKE_ptcache_id_from_particles(&pid, sim->ob, sim->psys); - - /* system type has changed so set sensible defaults and clear non applicable flags */ - if(part->from == PART_FROM_PARTICLE) { - //if(part->type != PART_REACTOR) - part->from = PART_FROM_FACE; - if(part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT) - part->distr = PART_DISTR_JIT; - } - - if(part->phystype != PART_PHYS_KEYED) - sim->psys->flag &= ~PSYS_KEYED; - - if(part->type == PART_HAIR) { - if(ELEM4(part->ren_as, PART_DRAW_NOT, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR)==0) - part->ren_as = PART_DRAW_PATH; - - if(ELEM3(part->draw_as, PART_DRAW_NOT, PART_DRAW_REND, PART_DRAW_PATH)==0) - part->draw_as = PART_DRAW_REND; - - CLAMP(part->path_start, 0.0f, 100.0f); - CLAMP(part->path_end, 0.0f, 100.0f); - - BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0); - } - else { - free_hair(sim->ob, sim->psys, 1); - - CLAMP(part->path_start, 0.0f, MAX2(100.0f, part->end + part->lifetime)); - CLAMP(part->path_end, 0.0f, MAX2(100.0f, part->end + part->lifetime)); - } - - psys_reset(sim->psys, PSYS_RESET_ALL); -} -void psys_check_boid_data(ParticleSystem *psys) -{ - BoidParticle *bpa; - PARTICLE_P; - - pa = psys->particles; - - if(!pa) - return; - - if(psys->part && psys->part->phystype==PART_PHYS_BOIDS) { - if(!pa->boid) { - bpa = MEM_callocN(psys->totpart * sizeof(BoidParticle), "Boid Data"); - - LOOP_PARTICLES - pa->boid = bpa++; - } - } - else if(pa->boid){ - MEM_freeN(pa->boid); - LOOP_PARTICLES - pa->boid = NULL; - } } -static void psys_changed_physics(ParticleSimulationData *sim) -{ - ParticleSettings *part = sim->psys->part; - - if(ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) { - PTCacheID pid; - BKE_ptcache_id_from_particles(&pid, sim->ob, sim->psys); - BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0); - } - else { - free_keyed_keys(sim->psys); - sim->psys->flag &= ~PSYS_KEYED; - } - - if(part->phystype == PART_PHYS_BOIDS && part->boids == NULL) { - BoidState *state; - - part->boids = MEM_callocN(sizeof(BoidSettings), "Boid Settings"); - boid_default_settings(part->boids); - - state = boid_new_state(part->boids); - BLI_addtail(&state->rules, boid_new_rule(eBoidRuleType_Separate)); - BLI_addtail(&state->rules, boid_new_rule(eBoidRuleType_Flock)); - - ((BoidRule*)state->rules.first)->flag |= BOIDRULE_CURRENT; - - state->flag |= BOIDSTATE_CURRENT; - BLI_addtail(&part->boids->states, state); - } - psys_check_boid_data(sim->psys); -} static void particles_fluid_step(ParticleSimulationData *sim, int cfra) { ParticleSystem *psys = sim->psys; @@ -3567,8 +3550,8 @@ static void particles_fluid_step(ParticleSimulationData *sim, int cfra) // ok, start loading strcpy(filename, fss->surfdataPath); strcat(filename, suffix); - BLI_convertstringcode(filename, G.sce); - BLI_convertstringframe(filename, curFrame, 0); // fixed #frame-no + BLI_path_abs(filename, G.sce); + BLI_path_frame(filename, curFrame, 0); // fixed #frame-no strcat(filename, suffix2); gzf = gzopen(filename, "rb"); @@ -3642,200 +3625,127 @@ static void particles_fluid_step(ParticleSimulationData *sim, int cfra) #endif // DISABLE_ELBEEM } -/* Calculates the next state for all particles of the system */ -/* In particles code most fra-ending are frames, time-ending are fra*timestep (seconds)*/ +static int emit_particles(ParticleSimulationData *sim, PTCacheID *pid, float cfra) +{ + ParticleSystem *psys = sim->psys; + ParticleSettings *part = psys->part; + int oldtotpart = psys->totpart; + int totpart = oldtotpart; + + if(pid && psys->pointcache->flag & PTCACHE_EXTERNAL) + totpart = pid->cache->totpoint; + else if(part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT) + totpart = part->grid_res*part->grid_res*part->grid_res; + else + totpart = psys->part->totpart; + + if(totpart != oldtotpart) + realloc_particles(sim, totpart); + + return totpart - oldtotpart; +} +/* Calculates the next state for all particles of the system + * In particles code most fra-ending are frames, time-ending are fra*timestep (seconds) + * 1. Emit particles + * 2. Check cache (if used) and return if frame is cached + * 3. Do dynamics + * 4. Save to cache */ static void system_step(ParticleSimulationData *sim, float cfra) { ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; PointCache *cache = psys->pointcache; - PTCacheID pid; + PTCacheID pid, *use_cache = NULL; PARTICLE_P; - int totpart, oldtotpart, totchild, oldtotchild; - float disp, *vg_vel= 0, *vg_tan= 0, *vg_rot= 0, *vg_size= 0; - int init= 0, distr= 0, alloc= 0, usecache= 0, only_children_changed= 0; - int framenr, framedelta, startframe, endframe; + int oldtotpart; + float disp; /*, *vg_vel= 0, *vg_tan= 0, *vg_rot= 0, *vg_size= 0; */ + int init= 0, emit= 0; //, only_children_changed= 0; + int framenr, framedelta, startframe = 0, endframe = 100; framenr= (int)sim->scene->r.cfra; framedelta= framenr - cache->simframe; - /* set suitable cache range automatically */ - if((cache->flag & (PTCACHE_BAKING|PTCACHE_BAKED))==0 && !(psys->flag & PSYS_HAIR_DYNAMICS)) - psys_get_pointcache_start_end(sim->scene, sim->psys, &cache->startframe, &cache->endframe); - - BKE_ptcache_id_from_particles(&pid, sim->ob, psys); - BKE_ptcache_id_time(&pid, sim->scene, 0.0f, &startframe, &endframe, NULL); - - psys_clear_temp_pointcache(sim->psys); - - /* update ipo's */ -#if 0 // XXX old animation system - if((part->flag & PART_ABS_TIME) && part->ipo) { - calc_ipo(part->ipo, cfra); - execute_ipo((ID *)part, part->ipo); + /* cache shouldn't be used for hair or "continue physics" */ + if(part->type != PART_HAIR && BKE_ptcache_get_continue_physics() == 0) { + BKE_ptcache_id_from_particles(&pid, sim->ob, psys); + use_cache = &pid; } -#endif // XXX old animation system - /* hair if it's already done is handled separate */ - if(part->type == PART_HAIR && (psys->flag & PSYS_HAIR_DONE)) { - hair_step(sim, cfra); - psys->cfra = cfra; - psys->recalc = 0; - return; - } - /* fluid is also handled separate */ - else if(part->type == PART_FLUID) { - particles_fluid_step(sim, framenr); - psys->cfra = cfra; - psys->recalc = 0; - return; - } + if(use_cache) { + psys_clear_temp_pointcache(sim->psys); - /* cache shouldn't be used for hair or "none" or "keyed" physics */ - if(part->type == PART_HAIR || ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) - usecache= 0; - else if(BKE_ptcache_get_continue_physics()) - usecache= 0; - else - usecache= 1; + /* set suitable cache range automatically */ + if((cache->flag & (PTCACHE_BAKING|PTCACHE_BAKED))==0) + psys_get_pointcache_start_end(sim->scene, sim->psys, &cache->startframe, &cache->endframe); + + BKE_ptcache_id_time(&pid, sim->scene, 0.0f, &startframe, &endframe, NULL); - if(usecache) { - /* frame clamping */ + /* simulation is only active during a specific period */ if(framenr < startframe) { psys_reset(psys, PSYS_RESET_CACHE_MISS); - psys->cfra = cfra; - psys->recalc = 0; return; } else if(framenr > endframe) { framenr= endframe; } - + if(framenr == startframe) { - BKE_ptcache_id_reset(sim->scene, &pid, PTCACHE_RESET_OUTDATED); - cache->simframe= framenr; - cache->flag |= PTCACHE_SIMULATION_VALID; + BKE_ptcache_id_reset(sim->scene, use_cache, PTCACHE_RESET_OUTDATED); + BKE_ptcache_validate(cache, framenr); cache->flag &= ~PTCACHE_REDO_NEEDED; } } +/* 1. emit particles */ + /* verify if we need to reallocate */ oldtotpart = psys->totpart; - oldtotchild = psys->totchild; - - if(psys->pointcache->flag & PTCACHE_EXTERNAL) - totpart = pid.cache->totpoint; - else if(part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT) - totpart = part->grid_res*part->grid_res*part->grid_res; - else - totpart = psys->part->totpart; - totchild = get_psys_tot_child(sim->scene, psys); - if(oldtotpart != totpart || oldtotchild != totchild) { - only_children_changed = (oldtotpart == totpart); - alloc = 1; - distr= 1; - init= 1; - } - - if(psys->recalc & PSYS_RECALC_RESET) { - distr= 1; - init= 1; - } + emit = emit_particles(sim, use_cache, cfra); + if(use_cache && emit > 0) + BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, cfra); + init = emit*emit + (psys->recalc & PSYS_RECALC_RESET); if(init) { - if(distr) { - if(alloc) { - realloc_particles(sim, totpart); - - if(oldtotpart && usecache && !only_children_changed) { - BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0); - BKE_ptcache_id_from_particles(&pid, sim->ob, psys); - } - } - - if(!only_children_changed) - distribute_particles(sim, part->from); - - if((psys->part->type == PART_HAIR) && !(psys->flag & PSYS_HAIR_DONE)) - /* don't generate children while growing hair - waste of time */ - psys_free_children(psys); - else if(get_psys_tot_child(sim->scene, psys)) - distribute_particles(sim, PART_FROM_CHILD); - } - - if(!only_children_changed) { - free_keyed_keys(psys); - - initialize_all_particles(sim); - - - if(alloc) { - reset_all_particles(sim, 0.0, cfra, oldtotpart); - } - } + distribute_particles(sim, part->from); + initialize_all_particles(sim); + reset_all_particles(sim, 0.0, cfra, oldtotpart); /* flag for possible explode modifiers after this system */ sim->psmd->flag |= eParticleSystemFlag_Pars; } - /* try to read from the cache */ - if(usecache) { - int result = BKE_ptcache_read_cache(&pid, cfra, sim->scene->r.frs_sec); +/* 2. try to read from the cache */ + if(use_cache) { + int cache_result = BKE_ptcache_read_cache(use_cache, cfra, sim->scene->r.frs_sec); - if(result == PTCACHE_READ_EXACT || result == PTCACHE_READ_INTERPOLATED) { + if(ELEM(cache_result, PTCACHE_READ_EXACT, PTCACHE_READ_INTERPOLATED)) { cached_step(sim, cfra); - psys->cfra=cfra; - psys->recalc = 0; - cache->simframe= framenr; - cache->flag |= PTCACHE_SIMULATION_VALID; + BKE_ptcache_validate(cache, framenr); - if(result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED) - BKE_ptcache_write_cache(&pid, (int)cfra); + if(cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED) + BKE_ptcache_write_cache(use_cache, framenr); return; } - else if(result==PTCACHE_READ_OLD) { + else if(cache_result == PTCACHE_READ_OLD) { psys->cfra = (float)cache->simframe; - LOOP_PARTICLES { - /* update alive status */ - if(pa->time > psys->cfra) - pa->alive = PARS_UNBORN; - else if(pa->dietime <= psys->cfra) - pa->alive = PARS_DEAD; - else - pa->alive = PARS_ALIVE; - } + cached_step(sim, psys->cfra); } else if(cfra != startframe && ( /*sim->ob->id.lib ||*/ (cache->flag & PTCACHE_BAKED))) { /* 2.4x disabled lib, but this can be used in some cases, testing further - campbell */ psys_reset(psys, PSYS_RESET_CACHE_MISS); - psys->cfra=cfra; - psys->recalc = 0; return; } - } - else { - cache->flag &= ~PTCACHE_SIMULATION_VALID; - cache->simframe= 0; - cache->last_exact= 0; - } - - /* if on second frame, write cache for first frame */ - if(usecache && psys->cfra == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) - BKE_ptcache_write_cache(&pid, startframe); - if(part->phystype==PART_PHYS_KEYED) - psys_count_keyed_targets(sim); - - /* initialize vertex groups */ - if(part->from!=PART_FROM_PARTICLE) { - vg_vel= psys_cache_vgroup(sim->psmd->dm,psys,PSYS_VG_VEL); - vg_tan= psys_cache_vgroup(sim->psmd->dm,psys,PSYS_VG_TAN); - vg_rot= psys_cache_vgroup(sim->psmd->dm,psys,PSYS_VG_ROT); - vg_size= psys_cache_vgroup(sim->psmd->dm,psys,PSYS_VG_SIZE); + /* if on second frame, write cache for first frame */ + if(psys->cfra == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) + BKE_ptcache_write_cache(use_cache, startframe); } + else + BKE_ptcache_invalidate(cache); +/* 3. do dynamics */ /* set particles to be not calculated TODO: can't work with pointcache */ disp= (float)get_current_display_percentage(psys)/100.0f; @@ -3848,50 +3758,153 @@ static void system_step(ParticleSimulationData *sim, float cfra) } if(psys->totpart) { - int dframe, totframesback = 0; - + int dframe, subframe = 0, totframesback = 0, totsubframe = part->subframes+1; + float fraction; + /* handle negative frame start at the first frame by doing * all the steps before the first frame */ if(framenr == startframe && part->sta < startframe) totframesback = (startframe - (int)part->sta); - + for(dframe=-totframesback; dframe<=0; dframe++) { /* ok now we're all set so let's go */ - dynamics_step(sim, cfra+dframe); - psys->cfra = cfra+dframe; + for (subframe = 1; subframe <= totsubframe; subframe++) { + fraction = (float)subframe/(float)totsubframe; + dynamics_step(sim, cfra+dframe+fraction - 1.f); + psys->cfra = cfra+dframe+fraction - 1.f; + } } + } - cache->simframe= framenr; - cache->flag |= PTCACHE_SIMULATION_VALID; +/* 4. only write cache starting from second frame */ + if(use_cache) { + BKE_ptcache_validate(cache, framenr); + if(framenr != startframe) + BKE_ptcache_write_cache(use_cache, framenr); + } - psys->recalc = 0; - psys->cfra = cfra; +/* cleanup */ + if(psys->lattice){ + end_latt_deform(psys->lattice); + psys->lattice= NULL; + } +} - /* only write cache starting from second frame */ - if(usecache && framenr != startframe) - BKE_ptcache_write_cache(&pid, (int)cfra); +/* system type has changed so set sensible defaults and clear non applicable flags */ +static void psys_changed_type(ParticleSimulationData *sim) +{ + ParticleSettings *part = sim->psys->part; + PTCacheID pid; - /* for keyed particles the path is allways known so it can be drawn */ - if(part->phystype==PART_PHYS_KEYED) { - set_keyed_keys(sim); - psys_update_path_cache(sim,(int)cfra); + BKE_ptcache_id_from_particles(&pid, sim->ob, sim->psys); + + if(part->from == PART_FROM_PARTICLE) { + //if(part->type != PART_REACTOR) + part->from = PART_FROM_FACE; + if(part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT) + part->distr = PART_DISTR_JIT; } - else if(psys->pathcache) - psys_free_path_cache(psys, NULL); - /* cleanup */ - if(vg_vel) MEM_freeN(vg_vel); - if(vg_tan) MEM_freeN(vg_tan); - if(vg_rot) MEM_freeN(vg_rot); - if(vg_size) MEM_freeN(vg_size); + if(part->phystype != PART_PHYS_KEYED) + sim->psys->flag &= ~PSYS_KEYED; - if(psys->lattice){ - end_latt_deform(psys->lattice); - psys->lattice= NULL; + if(part->type == PART_HAIR) { + if(ELEM4(part->ren_as, PART_DRAW_NOT, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR)==0) + part->ren_as = PART_DRAW_PATH; + + if(ELEM3(part->draw_as, PART_DRAW_NOT, PART_DRAW_REND, PART_DRAW_PATH)==0) + part->draw_as = PART_DRAW_REND; + + CLAMP(part->path_start, 0.0f, 100.0f); + CLAMP(part->path_end, 0.0f, 100.0f); + + BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0); + } + else { + free_hair(sim->ob, sim->psys, 1); + + CLAMP(part->path_start, 0.0f, MAX2(100.0f, part->end + part->lifetime)); + CLAMP(part->path_end, 0.0f, MAX2(100.0f, part->end + part->lifetime)); } + + psys_reset(sim->psys, PSYS_RESET_ALL); +} +void psys_check_boid_data(ParticleSystem *psys) +{ + BoidParticle *bpa; + PARTICLE_P; + + pa = psys->particles; + + if(!pa) + return; + + if(psys->part && psys->part->phystype==PART_PHYS_BOIDS) { + if(!pa->boid) { + bpa = MEM_callocN(psys->totpart * sizeof(BoidParticle), "Boid Data"); + + LOOP_PARTICLES + pa->boid = bpa++; + } + } + else if(pa->boid){ + MEM_freeN(pa->boid); + LOOP_PARTICLES + pa->boid = NULL; + } +} + +static void fluid_default_settings(ParticleSettings *part){ + SPHFluidSettings *fluid = part->fluid; + + fluid->radius = 0.5f; + fluid->spring_k = 0.f; + fluid->rest_length = 0.5f; + fluid->viscosity_omega = 2.f; + fluid->viscosity_beta = 0.f; + fluid->stiffness_k = 0.1f; + fluid->stiffness_knear = 0.05f; + fluid->rest_density = 10.f; + fluid->buoyancy = 0.f; } +static void psys_changed_physics(ParticleSimulationData *sim) +{ + ParticleSettings *part = sim->psys->part; + + if(ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) { + PTCacheID pid; + BKE_ptcache_id_from_particles(&pid, sim->ob, sim->psys); + BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0); + } + else { + free_keyed_keys(sim->psys); + sim->psys->flag &= ~PSYS_KEYED; + } + + if(part->phystype == PART_PHYS_BOIDS && part->boids == NULL) { + BoidState *state; + + part->boids = MEM_callocN(sizeof(BoidSettings), "Boid Settings"); + boid_default_settings(part->boids); + + state = boid_new_state(part->boids); + BLI_addtail(&state->rules, boid_new_rule(eBoidRuleType_Separate)); + BLI_addtail(&state->rules, boid_new_rule(eBoidRuleType_Flock)); + + ((BoidRule*)state->rules.first)->flag |= BOIDRULE_CURRENT; + + state->flag |= BOIDSTATE_CURRENT; + BLI_addtail(&part->boids->states, state); + } + else if(part->phystype == PART_PHYS_FLUID && part->fluid == NULL) { + part->fluid = MEM_callocN(sizeof(SPHFluidSettings), "SPH Fluid Settings"); + fluid_default_settings(part); + } + + psys_check_boid_data(sim->psys); +} static int hair_needs_recalc(ParticleSystem *psys) { if(!(psys->flag & PSYS_EDITED) && (!psys->edit || !psys->edit->edited) && @@ -3902,10 +3915,12 @@ static int hair_needs_recalc(ParticleSystem *psys) return 0; } -/* main particle update call, checks that things are ok on the large scale before actual particle calculations */ +/* main particle update call, checks that things are ok on the large scale and + * then advances in to actual particle calculations depending on particle type */ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) { ParticleSimulationData sim = {scene, ob, psys, NULL, NULL}; + ParticleSettings *part = psys->part; float cfra; /* drawdata is outdated after ANY change */ @@ -3914,7 +3929,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) if(!psys_check_enabled(ob, psys)) return; - cfra= bsystem_time(scene, ob, (float)scene->r.cfra, 0.0f); + cfra= BKE_curframe(scene); sim.psmd= psys_get_modifier(ob, psys); /* system was already updated from modifier stack */ @@ -3929,35 +3944,87 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) return; /* execute drivers only, as animation has already been done */ - BKE_animsys_evaluate_animdata(&psys->part->id, psys->part->adt, cfra, ADT_RECALC_DRIVERS); + BKE_animsys_evaluate_animdata(&part->id, part->adt, cfra, ADT_RECALC_DRIVERS); + + /* TODO: only free child paths in case of PSYS_RECALC_CHILD */ + if(psys->recalc & PSYS_RECALC || ob->recalc & OB_RECALC_ALL) + psys_free_path_cache(psys, NULL); + + if(psys->recalc & PSYS_RECALC_CHILD) + psys_free_children(psys); if(psys->recalc & PSYS_RECALC_TYPE) psys_changed_type(&sim); else if(psys->recalc & PSYS_RECALC_PHYS) psys_changed_physics(&sim); - /* (re-)create hair */ - if(psys->part->type==PART_HAIR && hair_needs_recalc(psys)) { - float hcfra=0.0f; - int i; - - free_hair(ob, psys, 0); + switch(part->type) { + case PART_HAIR: + { + /* (re-)create hair */ + if(hair_needs_recalc(psys)) { + float hcfra=0.0f; + int i, recalc = psys->recalc; + + free_hair(ob, psys, 0); + + /* first step is negative so particles get killed and reset */ + psys->cfra= 1.0f; + + for(i=0; i<=part->hair_step; i++){ + hcfra=100.0f*(float)i/(float)psys->part->hair_step; + BKE_animsys_evaluate_animdata(&part->id, part->adt, hcfra, ADT_RECALC_ANIM); + system_step(&sim, hcfra); + psys->cfra = hcfra; + psys->recalc = 0; + save_hair(&sim, hcfra); + } - /* first step is negative so particles get killed and reset */ - psys->cfra= 1.0f; + psys->flag |= PSYS_HAIR_DONE; + psys->recalc = recalc; + } - for(i=0; i<=psys->part->hair_step; i++){ - hcfra=100.0f*(float)i/(float)psys->part->hair_step; - BKE_animsys_evaluate_animdata(&psys->part->id, psys->part->adt, hcfra, ADT_RECALC_ANIM); - system_step(&sim, hcfra); - save_hair(&sim, hcfra); + if(psys->flag & PSYS_HAIR_DONE) + hair_step(&sim, cfra); + break; } + case PART_FLUID: + { + particles_fluid_step(&sim, (int)cfra); + break; + } + default: + { + switch(part->phystype) { + case PART_PHYS_NO: + case PART_PHYS_KEYED: + { + if(emit_particles(&sim, NULL, cfra)) { + free_keyed_keys(psys); + distribute_particles(&sim, part->from); + initialize_all_particles(&sim); + } + reset_all_particles(&sim, 0.0, cfra, 0); - psys->flag |= PSYS_HAIR_DONE; + if(part->phystype == PART_PHYS_KEYED) { + psys_count_keyed_targets(&sim); + set_keyed_keys(&sim); + } + break; + } + default: + { + /* the main dynamic particle system step */ + system_step(&sim, cfra); + break; + } + } + break; + } } - /* the main particle system step */ - system_step(&sim, cfra); + psys->cfra = cfra; + psys->recalc = 0; /* save matrix for duplicators */ invert_m4_m4(psys->imat, ob->obmat); |