From f8ecc3fd2fd11a40f5cea3a23b3c83b9861762cc Mon Sep 17 00:00:00 2001 From: Janne Karhu Date: Sun, 30 May 2010 14:53:26 +0000 Subject: Some cleanup of particle path drawing logic: * Path drawing now works for non hair particles. * Should fix the following bugs too: [#21316] Hair weight drawing is wrong [#21923] Consistent Crash When Rendering Particle Scene. [#21950] Path rendering option for particles causes crash --- source/blender/blenkernel/BKE_particle.h | 2 + source/blender/blenkernel/intern/particle.c | 91 +++++++++++++++++----- source/blender/blenkernel/intern/particle_system.c | 90 ++++++--------------- source/blender/editors/physics/particle_edit.c | 2 +- source/blender/editors/space_view3d/drawobject.c | 22 ++++-- .../blender/render/intern/source/convertblender.c | 7 +- 6 files changed, 115 insertions(+), 99 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index fcef00ae9b3..33a41821fe2 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -255,9 +255,11 @@ void psys_threads_free(ParticleThread *threads); void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3], float zvec[3], float center[3]); /* particle_system.c */ +void psys_update_path_cache(struct ParticleSimulationData *sim, float cfra); struct ParticleSystem *psys_get_target_system(struct Object *ob, struct ParticleTarget *pt); void psys_count_keyed_targets(struct ParticleSimulationData *sim); void psys_update_particle_tree(struct ParticleSystem *psys, float cfra); +void psys_update_children(struct ParticleSimulationData *sim); void psys_make_temp_pointcache(struct Object *ob, struct ParticleSystem *psys); void psys_get_pointcache_start_end(struct Scene *scene, ParticleSystem *psys, int *sfra, int *efra); diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index fffbd31aa02..0c55cc2aaac 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -433,7 +433,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; @@ -451,7 +451,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) @@ -462,7 +462,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) { @@ -1037,6 +1037,7 @@ typedef struct ParticleInterpolationData { ParticleKey *kkey[2]; PointCache *cache; + PTCacheMem *pm; PTCacheEditPoint *epoint; PTCacheEditKey *ekey[2]; @@ -1045,31 +1046,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; + + pm = *cur; BKE_ptcache_make_particle_key(key2, pm->index_array ? pm->index_array[index] - 1 : index, pm->data, (float)pm->frame); - BKE_ptcache_make_particle_key(key1, pm->prev->index_array ? pm->prev->index_array[index] - 1 : index, pm->prev->data, (float)pm->prev->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] - 1 : 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) { @@ -1091,10 +1135,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; @@ -1224,7 +1273,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]); @@ -2672,7 +2721,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; } @@ -2743,7 +2792,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)) @@ -2753,7 +2802,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); @@ -3148,7 +3197,7 @@ 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); } diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 25328a06328..ce84ee96d01 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -3075,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); @@ -3249,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) { @@ -3278,10 +3232,6 @@ static void hair_step(ParticleSimulationData *sim, float cfra) if(psys->part->type==PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) do_hair_dynamics(sim); - psys_update_effectors(sim); - - psys_update_path_cache(sim, cfra); - psys->flag |= PSYS_HAIR_UPDATED; } @@ -3500,14 +3450,19 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) } free_collider_cache(&sim->colliders); + + if(psys->pathcache) + psys_free_path_cache(psys, NULL); } -static void update_children(ParticleSimulationData *sim) +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 && sim->psys->totchild != get_psys_tot_child(sim->scene, sim->psys)) - distribute_particles(sim, PART_FROM_CHILD); + 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); } @@ -3762,8 +3717,6 @@ static void system_step(ParticleSimulationData *sim, float cfra) if(ELEM(cache_result, PTCACHE_READ_EXACT, PTCACHE_READ_INTERPOLATED)) { cached_step(sim, cfra); - update_children(sim); - psys_update_path_cache(sim, cfra); BKE_ptcache_validate(cache, framenr); @@ -3827,9 +3780,6 @@ static void system_step(ParticleSimulationData *sim, float cfra) BKE_ptcache_write_cache(use_cache, framenr); } - if(init) - update_children(sim); - /* cleanup */ if(psys->lattice){ end_latt_deform(psys->lattice); @@ -3992,6 +3942,13 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) /* execute drivers only, as animation has already been done */ 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) + 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) @@ -4048,7 +4005,6 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) if(part->phystype == PART_PHYS_KEYED) { psys_count_keyed_targets(&sim); set_keyed_keys(&sim); - psys_update_path_cache(&sim,(int)cfra); } break; } diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 6ec744ad027..541b0cf494f 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -160,7 +160,7 @@ void PE_free_ptcache_edit(PTCacheEdit *edit) edit->emitter_field= 0; } - psys_free_path_cache(NULL, edit); + psys_free_path_cache(edit->psys, edit); MEM_freeN(edit); } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 89a82e51cd8..d3b70f4553a 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -3466,12 +3466,11 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv select=1; } + psys_update_children(&sim); + psys->flag|=PSYS_DRAWING; - if(part->type==PART_HAIR && !psys->childcache) - totchild=0; - else - totchild=psys->totchild*part->disp/100; + totchild=psys->totchild*part->disp/100; ma= give_current_material(ob,part->omat); @@ -3506,11 +3505,18 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv totpart=psys->totpart; - //if(part->flag&PART_GLOB_TIME) cfra=bsystem_time(scene, 0, (float)CFRA, 0.0f); - if(draw_as==PART_DRAW_PATH && psys->pathcache==NULL && psys->childcache==NULL) - draw_as=PART_DRAW_DOT; + if(draw_as==PART_DRAW_PATH) { + if(psys->pathcache==NULL && psys->childcache==NULL) + psys_update_path_cache(&sim, cfra); + + /* can't create pathcache for some reason*/ + if(psys->pathcache==NULL && psys->childcache==NULL) + draw_as=PART_DRAW_DOT; + else if(psys->childcache==NULL) + totchild = 0; + } /* 3. */ switch(draw_as){ @@ -3862,7 +3868,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv UI_ThemeColor(TH_WIRE); }*/ - if(totchild && (part->draw&PART_DRAW_PARENT)==0) + if(totchild && ((part->draw&PART_DRAW_PARENT)==0 || psys_in_edit_mode(scene, psys))) totpart=0; else if(psys->pathcache==NULL) totpart=0; diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index f6be316dcfd..86c6a325bcd 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -1532,8 +1532,6 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem /* 1. check that everything is ok & updated */ if(psys==NULL) return 0; - - totchild=psys->totchild; part=psys->part; pars=psys->particles; @@ -1554,6 +1552,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem if(part->phystype==PART_PHYS_KEYED) psys_count_keyed_targets(&sim); + psys_update_children(&sim); + totchild=psys->totchild; if(G.rendering == 0) { /* preview render */ totchild = (int)((float)totchild * (float)part->disp / 100.0f); @@ -1657,6 +1657,9 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem transpose_m3(nmat); /* 2.6 setup strand rendering */ + if(part->ren_as == PART_DRAW_PATH && psys->pathcache==NULL) + psys_update_path_cache(&sim, cfra); + if(part->ren_as == PART_DRAW_PATH && psys->pathcache){ path_nbr=(int)pow(2.0,(double) part->ren_step); -- cgit v1.2.3