Revision: 16701
          
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=16701
Author:   jhk
Date:     2008-09-23 14:53:00 +0200 (Tue, 23 Sep 2008)

Log Message:
-----------
- Particle-particle effectors we're quite unstable and not accurate at all. Now 
this should be fixed (especially with other integrators than euler) as the 
needed inter-frame effector particle positions are interpolated properly from 
the current and previous positions (previously only the most recent position 
was used).
- In practice this removes the dependency of particle simulations from the 
update order of objects and different particle systems inside objects.
- As a nice side effect out of this we also get fully correct birth positions 
for "near reactor particles" (previously for example smoke trail reactor 
particles were not born smoothly along the target particles path).

Modified Paths:
--------------
    trunk/blender/source/blender/blenkernel/intern/particle.c
    trunk/blender/source/blender/blenkernel/intern/particle_system.c
    trunk/blender/source/blender/makesdna/DNA_particle_types.h

Modified: trunk/blender/source/blender/blenkernel/intern/particle.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/particle.c   2008-09-23 
11:51:40 UTC (rev 16700)
+++ trunk/blender/source/blender/blenkernel/intern/particle.c   2008-09-23 
12:53:00 UTC (rev 16701)
@@ -3721,6 +3721,7 @@
        float cfra;
        int totpart=psys->totpart, between=0;
 
+       /* negative time means "use current time" */
        if(state->time>0)
                cfra=state->time;
        else
