Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2007-12-04 16:57:28 +0300
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2007-12-04 16:57:28 +0300
commit32a8b4f8e686938ec2f0f95e6acc2eb3c25ebfdf (patch)
treeff232d89da0b2f0db1da4becb1980af513ea2274 /source/blender/blenkernel
parentebfedd20b290e356f35eb1fcbcb5ddfb8e8bf0a9 (diff)
Particles
========= - Fix crash in particle transform with the particle system not editable. - Particle child distribution and caching is now multithreaded. - Child particles now have a separate Render Amount next to the existing Amount. The render amount particles are now only distributed and cached at render time, which should make editing with child particles faster. - Two new options for diffuse strand shading: - Surface Diffuse: computes the strand normal taking the normal at the surface into account. - Blending Distance: the distance in Blender units over which to blend in the normal at the surface. - Special strand rendering for more memory efficient and faster hair and grass. This is a work in progress, and has a number of known issues, don't report bugs to me for this feature yet. More info: http://www.blender.org/development/current-projects/changes-since-244/particles/
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_particle.h50
-rw-r--r--source/blender/blenkernel/intern/anim.c6
-rw-r--r--source/blender/blenkernel/intern/material.c3
-rw-r--r--source/blender/blenkernel/intern/particle.c766
-rw-r--r--source/blender/blenkernel/intern/particle_system.c741
5 files changed, 944 insertions, 622 deletions
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index afed219dbc6..d419eac2fab 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -54,6 +54,7 @@ struct MVert;
struct IpoCurve;
struct LinkNode;
struct KDTree;
+struct RNG;
typedef struct ParticleEffectorCache {
struct ParticleEffectorCache *next, *prev;
@@ -148,6 +149,42 @@ typedef struct ParticleEdit{
int totkeys;
} ParticleEdit;
+typedef struct ParticleThreadContext {
+ /* shared */
+ struct Object *ob;
+ struct DerivedMesh *dm;
+ struct ParticleSystemModifierData *psmd;
+ struct ParticleSystem *psys;
+ struct Material *ma;
+
+ /* distribution */
+ struct KDTree *tree;
+
+ struct ParticleSeam *seams;
+ int totseam;
+
+ float *jit, *jitoff, *weight;
+ float maxweight;
+ int *index, jitlevel;
+
+ int from, cfrom, distr;
+
+ /* path caching */
+ int editupdate, between, steps;
+ int totchild, totparent;
+
+ float cfra;
+
+ float *vg_length, *vg_clump, *vg_kink;
+ float *vg_rough1, *vg_rough2, *vg_roughe;
+} ParticleThreadContext;
+
+typedef struct ParticleThread {
+ ParticleThreadContext *ctx;
+ struct RNG *rng, *rng_path;
+ int num, tot;
+} ParticleThread;
+
/* ----------- functions needed outside particlesystem ---------------- */
/* particle.c */
int count_particles(struct ParticleSystem *psys);
@@ -170,6 +207,7 @@ int psys_in_edit_mode(struct ParticleSystem *psys);
void psys_free_settings(struct ParticleSettings *part);
void free_child_path_cache(struct ParticleSystem *psys);
void psys_free_path_cache(struct ParticleSystem *psys);
+void psys_free_render_memory(struct Object *ob, struct ParticleSystem *psys);
void free_hair(struct ParticleSystem *psys);
void free_keyed_keys(struct ParticleSystem *psys);
void psys_free(struct Object * ob, struct ParticleSystem * psys);
@@ -195,11 +233,19 @@ void psys_cache_child_paths(struct Object *ob, struct ParticleSystem *psys, floa
int do_guide(struct ParticleKey *state, int pa_num, float time, struct ListBase *lb);
float psys_get_size(struct Object *ob, struct Material *ma, struct ParticleSystemModifierData *psmd, struct IpoCurve *icu_size, struct ParticleSystem *psys, struct ParticleSettings *part, struct ParticleData *pa, float *vg_size);
float psys_get_timestep(struct ParticleSettings *part);
-float psys_get_child_time(struct ParticleSystem *psys, int child_nbr, float cfra);
-float psys_get_child_size(struct ParticleSystem *psys, int child_nbr, float cfra, float *pa_time);
+float psys_get_child_time(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra);
+float psys_get_child_size(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *pa_time);
void psys_get_particle_on_path(struct Object *ob, struct ParticleSystem *psys, int pa_num, struct ParticleKey *state, int vel);
int psys_get_particle_state(struct Object *ob, struct ParticleSystem *psys, int p, struct ParticleKey *state, int always);
+ParticleThread *psys_threads_create(struct Object *ob, struct ParticleSystem *psys, int totthread);
+int psys_threads_init_distribution(ParticleThread *threads, struct DerivedMesh *dm, int from);
+int psys_threads_init_path(ParticleThread *threads, float cfra, int editupdate);
+void psys_threads_free(ParticleThread *threads);
+
+void psys_thread_distribute_particle(ParticleThread *thread, struct ParticleData *pa, struct ChildParticle *cpa, int p);
+void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, ParticleCacheKey *keys, int i);
+
/* particle_system.c */
int psys_count_keyed_targets(struct Object *ob, struct ParticleSystem *psys);
void psys_get_reactor_target(struct Object *ob, struct ParticleSystem *psys, struct Object **target_ob, struct ParticleSystem **target_psys);
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index ab17366163f..4aebd099885 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -640,7 +640,7 @@ static void new_particle_duplilist(ListBase *lb, Scene *sce, Object *par, Partic
pa_num = a;
pa_time = psys->particles[psys->child[a - totpart].parent].time;
- size=psys_get_child_size(psys, a - totpart, ctime, 0);
+ size=psys_get_child_size(psys, &psys->child[a - totpart], ctime, 0);
}
if(part->draw_as==PART_DRAW_GR) {
@@ -783,7 +783,7 @@ ListBase *object_duplilist(Scene *sce, Object *ob)
{
ListBase *duplilist= MEM_mallocN(sizeof(ListBase), "duplilist");
duplilist->first= duplilist->last= NULL;
-
+
if(ob->transflag & OB_DUPLI) {
if(ob->transflag & OB_DUPLIPARTS) {
ParticleSystem *psys = ob->particlesystem.first;
@@ -808,7 +808,7 @@ ListBase *object_duplilist(Scene *sce, Object *ob)
DupliObject *dob;
group_duplilist(duplilist, ob, 0); /* now recursive */
-
+
/* make copy already, because in group dupli's deform displists can be makde, requiring parent matrices */
for(dob= duplilist->first; dob; dob= dob->next)
Mat4CpyMat4(dob->ob->obmat, dob->mat);
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 0699e3b8655..42cac46c241 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -687,6 +687,9 @@ static void do_init_render_material(Material *ma, int r_mode, float *amb)
/* will become or-ed result of all node modes */
ma->mode_l= ma->mode;
ma->mode_l &= ~MA_SHLESS;
+
+ if(ma->strand_surfnor > 0.0f)
+ ma->mode_l |= MA_STR_SURFDIFF;
}
static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode, float *amb)
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 4fbe714d45c..f85efd23ad6 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -56,6 +56,7 @@
#include "BLI_kdtree.h"
#include "BLI_linklist.h"
#include "BLI_rand.h"
+#include "BLI_threads.h"
#include "BKE_anim.h"
@@ -299,6 +300,27 @@ void psys_free_path_cache(ParticleSystem *psys)
}
free_child_path_cache(psys);
}
+void psys_free_render_memory(Object *ob, ParticleSystem *psys)
+{
+ ParticleSystemModifierData *psmd;
+
+ /* this is a bad function, but saves a lot of memory rendering.
+ * particles should really be generated on the fly with render
+ * settings! */
+ psys_free_path_cache(psys);
+
+ if(psys->child){
+ MEM_freeN(psys->child);
+ psys->child=0;
+ psys->totchild=0;
+ }
+
+ psmd= psys_get_modifier(ob, psys);
+ psmd->flag &= ~eParticleSystemFlag_psys_updated;
+
+ psys->recalc |= PSYS_ALLOC|PSYS_DISTR;
+ //DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+}
/* free everything */
void psys_free(Object *ob, ParticleSystem * psys)
{
@@ -1195,41 +1217,33 @@ static void do_rough_end(float *loc, float t, float fac, float shape, ParticleKe
VECADD(state->co,state->co,rough);
}
-static int check_path_length(int k, int p, ParticleCacheKey **cache, ParticleCacheKey *state, float length, float *dvec)
+static int check_path_length(int k, ParticleCacheKey *keys, ParticleCacheKey *state, float max_length, float *cur_length, float length, float *dvec)
{
- static float max_length = 1.0, cur_length = 0.0;
-
- if(k) {
- if(cur_length + length > max_length){
- //if(p<totparent){
- // if(k<=(int)cache[totpart+p]->time){
- // /* parents need to be calculated fully first so that they don't mess up their children */
- // /* we'll make a note of where we got to though so that they're easy to finish later */
- // state->time=(max_length-cur_length)/length;
- // cache[totpart+p]->time=(float)k;
- // }
- //}
- //else{
- VecMulf(dvec, (max_length - cur_length) / length);
- VECADD(state->co, (state - 1)->co, dvec);
- cache[p]->steps = k;
- /* something over the maximum step value */
- return k=100000;
- //}
- }
- else {
- cur_length+=length;
- }
+ if(*cur_length + length > max_length){
+ //if(p<totparent){
+ // if(k<=(int)cache[totpart+p]->time){
+ // /* parents need to be calculated fully first so that they don't mess up their children */
+ // /* we'll make a note of where we got to though so that they're easy to finish later */
+ // state->time=(max_length-*cur_length)/length;
+ // cache[totpart+p]->time=(float)k;
+ // }
+ //}
+ //else{
+ VecMulf(dvec, (max_length - *cur_length) / length);
+ VECADD(state->co, (state - 1)->co, dvec);
+ keys->steps = k;
+ /* something over the maximum step value */
+ return k=100000;
+ //}
}
- else {/* reset signal */
- max_length=length;
- cur_length=0.0;
+ else {
+ *cur_length+=length;
+ return k;
}
- return k;
}
-static void finalize_path_length(int p, ParticleCacheKey **cache)
+static void finalize_path_length(ParticleCacheKey *keys)
{
- ParticleCacheKey *state = cache[p];
+ ParticleCacheKey *state = keys;
float dvec[3];
state += state->steps;
@@ -1301,42 +1315,54 @@ void psys_find_parents(Object *ob, ParticleSystemModifierData *psmd, ParticleSys
if(orcos)
MEM_freeN(orcos);
}
-void psys_cache_child_paths(Object *ob, ParticleSystem *psys, float cfra, int editupdate)
+
+static void get_strand_normal(Material *ma, float *surfnor, float surfdist, float *nor)
{
- ParticleSettings *part = psys->part;
- ParticleEditSettings *pset = &G.scene->toolsettings->particle;
- ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys);
- ParticleData *pa;
- ChildParticle *cpa;
- ParticleCacheKey **cache = psys->childcache, **pcache = psys->pathcache;
- ParticleCacheKey *tcache, *state, *par=0, *key[4];
- ParticleTexture ptex;
- Material *ma = give_current_material(ob, part->omat);
+ float cross[3], nstrand[3], vnor[3], blend;
- float length, pa_length = 1.0, pa_clump = 1.0, pa_kink = 1.0;
- float pa_rough1 = 1.0, pa_rough2 = 1.0, pa_roughe = 1.0;
- float t, rough_t;
- float dvec[3], orco[3], ornor[3], imat[4][4];
- float *vg_length = 0, *vg_clump = 0, *vg_kink = 0;
- float *vg_rough1 = 0, *vg_rough2 = 0, *vg_roughe = 0;
- float cpa_1st[3];
+ if(!((ma->mode & MA_STR_SURFDIFF) || (ma->strand_surfnor > 0.0f)))
+ return;
- int k, i, totparent=0, between=0, edit=0;
- int steps = (int)pow(2.0,(double)part->draw_step);
- int totchild = psys->totchild;
- int cpa_num; short cpa_from;
+ if(ma->mode & MA_STR_SURFDIFF) {
+ Crossf(cross, surfnor, nor);
+ Crossf(nstrand, nor, cross);
+
+ blend= INPR(nstrand, surfnor);
+ CLAMP(blend, 0.0f, 1.0f);
- if(part->flag & PART_ANIM_BRANCHING)
- BLI_srandom(31415926 + psys->seed + (int)cfra);
+ VecLerpf(vnor, nstrand, surfnor, blend);
+ Normalize(vnor);
+ }
else
- BLI_srandom(31415926 + psys->seed);
+ VECCOPY(vnor, nor)
+
+ if(ma->strand_surfnor > 0.0f) {
+ if(ma->strand_surfnor > surfdist) {
+ blend= (ma->strand_surfnor - surfdist)/ma->strand_surfnor;
+ VecLerpf(vnor, vnor, surfnor, blend);
+ Normalize(vnor);
+ }
+ }
+
+ VECCOPY(nor, vnor);
+}
+
+int psys_threads_init_path(ParticleThread *threads, float cfra, int editupdate)
+{
+ ParticleThreadContext *ctx= threads[0].ctx;
+ Object *ob= ctx->ob;
+ ParticleSystem *psys= ctx->psys;
+ ParticleSettings *part = psys->part;
+ ParticleEditSettings *pset = &G.scene->toolsettings->particle;
+ int totparent=0, between=0;
+ int steps = (int)pow(2.0,(double)part->draw_step);
+ int totchild = psys->totchild;
+ int i, seed, totthread= threads[0].tot;
/*---start figuring out what is actually wanted---*/
- if(psys_in_edit_mode(psys)){
+ if(psys_in_edit_mode(psys))
if(G.rendering==0 && (psys->edit==NULL || pset->flag & PE_SHOW_CHILD)==0)
totchild=0;
- edit=1;
- }
if(totchild && part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){
totparent=(int)(totchild*part->parents*0.3);
@@ -1346,39 +1372,44 @@ void psys_cache_child_paths(Object *ob, ParticleSystem *psys, float cfra, int ed
if(G.rendering)
steps=(int)pow(2.0,(double)part->ren_step);
- else if(part->flag & PART_CHILD_RENDER){
- totchild=0;
- }
else{
totchild=(int)((float)totchild*(float)part->disp/100.0f);
totparent=MIN2(totparent,totchild);
}
- if(totchild==0) return;
+ if(totchild==0) return 0;
- if(editupdate && psys->childcache && !(part->flag & PART_BRANCHING) && totchild == psys->totchildcache) {
- cache = psys->childcache;
+ /* init random number generator */
+ if(ctx->psys->part->flag & PART_ANIM_BRANCHING)
+ seed= 31415926 + ctx->psys->seed + (int)cfra;
+ else
+ seed= 31415926 + ctx->psys->seed;
+
+ if(part->flag & PART_BRANCHING || ctx->editupdate || totchild < 10000)
+ totthread= 1;
+
+ for(i=0; i<totthread; i++) {
+ threads[i].rng_path= rng_new(seed);
+ threads[i].tot= totthread;
}
- else {
- /* clear out old and create new empty path cache */
- free_child_path_cache(psys);
- cache = psys->childcache = MEM_callocN(totchild*sizeof(void *), "Child path cache array");
- tcache = MEM_callocN(totchild * (steps + 1) * sizeof(ParticleCacheKey), "Child path cache");
- for(i=0; i<totchild; i++)
- cache[i] = tcache + i * (steps + 1);
- }
+ /* fill context values */
+ ctx->between= between;
+ ctx->steps= steps;
+ ctx->totchild= totchild;
+ ctx->totparent= totparent;
+ ctx->cfra= cfra;
- psys->lattice = psys_get_lattice(ob,psys);
+ psys->lattice = psys_get_lattice(ob, psys);
/* cache all relevant vertex groups if they exist */
if(part->from!=PART_FROM_PARTICLE){
- vg_length = psys_cache_vgroup(psmd->dm,psys,PSYS_VG_LENGTH);
- vg_clump = psys_cache_vgroup(psmd->dm,psys,PSYS_VG_CLUMP);
- vg_kink = psys_cache_vgroup(psmd->dm,psys,PSYS_VG_KINK);
- vg_rough1 = psys_cache_vgroup(psmd->dm,psys,PSYS_VG_ROUGH1);
- vg_rough2 = psys_cache_vgroup(psmd->dm,psys,PSYS_VG_ROUGH2);
- vg_roughe = psys_cache_vgroup(psmd->dm,psys,PSYS_VG_ROUGHE);
+ ctx->vg_length = psys_cache_vgroup(ctx->dm,psys,PSYS_VG_LENGTH);
+ ctx->vg_clump = psys_cache_vgroup(ctx->dm,psys,PSYS_VG_CLUMP);
+ ctx->vg_kink = psys_cache_vgroup(ctx->dm,psys,PSYS_VG_KINK);
+ ctx->vg_rough1 = psys_cache_vgroup(ctx->dm,psys,PSYS_VG_ROUGH1);
+ ctx->vg_rough2 = psys_cache_vgroup(ctx->dm,psys,PSYS_VG_ROUGH2);
+ ctx->vg_roughe = psys_cache_vgroup(ctx->dm,psys,PSYS_VG_ROUGHE);
}
/* set correct ipo timing */
@@ -1387,294 +1418,373 @@ void psys_cache_child_paths(Object *ob, ParticleSystem *psys, float cfra, int ed
execute_ipo((ID *)part, part->ipo);
}
- Mat4Invert(imat,ob->obmat);
-
- for(i=0,cpa=psys->child; i<totchild; i++, cpa++){
- int guided=0;
- float *cpa_fuv=0;
- float branch_begin=0.0f, branch_end=0.0f, branch_prob=0.0f;
- float branchfac, rough_rand=0.0f;
-
- if(part->flag & PART_BRANCHING) {
- branch_begin=BLI_frand();
- branch_end=branch_begin+(1.0f-branch_begin)*BLI_frand();
- branch_prob=BLI_frand();
- rough_rand=BLI_frand();
- }
-
- if(i<psys->totpart){
- branch_begin=0.0f;
- branch_end=1.0f;
- branch_prob=0.0f;
- }
+ return 1;
+}
- if(between){
- int w, needupdate;
- float foffset;
+/* note: this function must be thread safe, except for branching! */
+void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, ParticleCacheKey *keys, int i)
+{
+ ParticleThreadContext *ctx= thread->ctx;
+ Object *ob= ctx->ob;
+ ParticleSystem *psys = ctx->psys;
+ ParticleSettings *part = psys->part;
+ ParticleCacheKey **cache= psys->childcache;
+ ParticleCacheKey **pcache= psys->pathcache;
+ ParticleCacheKey *state, *par = NULL, *key[4];
+ ParticleData *pa;
+ ParticleTexture ptex;
+ float *cpa_fuv=0;
+ float orco[3], ornor[3], t, rough_t, cpa_1st[3], dvec[3];
+ float branch_begin, branch_end, branch_prob, branchfac, rough_rand;
+ float pa_rough1, pa_rough2, pa_roughe, length, pa_length, pa_clump, pa_kink;
+ float max_length = 1.0f, cur_length = 0.0f;
+ int k, cpa_num, guided=0;
+ short cpa_from;
+
+ if(part->flag & PART_BRANCHING) {
+ branch_begin=rng_getFloat(thread->rng_path);
+ branch_end=branch_begin+(1.0f-branch_begin)*rng_getFloat(thread->rng_path);
+ branch_prob=rng_getFloat(thread->rng_path);
+ rough_rand=rng_getFloat(thread->rng_path);
+ }
+ else {
+ branch_begin= 0.0f;
+ branch_end= 0.0f;
+ branch_prob= 0.0f;
+ rough_rand= 0.0f;
+ }
- if(editupdate && !(part->flag & PART_BRANCHING)) {
- needupdate= 0;
- w= 0;
- while(w<4 && cpa->pa[w]>=0) {
- if(psys->particles[cpa->pa[w]].flag & PARS_EDIT_RECALC) {
- needupdate= 1;
- break;
- }
- w++;
- }
+ if(i<psys->totpart){
+ branch_begin=0.0f;
+ branch_end=1.0f;
+ branch_prob=0.0f;
+ }
- if(!needupdate)
- continue;
- else
- memset(cache[i], 0, sizeof(*cache[i])*(steps+1));
- }
+ if(ctx->between){
+ int w, needupdate;
+ float foffset;
- /* get parent paths */
+ if(ctx->editupdate && !(part->flag & PART_BRANCHING)) {
+ needupdate= 0;
w= 0;
- while(w<4 && cpa->pa[w]>=0){
- key[w] = pcache[cpa->pa[w]];
+ while(w<4 && cpa->pa[w]>=0) {
+ if(psys->particles[cpa->pa[w]].flag & PARS_EDIT_RECALC) {
+ needupdate= 1;
+ break;
+ }
w++;
}
- /* get the original coordinates (orco) for texture usage */
- cpa_num = cpa->num;
-
- foffset= cpa->foffset;
- if(part->childtype == PART_CHILD_FACES)
- foffset = -(2.0f + part->childspread);
- cpa_fuv = cpa->fuv;
- cpa_from = PART_FROM_FACE;
+ if(!needupdate)
+ return;
+ else
+ memset(keys, 0, sizeof(*keys)*(ctx->steps+1));
+ }
+
+ /* get parent paths */
+ w= 0;
+ while(w<4 && cpa->pa[w]>=0){
+ key[w] = pcache[cpa->pa[w]];
+ w++;
+ }
- psys_particle_on_emitter(ob,psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa->fuv,foffset,orco,ornor,0,0);
+ /* get the original coordinates (orco) for texture usage */
+ cpa_num = cpa->num;
+
+ foffset= cpa->foffset;
+ if(part->childtype == PART_CHILD_FACES)
+ foffset = -(2.0f + part->childspread);
+ cpa_fuv = cpa->fuv;
+ cpa_from = PART_FROM_FACE;
- /* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */
- VECCOPY(cpa_1st,orco);
- Mat4MulVecfl(ob->obmat,cpa_1st);
+ psys_particle_on_emitter(ob,ctx->psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa->fuv,foffset,orco,ornor,0,0);
- pa=0;
+ /* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */
+ VECCOPY(cpa_1st,orco);
+ Mat4MulVecfl(ob->obmat,cpa_1st);
+
+ pa=0;
+ }
+ else{
+ if(ctx->editupdate && !(part->flag & PART_BRANCHING)) {
+ if(!(psys->particles[cpa->parent].flag & PARS_EDIT_RECALC))
+ return;
+
+ memset(keys, 0, sizeof(*keys)*(ctx->steps+1));
}
- else{
- if(editupdate && !(part->flag & PART_BRANCHING)) {
- if(!(psys->particles[cpa->parent].flag & PARS_EDIT_RECALC))
- continue;
- memset(cache[i], 0, sizeof(*cache[i])*(steps+1));
- }
+ /* get the parent path */
+ key[0]=pcache[cpa->parent];
- /* get the parent path */
- key[0]=pcache[cpa->parent];
+ /* get the original coordinates (orco) for texture usage */
+ pa=psys->particles+cpa->parent;
- /* get the original coordinates (orco) for texture usage */
- pa=psys->particles+cpa->parent;
+ cpa_from=part->from;
+ cpa_num=pa->num;
+ cpa_fuv=pa->fuv;
- cpa_from=part->from;
- cpa_num=pa->num;
- cpa_fuv=pa->fuv;
+ psys_particle_on_emitter(ob,ctx->psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,orco,ornor,0,0);
+ }
- psys_particle_on_emitter(ob,psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,orco,ornor,0,0);
- }
+ keys->steps = ctx->steps;
- cache[i]->steps = steps;
+ /* correct child ipo timing */
+ if((part->flag&PART_ABS_TIME)==0 && part->ipo){
+ float dsta=part->end-part->sta;
+ calc_ipo(part->ipo, 100.0f*(ctx->cfra-(part->sta+dsta*cpa->rand[1]))/(part->lifetime*(1.0f - part->randlife*cpa->rand[0])));
+ execute_ipo((ID *)part, part->ipo);
+ }
- /* correct child ipo timing */
- if((part->flag&PART_ABS_TIME)==0 && part->ipo){
- float dsta=part->end-part->sta;
- calc_ipo(part->ipo, 100.0f*(cfra-(part->sta+dsta*cpa->rand[1]))/(part->lifetime*(1.0f - part->randlife*cpa->rand[0])));
- execute_ipo((ID *)part, part->ipo);
- }
+ /* get different child parameters from textures & vgroups */
+ ptex.length=part->length*(1.0f - part->randlength*cpa->rand[0]);
+ ptex.clump=1.0;
+ ptex.kink=1.0;
- /* get different child parameters from textures & vgroups */
- ptex.length=part->length*(1.0f - part->randlength*cpa->rand[0]);
- ptex.clump=1.0;
- ptex.kink=1.0;
+ get_cpa_texture(ctx->dm,ctx->ma,cpa_num,cpa_fuv,orco,&ptex,MAP_PA_CACHE);
+
+ pa_length=ptex.length;
+ pa_clump=ptex.clump;
+ pa_kink=ptex.kink;
+ pa_rough1=1.0;
+ pa_rough2=1.0;
+ pa_roughe=1.0;
+
+ if(ctx->vg_length)
+ pa_length*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_length);
+ if(ctx->vg_clump)
+ pa_clump*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_clump);
+ if(ctx->vg_kink)
+ pa_kink*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_kink);
+ if(ctx->vg_rough1)
+ pa_rough1*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_rough1);
+ if(ctx->vg_rough2)
+ pa_rough2*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_rough2);
+ if(ctx->vg_roughe)
+ pa_roughe*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_roughe);
+
+ /* create the child path */
+ for(k=0,state=keys; k<=ctx->steps; k++,state++){
+ t=(float)k/(float)ctx->steps;
+
+ if(ctx->between){
+ int w=0;
- get_cpa_texture(psmd->dm,ma,cpa_num,cpa_fuv,orco,&ptex,MAP_PA_CACHE);
-
- pa_length=ptex.length;
- pa_clump=ptex.clump;
- pa_kink=ptex.kink;
- pa_rough1=1.0;
- pa_rough2=1.0;
- pa_roughe=1.0;
-
- if(vg_length)
- pa_length*=psys_interpolate_value_from_verts(psmd->dm,cpa_from,cpa_num,cpa_fuv,vg_length);
- if(vg_clump)
- pa_clump*=psys_interpolate_value_from_verts(psmd->dm,cpa_from,cpa_num,cpa_fuv,vg_clump);
- if(vg_kink)
- pa_kink*=psys_interpolate_value_from_verts(psmd->dm,cpa_from,cpa_num,cpa_fuv,vg_kink);
- if(vg_rough1)
- pa_rough1*=psys_interpolate_value_from_verts(psmd->dm,cpa_from,cpa_num,cpa_fuv,vg_rough1);
- if(vg_rough2)
- pa_rough2*=psys_interpolate_value_from_verts(psmd->dm,cpa_from,cpa_num,cpa_fuv,vg_rough2);
- if(vg_roughe)
- pa_roughe*=psys_interpolate_value_from_verts(psmd->dm,cpa_from,cpa_num,cpa_fuv,vg_roughe);
-
- /* create the child path */
- for(k=0,state=cache[i]; k<=steps; k++,state++){
- t=(float)k/(float)steps;
-
- if(between){
- int w=0;
-
- state->co[0] = state->co[1] = state->co[2] = 0.0f;
- state->vel[0] = state->vel[1] = state->vel[2] = 0.0f;
-
- //QUATCOPY(state->rot,key[0]->rot);
-
- /* child position is the weighted sum of parent positions */
- while(w<4 && cpa->pa[w]>=0){
- state->co[0] += cpa->w[w] * key[w]->co[0];
- state->co[1] += cpa->w[w] * key[w]->co[1];
- state->co[2] += cpa->w[w] * key[w]->co[2];
-
- state->vel[0] += cpa->w[w] * key[w]->vel[0];
- state->vel[1] += cpa->w[w] * key[w]->vel[1];
- state->vel[2] += cpa->w[w] * key[w]->vel[2];
- key[w]++;
- w++;
- }
- if(k==0){
- /* calculate the offset between actual child root position and first position interpolated from parents */
- VECSUB(cpa_1st,cpa_1st,state->co);
- }
- /* apply offset for correct positioning */
- VECADD(state->co,state->co,cpa_1st);
- }
- else{
- /* offset the child from the parent position */
- offset_child(cpa, (ParticleKey*)key[0], (ParticleKey*)state, part->childflat, part->childrad);
+ state->co[0] = state->co[1] = state->co[2] = 0.0f;
+ state->vel[0] = state->vel[1] = state->vel[2] = 0.0f;
- key[0]++;
- }
+ //QUATCOPY(state->rot,key[0]->rot);
- if(totparent){
- if(i>=totparent)
- par = cache[cpa->parent] + k;
- else
- par=0;
+ /* child position is the weighted sum of parent positions */
+ while(w<4 && cpa->pa[w]>=0){
+ state->co[0] += cpa->w[w] * key[w]->co[0];
+ state->co[1] += cpa->w[w] * key[w]->co[1];
+ state->co[2] += cpa->w[w] * key[w]->co[2];
+
+ state->vel[0] += cpa->w[w] * key[w]->vel[0];
+ state->vel[1] += cpa->w[w] * key[w]->vel[1];
+ state->vel[2] += cpa->w[w] * key[w]->vel[2];
+ key[w]++;
+ w++;
}
- else if(cpa->parent>=0){
- par=pcache[cpa->parent]+k;
+ if(k==0){
+ /* calculate the offset between actual child root position and first position interpolated from parents */
+ VECSUB(cpa_1st,cpa_1st,state->co);
}
+ /* apply offset for correct positioning */
+ VECADD(state->co,state->co,cpa_1st);
+ }
+ else{
+ /* offset the child from the parent position */
+ offset_child(cpa, (ParticleKey*)key[0], (ParticleKey*)state, part->childflat, part->childrad);
- /* apply different deformations to the child path */
- if(part->flag & PART_CHILD_GUIDE)
- guided = do_guide((ParticleKey*)state, i, t, &(psys->effectors)); //safe to cast, since only co and vel are used
+ key[0]++;
+ }
- if(guided==0){
- if(part->kink)
- do_prekink((ParticleKey*)state, (ParticleKey*)par, par->rot, t,
- part->kink_freq * pa_kink, part->kink_shape, part->kink_amp, part->kink, part->kink_axis, ob->obmat);
-
- do_clump((ParticleKey*)state, (ParticleKey*)par, t, part->clumpfac, part->clumppow, pa_clump);
+ if(ctx->totparent){
+ if(i>=ctx->totparent)
+ /* this is not threadsafe, but should only happen for
+ * branching particles particles, which are not threaded */
+ par = cache[cpa->parent] + k;
+ else
+ par=0;
+ }
+ else if(cpa->parent>=0){
+ par=pcache[cpa->parent]+k;
+ }
- if(part->kink)
- do_postkink((ParticleKey*)state, (ParticleKey*)par, par->rot, t,
- part->kink_freq * pa_kink, part->kink_shape, part->kink_amp, part->kink, part->kink_axis, ob->obmat);
- }
+ /* apply different deformations to the child path */
+ if(part->flag & PART_CHILD_GUIDE)
+ guided = do_guide((ParticleKey*)state, i, t, &(psys->effectors)); //safe to cast, since only co and vel are used
+
+ if(guided==0){
+ if(part->kink)
+ do_prekink((ParticleKey*)state, (ParticleKey*)par, par->rot, t,
+ part->kink_freq * pa_kink, part->kink_shape, part->kink_amp, part->kink, part->kink_axis, ob->obmat);
+
+ do_clump((ParticleKey*)state, (ParticleKey*)par, t, part->clumpfac, part->clumppow, pa_clump);
+
+ if(part->kink)
+ do_postkink((ParticleKey*)state, (ParticleKey*)par, par->rot, t,
+ part->kink_freq * pa_kink, part->kink_shape, part->kink_amp, part->kink, part->kink_axis, ob->obmat);
+ }
- if(part->flag & PART_BRANCHING && between == 0 && part->flag & PART_ANIM_BRANCHING)
- rough_t = t * rough_rand;
- else
- rough_t = t;
+ if(part->flag & PART_BRANCHING && ctx->between == 0 && part->flag & PART_ANIM_BRANCHING)
+ rough_t = t * rough_rand;
+ else
+ rough_t = t;
+
+ if(part->rough1 != 0.0 && pa_rough1 != 0.0)
+ do_rough(orco, rough_t, pa_rough1*part->rough1, part->rough1_size, 0.0, (ParticleKey*)state);
- if(part->rough1 != 0.0 && pa_rough1 != 0.0)
- do_rough(orco, rough_t, pa_rough1*part->rough1, part->rough1_size, 0.0, (ParticleKey*)state);
+ if(part->rough2 != 0.0 && pa_rough2 != 0.0)
+ do_rough(cpa->rand, rough_t, pa_rough2*part->rough2, part->rough2_size, part->rough2_thres, (ParticleKey*)state);
- if(part->rough2 != 0.0 && pa_rough2 != 0.0)
- do_rough(cpa->rand, rough_t, pa_rough2*part->rough2, part->rough2_size, part->rough2_thres, (ParticleKey*)state);
+ if(part->rough_end != 0.0 && pa_roughe != 0.0)
+ do_rough_end(cpa->rand, rough_t, pa_roughe*part->rough_end, part->rough_end_shape, (ParticleKey*)state, (ParticleKey*)par);
- if(part->rough_end != 0.0 && pa_roughe != 0.0)
- do_rough_end(cpa->rand, rough_t, pa_roughe*part->rough_end, part->rough_end_shape, (ParticleKey*)state, (ParticleKey*)par);
+ if(part->flag & PART_BRANCHING && ctx->between==0){
+ if(branch_prob > part->branch_thres){
+ branchfac=0.0f;
+ }
+ else{
+ if(part->flag & PART_SYMM_BRANCHING){
+ if(t < branch_begin || t > branch_end)
+ branchfac=0.0f;
+ else{
+ if((t-branch_begin)/(branch_end-branch_begin)<0.5)
+ branchfac=2.0f*(t-branch_begin)/(branch_end-branch_begin);
+ else
+ branchfac=2.0f*(branch_end-t)/(branch_end-branch_begin);
- if(part->flag & PART_BRANCHING && between==0){
- if(branch_prob > part->branch_thres){
- branchfac=0.0f;
+ CLAMP(branchfac,0.0f,1.0f);
+ }
}
else{
- if(part->flag & PART_SYMM_BRANCHING){
- if(t < branch_begin || t > branch_end)
- branchfac=0.0f;
- else{
- if((t-branch_begin)/(branch_end-branch_begin)<0.5)
- branchfac=2.0f*(t-branch_begin)/(branch_end-branch_begin);
- else
- branchfac=2.0f*(branch_end-t)/(branch_end-branch_begin);
-
- CLAMP(branchfac,0.0f,1.0f);
- }
+ if(t < branch_begin){
+ branchfac=0.0f;
}
else{
- if(t < branch_begin){
- branchfac=0.0f;
- }
- else{
- branchfac=(t-branch_begin)/((1.0f-branch_begin)*0.5f);
- CLAMP(branchfac,0.0f,1.0f);
- }
+ branchfac=(t-branch_begin)/((1.0f-branch_begin)*0.5f);
+ CLAMP(branchfac,0.0f,1.0f);
}
}
-
- if(i<psys->totpart){
- VecLerpf(state->co, (pcache[i] + k)->co, state->co, branchfac);
- }
- else
- VecLerpf(state->co, (cache[i - psys->totpart] + k)->co, state->co, branchfac);
}
- /* we have to correct velocity because of kink & clump */
- if(k>1){
- VECSUB((state-1)->vel,state->co,(state-2)->co);
- VecMulf((state-1)->vel,0.5);
- }
-
- /* check if path needs to be cut before actual end of data points */
- if(k){
- VECSUB(dvec,state->co,(state-1)->co);
- if(part->flag&PART_ABS_LENGTH)
- length=VecLength(dvec);
- else
- length=1.0f/(float)steps;
+ if(i<psys->totpart)
+ VecLerpf(state->co, (pcache[i] + k)->co, state->co, branchfac);
+ else
+ /* this is not threadsafe, but should only happen for
+ * branching particles particles, which are not threaded */
+ VecLerpf(state->co, (cache[i - psys->totpart] + k)->co, state->co, branchfac);
+ }
- k=check_path_length(k,i,cache,state,length,dvec);
- }
- else{
- /* initialize length calculation */
- if(part->flag&PART_ABS_LENGTH)
- check_path_length(0,0,0,0,part->abslength*pa_length,0);
- else
- check_path_length(0,0,0,0,pa_length,0);
- }
+ /* we have to correct velocity because of kink & clump */
+ if(k>1){
+ VECSUB((state-1)->vel,state->co,(state-2)->co);
+ VecMulf((state-1)->vel,0.5);
if(part->draw & PART_DRAW_MAT_COL)
- VECCOPY(state->col, &ma->r)
+ get_strand_normal(ctx->ma, ornor, cur_length, (state-1)->vel);
+ }
+
+ /* check if path needs to be cut before actual end of data points */
+ if(k){
+ VECSUB(dvec,state->co,(state-1)->co);
+ if(part->flag&PART_ABS_LENGTH)
+ length=VecLength(dvec);
+ else
+ length=1.0f/(float)ctx->steps;
+
+ k=check_path_length(k,keys,state,max_length,&cur_length,length,dvec);
+ }
+ else{
+ /* initialize length calculation */
+ if(part->flag&PART_ABS_LENGTH)
+ max_length= part->abslength*pa_length;
+ else
+ max_length= pa_length;
+
+ cur_length= 0.0f;
+ }
+
+ if(part->draw & PART_DRAW_MAT_COL) {
+ VECCOPY(state->col, &ctx->ma->r)
+ get_strand_normal(ctx->ma, ornor, cur_length, state->vel);
}
}
+
/* now let's finalise the interpolated parents that we might have left half done before */
- if(totchild) for(i=0,cpa=psys->child; i<totparent; i++, cpa++)
- finalize_path_length(i,cache);
-
- if(vg_length)
- MEM_freeN(vg_length);
- if(vg_clump)
- MEM_freeN(vg_clump);
- if(vg_kink)
- MEM_freeN(vg_kink);
- if(vg_rough1)
- MEM_freeN(vg_rough1);
- if(vg_rough2)
- MEM_freeN(vg_roughe);
- if(vg_roughe)
- MEM_freeN(vg_roughe);
-
- psys->totchildcache = totchild;
-
- if(psys->lattice){
- end_latt_deform();
- psys->lattice=0;
+ if(i<ctx->totparent)
+ finalize_path_length(keys);
+}
+
+void *exec_child_path_cache(void *data)
+{
+ ParticleThread *thread= (ParticleThread*)data;
+ ParticleThreadContext *ctx= thread->ctx;
+ ParticleSystem *psys= ctx->psys;
+ ParticleCacheKey **cache= psys->childcache;
+ ChildParticle *cpa;
+ int i, totchild= ctx->totchild;
+
+ cpa= psys->child + thread->num;
+ for(i=thread->num; i<totchild; i+=thread->tot, cpa+=thread->tot)
+ psys_thread_create_path(thread, cpa, cache[i], i);
+
+ return 0;
+}
+
+void psys_cache_child_paths(Object *ob, ParticleSystem *psys, float cfra, int editupdate)
+{
+ ParticleSettings *part = psys->part;
+ ParticleThread *pthreads;
+ ParticleThreadContext *ctx;
+ ParticleCacheKey **cache, *tcache;
+ ListBase threads;
+ int i, totchild, totparent, totthread;
+
+ pthreads= psys_threads_create(ob, psys, G.scene->r.threads);
+
+ if(!psys_threads_init_path(pthreads, cfra, editupdate)) {
+ psys_threads_free(pthreads);
+ return;
+ }
+
+ ctx= pthreads[0].ctx;
+ totchild= ctx->totchild;
+ totparent= ctx->totparent;
+
+ if(editupdate && psys->childcache && !(part->flag & PART_BRANCHING) && totchild == psys->totchildcache) {
+ cache = psys->childcache;
+ }
+ else {
+ /* clear out old and create new empty path cache */
+ free_child_path_cache(psys);
+
+ cache = psys->childcache = MEM_callocN(totchild*sizeof(void *), "Child path cache array");
+ tcache = MEM_callocN(totchild * (ctx->steps + 1) * sizeof(ParticleCacheKey), "Child path cache");
+ for(i=0; i<totchild; i++)
+ cache[i] = tcache + i * (ctx->steps + 1);
+
+ psys->totchildcache = totchild;
+ }
+
+ totthread= pthreads[0].tot;
+
+ if(totthread > 1) {
+ BLI_init_threads(&threads, exec_child_path_cache, totthread);
+
+ for(i=0; i<totthread; i++)
+ BLI_insert_thread(&threads, &pthreads[i]);
+
+ BLI_end_threads(&threads);
}
+ else
+ exec_child_path_cache(&pthreads[0]);
+
+ psys_threads_free(pthreads);
}
+
/* Calculates paths ready for drawing/rendering. */
/* -Usefull for making use of opengl vertex arrays for super fast strand drawing. */
/* -Makes child strands possible and creates them too into the cache. */
@@ -2260,6 +2370,7 @@ static void default_particle_settings(ParticleSettings *part)
part->childsize=1.0;
part->child_nbr=10;
+ part->ren_child_nbr=100;
part->childrad=0.2f;
part->childflat=0.0f;
part->clumppow=0.0f;
@@ -2491,12 +2602,14 @@ void psys_get_texture(Object *ob, Material *ma, ParticleSystemModifierData *psmd
else
//psys_particle_on_emitter(ob,psmd,psys->part->from,pa->num,pa->fuv,pa->foffset,texco,0,0,0);
/* <jahka> anyways I think it will be too small a difference to notice, so psys_get_texture should only know about the original mesh structure.. no dm needed anywhere */
- psys_particle_on_emitter(ob,psmd,psys->part->from,pa->num,-1,pa->fuv,pa->foffset,texco,0,0,0);
+ /* <brecht> the code only does dm based lookup now, so passing num_dmcache anyway to avoid^
+ * massive slowdown here */
+ psys_particle_on_emitter(ob,psmd,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,texco,0,0,0);
}
else{
//psys_particle_on_emitter(ob,psmd,psys->part->from,pa->num,pa->fuv,pa->offset,texco,0,0,0);
/* ditto above */
- psys_particle_on_emitter(ob,psmd,psys->part->from,pa->num,-1,pa->fuv,pa->foffset,texco,0,0,0);
+ psys_particle_on_emitter(ob,psmd,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,texco,0,0,0);
}
externtex(mtex, texco, &value, rgba, rgba+1, rgba+2, rgba+3);
@@ -2566,10 +2679,9 @@ float psys_get_size(Object *ob, Material *ma, ParticleSystemModifierData *psmd,
return size*part->size;
}
-float psys_get_child_time(ParticleSystem *psys, int child_nbr, float cfra)
+float psys_get_child_time(ParticleSystem *psys, ChildParticle *cpa, float cfra)
{
ParticleSettings *part = psys->part;
- ChildParticle *cpa=psys->child+child_nbr;
if(part->childtype==PART_CHILD_FACES){
float time;
@@ -2587,17 +2699,16 @@ float psys_get_child_time(ParticleSystem *psys, int child_nbr, float cfra)
return (cfra-pa->time)/pa->lifetime;
}
}
-float psys_get_child_size(ParticleSystem *psys, int child_nbr, float cfra, float *pa_time)
+float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float cfra, float *pa_time)
{
ParticleSettings *part = psys->part;
- ChildParticle *cpa = psys->child + child_nbr;
float size, time;
if(part->childtype==PART_CHILD_FACES){
if(pa_time)
time=*pa_time;
else
- time=psys_get_child_time(psys,child_nbr,cfra);
+ time=psys_get_child_time(psys,cpa,cfra);
if((part->flag&PART_ABS_TIME)==0 && part->ipo){
calc_ipo(part->ipo, 100*time);
@@ -2645,9 +2756,6 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle
// edit=1;
//}
- if(G.rendering==0 && part->flag & PART_CHILD_RENDER)
- totchild=0;
-
/* user want's cubic interpolation but only without sb it possible */
//if(interpolation==PART_INTER_CUBIC && baked && psys->softflag==OB_SB_ENABLE)
// interpolation=PART_INTER_BSPLINE;
@@ -2907,8 +3015,6 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey
cfra=bsystem_time(0,(float)G.scene->r.cfra,0.0);
if(psys->totchild && p>=totpart){
- if(G.rendering==0 && part->flag&PART_CHILD_RENDER)
- return 0;
if(part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){
between=1;
}
@@ -2919,7 +3025,7 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey
pa=psys->particles+p;
if(between){
- state->time = psys_get_child_time(psys,p-totpart,cfra);
+ state->time = psys_get_child_time(psys,&psys->child[p-totpart],cfra);
if(always==0)
if((state->time<0.0 && (part->flag & PART_UNBORN)==0)
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 30f061743c4..c8a0c2632be 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -57,6 +57,7 @@
#include "BLI_blenlib.h"
#include "BLI_kdtree.h"
#include "BLI_linklist.h"
+#include "BLI_threads.h"
#include "BKE_anim.h"
#include "BKE_bad_level_calls.h"
@@ -106,7 +107,7 @@ static int get_current_display_percentage(ParticleSystem *psys)
static void alloc_particles(ParticleSystem *psys, int new_totpart)
{
ParticleData *newpars = 0, *pa;
- int i, totpart, totsaved = 0;
+ int i, child_nbr, totpart, totsaved = 0;
if(new_totpart<0){
if(psys->part->distr==PART_DISTR_GRID){
@@ -134,13 +135,14 @@ static void alloc_particles(ParticleSystem *psys, int new_totpart)
}
psys->particles=newpars;
- if(psys->part->child_nbr && psys->part->childtype){
+ child_nbr= (G.rendering)? psys->part->ren_child_nbr: psys->part->child_nbr;
+ if(child_nbr && psys->part->childtype){
if(psys->child)
MEM_freeN(psys->child);
psys->child = NULL;
if(totpart)
- psys->child= MEM_callocN(totpart*psys->part->child_nbr*sizeof(ChildParticle), "child_particles");
- psys->totchild=totpart*psys->part->child_nbr;
+ psys->child= MEM_callocN(totpart*child_nbr*sizeof(ChildParticle), "child_particles");
+ psys->totchild=totpart*child_nbr;
}
else if(psys->child){
MEM_freeN(psys->child);
@@ -462,6 +464,297 @@ static int binary_search_distribution(float *sum, int n, float value)
return low;
}
+/* note: this function must be thread safe, for from == PART_FROM_CHILD */
+#define ONLY_WORKING_WITH_PA_VERTS 0
+void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, ChildParticle *cpa, int p)
+{
+ ParticleThreadContext *ctx= thread->ctx;
+ Object *ob= ctx->ob;
+ DerivedMesh *dm= ctx->dm;
+ ParticleData *tpars=0, *tpa;
+ ParticleSettings *part= ctx->psys->part;
+ float *v1, *v2, *v3, *v4, nor[3], co1[3], co2[3], nor1[3];
+ float cur_d, min_d;
+ int from= ctx->from;
+ int cfrom= ctx->cfrom;
+ int distr= ctx->distr;
+ int i, intersect, tot;
+
+ if(from == PART_FROM_VERT) {
+ /* TODO_PARTICLE - use original index */
+ pa->num= ctx->index[p];
+ pa->fuv[0] = 1.0f;
+ pa->fuv[1] = pa->fuv[2] = pa->fuv[3] = 0.0;
+ //pa->verts[0] = pa->verts[1] = pa->verts[2] = 0;
+
+#if ONLY_WORKING_WITH_PA_VERTS
+ if(ctx->tree){
+ KDTreeNearest ptn[3];
+ int w, maxw;
+
+ psys_particle_on_dm(ctx->ob,ctx->dm,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0);
+ maxw = BLI_kdtree_find_n_nearest(ctx->tree,3,co1,NULL,ptn);
+
+ for(w=0; w<maxw; w++){
+ pa->verts[w]=ptn->num;
+ }
+ }
+#endif
+ }
+ else if(from == PART_FROM_FACE || from == PART_FROM_VOLUME) {
+ MFace *mface;
+
+ pa->num = i = ctx->index[p];
+ mface = dm->getFaceData(dm,i,CD_MFACE);
+
+ switch(distr){
+ case PART_DISTR_JIT:
+ ctx->jitoff[i] = fmod(ctx->jitoff[i],(float)ctx->jitlevel);
+ psys_uv_to_w(ctx->jit[2*(int)ctx->jitoff[i]], ctx->jit[2*(int)ctx->jitoff[i]+1], mface->v4, pa->fuv);
+ ctx->jitoff[i]++;
+ //ctx->jitoff[i]=(float)fmod(ctx->jitoff[i]+ctx->maxweight/ctx->weight[i],(float)ctx->jitlevel);
+ break;
+ case PART_DISTR_RAND:
+ psys_uv_to_w(rng_getFloat(thread->rng), rng_getFloat(thread->rng), mface->v4, pa->fuv);
+ break;
+ }
+ pa->foffset= 0.0f;
+
+ /*
+ pa->verts[0] = mface->v1;
+ pa->verts[1] = mface->v2;
+ pa->verts[2] = mface->v3;
+ */
+
+ /* experimental */
+ if(from==PART_FROM_VOLUME){
+ MVert *mvert=dm->getVertDataArray(dm,CD_MVERT);
+
+ tot=dm->getNumFaces(dm);
+
+ psys_interpolate_face(mvert,mface,0,pa->fuv,co1,nor,0,0);
+
+ Normalize(nor);
+ VecMulf(nor,-100.0);
+
+ VECADD(co2,co1,nor);
+
+ min_d=2.0;
+ intersect=0;
+
+ for(i=0,mface=dm->getFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++){
+ if(i==pa->num) continue;
+
+ v1=mvert[mface->v1].co;
+ v2=mvert[mface->v2].co;
+ v3=mvert[mface->v3].co;
+
+ if(LineIntersectsTriangle(co1, co2, v2, v3, v1, &cur_d, 0)){
+ if(cur_d<min_d){
+ min_d=cur_d;
+ pa->foffset=cur_d*50.0f; /* to the middle of volume */
+ intersect=1;
+ }
+ }
+ if(mface->v4){
+ v4=mvert[mface->v4].co;
+
+ if(LineIntersectsTriangle(co1, co2, v4, v1, v3, &cur_d, 0)){
+ if(cur_d<min_d){
+ min_d=cur_d;
+ pa->foffset=cur_d*50.0f; /* to the middle of volume */
+ intersect=1;
+ }
+ }
+ }
+ }
+ if(intersect==0)
+ pa->foffset=0.0;
+ else switch(distr){
+ case PART_DISTR_JIT:
+ pa->foffset*= ctx->jit[2*(int)ctx->jitoff[i]];
+ break;
+ case PART_DISTR_RAND:
+ pa->foffset*=BLI_frand();
+ break;
+ }
+ }
+ }
+ else if(from == PART_FROM_PARTICLE) {
+ //pa->verts[0]=0; /* not applicable */
+ //pa->verts[1]=0;
+ //pa->verts[2]=0;
+
+ tpa=tpars+ctx->index[p];
+ pa->num=ctx->index[p];
+ pa->fuv[0]=tpa->fuv[0];
+ pa->fuv[1]=tpa->fuv[1];
+ /* abusing foffset a little for timing in near reaction */
+ pa->foffset=ctx->weight[ctx->index[p]];
+ ctx->weight[ctx->index[p]]+=ctx->maxweight;
+ }
+ else if(from == PART_FROM_CHILD) {
+ MFace *mf;
+
+ if(ctx->index[p] < 0) {
+ cpa->num=0;
+ cpa->fuv[0]=cpa->fuv[1]=cpa->fuv[2]=cpa->fuv[3]=0.0f;
+ cpa->pa[0]=cpa->pa[1]=cpa->pa[2]=cpa->pa[3]=0;
+ cpa->rand[0]=cpa->rand[1]=cpa->rand[2]=0.0f;
+ return;
+ }
+
+ mf= dm->getFaceData(dm, ctx->index[p], CD_MFACE);
+
+ //switch(distr){
+ // case PART_DISTR_JIT:
+ // i=index[p];
+ // psys_uv_to_w(ctx->jit[2*(int)ctx->jitoff[i]], ctx->jit[2*(int)ctx->jitoff[i]+1], mf->v4, cpa->fuv);
+ // ctx->jitoff[i]=(float)fmod(ctx->jitoff[i]+ctx->maxweight/ctx->weight[i],(float)ctx->jitlevel);
+ // break;
+ // case PART_DISTR_RAND:
+ psys_uv_to_w(rng_getFloat(thread->rng), rng_getFloat(thread->rng), mf->v4, cpa->fuv);
+ // break;
+ //}
+
+ cpa->rand[0] = rng_getFloat(thread->rng);
+ cpa->rand[1] = rng_getFloat(thread->rng);
+ cpa->rand[2] = rng_getFloat(thread->rng);
+ cpa->num = ctx->index[p];
+
+ if(ctx->tree){
+ KDTreeNearest ptn[10];
+ int w,maxw, do_seams;
+ float maxd,mind,dd,totw=0.0;
+ int parent[10];
+ float pweight[10];
+
+ do_seams= (part->flag&PART_CHILD_SEAMS && ctx->seams);
+
+ psys_particle_on_dm(ob,dm,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,0,0);
+ maxw = BLI_kdtree_find_n_nearest(ctx->tree,(do_seams)?10:4,co1,nor1,ptn);
+
+ maxd=ptn[maxw-1].dist;
+ mind=ptn[0].dist;
+ dd=maxd-mind;
+
+ /* the weights here could be done better */
+ for(w=0; w<maxw; w++){
+ parent[w]=ptn[w].index;
+ pweight[w]=(float)pow(2.0,(double)(-6.0f*ptn[w].dist/maxd));
+ //totw+=cpa->w[w];
+ }
+ for(;w<10; w++){
+ parent[w]=-1;
+ pweight[w]=0.0f;
+ }
+ if(do_seams){
+ ParticleSeam *seam=ctx->seams;
+ float temp[3],temp2[3],tan[3];
+ float inp,cur_len,min_len=10000.0f;
+ int min_seam=0, near_vert=0;
+ /* find closest seam */
+ for(i=0; i<ctx->totseam; i++, seam++){
+ VecSubf(temp,co1,seam->v0);
+ inp=Inpf(temp,seam->dir)/seam->length2;
+ if(inp<0.0f){
+ cur_len=VecLenf(co1,seam->v0);
+ }
+ else if(inp>1.0f){
+ cur_len=VecLenf(co1,seam->v1);
+ }
+ else{
+ VecCopyf(temp2,seam->dir);
+ VecMulf(temp2,inp);
+ cur_len=VecLenf(temp,temp2);
+ }
+ if(cur_len<min_len){
+ min_len=cur_len;
+ min_seam=i;
+ if(inp<0.0f) near_vert=-1;
+ else if(inp>1.0f) near_vert=1;
+ else near_vert=0;
+ }
+ }
+ seam=ctx->seams+min_seam;
+
+ VecCopyf(temp,seam->v0);
+
+ if(near_vert){
+ if(near_vert==-1)
+ VecSubf(tan,co1,seam->v0);
+ else{
+ VecSubf(tan,co1,seam->v1);
+ VecCopyf(temp,seam->v1);
+ }
+
+ Normalize(tan);
+ }
+ else{
+ VecCopyf(tan,seam->tan);
+ VecSubf(temp2,co1,temp);
+ if(Inpf(tan,temp2)<0.0f)
+ VecMulf(tan,-1.0f);
+ }
+ for(w=0; w<maxw; w++){
+ VecSubf(temp2,ptn[w].co,temp);
+ if(Inpf(tan,temp2)<0.0f){
+ parent[w]=-1;
+ pweight[w]=0.0f;
+ }
+ }
+
+ }
+
+ for(w=0,i=0; w<maxw && i<4; w++){
+ if(parent[w]>=0){
+ cpa->pa[i]=parent[w];
+ cpa->w[i]=pweight[w];
+ totw+=pweight[w];
+ i++;
+ }
+ }
+ for(;i<4; i++){
+ cpa->pa[i]=-1;
+ cpa->w[i]=0.0f;
+ }
+
+ if(totw>0.0f) for(w=0; w<4; w++)
+ cpa->w[w]/=totw;
+
+ cpa->parent=cpa->pa[0];
+ }
+ }
+}
+
+void *exec_distribution(void *data)
+{
+ ParticleThread *thread= (ParticleThread*)data;
+ ParticleSystem *psys= thread->ctx->psys;
+ ParticleData *pa;
+ ChildParticle *cpa;
+ int p, totpart;
+
+ if(thread->ctx->from == PART_FROM_CHILD) {
+ totpart= psys->totchild;
+ cpa= psys->child + thread->num;
+
+ rng_skip(thread->rng, 5*thread->num);
+ for(p=thread->num; p<totpart; p+=thread->tot, cpa+=thread->tot) {
+ psys_thread_distribute_particle(thread, NULL, cpa, p);
+ rng_skip(thread->rng, 5*(thread->tot-1));
+ }
+ }
+ else {
+ totpart= psys->totpart;
+ pa= psys->particles + thread->num;
+ for(p=thread->num; p<totpart; p+=thread->tot, pa+=thread->tot)
+ psys_thread_distribute_particle(thread, pa, NULL, p);
+ }
+
+ return 0;
+}
+
/* creates a distribution of coordinates on a DerivedMesh */
/* */
/* 1. lets check from what we are emitting */
@@ -477,39 +770,39 @@ static int binary_search_distribution(float *sum, int n, float value)
/* 6. and we're done! */
/* This is to denote functionality that does not yet work with mesh - only derived mesh */
-#define ONLY_WORKING_WITH_PA_VERTS 0
-static void distribute_particles_on_dm(DerivedMesh *finaldm, Object *ob, ParticleSystem *psys, int from)
+int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm, int from)
{
+ ParticleThreadContext *ctx= threads[0].ctx;
+ Object *ob= ctx->ob;
+ ParticleSystem *psys= ctx->psys;
Object *tob;
- ParticleData *pa=0, *tpars=0, *tpa;
+ ParticleData *pa=0, *tpars;
ParticleSettings *part;
ParticleSystem *tpsys;
+ ParticleSeam *seams= 0;
ChildParticle *cpa=0;
KDTree *tree=0;
- ParticleSeam *seams=0;
+ DerivedMesh *dm= NULL;
float *jit= NULL;
- int p=0,i;
+ int i, seed, p=0, totthread= threads[0].tot;
int no_distr=0, cfrom=0;
int tot=0, totpart, *index=0, children=0, totseam=0;
//int *vertpart=0;
- int jitlevel= 1, intersect, distr;
+ int jitlevel= 1, distr;
float *weight=0,*sum=0,*jitoff=0;
- float cur, maxweight=0.0, tweight, totweight;
- float *v1, *v2, *v3, *v4, co[3], nor[3], co1[3], co2[3], nor1[3];
- float cur_d, min_d;
- DerivedMesh *dm= NULL;
+ float cur, maxweight=0.0, tweight, totweight, co[3], nor[3];
if(ob==0 || psys==0 || psys->part==0)
- return;
+ return 0;
part=psys->part;
totpart=psys->totpart;
if(totpart==0)
- return;
+ return 0;
if (!finaldm->deformedOnly && !CustomData_has_layer( &finaldm->faceData, CD_ORIGINDEX ) ) {
error("Can't paint with the current modifier stack, disable destructive modifiers");
- return;
+ return 0;
}
BLI_srandom(31415926 + psys->seed);
@@ -579,7 +872,9 @@ static void distribute_particles_on_dm(DerivedMesh *finaldm, Object *ob, Particl
}
else{
/* no need to figure out distribution */
- for(i=0; i<part->child_nbr; i++){
+ int child_nbr= (G.rendering)? part->ren_child_nbr: part->child_nbr;
+
+ for(i=0; i<child_nbr; i++){
for(p=0; p<psys->totpart; p++,cpa++){
float length=2.0;
cpa->parent=p;
@@ -600,7 +895,7 @@ static void distribute_particles_on_dm(DerivedMesh *finaldm, Object *ob, Particl
}
}
- return;
+ return 0;
}
}
else{
@@ -610,7 +905,7 @@ static void distribute_particles_on_dm(DerivedMesh *finaldm, Object *ob, Particl
if(part->distr==PART_DISTR_GRID){
distribute_particles_in_grid(dm,psys);
dm->release(dm);
- return;
+ return 0;
}
distr=part->distr;
@@ -674,7 +969,7 @@ static void distribute_particles_on_dm(DerivedMesh *finaldm, Object *ob, Particl
}
if(dm != finaldm) dm->release(dm);
- return;
+ return 0;
}
/* 2. */
@@ -796,6 +1091,8 @@ static void distribute_particles_on_dm(DerivedMesh *finaldm, Object *ob, Particl
}
}
+ MEM_freeN(sum);
+
/* weights are no longer used except for FROM_PARTICLE, which needs them zeroed for indexing */
if(from==PART_FROM_PARTICLE){
for(i=0; i<tot; i++)
@@ -820,277 +1117,71 @@ static void distribute_particles_on_dm(DerivedMesh *finaldm, Object *ob, Particl
}
/* 5. */
- if(children) from=PART_FROM_CHILD;
- for(p=0,pa=psys->particles; p<totpart; p++,pa++,cpa++){
- switch(from){
- case PART_FROM_VERT:
- /* TODO_PARTICLE - use original index */
- pa->num=index[p];
- pa->fuv[0] = 1.0f;
- pa->fuv[1] = pa->fuv[2] = pa->fuv[3] = 0.0;
- //pa->verts[0] = pa->verts[1] = pa->verts[2] = 0;
-
-#if ONLY_WORKING_WITH_PA_VERTS
- if(tree){
- KDTreeNearest ptn[3];
- int w,maxw;
-
- psys_particle_on_dm(ob,dm,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0);
- maxw = BLI_kdtree_find_n_nearest(tree,3,co1,NULL,ptn);
-
- for(w=0; w<maxw; w++){
- pa->verts[w]=ptn->num;
- }
- }
-#endif
- break;
- case PART_FROM_FACE:
- case PART_FROM_VOLUME:
- {
- MFace *mface;
- pa->num = i = index[p];
- mface = dm->getFaceData(dm,i,CD_MFACE);
-
- switch(distr){
- case PART_DISTR_JIT:
- jitoff[i] = fmod(jitoff[i],(float)jitlevel);
- psys_uv_to_w(jit[2*(int)jitoff[i]], jit[2*(int)jitoff[i]+1], mface->v4, pa->fuv);
- jitoff[i]++;
- //jitoff[i]=(float)fmod(jitoff[i]+maxweight/weight[i],(float)jitlevel);
- break;
- case PART_DISTR_RAND:
- psys_uv_to_w(BLI_frand(), BLI_frand(), mface->v4, pa->fuv);
- break;
- }
- pa->foffset= 0.0f;
-
- /*
- pa->verts[0] = mface->v1;
- pa->verts[1] = mface->v2;
- pa->verts[2] = mface->v3;
- */
-
- /* experimental */
- if(from==PART_FROM_VOLUME){
- MVert *mvert=dm->getVertDataArray(dm,CD_MVERT);
-
- tot=dm->getNumFaces(dm);
-
- psys_interpolate_face(mvert,mface,0,pa->fuv,co1,nor,0,0);
-
- Normalize(nor);
- VecMulf(nor,-100.0);
-
- VECADD(co2,co1,nor);
-
- min_d=2.0;
- intersect=0;
-
- for(i=0,mface=dm->getFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++){
- if(i==pa->num) continue;
-
- v1=mvert[mface->v1].co;
- v2=mvert[mface->v2].co;
- v3=mvert[mface->v3].co;
-
- if(LineIntersectsTriangle(co1, co2, v2, v3, v1, &cur_d, 0)){
- if(cur_d<min_d){
- min_d=cur_d;
- pa->foffset=cur_d*50.0f; /* to the middle of volume */
- intersect=1;
- }
- }
- if(mface->v4){
- v4=mvert[mface->v4].co;
+ if(children)
+ from=PART_FROM_CHILD;
+
+ ctx->tree= tree;
+ ctx->seams= seams;
+ ctx->totseam= totseam;
+ ctx->psys= psys;
+ ctx->index= index;
+ ctx->jit= jit;
+ ctx->jitlevel= jitlevel;
+ ctx->jitoff= jitoff;
+ ctx->weight= weight;
+ ctx->maxweight= maxweight;
+ ctx->from= from;
+ ctx->cfrom= cfrom;
+ ctx->distr= distr;
+ ctx->dm= dm;
+
+ seed= 31415926 + ctx->psys->seed;
+
+ if(from!=PART_FROM_CHILD || psys->totchild < 10000)
+ totthread= 1;
+
+ for(i=0; i<totthread; i++) {
+ threads[i].rng= rng_new(seed);
+ threads[i].tot= totthread;
+ }
- if(LineIntersectsTriangle(co1, co2, v4, v1, v3, &cur_d, 0)){
- if(cur_d<min_d){
- min_d=cur_d;
- pa->foffset=cur_d*50.0f; /* to the middle of volume */
- intersect=1;
- }
- }
- }
- }
- if(intersect==0)
- pa->foffset=0.0;
- else switch(distr){
- case PART_DISTR_JIT:
- pa->foffset*= jit[2*(int)jitoff[i]];
- break;
- case PART_DISTR_RAND:
- pa->foffset*=BLI_frand();
- break;
- }
- }
- break;
- }
- case PART_FROM_PARTICLE:
-
- //pa->verts[0]=0; /* not applicable */
- //pa->verts[1]=0;
- //pa->verts[2]=0;
-
- tpa=tpars+index[p];
- pa->num=index[p];
- pa->fuv[0]=tpa->fuv[0];
- pa->fuv[1]=tpa->fuv[1];
- /* abusing foffset a little for timing in near reaction */
- pa->foffset=weight[index[p]];
- weight[index[p]]+=maxweight;
- break;
- case PART_FROM_CHILD:
- if(index[p]>=0){
- MFace *mf;
+ return 1;
+}
- mf=dm->getFaceData(dm,index[p],CD_MFACE);
-
- //switch(distr){
- // case PART_DISTR_JIT:
- // i=index[p];
- // psys_uv_to_w(jit[2*(int)jitoff[i]], jit[2*(int)jitoff[i]+1], mf->v4, cpa->fuv);
- // jitoff[i]=(float)fmod(jitoff[i]+maxweight/weight[i],(float)jitlevel);
- // break;
- // case PART_DISTR_RAND:
- psys_uv_to_w(BLI_frand(), BLI_frand(), mf->v4, cpa->fuv);
- // break;
- //}
-
- cpa->rand[0] = BLI_frand();
- cpa->rand[1] = BLI_frand();
- cpa->rand[2] = BLI_frand();
- cpa->num = index[p];
-
- if(tree){
- KDTreeNearest ptn[10];
- int w,maxw, do_seams;
- float maxd,mind,dd,totw=0.0;
- int parent[10];
- float pweight[10];
-
- do_seams= (part->flag&PART_CHILD_SEAMS && seams);
-
- psys_particle_on_dm(ob,dm,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,0,0);
- maxw = BLI_kdtree_find_n_nearest(tree,(do_seams)?10:4,co1,nor1,ptn);
-
- maxd=ptn[maxw-1].dist;
- mind=ptn[0].dist;
- dd=maxd-mind;
-
- /* the weights here could be done better */
- for(w=0; w<maxw; w++){
- parent[w]=ptn[w].index;
- pweight[w]=(float)pow(2.0,(double)(-6.0f*ptn[w].dist/maxd));
- //totw+=cpa->w[w];
- }
- for(;w<10; w++){
- parent[w]=-1;
- pweight[w]=0.0f;
- }
- if(do_seams){
- ParticleSeam *seam=seams;
- float temp[3],temp2[3],tan[3];
- float inp,cur_len,min_len=10000.0f;
- int min_seam=0, near_vert=0;
- /* find closest seam */
- for(i=0; i<totseam; i++, seam++){
- VecSubf(temp,co1,seam->v0);
- inp=Inpf(temp,seam->dir)/seam->length2;
- if(inp<0.0f){
- cur_len=VecLenf(co1,seam->v0);
- }
- else if(inp>1.0f){
- cur_len=VecLenf(co1,seam->v1);
- }
- else{
- VecCopyf(temp2,seam->dir);
- VecMulf(temp2,inp);
- cur_len=VecLenf(temp,temp2);
- }
- if(cur_len<min_len){
- min_len=cur_len;
- min_seam=i;
- if(inp<0.0f) near_vert=-1;
- else if(inp>1.0f) near_vert=1;
- else near_vert=0;
- }
- }
- seam=seams+min_seam;
-
- VecCopyf(temp,seam->v0);
-
- if(near_vert){
- if(near_vert==-1)
- VecSubf(tan,co1,seam->v0);
- else{
- VecSubf(tan,co1,seam->v1);
- VecCopyf(temp,seam->v1);
- }
+static void distribute_particles_on_dm(DerivedMesh *finaldm, Object *ob, ParticleSystem *psys, int from)
+{
+ ListBase threads;
+ ParticleThread *pthreads;
+ ParticleThreadContext *ctx;
+ int i, totthread;
- Normalize(tan);
- }
- else{
- VecCopyf(tan,seam->tan);
- VecSubf(temp2,co1,temp);
- if(Inpf(tan,temp2)<0.0f)
- VecMulf(tan,-1.0f);
- }
- for(w=0; w<maxw; w++){
- VecSubf(temp2,ptn[w].co,temp);
- if(Inpf(tan,temp2)<0.0f){
- parent[w]=-1;
- pweight[w]=0.0f;
- }
- }
+ pthreads= psys_threads_create(ob, psys, G.scene->r.threads);
- }
+ if(!psys_threads_init_distribution(pthreads, finaldm, from)) {
+ psys_threads_free(pthreads);
+ return;
+ }
- for(w=0,i=0; w<maxw && i<4; w++){
- if(parent[w]>=0){
- cpa->pa[i]=parent[w];
- cpa->w[i]=pweight[w];
- totw+=pweight[w];
- i++;
- }
- }
- for(;i<4; i++){
- cpa->pa[i]=-1;
- cpa->w[i]=0.0f;
- }
+ totthread= pthreads[0].tot;
+ if(totthread > 1) {
+ BLI_init_threads(&threads, exec_distribution, totthread);
- if(totw>0.0f) for(w=0; w<4; w++)
- cpa->w[w]/=totw;
+ for(i=0; i<totthread; i++)
+ BLI_insert_thread(&threads, &pthreads[i]);
- cpa->parent=cpa->pa[0];
- }
- }
- else{
- cpa->num=0;
- cpa->fuv[0]=cpa->fuv[1]=cpa->fuv[2]=cpa->fuv[3]=0.0f;
- cpa->pa[0]=cpa->pa[1]=cpa->pa[2]=cpa->pa[3]=0;
- cpa->rand[0]=cpa->rand[1]=cpa->rand[2]=0.0f;
- }
- break;
- }
+ BLI_end_threads(&threads);
}
+ else
+ exec_distribution(&pthreads[0]);
- /* 6. */
- if(jit) MEM_freeN(jit);
- if(sum) MEM_freeN(sum);
- if(jitoff) MEM_freeN(jitoff);
- if(weight){
- MEM_freeN(weight);
- weight=0;
- }
- if(index) MEM_freeN(index);
- if(seams) MEM_freeN(seams);
- //if(vertpart) MEM_freeN(vertpart);
- BLI_kdtree_free(tree);
-
if (from == PART_FROM_FACE)
psys_calc_dmfaces(ob, finaldm, psys);
-
- if(dm != finaldm) dm->release(dm);
+
+ ctx= pthreads[0].ctx;
+ if(ctx->dm != finaldm)
+ ctx->dm->release(ctx->dm);
+
+ psys_threads_free(pthreads);
}
/* ready for future use, to emit particles without geometry */
@@ -1135,6 +1226,79 @@ static void distribute_particles(Object *ob, ParticleSystem *psys, int from)
}
}
}
+
+/* threaded child particle distribution and path caching */
+ParticleThread *psys_threads_create(struct Object *ob, struct ParticleSystem *psys, int totthread)
+{
+ ParticleThread *threads;
+ ParticleThreadContext *ctx;
+ int i;
+
+ threads= MEM_callocN(sizeof(ParticleThread)*totthread, "ParticleThread");
+ ctx= MEM_callocN(sizeof(ParticleThreadContext), "ParticleThreadContext");
+
+ ctx->ob= ob;
+ ctx->psys= psys;
+ ctx->psmd= psys_get_modifier(ob, psys);
+ ctx->dm= ctx->psmd->dm;
+ ctx->ma= give_current_material(ob, psys->part->omat);
+
+ memset(threads, 0, sizeof(ParticleThread)*totthread);
+
+ for(i=0; i<totthread; i++) {
+ threads[i].ctx= ctx;
+ threads[i].num= i;
+ threads[i].tot= totthread;
+ }
+
+ return threads;
+}
+
+void psys_threads_free(ParticleThread *threads)
+{
+ ParticleThreadContext *ctx= threads[0].ctx;
+ int i, totthread= threads[0].tot;
+
+ /* path caching */
+ if(ctx->vg_length)
+ MEM_freeN(ctx->vg_length);
+ if(ctx->vg_clump)
+ MEM_freeN(ctx->vg_clump);
+ if(ctx->vg_kink)
+ MEM_freeN(ctx->vg_kink);
+ if(ctx->vg_rough1)
+ MEM_freeN(ctx->vg_rough1);
+ if(ctx->vg_rough2)
+ MEM_freeN(ctx->vg_roughe);
+ if(ctx->vg_roughe)
+ MEM_freeN(ctx->vg_roughe);
+
+ if(ctx->psys->lattice){
+ end_latt_deform();
+ ctx->psys->lattice=0;
+ }
+
+ /* distribution */
+ if(ctx->jit) MEM_freeN(ctx->jit);
+ if(ctx->jitoff) MEM_freeN(ctx->jitoff);
+ if(ctx->weight) MEM_freeN(ctx->weight);
+ if(ctx->index) MEM_freeN(ctx->index);
+ if(ctx->seams) MEM_freeN(ctx->seams);
+ //if(ctx->vertpart) MEM_freeN(ctx->vertpart);
+ BLI_kdtree_free(ctx->tree);
+
+ /* threads */
+ for(i=0; i<totthread; i++) {
+ if(threads[i].rng)
+ rng_free(threads[i].rng);
+ if(threads[i].rng_path)
+ rng_free(threads[i].rng_path);
+ }
+
+ MEM_freeN(ctx);
+ MEM_freeN(threads);
+}
+
/* set particle parameters that don't change during particle's life */
void initialize_particle(ParticleData *pa, int p, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd)
{
@@ -3980,8 +4144,9 @@ static void psys_update_path_cache(Object *ob, ParticleSystemModifierData *psmd,
ParticleSettings *part=psys->part;
ParticleEditSettings *pset=&G.scene->toolsettings->particle;
int distr=0,alloc=0;
+ int child_nbr= (G.rendering)? part->ren_child_nbr: part->child_nbr;
- if((psys->part->childtype && psys->totchild != psys->totpart*part->child_nbr) || psys->recalc&PSYS_ALLOC)
+ if((psys->part->childtype && psys->totchild != psys->totpart*child_nbr) || psys->recalc&PSYS_ALLOC)
alloc=1;
if(alloc || psys->recalc&PSYS_DISTR || (psys->vgroup[PSYS_VG_DENSITY] && (G.f & G_WEIGHTPAINT)))
@@ -4003,9 +4168,9 @@ static void psys_update_path_cache(Object *ob, ParticleSystemModifierData *psmd,
|| part->draw_as==PART_DRAW_PATH || part->draw&PART_DRAW_KEYS)){
psys_cache_paths(ob, psys, cfra, 0);
- if(part->childtype){
- if((G.rendering || (part->flag&PART_CHILD_RENDER)==0)
- || (psys_in_edit_mode(psys) && (pset->flag&PE_SHOW_CHILD)))
+ /* for render, child particle paths are computed on the fly */
+ if(part->childtype) {
+ if(((psys->totchild!=0)) || (psys_in_edit_mode(psys) && (pset->flag&PE_SHOW_CHILD)))
psys_cache_child_paths(ob, psys, cfra, 0);
}
}
@@ -4133,6 +4298,7 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier
int totpart,oldtotpart=0,p;
float disp, *vg_vel=0, *vg_tan=0, *vg_rot=0, *vg_size=0;
int init=0,distr=0,alloc=0;
+ int child_nbr;
/*----start validity checks----*/
@@ -4197,7 +4363,8 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier
else
totpart = psys->part->totpart;
- if(oldtotpart != totpart || psys->recalc&PSYS_ALLOC || (psys->part->childtype && psys->totchild != psys->totpart*part->child_nbr))
+ child_nbr= (G.rendering)? part->ren_child_nbr: part->child_nbr;
+ if(oldtotpart != totpart || psys->recalc&PSYS_ALLOC || (psys->part->childtype && psys->totchild != psys->totpart*child_nbr))
alloc = 1;
if(alloc || psys->recalc&PSYS_DISTR || (psys->vgroup[PSYS_VG_DENSITY] && (G.f & G_WEIGHTPAINT) && ob==OBACT))
@@ -4368,7 +4535,7 @@ void particle_system_update(Object *ob, ParticleSystem *psys){
if(psys->softflag&OB_SB_ENABLE)
psys_to_softbody(ob,psys,1);
}
-
+
system_step(ob,psys,psmd,cfra);
Mat4CpyMat4(psys->imat, ob->imat); /* used for duplicators */