Fix for: [#18371] VParent breaks fur effects.
authorJanne Karhu <jhkarh@gmail.com>
Mon, 6 Apr 2009 00:10:52 +0000 (00:10 +0000)
committerJanne Karhu <jhkarh@gmail.com>
Mon, 6 Apr 2009 00:10:52 +0000 (00:10 +0000)
-Virtual parents were not randomly selected due to optimization in child particle distribution code.
-Wave-kink had a wrong matrix multiplication.
-Amount of virtual parents wasn't scaled properly to the amount of children rendered.
-Calculating virtual parents is now thread safe.

source/blender/blenkernel/BKE_particle.h
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/particle_system.c

index 5dbfe2fe520ecbb9a5775dedc474314828d12eeb..5f5635bae1f03edabc755465a6d18f58d99f7fec 100644 (file)
@@ -173,7 +173,7 @@ typedef struct ParticleThreadContext {
 
        /* path caching */
        int editupdate, between, steps;
-       int totchild, totparent;
+       int totchild, totparent, parent_pass;
 
        float cfra;
 
index 4eabb82f6cb9dde4b791a175647abe5cd0cbe87e..3fea9e44acba9099a660e6b8d48bab122fad6ffd 100644 (file)
@@ -1461,7 +1461,7 @@ static void do_prekink(ParticleKey *state, ParticleKey *par, float *par_rot, flo
                case PART_KINK_WAVE:
                        vec[axis]=1.0;
                        if(obmat)
-                               Mat4MulVecfl(obmat,vec);
+                               Mat4Mul3Vecfl(obmat,vec);
 
                        if(par_rot)
                                QuatMulVecf(par_rot,vec);
@@ -1805,10 +1805,13 @@ void psys_find_parents(Object *ob, ParticleSystemModifierData *psmd, ParticleSys
        int from=PART_FROM_FACE;
        totparent=(int)(totchild*part->parents*0.3);
 
+       if(G.rendering && part->child_nbr && part->ren_child_nbr)
+               totparent*=(float)part->child_nbr/(float)part->ren_child_nbr;
+
        tree=BLI_kdtree_new(totparent);
 
        for(p=0,cpa=psys->child; p<totparent; p++,cpa++){
-               psys_particle_on_emitter(psmd,from,cpa->num,-1,cpa->fuv,cpa->foffset,co,0,0,0,orco,0);
+               psys_particle_on_emitter(psmd,from,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co,0,0,0,orco,0);
                BLI_kdtree_insert(tree, p, orco, NULL);
        }
 
@@ -1872,6 +1875,10 @@ int psys_threads_init_path(ParticleThread *threads, float cfra, int editupdate)
 
        if(totchild && part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){
                totparent=(int)(totchild*part->parents*0.3);
+               
+               if(G.rendering && part->child_nbr && part->ren_child_nbr)
+                       totparent*=(float)part->child_nbr/(float)part->ren_child_nbr;
+
                /* part->parents could still be 0 so we can't test with totparent */
                between=1;
        }
@@ -1904,6 +1911,7 @@ int psys_threads_init_path(ParticleThread *threads, float cfra, int editupdate)
        ctx->steps= steps;
        ctx->totchild= totchild;
        ctx->totparent= totparent;
+       ctx->parent_pass= 0;
        ctx->cfra= cfra;
 
        psys->lattice = psys_get_lattice(ob, psys);
@@ -1941,14 +1949,14 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
        ParticleCacheKey *state, *par = NULL, *key[4];
        ParticleData *pa=NULL;
        ParticleTexture ptex;
-       float *cpa_fuv=0;
+       float *cpa_fuv=0, *par_rot=0;
        float co[3], 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;
        float length, pa_length, pa_clump, pa_kink, pa_effector;
        float max_length = 1.0f, cur_length = 0.0f;
        float eff_length, eff_vec[3];
-       int k, cpa_num, guided=0;
+       int k, cpa_num, guided = 0;
        short cpa_from;
 
        if(part->flag & PART_BRANCHING) {
@@ -2138,15 +2146,16 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
                t=(float)k/(float)ctx->steps;
 
                if(ctx->totparent){
-                       if(i>=ctx->totparent)
-                               /* this is not threadsafe, but should only happen for
-                                * branching particles particles, which are not threaded */
+                       if(i>=ctx->totparent) {
+                               /* this is now threadsafe, virtual parents are calculated before rest of children */
                                par = cache[cpa->parent] + k;
+                       }
                        else
                                par=0;
                }
                else if(cpa->parent>=0){
                        par=pcache[cpa->parent]+k;
+                       par_rot = par->rot;
                }
 
                /* apply different deformations to the child path */
@@ -2156,7 +2165,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
 
                if(guided==0){
                        if(part->kink)
-                               do_prekink((ParticleKey*)state, (ParticleKey*)par, par->rot, t,
+                               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);
@@ -2255,10 +2264,15 @@ static void *exec_child_path_cache(void *data)
        ParticleSystem *psys= ctx->psys;
        ParticleCacheKey **cache= psys->childcache;
        ChildParticle *cpa;
-       int i, totchild= ctx->totchild;
+       int i, totchild= ctx->totchild, first= 0;
+
+       if(thread->tot > 1){
+               first= ctx->parent_pass? 0 : ctx->totparent;
+               totchild= ctx->parent_pass? ctx->totparent : ctx->totchild;
+       }
        
-       cpa= psys->child + thread->num;
-       for(i=thread->num; i<totchild; i+=thread->tot, cpa+=thread->tot)
+       cpa= psys->child + first + thread->num;
+       for(i=first+thread->num; i<totchild; i+=thread->tot, cpa+=thread->tot)
                psys_thread_create_path(thread, cpa, cache[i], i);
 
        return 0;
@@ -2297,6 +2311,22 @@ void psys_cache_child_paths(Object *ob, ParticleSystem *psys, float cfra, int ed
        totthread= pthreads[0].tot;
 
        if(totthread > 1) {
+
+               /* make virtual child parents thread safe by calculating them first */
+               if(totparent) {
+                       BLI_init_threads(&threads, exec_child_path_cache, totthread);
+                       
+                       for(i=0; i<totthread; i++) {
+                               pthreads[i].ctx->parent_pass = 1;
+                               BLI_insert_thread(&threads, &pthreads[i]);
+                       }
+
+                       BLI_end_threads(&threads);
+
+                       for(i=0; i<totthread; i++)
+                               pthreads[i].ctx->parent_pass = 0;
+               }
+
                BLI_init_threads(&threads, exec_child_path_cache, totthread);
 
                for(i=0; i<totthread; i++)
@@ -3495,6 +3525,10 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle
                
                if(totchild && part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){
                        totparent=(int)(totchild*part->parents*0.3);
+                       
+                       if(G.rendering && part->child_nbr && part->ren_child_nbr)
+                               totparent*=(float)part->child_nbr/(float)part->ren_child_nbr;
+                       
                        /* part->parents could still be 0 so we can't test with totparent */
                        between=1;
                }
index 2728addeddd23199240ee8b79ba445cfd1cf3a48..8720edf6c24bbd851f64025a5b9dc3a84ba8aa9f 100644 (file)
@@ -1301,7 +1301,8 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm
        MEM_freeN(sum);
 
        /* for hair, sort by origindex, allows optimizations in rendering */
-       if(part->type == PART_HAIR) {
+       /* however with virtual parents the children need to be in random order */
+       if(part->type == PART_HAIR && !(part->childtype==PART_CHILD_FACES && part->parents!=0.0)) {
                COMPARE_ORIG_INDEX= dm->getFaceDataArray(dm, CD_ORIGINDEX);
                if(COMPARE_ORIG_INDEX)
                        qsort(index, totpart, sizeof(int), compare_orig_index);