@@ -3796,8 +3797,46 @@
                }
                else{
                        if (pa) { /* TODO PARTICLE - should this ever be NULL? 
- Campbell */
-                               copy_particle_key(state,&pa->state,0);
+                               if(pa->state.time==state->time)
+                                       copy_particle_key(state, &pa->state, 1);
+                               else if(pa->prev_state.time==state->time)
+                                       copy_particle_key(state, 
&pa->prev_state, 1);
+                               else {
+                                       /* let's interpolate to try to be as 
accurate as possible */
+                                       if(pa->state.time + 1.0f > state->time 
&& pa->prev_state.time - 1.0f < state->time) {
+                                               ParticleKey keys[4];
+                                               float dfra, keytime, frs_sec = 
G.scene->r.frs_sec;
 
+                                               if(pa->prev_state.time >= 
pa->state.time) {
+                                                       /* prev_state is wrong 
so let's not use it, this can happen at frame 1 or particle birth */
+                                                       
copy_particle_key(state, &pa->state, 1);
+
+                                                       VECADDFAC(state->co, 
state->co, state->vel, (state->time-pa->state.time)/frs_sec);
+                                               }
+                                               else {
+                                                       
copy_particle_key(keys+1, &pa->prev_state, 1);
+                                                       
copy_particle_key(keys+2, &pa->state, 1);
+
+                                                       dfra = keys[2].time - 
keys[1].time;
+
+                                                       keytime = (state->time 
- keys[1].time) / dfra;
+
+                                                       /* convert velocity to 
timestep size */
+                                                       VecMulf(keys[1].vel, 
dfra / frs_sec);
+                                                       VecMulf(keys[2].vel, 
dfra / frs_sec);
+                                                       
+                                                       
interpolate_particle(-1, keys, keytime, state, 1);
+                                                       
+                                                       /* convert back to real 
velocity */
+                                                       VecMulf(state->vel, 
frs_sec / dfra);
+                                               }
+                                       }
+                                       else {
+                                               /* extrapolating over big 
ranges is not accurate so let's just give something close to reasonable back */
+                                               copy_particle_key(state, 
&pa->state, 0);
+                                       }
+                               }
+
                                if(pa->alive==PARS_DEAD && 
part->flag&PART_STICKY && pa->flag&PARS_STICKY && pa->stick_ob){
                                        key_from_object(pa->stick_ob,state);
                                }

Modified: trunk/blender/source/blender/blenkernel/intern/particle_system.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/particle_system.c    
2008-09-23 11:51:40 UTC (rev 16700)
+++ trunk/blender/source/blender/blenkernel/intern/particle_system.c    
2008-09-23 12:53:00 UTC (rev 16701)
@@ -1714,10 +1714,8 @@
                        tob=ob;
 
                tpsys=BLI_findlink(&tob->particlesystem,psys->target_psys-1);
-               
-               /*TODO: get precise location of particle at birth*/
 
-               state.time=cfra;
+               state.time = pa->time;
                if(pa->num == -1)
                        memset(&state, 0, sizeof(state));
                else
@@ -1809,6 +1807,12 @@
        }
        /* conversion done so now we apply new: */
        /* -velocity from:                                              */
+
+       /*              *reactions                                              
*/
+       if(dtime>0.0f){
+               VECSUB(vel,pa->state.vel,pa->prev_state.vel);
+       }
+
        /*              *emitter velocity                               */
        if(dtime!=0.0 && part->obfac!=0.0){
                VECSUB(vel,loc,pa->state.co);
@@ -2204,6 +2208,8 @@
 
        /* assuming struct consists of tightly packed floats */
        for(i=0, pa=psys->particles; i<totpart; i++, pa++) {
+               if(cfra!=pa->state.time)
+                       copy_particle_key(&pa->prev_state,&pa->state,1);
                if(!BKE_ptcache_file_read_floats(pf, (float*)&pa->state, 
sizeof(ParticleKey)/sizeof(float))) {
                        BKE_ptcache_file_close(pf);
                        return 0;
@@ -2489,14 +2495,12 @@
                        Object *eob = ec->ob;
                        ParticleSystem *epsys = 
BLI_findlink(&eob->particlesystem,ec->psys_nbr);
                        ParticleSettings *epart = epsys->part;
-                       ParticleData *epa = epsys->particles;
-                       int totepart = epsys->totpart;
+                       ParticleData *epa;
+                       int p, totepart = epsys->totpart;
 
                        if(psys->part->phystype==PART_PHYS_BOIDS){
-                               ParticleData *epa;
                                ParticleKey state;
                                PartDeflect *pd;
-                               int p;
                                
                                pd= epart->pd;
                                if(pd->forcefield==PFIELD_FORCE && totepart){
@@ -2512,6 +2516,7 @@
                                        BLI_kdtree_balance(tree);
                                }
                        }
+
                }
                else if(ec->type==PSYS_EC_DEFLECT) {
                        CollisionModifierData *collmd = ( CollisionModifierData 
* ) ( modifiers_findByType ( ec->ob, eModifierType_Collision ) );
@@ -2573,7 +2578,7 @@
                                } else {
                                        do_physical_effector(eob, state->co, 
pd->forcefield,pd->f_strength,distance,
                                                                                
falloff,0.0,pd->f_damp,eob->obmat[2],vec_to_part,
-                                                                               
pa->state.vel,force_field,pd->flag&PFIELD_PLANAR,ec->rng,pd->f_noise,charge,pa->size);
+                                                                               
state->vel,force_field,pd->flag&PFIELD_PLANAR,ec->rng,pd->f_noise,charge,pa->size);
                                }
                        }
                        if(ec->type & PSYS_EC_PARTICLE){
@@ -2602,7 +2607,7 @@
                                        if(epsys==psys && p == pa_no) continue;
 
                                        epa = epsys->particles + p;
-                                       estate.time=-1.0;
+                                       estate.time=cfra;
                                        
if(psys_get_particle_state(eob,epsys,p,&estate,0)){
                                                VECSUB(vec_to_part, state->co, 
estate.co);
                                                distance = 
VecLength(vec_to_part);
@@ -2641,7 +2646,7 @@
 /*                     Newtonian physics                                       
*/
 /************************************************/
 /* gathers all forces that effect particles and calculates a new state for the 
particle */
-static void apply_particle_forces(int pa_no, ParticleData *pa, Object *ob, 
ParticleSystem *psys, ParticleSettings *part, float timestep, float dfra, float 
cfra, ParticleKey *state)
+static void apply_particle_forces(int pa_no, ParticleData *pa, Object *ob, 
ParticleSystem *psys, ParticleSettings *part, float timestep, float dfra, float 
cfra)
 {
        ParticleKey states[5], tkey;
        float force[3],tvel[3],dx[4][3],dv[4][3];
@@ -2649,7 +2654,7 @@
        int i, steps=1;
        
        /* maintain angular velocity */
-       VECCOPY(state->ave,pa->state.ave);
+       VECCOPY(pa->state.ave,pa->prev_state.ave);
 
        if(part->flag & PART_SIZEMASS)
                pa_mass*=pa->size;
@@ -2699,8 +2704,8 @@
 
                switch(part->integrator){
                        case PART_INT_EULER:
-                               
VECADDFAC(state->co,states->co,states->vel,dtime);
-                               VECADDFAC(state->vel,states->vel,force,dtime);
+                               
VECADDFAC(pa->state.co,states->co,states->vel,dtime);
+                               
VECADDFAC(pa->state.vel,states->vel,force,dtime);
                                break;
                        case PART_INT_MIDPOINT:
                                if(i==0){
@@ -2709,8 +2714,8 @@
                                        fra=psys->cfra+0.5f*dfra;
                                }
                                else{
-                                       
VECADDFAC(state->co,states->co,states[1].vel,dtime);
-                                       
VECADDFAC(state->vel,states->vel,force,dtime);
+                                       
VECADDFAC(pa->state.co,states->co,states[1].vel,dtime);
+                                       
VECADDFAC(pa->state.vel,states->vel,force,dtime);
                                }
                                break;
                        case PART_INT_RK4:
@@ -2750,15 +2755,15 @@
                                                VECCOPY(dv[3],force);
                                                VecMulf(dv[3],dtime);
 
-                                               
VECADDFAC(state->co,states->co,dx[0],1.0f/6.0f);
-                                               
VECADDFAC(state->co,state->co,dx[1],1.0f/3.0f);
-                                               
VECADDFAC(state->co,state->co,dx[2],1.0f/3.0f);
-                                               
VECADDFAC(state->co,state->co,dx[3],1.0f/6.0f);
+                                               
VECADDFAC(pa->state.co,states->co,dx[0],1.0f/6.0f);
+                                               
VECADDFAC(pa->state.co,pa->state.co,dx[1],1.0f/3.0f);
+                                               
VECADDFAC(pa->state.co,pa->state.co,dx[2],1.0f/3.0f);
+                                               
VECADDFAC(pa->state.co,pa->state.co,dx[3],1.0f/6.0f);
 
-                                               
VECADDFAC(state->vel,states->vel,dv[0],1.0f/6.0f);
-                                               
VECADDFAC(state->vel,state->vel,dv[1],1.0f/3.0f);
-                                               
VECADDFAC(state->vel,state->vel,dv[2],1.0f/3.0f);
-                                               
VECADDFAC(state->vel,state->vel,dv[3],1.0f/6.0f);
+                                               
VECADDFAC(pa->state.vel,states->vel,dv[0],1.0f/6.0f);
+                                               
VECADDFAC(pa->state.vel,pa->state.vel,dv[1],1.0f/3.0f);
+                                               
VECADDFAC(pa->state.vel,pa->state.vel,dv[2],1.0f/3.0f);
+                                               
VECADDFAC(pa->state.vel,pa->state.vel,dv[3],1.0f/6.0f);
                                }
                                break;
                }
@@ -2766,62 +2771,62 @@
 
        /* damp affects final velocity */
        if(part->dampfac!=0.0)
-               VecMulf(state->vel,1.0f-part->dampfac);
+               VecMulf(pa->state.vel,1.0f-part->dampfac);
 
        /* finally we do guides */
        time=(cfra-pa->time)/pa->lifetime;
        CLAMP(time,0.0,1.0);
 
-       VECCOPY(tkey.co,state->co);
-       VECCOPY(tkey.vel,state->vel);
-       tkey.time=state->time;
+       VECCOPY(tkey.co,pa->state.co);
+       VECCOPY(tkey.vel,pa->state.vel);
+       tkey.time=pa->state.time;
 
        if(part->type != PART_HAIR) {
                if(do_guide(&tkey,pa_no,time,&psys->effectors)) {
-                       VECCOPY(state->co,tkey.co);
+                       VECCOPY(pa->state.co,tkey.co);
                        /* guides don't produce valid velocity */
-                       VECSUB(state->vel,tkey.co,pa->state.co);
-                       VecMulf(state->vel,1.0f/dtime);
-                       state->time=tkey.time;
+                       VECSUB(pa->state.vel,tkey.co,pa->prev_state.co);
+                       VecMulf(pa->state.vel,1.0f/dtime);
+                       pa->state.time=tkey.time;
                }
        }
 }
-static void rotate_particle(ParticleSettings *part, ParticleData *pa, float 
dfra, float timestep, ParticleKey *state)
+static void rotate_particle(ParticleSettings *part, ParticleData *pa, float 
dfra, float timestep)
 {
        float rotfac, rot1[4], rot2[4]={1.0,0.0,0.0,0.0}, dtime=dfra*timestep;
 
        if((part->flag & PART_ROT_DYN)==0){
                if(part->avemode==PART_AVE_SPIN){
                        float angle;
-                       float len1 = VecLength(pa->state.vel);
-                       float len2 = VecLength(state->vel);
+                       float len1 = VecLength(pa->prev_state.vel);
+                       float len2 = VecLength(pa->state.vel);
 
                        if(len1==0.0f || len2==0.0f)
-                               state->ave[0]=state->ave[1]=state->ave[2]=0.0f;
+                               
pa->state.ave[0]=pa->state.ave[1]=pa->state.ave[2]=0.0f;
                        else{
-                               Crossf(state->ave,pa->state.vel,state->vel);
-                               Normalize(state->ave);
-                               
angle=Inpf(pa->state.vel,state->vel)/(len1*len2);
-                               VecMulf(state->ave,saacos(angle)/dtime);
+                               
Crossf(pa->state.ave,pa->prev_state.vel,pa->state.vel);
+                               Normalize(pa->state.ave);
+                               
angle=Inpf(pa->prev_state.vel,pa->state.vel)/(len1*len2);
+                               VecMulf(pa->state.ave,saacos(angle)/dtime);
                        }
 
-                       VecRotToQuat(state->vel,dtime*part->avefac,rot2);
+                       VecRotToQuat(pa->state.vel,dtime*part->avefac,rot2);
                }
        }
 
-       rotfac=VecLength(state->ave);
+       rotfac=VecLength(pa->state.ave);
        if(rotfac==0.0){ /* QuatOne (in VecRotToQuat) doesn't give unit quat 
[1,0,0,0]?? */
                rot1[0]=1.0;
                rot1[1]=rot1[2]=rot1[3]=0;
        }
        else{
-               VecRotToQuat(state->ave,rotfac*dtime,rot1);
+               VecRotToQuat(pa->state.ave,rotfac*dtime,rot1);
        }
-       QuatMul(state->rot,rot1,pa->state.rot);
-       QuatMul(state->rot,rot2,state->rot);
+       QuatMul(pa->state.rot,rot1,pa->prev_state.rot);
+       QuatMul(pa->state.rot,rot2,pa->state.rot);
 
        /* keep rotation quat in good health */
-       NormalQuat(state->rot);
+       NormalQuat(pa->state.rot);
 }
 
 /* convert from triangle barycentric weights to quad mean value weights */
@@ -3055,7 +3060,7 @@

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to