diff options
Diffstat (limited to 'source/blender/blenkernel/intern/particle.c')
-rw-r--r-- | source/blender/blenkernel/intern/particle.c | 228 |
1 files changed, 162 insertions, 66 deletions
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 7cee4b1d7bb..4c68c5487c8 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -35,27 +35,15 @@ #include "MEM_guardedalloc.h" -#include "DNA_boid_types.h" #include "DNA_curve_types.h" #include "DNA_group_types.h" -#include "DNA_ipo_types.h" // XXX old animation system stuff to remove! #include "DNA_key_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_force.h" -#include "DNA_object_types.h" #include "DNA_particle_types.h" -#include "DNA_scene_types.h" #include "DNA_smoke_types.h" -#include "DNA_texture_types.h" -#include "BLI_math.h" -#include "BLI_blenlib.h" -#include "BLI_dynstr.h" #include "BLI_kdtree.h" -#include "BLI_listbase.h" #include "BLI_rand.h" #include "BLI_threads.h" #include "BLI_cellalloc.h" @@ -73,9 +61,7 @@ #include "BKE_utildefines.h" #include "BKE_displist.h" #include "BKE_particle.h" -#include "BKE_DerivedMesh.h" #include "BKE_object.h" -#include "BKE_cloth.h" #include "BKE_material.h" #include "BKE_key.h" #include "BKE_library.h" @@ -370,6 +356,12 @@ int psys_uses_gravity(ParticleSimulationData *sim) /************************************************/ /* Freeing stuff */ /************************************************/ +void fluid_free_settings(SPHFluidSettings *fluid) +{ + if(fluid) + MEM_freeN(fluid); +} + void psys_free_settings(ParticleSettings *part) { BKE_free_animdata(&part->id); @@ -382,6 +374,7 @@ void psys_free_settings(ParticleSettings *part) BLI_freelistN(&part->dupliweights); boid_free_settings(part->boids); + fluid_free_settings(part->fluid); } void free_hair(Object *ob, ParticleSystem *psys, int dynamics) @@ -404,7 +397,7 @@ void free_hair(Object *ob, ParticleSystem *psys, int dynamics) if(dynamics) { BKE_ptcache_free_list(&psys->ptcaches); psys->clmd->point_cache = psys->pointcache = NULL; - psys->clmd->ptcaches.first = psys->clmd->ptcaches.first = NULL; + psys->clmd->ptcaches.first = psys->clmd->ptcaches.last = NULL; modifier_free((ModifierData*)psys->clmd); @@ -441,7 +434,7 @@ void free_keyed_keys(ParticleSystem *psys) } } } -static void free_child_path_cache(ParticleSystem *psys) +void psys_free_child_path_cache(ParticleSystem *psys) { psys_free_path_cache_buffers(psys->childcache, &psys->childcachebufs); psys->childcache = NULL; @@ -459,7 +452,7 @@ void psys_free_path_cache(ParticleSystem *psys, PTCacheEdit *edit) psys->pathcache= NULL; psys->totcached= 0; - free_child_path_cache(psys); + psys_free_child_path_cache(psys); } } void psys_free_children(ParticleSystem *psys) @@ -470,7 +463,7 @@ void psys_free_children(ParticleSystem *psys) psys->totchild=0; } - free_child_path_cache(psys); + psys_free_child_path_cache(psys); } void psys_free_particles(ParticleSystem *psys) { @@ -1045,6 +1038,7 @@ typedef struct ParticleInterpolationData { ParticleKey *kkey[2]; PointCache *cache; + PTCacheMem *pm; PTCacheEditPoint *epoint; PTCacheEditKey *ekey[2]; @@ -1053,31 +1047,74 @@ typedef struct ParticleInterpolationData { int bspline; } ParticleInterpolationData; /* Assumes pointcache->mem_cache exists, so for disk cached particles call psys_make_temp_pointcache() before use */ -static void get_pointcache_keys_for_time(Object *ob, PointCache *cache, int index, float t, ParticleKey *key1, ParticleKey *key2) +/* It uses ParticleInterpolationData->pm to store the current memory cache frame so it's thread safe. */ +static void get_pointcache_keys_for_time(Object *ob, PointCache *cache, PTCacheMem **cur, int index, float t, ParticleKey *key1, ParticleKey *key2) { - static PTCacheMem *pm = NULL; /* not thread safe */ + static PTCacheMem *pm = NULL; if(index < 0) { /* initialize */ - pm = cache->mem_cache.first; + *cur = cache->mem_cache.first; - if(pm) - pm = pm->next; + if(*cur) + *cur = (*cur)->next; } else { - if(pm) { - while(pm && pm->next && (float)pm->frame < t) - pm = pm->next; + if(*cur) { + while(*cur && (*cur)->next && (float)(*cur)->frame < t) + *cur = (*cur)->next; - BKE_ptcache_make_particle_key(key2, pm->index_array ? pm->index_array[index] : index, pm->data, (float)pm->frame); - BKE_ptcache_make_particle_key(key1, pm->prev->index_array ? pm->prev->index_array[index] : index, pm->prev->data, (float)pm->prev->frame); + pm = *cur; + + BKE_ptcache_make_particle_key(key2, pm->index_array ? pm->index_array[index] - 1 : index, pm->data, (float)pm->frame); + if(pm->prev->index_array && pm->prev->index_array[index] == 0) + copy_particle_key(key1, key2, 1); + else + BKE_ptcache_make_particle_key(key1, pm->prev->index_array ? pm->prev->index_array[index] - 1 : index, pm->prev->data, (float)pm->prev->frame); } else if(cache->mem_cache.first) { - PTCacheMem *pm2 = cache->mem_cache.first; - BKE_ptcache_make_particle_key(key2, pm2->index_array ? pm2->index_array[index] : index, pm2->data, (float)pm2->frame); + pm = cache->mem_cache.first; + BKE_ptcache_make_particle_key(key2, pm->index_array ? pm->index_array[index] - 1 : index, pm->data, (float)pm->frame); copy_particle_key(key1, key2, 1); } } } +static int get_pointcache_times_for_particle(PointCache *cache, int index, float *start, float *end) +{ + PTCacheMem *pm; + int ret = 0; + + for(pm=cache->mem_cache.first; pm; pm=pm->next) { + if(pm->index_array) { + if(pm->index_array[index]) { + *start = pm->frame; + ret++; + break; + } + } + else { + *start = pm->frame; + ret++; + break; + } + } + + for(pm=cache->mem_cache.last; pm; pm=pm->prev) { + if(pm->index_array) { + if(pm->index_array[index]) { + *end = pm->frame; + ret++; + break; + } + } + else { + *end = pm->frame; + ret++; + break; + } + } + + return ret == 2; +} static void init_particle_interpolation(Object *ob, ParticleSystem *psys, ParticleData *pa, ParticleInterpolationData *pind) { @@ -1099,10 +1136,15 @@ static void init_particle_interpolation(Object *ob, ParticleSystem *psys, Partic pind->dietime = (key + pa->totkey - 1)->time; } else if(pind->cache) { - get_pointcache_keys_for_time(ob, pind->cache, -1, 0.0f, NULL, NULL); - + float start, end; + get_pointcache_keys_for_time(ob, pind->cache, &pind->pm, -1, 0.0f, NULL, NULL); pind->birthtime = pa ? pa->time : pind->cache->startframe; pind->dietime = pa ? pa->dietime : pind->cache->endframe; + + if(get_pointcache_times_for_particle(pind->cache, pa - psys->particles, &start, &end)) { + pind->birthtime = MAX2(pind->birthtime, start); + pind->dietime = MIN2(pind->dietime, end); + } } else { HairKey *key = pa->hair; @@ -1145,6 +1187,9 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData int point_vel = (point && point->keys->vel); float real_t, dfra, keytime; + /* billboards wont fill in all of these, so start cleared */ + memset(keys, 0, sizeof(keys)); + /* interpret timing and find keys */ if(point) { if(result->time < 0.0f) @@ -1229,7 +1274,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData memcpy(keys + 2, pind->kkey[1], sizeof(ParticleKey)); } else if(pind->cache) { - get_pointcache_keys_for_time(NULL, pind->cache, p, real_t, keys+1, keys+2); + get_pointcache_keys_for_time(NULL, pind->cache, &pind->pm, p, real_t, keys+1, keys+2); } else { hair_to_particle(keys + 1, pind->hkey[0]); @@ -1993,7 +2038,7 @@ int do_guides(ListBase *effectors, ParticleKey *state, int index, float time) float effect[3] = {0.0f, 0.0f, 0.0f}, veffect[3] = {0.0f, 0.0f, 0.0f}; float guidevec[4], guidedir[3], rot2[4], temp[3]; - float guidetime, radius, angle, totstrength = 0.0f; + float guidetime, radius, weight, angle, totstrength = 0.0f; float vec_to_point[3]; if(effectors) for(eff = effectors->first; eff; eff=eff->next) { @@ -2015,11 +2060,11 @@ int do_guides(ListBase *effectors, ParticleKey *state, int index, float time) cu = (Curve*)eff->ob->data; if(pd->flag & PFIELD_GUIDE_PATH_ADD) { - if(where_on_path(eff->ob, data->strength * guidetime, guidevec, guidedir, NULL, &radius)==0) + if(where_on_path(eff->ob, data->strength * guidetime, guidevec, guidedir, NULL, &radius, &weight)==0) return 0; } else { - if(where_on_path(eff->ob, guidetime, guidevec, guidedir, NULL, &radius)==0) + if(where_on_path(eff->ob, guidetime, guidevec, guidedir, NULL, &radius, &weight)==0) return 0; } @@ -2059,10 +2104,14 @@ int do_guides(ListBase *effectors, ParticleKey *state, int index, float time) VECCOPY(vec_to_point, key.co); VECADD(vec_to_point, vec_to_point, guidevec); + //VECSUB(pa_loc,pa_loc,pa_zero); VECADDFAC(effect, effect, vec_to_point, data->strength); VECADDFAC(veffect, veffect, guidedir, data->strength); totstrength += data->strength; + + if(pd->flag & PFIELD_GUIDE_PATH_WEIGHT) + totstrength *= weight; } if(totstrength != 0.0){ @@ -2130,7 +2179,7 @@ static void do_path_effectors(ParticleSimulationData *sim, int i, ParticleCacheK mul_v3_fl(force, effector*pow((float)k / (float)steps, 100.0f * sim->psys->part->eff_hair) / (float)steps); - add_v3_v3v3(force, force, vec); + add_v3_v3(force, vec); normalize_v3(force); @@ -2673,7 +2722,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupd } else { /* clear out old and create new empty path cache */ - free_child_path_cache(sim->psys); + psys_free_child_path_cache(sim->psys); sim->psys->childcache= psys_alloc_path_cache_buffers(&sim->psys->childcachebufs, totchild, ctx->steps+1); sim->psys->totchildcache = totchild; } @@ -2744,7 +2793,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra) int keyed, baked; /* we don't have anything valid to create paths from so let's quit here */ - if((psys->flag & PSYS_HAIR_DONE || psys->flag & PSYS_KEYED || psys->pointcache->flag & PTCACHE_BAKED)==0) + if((psys->flag & PSYS_HAIR_DONE || psys->flag & PSYS_KEYED || psys->pointcache)==0) return; if(psys_in_edit_mode(sim->scene, psys)) @@ -2754,7 +2803,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra) BLI_srandom(psys->seed); keyed = psys->flag & PSYS_KEYED; - baked = !hair_dm && psys->pointcache->flag & PTCACHE_BAKED; + baked = !hair_dm && psys->pointcache->mem_cache.first; /* clear out old and create new empty path cache */ psys_free_path_cache(psys, psys->edit); @@ -2941,7 +2990,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf ParticleCacheKey *ca, **cache= edit->pathcache; ParticleEditSettings *pset = &scene->toolsettings->particle; - PTCacheEditPoint *point = edit->points; + PTCacheEditPoint *point = NULL; PTCacheEditKey *ekey = NULL; ParticleSystem *psys = edit->psys; @@ -2954,9 +3003,9 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf float birthtime = 0.0, dietime = 0.0; float t, time = 0.0, keytime = 0.0, frs_sec; float hairmat[4][4], rotmat[3][3], prev_tangent[3]; - int k,i; + int k, i; int steps = (int)pow(2.0, (double)pset->draw_step); - int totpart = edit->totpoint; + int totpart = edit->totpoint, recalc_set=0; float sel_col[3]; float nosel_col[3]; @@ -2966,6 +3015,11 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf /* clear out old and create new empty path cache */ psys_free_path_cache(edit->psys, edit); cache= edit->pathcache= psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, steps+1); + + /* set flag for update (child particles check this too) */ + for(i=0, point=edit->points; i<totpart; i++, point++) + point->flag |= PEP_EDIT_RECALC; + recalc_set = 1; } frs_sec = (psys || edit->pid.flag & PTCACHE_VEL_PER_SEC) ? 25.0f : 1.0f; @@ -2987,7 +3041,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf } /*---first main loop: create all actual particles' paths---*/ - for(i=0; i<totpart; i++, pa+=pa?1:0, point++){ + for(i=0, point=edit->points; i<totpart; i++, pa+=pa?1:0, point++){ if(edit->totcached && !(point->flag & PEP_EDIT_RECALC)) continue; @@ -3096,17 +3150,26 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf /* selection coloring in edit mode */ if(pset->brushtype==PE_BRUSH_WEIGHT){ - if(k==0) + float t2; + + if(k==0) { weight_to_rgb(pind.hkey[1]->weight, ca->col, ca->col+1, ca->col+2); - else if(k >= steps - 1) - weight_to_rgb(pind.hkey[0]->weight, ca->col, ca->col+1, ca->col+2); - else - weight_to_rgb((1.0f - keytime) * pind.hkey[0]->weight + keytime * pind.hkey[1]->weight, ca->col, ca->col+1, ca->col+2); + } else { + float w1[3], w2[3]; + keytime = (t - (*pind.ekey[0]->time))/((*pind.ekey[1]->time) - (*pind.ekey[0]->time)); + + weight_to_rgb(pind.hkey[0]->weight, w1, w1+1, w1+2); + weight_to_rgb(pind.hkey[1]->weight, w2, w2+1, w2+2); + + interp_v3_v3v3(ca->col, w1, w2, keytime); + } /* at the moment this is only used for weight painting. * will need to move out of this check if its used elsewhere. */ - pind.hkey[0] = pind.hkey[1]; - pind.hkey[1]++; + t2 = birthtime + ((float)(k+1)/(float)steps) * (dietime - birthtime); + + while (pind.hkey[1]->time < t2) pind.hkey[1]++; + pind.hkey[0] = pind.hkey[1] - 1; } else { if((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT){ @@ -3135,10 +3198,16 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf edit->totcached = totpart; - if(psys && psys->part->type == PART_HAIR) { + if(psys) { ParticleSimulationData sim = {scene, ob, psys, psys_get_modifier(ob, psys), NULL}; psys_cache_child_paths(&sim, cfra, 1); } + + /* clear recalc flag if set here */ + if(recalc_set) { + for(i=0, point=edit->points; i<totpart; i++, point++) + point->flag &= ~PEP_EDIT_RECALC; + } } /************************************************/ /* Particle Key handling */ @@ -3468,6 +3537,7 @@ ParticleSettings *psys_copy_settings(ParticleSettings *part) partn= copy_libblock(part); if(partn->pd) partn->pd= MEM_dupallocN(part->pd); if(partn->pd2) partn->pd2= MEM_dupallocN(part->pd2); + partn->effector_weights = MEM_dupallocN(part->effector_weights); partn->boids = boid_copy_settings(part->boids); @@ -3481,9 +3551,9 @@ void make_local_particlesettings(ParticleSettings *part) int local=0, lib=0; /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ + * - only local users: set flag + * - mixed: make copy + */ if(part->id.lib==0) return; if(part->id.us==1) { @@ -4188,8 +4258,13 @@ void psys_get_dupli_texture(Object *ob, ParticleSettings *part, ParticleSystemMo num= pa->num_dmcache; if(num == DMCACHE_NOTFOUND) - if(pa->num < psmd->dm->getNumTessFaces(psmd->dm)) - num= pa->num; + num= pa->num; + + if (num >= psmd->dm->getNumFaces(psmd->dm)) { + /* happens when simplify is enabled + * gives invalid coords but would crash otherwise */ + num= DMCACHE_NOTFOUND; + } if(mtface && num != DMCACHE_NOTFOUND) { mface= psmd->dm->getTessFaceData(psmd->dm, num, CD_MFACE); @@ -4212,18 +4287,11 @@ void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa ParticleSystem *psys = sim->psys; ParticleSystemModifierData *psmd = sim->psmd; float loc[3], nor[3], vec[3], side[3], len, obrotmat[4][4], qmat[4][4]; - float xvec[3] = {-1.0, 0.0, 0.0}, q[4]; + float xvec[3] = {-1.0, 0.0, 0.0}, q[4], nmat[3][3]; sub_v3_v3v3(vec, (cache+cache->steps-1)->co, cache->co); len= normalize_v3(vec); - if(pa) - psys_particle_on_emitter(psmd,sim->psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,loc,nor,0,0,0,0); - else - psys_particle_on_emitter(psmd, - (psys->part->childtype == PART_CHILD_FACES)? PART_FROM_FACE: PART_FROM_PARTICLE, - cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,loc,nor,0,0,0,0); - if(psys->part->rotmode) { if(!pa) pa= psys->particles+cpa->pa[0]; @@ -4236,6 +4304,17 @@ void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa mul_m4_m4m4(mat, obrotmat, qmat); } else { + if(pa) + psys_particle_on_emitter(psmd,sim->psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,loc,nor,0,0,0,0); + else + psys_particle_on_emitter(psmd, + (psys->part->childtype == PART_CHILD_FACES)? PART_FROM_FACE: PART_FROM_PARTICLE, + cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,loc,nor,0,0,0,0); + + copy_m3_m4(nmat, ob->imat); + transpose_m3(nmat); + mul_m3_v3(nmat, nor); + /* make sure that we get a proper side vector */ if(fabs(dot_v3v3(nor,vec))>0.999999) { if(fabs(dot_v3v3(nor,xvec))>0.999999) { @@ -4253,7 +4332,7 @@ void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa normalize_v3(side); cross_v3_v3v3(nor, vec, side); - unit_m4(mat); + unit_m4(mat); VECCOPY(mat[0], vec); VECCOPY(mat[1], side); VECCOPY(mat[2], nor); @@ -4269,6 +4348,23 @@ void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3] xvec[0] = 1.0f; xvec[1] = 0.0f; xvec[2] = 0.0f; yvec[0] = 0.0f; yvec[1] = 1.0f; yvec[2] = 0.0f; + /* can happen with bad pointcache or physics calculation + * since this becomes geometry, nan's and inf's crash raytrace code. + * better not allow this. */ + if( !finite(bb->vec[0]) || !finite(bb->vec[1]) || !finite(bb->vec[2]) || + !finite(bb->vel[0]) || !finite(bb->vel[1]) || !finite(bb->vel[2]) ) + { + zero_v3(bb->vec); + zero_v3(bb->vel); + + zero_v3(xvec); + zero_v3(yvec); + zero_v3(zvec); + zero_v3(center); + + return; + } + if(bb->align < PART_BB_VIEW) onevec[bb->align]=1.0f; |