[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [16701] trunk/blender/source/blender: - Particle-particle effectors we're quite unstable and not accurate at all .

Janne Karhu jhkarh at utu.fi
Tue Sep 23 14:53:05 CEST 2008


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. @@




More information about the Bf-blender-cvs mailing list