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:
authorTon Roosendaal <ton@blender.org>2005-11-10 19:01:56 +0300
committerTon Roosendaal <ton@blender.org>2005-11-10 19:01:56 +0300
commitf8845d5d1105044779ff9cd5dc18e9d82dfcc7f9 (patch)
treeb02aef5eb5378332914209c599c5067ee30c91b8 /source/blender/blenkernel
parent0093857b4ffb8c65fc9a3a62f1c5fb29ed6ec9ed (diff)
The long awaited Particle patch from Janne Karhu
http://www.blender3d.org/cms/New_Particle_options_a.721.0.html There's no doubt this patch had a lot of good ideas for features, and I want to compliment Janne again for getting it all to work even! A more careful review of the features and code did show however quite some flaws and bugs... partially because the current particle code was very much polluted already, but also because of the implementation lacked quality. However, the patch was too good to reject, so I've fixed and recoded the parts that needed it most. :) Here's a list of of most evident changes in the patch; - Guides support recoded. It was implemented as a true 'force field', checking all Curve path points for each particle to find the closest. Was just far too slow, and didn't support looping or bends well. The new implementation is fast (real time) and treats the paths as actual trajectory for the particle. - Guides didn't integrate in the physics/speed system either, was added as exception. Now it's integrated and can be combined with other velocities or forces - Use of Fields was slow code in general, made it use a Cache instead. - The "even" distribution didn't work for Jittered sample patterns. - The "even" or "vertexgroup" code in the main loops were badly constructed, giving too much cpu for a simple task. Instead of going over all faces many times, it now only does it once. Same part of the code used a lot of temporal unneeded mallocs. - Use of DerivedMesh or Mesh was confused, didn't work for Subsurfs in all cases - Support for vertex groups was slow, evaluating vertexgroups too often - When a vertexgroup failed to read, it was wrongly handled (set to zero). VertexGroup support now is with a name. - Split up the too huge build_particle() call in some parts (moving new code) - The "texture re-timing" option failed for moving Objects. The old code used the convention that particles were added with increasing time steps. Solved by creating a object Matrix Cache. Also: the texture coordinates had to be corrected to become "OrCo". - The "Disp" option only was used to draw less particles. Changed it to actually calculate fewer particles for 3D viewing, but render all still. So now it can be used to keep editing realtime. Removed; The "speed threshold" and "Tight" features were not copied over. This resembled too much to feature overkill. Needs re-evaluation. Also the "Deform" option was not added, I prefer to first check if the current particle system really works for the Modifier system. And: - Added integration for particle force fields in the dependency graph - Added TAB completion for vertexgroup names! - Made the 'wait cursor' only appear when particles take more than 0.5 sec - The particle jitter table order now is randomized too, giving much nicer emitting of particles in large faces. - Vortex field didn't correctly use speed/forces, so it didn't work for collisions. - Triangle distribution was wrong - Removed ancient bug that applied in a *very* weird way speed and forces. (location changes got the half force, speed the full...???) So much... might have forgotten some notes! :)
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_effect.h4
-rw-r--r--source/blender/blenkernel/intern/anim.c41
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c6
-rw-r--r--source/blender/blenkernel/intern/effect.c1331
-rw-r--r--source/blender/blenkernel/intern/softbody.c50
5 files changed, 949 insertions, 483 deletions
diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h
index cb58496465f..9ebafdff3e4 100644
--- a/source/blender/blenkernel/BKE_effect.h
+++ b/source/blender/blenkernel/BKE_effect.h
@@ -57,7 +57,9 @@ void build_particle_system(struct Object *ob);
/* particle deflector */
#define PE_WIND_AS_SPEED 0x00000001
-void pdDoEffector(float *opco, float *force, float *speed, float cur_time, unsigned int par_layer,unsigned int flags);
+struct ListBase *pdInitEffectors(unsigned int layer);
+void pdEndEffectors(struct ListBase *lb);
+void pdDoEffectors(struct ListBase *lb, float *opco, float *force, float *speed, float cur_time, float loc_time, unsigned int flags);
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index 4d08f958057..dcd49f9f0b2 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -200,6 +200,7 @@ int interval_test(int min, int max, int p1, int cycl)
}
/* warning, *vec needs FOUR items! */
+/* ctime is normalized range <0-1> */
int where_on_path(Object *ob, float ctime, float *vec, float *dir) /* returns OK */
{
Curve *cu;
@@ -488,29 +489,29 @@ void particle_duplilist(Scene *sce, Object *par, PartEff *paf)
}
else { // non static particles
- if(ctime > pa->time) {
- if(ctime < pa->time+pa->lifetime) {
- newob= new_dupli_object(&duplilist, ob, par);
+ if((paf->flag & PAF_UNBORN)==0 && ctime < pa->time) continue;
+ if((paf->flag & PAF_DIED)==0 && ctime > pa->time+pa->lifetime) continue;
- /* to give ipos in object correct offset */
- where_is_object_time(newob, ctime-pa->time);
-
- where_is_particle(paf, pa, ctime, vec);
- if(paf->stype==PAF_VECT) {
- where_is_particle(paf, pa, ctime+1.0f, vec1);
-
- VecSubf(vec1, vec1, vec);
- q2= vectoquat(vec1, ob->trackflag, ob->upflag);
-
- QuatToMat3(q2, mat);
- Mat4CpyMat4(tmat, newob->obmat);
- Mat4MulMat43(newob->obmat, tmat, mat);
- }
+ //if(ctime < pa->time+pa->lifetime) {
+ newob= new_dupli_object(&duplilist, ob, par);
- VECCOPY(newob->obmat[3], vec);
- }
+ /* to give ipos in object correct offset */
+ where_is_object_time(newob, ctime-pa->time);
+
+ where_is_particle(paf, pa, ctime, vec);
+ if(paf->stype==PAF_VECT) {
+ where_is_particle(paf, pa, ctime+1.0f, vec1);
+
+ VecSubf(vec1, vec1, vec);
+ q2= vectoquat(vec1, ob->trackflag, ob->upflag);
+
+ QuatToMat3(q2, mat);
+ Mat4CpyMat4(tmat, newob->obmat);
+ Mat4MulMat43(newob->obmat, tmat, mat);
}
- }
+
+ VECCOPY(newob->obmat[3], vec);
+ }
}
break;
}
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 8bb010a7847..d211305f0f3 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -467,9 +467,13 @@ struct DagForest *build_dag(struct Scene *sce, short mask)
}
else if(ob->type==OB_MESH) {
PartEff *paf= give_parteff(ob);
- if(paf && (paf->flag & PAF_STATIC)) {
+ if(paf) {
Base *base1;
+ /* ob location depends on itself */
+ if((paf->flag & PAF_STATIC)==0)
+ dag_add_relation(dag, node, node, DAG_RL_OB_DATA);
+
/* force fields, warning for loop inside loop... */
for(base1 = G.scene->base.first; base1; base1= base1->next) {
if( (base1->lay & base->lay) && base1->object->pd) {
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index eb4eb243000..21eafc39fc0 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -55,6 +55,7 @@
#include "BLI_rand.h"
#include "BKE_action.h"
+#include "BKE_anim.h" /* needed for where_on_path */
#include "BKE_armature.h"
#include "BKE_bad_level_calls.h"
#include "BKE_blender.h"
@@ -74,8 +75,8 @@
#include "BKE_screen.h"
#include "BKE_utildefines.h"
-#include "render.h" // externtex, bad level call (ton)
-
+#include "render.h" // externtex, bad level call (ton)
+#include "PIL_time.h"
Effect *add_effect(int type)
{
@@ -102,7 +103,9 @@ Effect *add_effect(int type)
paf->staticstep= 5;
paf->defvec[2]= 1.0f;
paf->nabla= 0.05f;
-
+ paf->disp = 100;
+ paf->speedtex = 8;
+ paf->omat = 1;
break;
}
@@ -205,7 +208,7 @@ static Particle *new_particle(PartEff *paf)
static int cur;
/* we agree: when paf->keys==0: alloc */
- if(paf->keys==0) {
+ if(paf->keys==NULL) {
pa= paf->keys= MEM_callocN( paf->totkey*paf->totpart*sizeof(Particle), "particlekeys" );
cur= 0;
}
@@ -234,7 +237,7 @@ void where_is_particle(PartEff *paf, Particle *pa, float ctime, float *vec)
float dt, t[4];
int a;
- if(paf->totkey==1) {
+ if(paf->totkey==1 || ctime < pa->time) {
VECCOPY(vec, pa->co);
return;
}
@@ -252,7 +255,7 @@ void where_is_particle(PartEff *paf, Particle *pa, float ctime, float *vec)
if(a+1<paf->totkey) p[2]= pa+1; else p[2]= pa;
if(a+2<paf->totkey) p[3]= pa+2; else p[3]= p[2];
- if(p[1]==p[2]) dt= 0.0;
+ if(p[1]==p[2] || p[2]->time == p[1]->time) dt= 0.0;
else dt= (ctime-p[1]->time)/(p[2]->time - p[1]->time);
if(paf->flag & PAF_BSPLINE) set_four_ipo(dt, t, KEY_BSPLINE);
@@ -301,16 +304,111 @@ static void particle_tex(MTex *mtex, PartEff *paf, float *co, float *no)
}
}
-/* -------- pdDoEffector() --------
+
+/* -------------------------- Effectors ------------------ */
+
+typedef struct pEffectorCache {
+ struct pEffectorCache *next, *prev;
+ struct Object *ob;
+
+ /* precalculated variables */
+ float oldloc[3], oldspeed[3];
+ float scale, time_scale;
+ float guide_dist;
+} pEffectorCache;
+
+
+/* returns ListBase handle with objects taking part in the effecting */
+ListBase *pdInitEffectors(unsigned int layer)
+{
+ static ListBase listb={NULL, NULL};
+ Base *base;
+
+ for(base = G.scene->base.first; base; base= base->next) {
+ if( (base->lay & layer) && base->object->pd) {
+ Object *ob= base->object;
+ PartDeflect *pd= ob->pd;
+
+ if(pd->forcefield == PFIELD_GUIDE) {
+ if(ob->type==OB_CURVE) {
+ Curve *cu= ob->data;
+ if((cu->flag & CU_PATH) && cu->path && cu->path->data) {
+ pEffectorCache *ec= MEM_callocN(sizeof(pEffectorCache), "effector cache");
+ ec->ob= ob;
+ BLI_addtail(&listb, ec);
+ }
+ }
+ }
+ else if(pd->forcefield) {
+ pEffectorCache *ec= MEM_callocN(sizeof(pEffectorCache), "effector cache");
+ ec->ob= ob;
+ BLI_addtail(&listb, ec);
+ }
+ }
+ }
+ if(listb.first)
+ return &listb;
+
+ return NULL;
+}
+
+void pdEndEffectors(ListBase *lb)
+{
+ if(lb)
+ BLI_freelistN(lb);
+}
+
+/* local for this c file, only for guides now */
+static void precalc_effectors(Object *ob, PartEff *paf, Particle *pa, ListBase *lb)
+{
+ pEffectorCache *ec;
+
+ for(ec= lb->first; ec; ec= ec->next) {
+ if(ec->ob->type==OB_CURVE) {
+ float vec[4], dir[3];
+
+ /* scale corrects speed vector to curve size */
+ if(paf->totkey>1) ec->scale= (paf->totkey-1)/pa->lifetime;
+ else ec->scale= 1.0f;
+
+ /* time_scale is for random life */
+ if(pa->lifetime>paf->lifetime)
+ ec->time_scale= paf->lifetime/pa->lifetime;
+ else
+ ec->time_scale= pa->lifetime/paf->lifetime;
+
+ /* distance of first path point to particle origin */
+ where_on_path(ec->ob, 0.0f, vec, dir);
+ VECCOPY(ec->oldloc, vec); /* store local coord for differences */
+ Mat4MulVecfl(ec->ob->obmat, vec);
+
+ /* for static we need to move to global space */
+ if(paf->flag & PAF_STATIC) {
+ VECCOPY(dir, pa->co);
+ Mat4MulVecfl(ob->obmat, dir);
+ ec->guide_dist= VecLenf(vec, dir);
+ }
+ else
+ ec->guide_dist= VecLenf(vec, pa->co);
+ }
+ }
+}
+
+
+/* -------- pdDoEffectors() --------
generic force/speed system, now used for particles and softbodies
+ lb = listbase with objects that take part in effecting
opco = global coord, as input
force = force accumulator
- speed = speed accumulator
- cur_time = in frames
+ speed = actual current speed which can be altered
+ cur_time = "external" time in frames, is constant for static particles
+ loc_time = "local" time in frames, range <0-1> for the lifetime of particle
par_layer = layer the caller is in
+ flags = only used for softbody wind now
+ guide = old speed of particle
*/
-void pdDoEffector(float *opco, float *force, float *speed, float cur_time, unsigned int par_layer,unsigned int flags)
+void pdDoEffectors(ListBase *lb, float *opco, float *force, float *speed, float cur_time, float loc_time, unsigned int flags)
{
/*
Modifies the force on a particle according to its
@@ -321,116 +419,186 @@ void pdDoEffector(float *opco, float *force, float *speed, float cur_time, unsig
Vortex fields: swirling effectors
(particles rotate around Z-axis of the object. otherwise, same relation as)
(Forcefields, but this is not done through a force/acceleration)
-
+ Guide: particles on a path
+ (particles are guided along a curve bezier or old nurbs)
+ (is independent of other effectors)
*/
Object *ob;
- Base *base;
+ pEffectorCache *ec;
PartDeflect *pd;
float vect_to_vert[3];
- float force_vec[3];
- float f_force, distance;
+ float f_force, force_vec[3];
float *obloc;
- float force_val, ffall_val;
+ float distance, force_val, ffall_val;
+ float guidecollect[3], guidedist= 0.0f;
short cur_frame;
+
+ guidecollect[0]= guidecollect[1]= guidecollect[2]=0.0f;
- /* Cycle through objects, get total of (1/(gravity_strength * dist^gravity_power)) */
+ /* Cycle through collected objects, get total of (1/(gravity_strength * dist^gravity_power)) */
/* Check for min distance here? (yes would be cool to add that, ton) */
- for(base = G.scene->base.first; base; base= base->next) {
- if( (base->lay & par_layer) && base->object->pd) {
- ob= base->object;
- pd= ob->pd;
+ for(ec = lb->first; ec; ec= ec->next) {
+ /* object effectors were fully checked to be OK to evaluate! */
+ ob= ec->ob;
+ pd= ob->pd;
- /* checking if to continue or not */
- if(pd->forcefield==0) continue;
+ /* Get IPO force strength and fall off values here */
+ if (has_ipo_code(ob->ipo, OB_PD_FSTR))
+ force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, cur_time);
+ else
+ force_val = pd->f_strength;
+
+ if (has_ipo_code(ob->ipo, OB_PD_FFALL))
+ ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, cur_time);
+ else
+ ffall_val = pd->f_power;
- /* Get IPO force strength and fall off values here */
- if (has_ipo_code(ob->ipo, OB_PD_FSTR))
- force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, cur_time);
- else
- force_val = pd->f_strength;
+ /* Need to set r.cfra for paths (investigate, ton) (uses ob->ctime now, ton) */
+ if(ob->ctime!=cur_time) {
+ cur_frame = G.scene->r.cfra;
+ G.scene->r.cfra = (short)cur_time;
+ where_is_object_time(ob, cur_time);
+ G.scene->r.cfra = cur_frame;
+ }
- if (has_ipo_code(ob->ipo, OB_PD_FFALL))
- ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, cur_time);
- else
- ffall_val = pd->f_power;
+ /* use center of object for distance calculus */
+ obloc= ob->obmat[3];
+ VECSUB(vect_to_vert, obloc, opco);
+ distance = VecLength(vect_to_vert);
+ if((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist && pd->forcefield != PFIELD_GUIDE)
+ ; /* don't do anything */
+ else if(pd->forcefield == PFIELD_WIND) {
+ VECCOPY(force_vec, ob->obmat[2]);
- /* Need to set r.cfra for paths (investigate, ton) (uses ob->ctime now, ton) */
- if(ob->ctime!=cur_time) {
- cur_frame = G.scene->r.cfra;
- G.scene->r.cfra = (short)cur_time;
- where_is_object_time(ob, cur_time);
- G.scene->r.cfra = cur_frame;
+ /* wind works harder perpendicular to normal, would be nice for softbody later (ton) */
+
+ /* Limit minimum distance to vertex so that */
+ /* the force is not too big */
+ if (distance < 0.001) distance = 0.001f;
+ f_force = (force_val)*(1/(1000 * (float)pow((double)distance, (double)ffall_val)));
+ /* this option for softbody only */
+ if(flags && PE_WIND_AS_SPEED){
+ speed[0] -= (force_vec[0] * f_force );
+ speed[1] -= (force_vec[1] * f_force );
+ speed[2] -= (force_vec[2] * f_force );
+ }
+ else{
+ force[0] += force_vec[0]*f_force;
+ force[1] += force_vec[1]*f_force;
+ force[2] += force_vec[2]*f_force;
}
+ }
+ else if(pd->forcefield == PFIELD_FORCE) {
- /* use center of object for distance calculus */
+ /* only use center of object */
obloc= ob->obmat[3];
+
+ /* Now calculate the gravitational force */
VECSUB(vect_to_vert, obloc, opco);
distance = VecLength(vect_to_vert);
+
+ /* Limit minimum distance to vertex so that */
+ /* the force is not too big */
+ if (distance < 0.001) distance = 0.001f;
+ f_force = (force_val)*(1.0/(1000.0 * (float)pow((double)distance, (double)ffall_val)));
+ force[0] += (vect_to_vert[0] * f_force );
+ force[1] += (vect_to_vert[1] * f_force );
+ force[2] += (vect_to_vert[2] * f_force );
+ }
+ else if(pd->forcefield == PFIELD_VORTEX) {
+ float vortexvec[3];
- if((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist)
- ; /* don't do anything */
- else if(pd->forcefield == PFIELD_WIND) {
- VECCOPY(force_vec, ob->obmat[2]);
-
- /* wind works harder perpendicular to normal, would be nice for softbody later (ton) */
-
- /* Limit minimum distance to vertex so that */
- /* the force is not too big */
- if (distance < 0.001) distance = 0.001f;
- f_force = (force_val)*(1/(1000 * (float)pow((double)distance, (double)ffall_val)));
- if(flags &&PE_WIND_AS_SPEED){
- speed[0] -= (force_vec[0] * f_force );
- speed[1] -= (force_vec[1] * f_force );
- speed[2] -= (force_vec[2] * f_force );
- }
- else{
- force[0] += force_vec[0]*f_force;
- force[1] += force_vec[1]*f_force;
- force[2] += force_vec[2]*f_force;
- }
- }
- else if(pd->forcefield == PFIELD_FORCE) {
-
- /* only use center of object */
- obloc= ob->obmat[3];
+ /* only use center of object */
+ obloc= ob->obmat[3];
- /* Now calculate the gravitational force */
- VECSUB(vect_to_vert, obloc, opco);
- distance = VecLength(vect_to_vert);
+ /* Now calculate the vortex force */
+ VECSUB(vect_to_vert, obloc, opco);
+ distance = VecLength(vect_to_vert);
- /* Limit minimum distance to vertex so that */
- /* the force is not too big */
- if (distance < 0.001) distance = 0.001f;
- f_force = (force_val)*(1/(1000 * (float)pow((double)distance, (double)ffall_val)));
- force[0] += (vect_to_vert[0] * f_force );
- force[1] += (vect_to_vert[1] * f_force );
- force[2] += (vect_to_vert[2] * f_force );
+ Crossf(force_vec, ob->obmat[2], vect_to_vert);
+ Normalise(force_vec);
+ /* Limit minimum distance to vertex so that */
+ /* the force is not too big */
+ if (distance < 0.001) distance = 0.001f;
+ f_force = (force_val)*(1.0/(100.0 * (float)pow((double)distance, (double)ffall_val)));
+ vortexvec[0]= -(force_vec[0] * f_force );
+ vortexvec[1]= -(force_vec[1] * f_force );
+ vortexvec[2]= -(force_vec[2] * f_force );
+
+ /* this option for softbody only */
+ if(flags &&PE_WIND_AS_SPEED) {
+ speed[0]+= vortexvec[0];
+ speed[1]+= vortexvec[1];
+ speed[2]+= vortexvec[2];
}
- else if(pd->forcefield == PFIELD_VORTEX) {
-
- /* only use center of object */
- obloc= ob->obmat[3];
-
- /* Now calculate the vortex force */
- VECSUB(vect_to_vert, obloc, opco);
- distance = VecLength(vect_to_vert);
-
- Crossf(force_vec, ob->obmat[2], vect_to_vert);
- Normalise(force_vec);
-
- /* Limit minimum distance to vertex so that */
- /* the force is not too big */
- if (distance < 0.001) distance = 0.001f;
- f_force = (force_val)*(1/(100 * (float)pow((double)distance, (double)ffall_val)));
- speed[0] -= (force_vec[0] * f_force );
- speed[1] -= (force_vec[1] * f_force );
- speed[2] -= (force_vec[2] * f_force );
-
+ else {
+ /* since vortex alters the speed, we have to correct for the previous vortex result */
+ speed[0]+= vortexvec[0] - ec->oldspeed[0];
+ speed[1]+= vortexvec[1] - ec->oldspeed[1];
+ speed[2]+= vortexvec[2] - ec->oldspeed[2];
+
+ VECCOPY(ec->oldspeed, vortexvec);
}
}
+ else if(pd->forcefield == PFIELD_GUIDE) {
+ float guidevec[4], guidedir[3];
+ float mindist= force_val; /* force_val is actually mindist in the UI */
+
+ distance= ec->guide_dist;
+
+ /* WARNING: bails out with continue here */
+ if((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist) continue;
+
+ /* derive path point from loc_time */
+ where_on_path(ob, loc_time*ec->time_scale, guidevec, guidedir);
+ VECSUB(guidedir, guidevec, ec->oldloc);
+ VECCOPY(ec->oldloc, guidevec);
+
+ Mat4Mul3Vecfl(ob->obmat, guidedir);
+ VecMulf(guidedir, ec->scale); /* correction for lifetime and speed */
+
+ /* we subtract the speed we gave it previous step */
+ VECCOPY(guidevec, guidedir);
+ VECSUB(guidedir, guidedir, ec->oldspeed);
+ VECCOPY(ec->oldspeed, guidevec);
+
+ /* calculate contribution factor for this guide */
+ if(distance<=mindist) f_force= 1.0f;
+ else if(pd->flag & PFIELD_USEMAX) {
+ if(distance>pd->maxdist || mindist>=pd->maxdist) f_force= 0.0f;
+ else {
+ f_force= 1.0f - (distance-mindist)/(pd->maxdist - mindist);
+ if(ffall_val!=0.0f)
+ f_force = (float)pow(f_force, ffall_val+1.0);
+ }
+ }
+ else {
+ f_force= 1.0f/(1.0f + distance-mindist);
+ if(ffall_val!=0.0f)
+ f_force = (float)pow(f_force, ffall_val+1.0);
+ }
+
+ /* if it fully contributes, we stop */
+ if(f_force==1.0) {
+ VECCOPY(guidecollect, guidedir);
+ guidedist= 1.0f;
+ break;
+ }
+ else if(guidedist<1.0f) {
+ VecMulf(guidedir, f_force);
+ VECADD(guidecollect, guidecollect, guidedir);
+ guidedist += f_force;
+ }
+ }
+ }
+
+ /* all guides are accumulated here */
+ if(guidedist!=0.0f) {
+ if(guidedist!=1.0f) VecMulf(guidecollect, 1.0f/guidedist);
+ VECADD(speed, speed, guidecollect);
}
}
@@ -788,11 +956,11 @@ static int pdDoDeflection(RNG *rng, float opco[3], float npco[3], float opno[3],
part = current particle
force = force vector
deform = flag to indicate lattice deform
- cfraont = current frame
*/
-static void make_particle_keys(RNG *rng, Object *ob, int depth, int nr, PartEff *paf, Particle *part, float *force, int deform, MTex *mtex, unsigned int par_layer, int cfraont)
+static void make_particle_keys(RNG *rng, Object *ob, int depth, int nr, PartEff *paf, Particle *part, float *force, int deform, MTex *mtex, unsigned int par_layer)
{
Particle *pa, *opa = NULL;
+ ListBase *effectorbase;
float damp, deltalife, life;
float cur_time;
float opco[3], opno[3], npco[3], npno[3], new_force[3], new_speed[3];
@@ -814,120 +982,122 @@ static void make_particle_keys(RNG *rng, Object *ob, int depth, int nr, PartEff
particle_tex(mtex, paf, pa->co, pa->no);
}
+ /* effectors here? */
+ effectorbase= pdInitEffectors(par_layer);
+ if(effectorbase)
+ precalc_effectors(ob, paf, pa, effectorbase);
+
if(paf->totkey>1) deltalife= pa->lifetime/(paf->totkey-1);
else deltalife= pa->lifetime;
+ /* longer lifetime results in longer distance covered */
+ VecMulf(pa->no, deltalife);
+
opa= pa;
pa++;
- b= paf->totkey-1;
- while(b--) {
+ for(b=1; b<paf->totkey; b++) {
+
/* new time */
pa->time= opa->time+deltalife;
+ cur_time = pa->time;
/* set initial variables */
- opco[0] = opa->co[0];
- opco[1] = opa->co[1];
- opco[2] = opa->co[2];
-
- new_force[0] = force[0];
- new_force[1] = force[1];
- new_force[2] = force[2];
- new_speed[0] = 0.0;
- new_speed[1] = 0.0;
- new_speed[2] = 0.0;
-
- /* handle differences between static (local coords, fixed frae) and dynamic */
- if(paf->flag & PAF_STATIC) {
- float opco1[3], new_force1[3], new_speed1[3];
-
- /* move to global coords */
- VECCOPY(opco1, opco);
- Mat4MulVecfl(ob->obmat, opco1);
-
- VECCOPY(new_force1, new_force);
- Mat4Mul3Vecfl(ob->obmat, new_force1);
- VECCOPY(new_speed1, new_speed);
- Mat4Mul3Vecfl(ob->obmat, new_speed1);
-
- cur_time = cfraont;
-
- /* force fields */
- pdDoEffector(opco1, new_force1, new_speed1, cur_time, par_layer, 0);
+ VECCOPY(opco, opa->co);
+ VECCOPY(new_force, force);
+ VECCOPY(new_speed, opa->no);
+ VecMulf(new_speed, 1.0f/deltalife);
+ //new_speed[0] = new_speed[1] = new_speed[2] = 0.0f;
+
+ /* handle differences between static (local coords, fixed frame) and dynamic */
+ if(effectorbase) {
+ float loc_time= ((float)b)/(float)(paf->totkey-1);
- /* move back to local */
- VECCOPY(opco, opco1);
- Mat4MulVecfl(ob->imat, opco);
-
- VECCOPY(new_force, new_force1);
- Mat4Mul3Vecfl(ob->imat, new_force);
- VECCOPY(new_speed, new_speed1);
- Mat4Mul3Vecfl(ob->imat, new_speed);
- }
- else {
- cur_time = pa->time;
-
- /* force fields */
- pdDoEffector(opco, new_force, new_speed, cur_time, par_layer,0);
- }
-
- /* new location */
- pa->co[0]= opa->co[0] + deltalife * (opa->no[0] + new_speed[0] + 0.5f*new_force[0]);
- pa->co[1]= opa->co[1] + deltalife * (opa->no[1] + new_speed[1] + 0.5f*new_force[1]);
- pa->co[2]= opa->co[2] + deltalife * (opa->no[2] + new_speed[2] + 0.5f*new_force[2]);
-
- /* new speed */
- pa->no[0]= opa->no[0] + deltalife*new_force[0];
- pa->no[1]= opa->no[1] + deltalife*new_force[1];
- pa->no[2]= opa->no[2] + deltalife*new_force[2];
-
- /* Particle deflection code */
- deflection = 0;
- finish_defs = 1;
- def_count = 0;
-
- VECCOPY(opno, opa->no);
- VECCOPY(npco, pa->co);
- VECCOPY(npno, pa->no);
-
- life = deltalife;
- cur_time -= deltalife;
-
- last_ob = -1;
- last_fc = -1;
- same_fc = 0;
-
- /* First call the particle deflection check for the particle moving */
- /* between the old co-ordinates and the new co-ordinates */
- /* If a deflection occurs, call the code again, this time between the */
- /* intersection point and the updated new co-ordinates */
- /* Bail out if we've done the calculation 10 times - this seems ok */
- /* for most scenes I've tested */
- while (finish_defs) {
- deflected = pdDoDeflection(rng, opco, npco, opno, npno, life, new_force,
- def_count, cur_time, par_layer,
- &last_ob, &last_fc, &same_fc);
- if (deflected) {
- def_count = def_count + 1;
- deflection = 1;
- if (def_count==10) finish_defs = 0;
+ if(paf->flag & PAF_STATIC) {
+ float opco1[3], new_force1[3];
+
+ /* move co and force to global coords */
+ VECCOPY(opco1, opco);
+ Mat4MulVecfl(ob->obmat, opco1);
+ VECCOPY(new_force1, new_force);
+ Mat4Mul3Vecfl(ob->obmat, new_force1);
+
+ cur_time = G.scene->r.cfra;
+
+ /* force fields */
+ pdDoEffectors(effectorbase, opco1, new_force1, new_speed, cur_time, loc_time, 0);
+
+ /* move co, force and newspeed back to local */
+ VECCOPY(opco, opco1);
+ Mat4MulVecfl(ob->imat, opco);
+ VECCOPY(new_force, new_force1);
+ Mat4Mul3Vecfl(ob->imat, new_force);
+ Mat4Mul3Vecfl(ob->imat, new_speed);
}
else {
- finish_defs = 0;
+ /* force fields */
+ pdDoEffectors(effectorbase, opco, new_force, new_speed, cur_time, loc_time, 0);
}
}
+
+ /* new speed */
+ pa->no[0]= deltalife * (new_speed[0] + new_force[0]);
+ pa->no[1]= deltalife * (new_speed[1] + new_force[1]);
+ pa->no[2]= deltalife * (new_speed[2] + new_force[2]);
+
+ /* new location */
+ pa->co[0]= opa->co[0] + pa->no[0];
+ pa->co[1]= opa->co[1] + pa->no[1];
+ pa->co[2]= opa->co[2] + pa->no[2];
- /* Only update the particle positions and speed if we had a deflection */
- if (deflection) {
- pa->co[0] = npco[0];
- pa->co[1] = npco[1];
- pa->co[2] = npco[2];
- pa->no[0] = npno[0];
- pa->no[1] = npno[1];
- pa->no[2] = npno[2];
- }
-
+ /* Particle deflection code */
+ if((paf->flag & PAF_STATIC)==0) {
+ deflection = 0;
+ finish_defs = 1;
+ def_count = 0;
+
+ VECCOPY(opno, opa->no);
+ VECCOPY(npco, pa->co);
+ VECCOPY(npno, pa->no);
+
+ life = deltalife;
+ cur_time -= deltalife;
+
+ last_ob = -1;
+ last_fc = -1;
+ same_fc = 0;
+
+ /* First call the particle deflection check for the particle moving */
+ /* between the old co-ordinates and the new co-ordinates */
+ /* If a deflection occurs, call the code again, this time between the */
+ /* intersection point and the updated new co-ordinates */
+ /* Bail out if we've done the calculation 10 times - this seems ok */
+ /* for most scenes I've tested */
+ while (finish_defs) {
+ deflected = pdDoDeflection(rng, opco, npco, opno, npno, life, new_force,
+ def_count, cur_time, par_layer,
+ &last_ob, &last_fc, &same_fc);
+ if (deflected) {
+ def_count = def_count + 1;
+ deflection = 1;
+ if (def_count==10) finish_defs = 0;
+ }
+ else {
+ finish_defs = 0;
+ }
+ }
+ /* Only update the particle positions and speed if we had a deflection */
+ if (deflection) {
+ pa->co[0] = npco[0];
+ pa->co[1] = npco[1];
+ pa->co[2] = npco[2];
+ pa->no[0] = npno[0];
+ pa->no[1] = npno[1];
+ pa->no[2] = npno[2];
+ }
+ }
+
/* speed: texture */
if(mtex && paf->texfac!=0.0) {
particle_tex(mtex, paf, pa->co, pa->no);
@@ -937,9 +1107,7 @@ static void make_particle_keys(RNG *rng, Object *ob, int depth, int nr, PartEff
pa->no[1]*= damp;
pa->no[2]*= damp;
}
-
-
-
+
opa= pa;
pa++;
/* opa is used later on too! */
@@ -974,13 +1142,18 @@ static void make_particle_keys(RNG *rng, Object *ob, int depth, int nr, PartEff
}
pa->mat_nr= paf->mat[depth];
- make_particle_keys(rng, ob, depth+1, b, paf, pa, force, deform, mtex, par_layer, cfraont);
+ make_particle_keys(rng, ob, depth+1, b, paf, pa, force, deform, mtex, par_layer);
}
}
}
+
+ /* cleanup */
+ if(effectorbase)
+ pdEndEffectors(effectorbase);
+
}
-static void init_mv_jit(float *jit, int num,int seed2)
+static void init_mv_jit(float *jit, int num, int seed2)
{
RNG *rng;
float *jit2, x, rad1, rad2, rad3;
@@ -1018,211 +1191,414 @@ static void init_mv_jit(float *jit, int num,int seed2)
rng_free(rng);
}
+#define JIT_RAND 32
-static void give_mesh_mvert(Mesh *me, DispListMesh *dlm, int nr, float *co, short *no, int seed2)
+/* for a position within a face, tot is total amount of faces */
+static void give_mesh_particle_coord(PartEff *paf, MVert *mvert, MFace *mface, int partnr, int subnr, float *co, short *no)
{
- static float *jit=0;
- static int jitlevel=1;
- MVert *mvert, *mvertbase=NULL;
- MFace *mface, *mfacebase=NULL;
- float u, v, *v1, *v2, *v3, *v4;
- int totface=0, totvert=0, curface, curjit;
+ static float *jit= NULL;
+ static float *trands= NULL;
+ static int jitlevel= 1;
+ float *v1, *v2, *v3, *v4;
+ float u, v;
short *n1, *n2, *n3, *n4;
- /* signal */
- if(me==0) {
+ /* free signal */
+ if(paf==NULL) {
if(jit) MEM_freeN(jit);
- jit= 0;
+ jit= NULL;
+ if(trands) MEM_freeN(trands);
+ trands= NULL;
return;
}
- if(dlm) {
- mvertbase= dlm->mvert;
- mfacebase= dlm->mface;
- totface= dlm->totface;
- totvert= dlm->totvert;
+ /* first time initialize jitter or trand, partnr then is total amount of particles, subnr total amount of faces */
+ if(trands==NULL && jit==NULL) {
+ RNG *rng = rng_new(31415926 + paf->seed);
+ int i, tot;
+
+ if(paf->flag & PAF_TRAND)
+ tot= partnr;
+ else
+ tot= JIT_RAND; /* arbitrary... allows JIT_RAND times more particles in a face for jittered distro */
+
+ trands= MEM_callocN(2+2*tot*sizeof(float), "trands");
+ for(i=0; i<tot; i++) {
+ trands[2*i]= rng_getFloat(rng);
+ trands[2*i+1]= rng_getFloat(rng);
+ }
+ rng_free(rng);
+
+ if((paf->flag & PAF_TRAND)==0) {
+ jitlevel= paf->userjit;
+
+ if(jitlevel == 0) {
+ jitlevel= partnr/subnr;
+ if(paf->flag & PAF_EDISTR) jitlevel*= 2; /* looks better in general, not very scietific */
+ if(jitlevel<3) jitlevel= 3;
+ if(jitlevel>100) jitlevel= 100;
+ }
+
+ jit= MEM_callocN(2+ jitlevel*2*sizeof(float), "jit");
+ init_mv_jit(jit, jitlevel, paf->seed);
+ BLI_array_randomize(jit, 2*sizeof(float), jitlevel, paf->seed); /* for custom jit or even distribution */
+ }
+ return;
}
- if(totvert==0) {
- mvertbase= me->mvert;
- mfacebase= me->mface;
- totface= me->totface;
- totvert= me->totvert;
+ if(paf->flag & PAF_TRAND) {
+ u= trands[2*partnr];
+ v= trands[2*partnr+1];
}
+ else {
+ /* jittered distribution gets fixed random offset */
+ if(subnr>=jitlevel) {
+ int jitrand= (subnr/jitlevel) % JIT_RAND;
+
+ subnr %= jitlevel;
+ u= jit[2*subnr] + trands[2*jitrand];
+ v= jit[2*subnr+1] + trands[2*jitrand+1];
+ if(u > 1.0f) u-= 1.0f;
+ if(v > 1.0f) v-= 1.0f;
+ }
+ else {
+ u= jit[2*subnr];
+ v= jit[2*subnr+1];
+ }
+ }
+
+ v1= (mvert+(mface->v1))->co;
+ v2= (mvert+(mface->v2))->co;
+ v3= (mvert+(mface->v3))->co;
+ n1= (mvert+(mface->v1))->no;
+ n2= (mvert+(mface->v2))->no;
+ n3= (mvert+(mface->v3))->no;
- if(totface==0 || nr<totvert) {
- mvert= mvertbase + (nr % totvert);
- VECCOPY(co, mvert->co);
- VECCOPY(no, mvert->no);
+ if(mface->v4) {
+ float uv= u*v;
+ float muv= (1.0f-u)*(v);
+ float umv= (u)*(1.0f-v);
+ float mumv= (1.0f-u)*(1.0f-v);
+
+ v4= (mvert+(mface->v4))->co;
+ n4= (mvert+(mface->v4))->no;
+
+ co[0]= mumv*v1[0] + muv*v2[0] + uv*v3[0] + umv*v4[0];
+ co[1]= mumv*v1[1] + muv*v2[1] + uv*v3[1] + umv*v4[1];
+ co[2]= mumv*v1[2] + muv*v2[2] + uv*v3[2] + umv*v4[2];
+
+ no[0]= (short)(mumv*n1[0] + muv*n2[0] + uv*n3[0] + umv*n4[0]);
+ no[1]= (short)(mumv*n1[1] + muv*n2[1] + uv*n3[1] + umv*n4[1]);
+ no[2]= (short)(mumv*n1[2] + muv*n2[2] + uv*n3[2] + umv*n4[2]);
}
else {
-
- nr-= totvert;
+ /* mirror triangle uv coordinates when on other side */
+ if(u + v > 1.0f) {
+ u= 1.0f-u;
+ v= 1.0f-v;
+ }
+ co[0]= v1[0] + u*(v3[0]-v1[0]) + v*(v2[0]-v1[0]);
+ co[1]= v1[1] + u*(v3[1]-v1[1]) + v*(v2[1]-v1[1]);
+ co[2]= v1[2] + u*(v3[2]-v1[2]) + v*(v2[2]-v1[2]);
- if(jit==0) {
- jitlevel= nr/totface;
- if(jitlevel==0) jitlevel= 1;
- if(jitlevel>100) jitlevel= 100;
+ no[0]= (short)(n1[0] + u*(n3[0]-n1[0]) + v*(n2[0]-n1[0]));
+ no[1]= (short)(n1[1] + u*(n3[1]-n1[1]) + v*(n2[1]-n1[1]));
+ no[2]= (short)(n1[2] + u*(n3[2]-n1[2]) + v*(n2[2]-n1[2]));
+ }
+}
- jit= MEM_callocN(2+ jitlevel*2*sizeof(float), "jit");
- init_mv_jit(jit, jitlevel,seed2);
-
+
+/* Gets a MDeformVert's weight in group (0 if not in group) */
+/* note; this call could be in mesh.c or deform.c, but OK... it's in armature.c too! (ton) */
+static float vert_weight(MDeformVert *dvert, int group)
+{
+ MDeformWeight *dw;
+ int i;
+
+ if(dvert) {
+ dw= dvert->dw;
+ for(i= dvert->totweight; i>0; i--, dw++) {
+ if(dw->def_nr == group) return dw->weight;
+ if(i==1) break; /*otherwise dw will point to somewhere it shouldn't*/
}
+ }
+ return 0.0;
+}
- curjit= nr/totface;
- curjit= curjit % jitlevel;
+/* Gets a faces average weight in a group, helper for below, face and weights are always set */
+static float face_weight(MFace *face, float *weights)
+{
+ float tweight;
+
+ tweight = weights[face->v1] + weights[face->v2] + weights[face->v3];
+
+ if(face->v4) {
+ tweight += weights[face->v4];
+ tweight /= 4.0;
+ }
+ else {
+ tweight /= 3.0;
+ }
- curface= nr % totface;
+ return tweight;
+}
+
+/* helper function for build_particle_system() */
+static void make_weight_tables(PartEff *paf, Mesh *me, int totpart, MVert *vertlist, int totvert, MFace *facelist, int totface, float **vweights, float **fweights)
+{
+ MFace *mface;
+ float *foweights=NULL, *voweights=NULL;
+ float totvweight=0.0f, totfweight=0.0f;
+ int a;
+
+ if((paf->flag & PAF_FACE)==0) totface= 0;
+
+ /* collect emitting vertices & faces if vert groups used */
+ if(paf->vertgroup && me->dvert) {
+
+ /* allocate weights array for all vertices, also for lookup of faces later on. note it's a malloc */
+ *vweights= voweights= MEM_mallocN( totvert*sizeof(float), "pafvoweights" );
+ totvweight= 0.0f;
+ for(a=0; a<totvert; a++) {
+ voweights[a]= vert_weight(me->dvert+a, paf->vertgroup-1);
+ totvweight+= voweights[a];
+ }
+
+ if(totface) {
+ /* allocate weights array for faces, note it's a malloc */
+ *fweights= foweights= MEM_mallocN(totface*sizeof(float), "paffoweights" );
+ for(a=0, mface=facelist; a<totface; a++, mface++) {
+ foweights[a] = face_weight(mface, voweights);
+ }
+ }
+ }
+
+ /* make weights for faces or for even area distribution */
+ if(totface && (paf->flag & PAF_EDISTR)) {
+ float maxfarea= 0.0f, curfarea;
- mface= mfacebase;
- mface+= curface;
-
- v1= (mvertbase+(mface->v1))->co;
- v2= (mvertbase+(mface->v2))->co;
- n1= (mvertbase+(mface->v1))->no;
- n2= (mvertbase+(mface->v2))->no;
- v3= (mvertbase+(mface->v3))->co;
- n3= (mvertbase+(mface->v3))->no;
- if(mface->v4==0) {
- v4= (mvertbase+(mface->v1))->co;
- n4= (mvertbase+(mface->v1))->no;
+ /* two cases for area distro, second case we already have group weights */
+ if(foweights==NULL) {
+ /* allocate weights array for faces, note it's a malloc */
+ *fweights= foweights= MEM_mallocN(totface*sizeof(float), "paffoweights" );
+
+ for(a=0, mface=facelist; a<totface; a++, mface++) {
+ if (mface->v4)
+ curfarea= AreaQ3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co, vertlist[mface->v4].co);
+ else
+ curfarea= AreaT3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co);
+ if(curfarea>maxfarea)
+ maxfarea = curfarea;
+ foweights[a]= curfarea;
+ }
}
else {
- v4= (mvertbase+(mface->v4))->co;
- n4= (mvertbase+(mface->v4))->no;
+ for(a=0, mface=facelist; a<totface; a++, mface++) {
+ if(foweights[a]!=0.0f) {
+ if (mface->v4)
+ curfarea= AreaQ3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co, vertlist[mface->v4].co);
+ else
+ curfarea= AreaT3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co);
+ if(curfarea>maxfarea)
+ maxfarea = curfarea;
+ foweights[a]*= curfarea;
+ }
+ }
+ }
+
+ /* normalize weights for max face area, calculate tot */
+ if(maxfarea!=0.0f) {
+ maxfarea= 1.0f/maxfarea;
+ for(a=0; a< totface; a++) {
+ if(foweights[a]!=0.0) {
+ foweights[a] *= maxfarea;
+ totfweight+= foweights[a];
+ }
+ }
+ }
+ }
+ else if(foweights) {
+ /* only add totfweight value */
+ for(a=0; a< totface; a++) {
+ if(foweights[a]!=0.0) {
+ totfweight+= foweights[a];
+ }
+ }
+ }
+
+ /* if weight arrays, we turn these arrays into the amount of particles */
+ if(totvert && voweights) {
+ float mult= (float)totpart/totvweight;
+
+ for(a=0; a< totvert; a++) {
+ if(voweights[a]!=0.0)
+ voweights[a] *= mult;
+ }
+ }
+
+ if(totface && foweights) {
+ float mult= (float)totpart/totfweight;
+
+ for(a=0; a< totface; a++) {
+ if(foweights[a]!=0.0)
+ foweights[a] *= mult;
}
+ }
+}
- u= jit[2*curjit];
- v= jit[2*curjit+1];
+/* for paf start to end, store all matrices for objects */
+typedef struct pMatrixCache {
+ float obmat[4][4];
+ float imat[3][3];
+} pMatrixCache;
- co[0]= (float)((1.0-u)*(1.0-v)*v1[0] + (1.0-u)*(v)*v2[0] + (u)*(v)*v3[0] + (u)*(1.0-v)*v4[0]);
- co[1]= (float)((1.0-u)*(1.0-v)*v1[1] + (1.0-u)*(v)*v2[1] + (u)*(v)*v3[1] + (u)*(1.0-v)*v4[1]);
- co[2]= (float)((1.0-u)*(1.0-v)*v1[2] + (1.0-u)*(v)*v2[2] + (u)*(v)*v3[2] + (u)*(1.0-v)*v4[2]);
+static pMatrixCache *cache_object_matrices(Object *ob, int start, int end)
+{
+ pMatrixCache *mcache, *mc;
+ Object *par;
+ float framelenold, sfrao;
+ int cfrao;
+
+ mcache= mc= MEM_mallocN( (end-start+1)*sizeof(pMatrixCache), "ob matrix cache");
+
+ framelenold= G.scene->r.framelen;
+ G.scene->r.framelen= 1.0f;
+ cfrao= G.scene->r.cfra;
+ sfrao= ob->sf;
+ ob->sf= 0.0f;
+
+ for(G.scene->r.cfra= start; G.scene->r.cfra<=end; G.scene->r.cfra++, mc++) {
- no[0]= (short)((1.0-u)*(1.0-v)*n1[0] + (1.0-u)*(v)*n2[0] + (u)*(v)*n3[0] + (u)*(1.0-v)*n4[0]);
- no[1]= (short)((1.0-u)*(1.0-v)*n1[1] + (1.0-u)*(v)*n2[1] + (u)*(v)*n3[1] + (u)*(1.0-v)*n4[1]);
- no[2]= (short)((1.0-u)*(1.0-v)*n1[2] + (1.0-u)*(v)*n2[2] + (u)*(v)*n3[2] + (u)*(1.0-v)*n4[2]);
+ par= ob;
+ while(par) {
+ par->ctime= -1234567.0; /* hrms? */
+ do_ob_key(par);
+ if(par->type==OB_ARMATURE) {
+ do_all_pose_actions(par); // only does this object actions
+ where_is_pose(par);
+ }
+ par= par->parent;
+ }
+
+ where_is_object(ob);
+ Mat4CpyMat4(mc->obmat, ob->obmat);
+ Mat4Invert(ob->imat, ob->obmat);
+ Mat3CpyMat4(mc->imat, ob->imat);
+ Mat3Transp(mc->imat);
+ }
+
+
+ /* restore */
+ G.scene->r.cfra= cfrao;
+ G.scene->r.framelen= framelenold;
+ ob->sf= sfrao;
+
+ /* restore hierarchy */
+ par= ob;
+ while(par) {
+ /* do not do ob->ipo: keep insertkey */
+ par->ctime= -1234567.0; /* hrms? */
+ do_ob_key(par);
+ if(par->type==OB_ARMATURE) {
+ do_all_pose_actions(par); // only does this object actions
+ where_is_pose(par);
+ }
+ par= par->parent;
}
+
+ where_is_object(ob);
+
+ return mcache;
}
-
+/* main particle building function
+ one day particles should become dynamic (realtime) with the current method as a 'bake' (ton) */
void build_particle_system(Object *ob)
{
RNG *rng;
- Base *base;
- Object *par;
PartEff *paf;
Particle *pa;
Mesh *me;
- MTex *mtexmove=0;
+ Base *base;
+ MTex *mtexmove=0, *mtextime=0;
Material *ma;
DispListMesh *dlm;
- int dmNeedsFree;
+ MFace *facelist= NULL;
+ MVert *vertlist= NULL;
DerivedMesh *dm;
- float framelenont, ftime, dtime, force[3], imat[3][3], vec[3];
- float fac, prevobmat[4][4], sfraont, co[3];
- int deform=0, a, cur, cfraont, cfralast, totpart, totvert;
+ pMatrixCache *mcache=NULL, *mcnow, *mcprev;
+ double startseconds= PIL_check_seconds_timer();
+ float ftime, dtime, force[3], vec[3];
+ float fac, co[3];
+ float *voweights= NULL, *foweights= NULL, maxw=1.0f;
+ int deform=0, a, totpart, paf_sta, paf_end;
+ int dmNeedsFree, waitcursor_set= 0, totvert, totface, curface, curvert;
short no[3];
-
+
+ /* return conditions */
if(ob->type!=OB_MESH) return;
me= ob->data;
- if(me->totvert==0) return;
-
- ma= give_current_material(ob, 1);
- if(ma) {
- mtexmove= ma->mtex[7];
- }
paf= give_parteff(ob);
if(paf==NULL) return;
+ if(paf->keys) MEM_freeN(paf->keys); /* free as early as possible, for returns */
+ paf->keys= NULL;
+
+ if(paf->end < paf->sta) return;
+
+ if( (paf->flag & PAF_OFACE) && (paf->flag & PAF_FACE)==0) return;
+
+ if(me->totvert==0) return;
+
+ /* this call returns NULL during editmode, just ignore it and
+ * particles should be recalc'd on exit. */
+ dm = mesh_get_derived_deform(ob, &dmNeedsFree);
+ if (dm==NULL)
+ return;
+
+ /* No returns after this line! */
+
+ /* material */
+ ma= give_current_material(ob, paf->omat);
+ if(ma) {
+ if(paf->speedtex)
+ mtexmove= ma->mtex[paf->speedtex-1];
+ mtextime= ma->mtex[paf->timetex-1];
+ }
- waitcursor(1);
-
- disable_speed_curve(1);
+ disable_speed_curve(1); /* check this... */
- /* generate all particles */
- if(paf->keys) MEM_freeN(paf->keys);
- paf->keys= NULL;
+ /* initialize particles */
new_particle(paf);
/* reset deflector cache, sumohandle is free, but its still sorta abuse... (ton) */
- for(base= G.scene->base.first; base; base= base->next) {
+ for(base= G.scene->base.first; base; base= base->next)
base->object->sumohandle= NULL;
- }
-
- cfraont= G.scene->r.cfra;
- cfralast= -1000;
- framelenont= G.scene->r.framelen;
- G.scene->r.framelen= 1.0;
- sfraont= ob->sf;
- ob->sf= 0.0;
+ /* all object positions from start to end */
+ paf_sta= (int)floor(paf->sta);
+ paf_end= (int)ceil(paf->end);
+ if((paf->flag & PAF_STATIC)==0)
+ mcache= cache_object_matrices(ob, paf_sta, paf_end);
+
/* mult generations? */
- totpart= paf->totpart;
+ totpart= (R.flag & R_RENDERING)?paf->totpart:(paf->disp*paf->totpart)/100;
for(a=0; a<PAF_MAXMULT; a++) {
if(paf->mult[a]!=0.0) {
- /* interessant formula! this way after 'x' generations the total is paf->totpart */
+ /* interesting formula! this way after 'x' generations the total is paf->totpart */
totpart= (int)(totpart / (1.0+paf->mult[a]*paf->child[a]));
}
else break;
}
- if (paf->flag & PAF_STATIC) {
- ftime = cfraont;
- dtime = 0;
- } else {
- ftime= paf->sta;
- dtime= (paf->end - paf->sta)/totpart;
- }
-
- /* this call returns NULL during editmode, just ignore it and
- * particles should be recalc'd on exit.
- */
- dm = mesh_get_derived_final(ob, &dmNeedsFree);
- if (!dm) {
- waitcursor(0);
- return;
- }
-
- /* WARNING!!!! pushdata and popdata actually copy object memory!!!!
- * Changes between these calls will be lost!!!
- */
-
- /* remember full hierarchy */
- par= ob;
- while(par) {
- pushdata(par, sizeof(Object));
- par= par->parent;
- }
-
- /* for static particles, calculate system on current frame */
+ /* for static particles, calculate system on current frame (? ton) */
if(ma) do_mat_ipo(ma);
-
- /* set it all at first frame */
- G.scene->r.cfra= cfralast= (int)floor(ftime);
- par= ob;
- while(par) {
- /* do_ob_ipo(par); */
- do_ob_key(par);
- par= par->parent;
- }
- /* matrix stuff for static too */
+ /* matrix invert for static too */
Mat4Invert(ob->imat, ob->obmat);
- if((paf->flag & PAF_STATIC)==0) {
- if(ma) do_mat_ipo(ma); // nor for static
-
- where_is_object(ob);
- Mat4CpyMat4(prevobmat, ob->obmat);
- Mat3CpyMat4(imat, ob->imat);
- }
- else {
- Mat4One(prevobmat);
- Mat3One(imat);
- }
-
+ /* new random generator */
rng = rng_new(paf->seed);
/* otherwise it goes way too fast */
@@ -1236,142 +1612,223 @@ void build_particle_system(Object *ob)
if(deform) init_latt_deform(ob->parent, 0);
}
- /* init */
-
+ /* init geometry */
dlm = dm->convertToDispListMesh(dm, 1);
- totvert = dlm->totvert;
-
- give_mesh_mvert(me, dlm, totpart, co, no, paf->seed);
- if(G.f & G_DEBUG) {
- printf("\n");
- printf("Calculating particles......... \n");
+ /* subsurfs don't have vertexgroups, so we need to use me->mvert in that case */
+ if(paf->vertgroup && me->dvert && (dlm->totvert != me->totvert)) {
+ vertlist= me->mvert;
+ facelist= me->mface;
+ totvert= me->totvert;
+ totface= me->totface;
+ }
+ else {
+ vertlist= dlm->mvert;
+ facelist= dlm->mface;
+ totvert= dlm->totvert;
+ totface= dlm->totface;
+ }
+ /* if vertexweights or even distribution, it makes weight tables, also checks where it emits from */
+ make_weight_tables(paf, me, totpart, vertlist, totvert, facelist, totface, &voweights, &foweights);
+
+ /* now define where to emit from, if there are face weights we skip vertices */
+ if(paf->flag & PAF_OFACE) totvert= 0;
+ if((paf->flag & PAF_FACE)==0) totface= 0;
+ if(foweights) totvert= 0;
+
+ /* initialize give_mesh_particle_coord */
+ if(totface)
+ give_mesh_particle_coord(paf, vertlist, facelist, totpart, totface, NULL, NULL);
+
+ /* correction for face timing when using weighted average */
+ if(totface && foweights) {
+ maxw= (paf->end-paf->sta)/foweights[0];
+ }
+ else if(totvert && voweights) {
+ maxw= (paf->end-paf->sta)/voweights[0];
+ }
+
+ /* for loop below */
+ if (paf->flag & PAF_STATIC) {
+ ftime = G.scene->r.cfra;
+ dtime= 0.0f;
+ } else {
+ ftime= paf->sta;
+ dtime= (paf->end - paf->sta)/(float)totpart;
}
+
+ curface= curvert= 0;
for(a=0; a<totpart; a++, ftime+=dtime) {
+ /* we set waitcursor only when a half second expired, particles now are realtime updated */
+ if(waitcursor_set==0 && (a % 256)==255) {
+ double seconds= PIL_check_seconds_timer();
+ if(seconds - startseconds > 0.5) {
+ waitcursor(1);
+ waitcursor_set= 1;
+ }
+ }
+
pa= new_particle(paf);
pa->time= ftime;
-
- if(G.f & G_DEBUG) {
- int b, c;
+
+ /* get coordinates from faces, only when vertices set to zero */
+ if(totvert==0 && totface) {
+ int curjit;
- c = totpart/100;
- if (c==0){
- c = 1;
+ /* use weight table, we have to do faces in order to be able to use jitter table... */
+ if(foweights) {
+
+ if(foweights[curface] < 1.0f) {
+ float remainder= 0.0f;
+
+ while(remainder + foweights[curface] < 1.0f && curface<totface-1) {
+ remainder += foweights[curface];
+ curface++;
+ }
+ foweights[curface] += remainder;
+ maxw= (paf->end-paf->sta)/foweights[curface];
+ }
+
+ if(foweights[curface]==0.0f)
+ break; /* WARN skips here out of particle generating */
+ else {
+ if(foweights[curface] > 1.0f)
+ foweights[curface] -= 1.0f;
+
+ curjit= (int) foweights[curface];
+ give_mesh_particle_coord(paf, vertlist, facelist+curface, a, curjit, co, no);
+
+ /* time correction to make particles appear evenly, maxw does interframe (0-1) */
+ pa->time= paf->sta + maxw*foweights[curface];
+ }
}
-
- b=(a%c);
- if (b==0) {
- printf("\r Particle: %d / %d ", a, totpart);
- fflush(stdout);
+ else {
+ curface= a % totface;
+ curjit= a/totface;
+ give_mesh_particle_coord(paf, vertlist, facelist+curface, a, curjit, co, no);
}
}
- /* set ob at correct time */
-
- if((paf->flag & PAF_STATIC)==0) {
-
- cur= (int)floor(ftime) + 1 ; /* + 1 has a reason: (obmat/prevobmat) otherwise comet-tails start too late */
- if(cfralast != cur) {
- G.scene->r.cfra= cfralast= cur;
-
- /* added later: blur? */
- bsystem_time(ob, ob->parent, (float)G.scene->r.cfra, 0.0);
-
- par= ob;
- while(par) {
- /* do_ob_ipo(par); */
- par->ctime= -1234567.0;
- do_ob_key(par);
- if(par->type==OB_ARMATURE) {
- do_all_pose_actions(par); // only does this object actions
- where_is_pose(par);
+ /* get coordinates from vertices */
+ if(totvert) {
+ /* use weight table */
+ if(voweights) {
+
+ if(voweights[curvert] < 1.0f) {
+ float remainder= 0.0f;
+
+ while(remainder + voweights[curvert] < 1.0f && curvert<totvert-1) {
+ remainder += voweights[curvert];
+ curvert++;
}
- par= par->parent;
+ voweights[curvert] += remainder;
+ maxw= (paf->end-paf->sta)/voweights[curvert];
+ }
+
+ if(voweights[curvert]==0.0f)
+ break; /* WARN skips here out of particle generating */
+ else {
+ if(voweights[curvert] > 1.0f)
+ voweights[curvert] -= 1.0f;
+
+ /* time correction to make particles appear evenly */
+ pa->time= paf->sta + maxw*voweights[curvert];
}
- if(ma) do_mat_ipo(ma);
- Mat4CpyMat4(prevobmat, ob->obmat);
- where_is_object(ob);
- Mat4Invert(ob->imat, ob->obmat);
- Mat3CpyMat4(imat, ob->imat);
}
- }
- /* get coordinates */
- if(paf->flag & PAF_FACE) give_mesh_mvert(me, dlm, a, co, no, paf->seed);
- else {
- if (totvert) {
- VECCOPY(co, dlm->mvert[a%totvert].co);
- VECCOPY(no, dlm->mvert[a%totvert].no);
- } else {
- co[0] = co[1] = co[2] = 0.0f;
- no[0] = no[1] = no[2] = 0;
+ else {
+ curvert= a % totvert;
+ if(a >= totvert && totface)
+ totvert= 0;
}
+
+ VECCOPY(co, vertlist[curvert].co);
+ VECCOPY(no, vertlist[curvert].no);
}
VECCOPY(pa->co, co);
- if(paf->flag & PAF_STATIC);
- else {
- Mat4MulVecfl(ob->obmat, pa->co);
+ /* dynamic options */
+ if((paf->flag & PAF_STATIC)==0) {
+ int cur;
+
+ /* particle retiming with texture */
+ if(mtextime && (paf->flag2 & PAF_TEXTIME)) {
+ float tin, tr, tg, tb, ta, orco[3];
+
+ /* calculate normalized orco */
+ orco[0] = (co[0]-me->loc[0])/me->size[0];
+ orco[1] = (co[1]-me->loc[1])/me->size[1];
+ orco[2] = (co[2]-me->loc[2])/me->size[2];
+ externtex(mtextime, orco, &tin, &tr, &tg, &tb, &ta);
+
+ if(paf->flag2neg & PAF_TEXTIME)
+ pa->time = paf->sta + (paf->end - paf->sta)*tin;
+ else
+ pa->time = paf->sta + (paf->end - paf->sta)*(1.0f-tin);
+ }
+
+ /* set ob at correct time, we use cached matrices */
+ cur= (int)floor(pa->time) + 1 ; /* + 1 has a reason: (obmat/prevobmat) otherwise comet-tails start too late */
+
+ if(cur <= paf_end) mcnow= mcache + cur - paf_sta;
+ else mcnow= mcache + paf_end - paf_sta + 1;
+
+ if(cur > paf_sta) mcprev= mcnow-1;
+ else mcprev= mcache;
+
+ /* move to global space */
+ Mat4MulVecfl(mcnow->obmat, pa->co);
VECCOPY(vec, co);
- Mat4MulVecfl(prevobmat, vec);
+ Mat4MulVecfl(mcprev->obmat, vec);
/* first start speed: object */
VECSUB(pa->no, pa->co, vec);
+
VecMulf(pa->no, paf->obfac);
/* calculate the correct inter-frame */
- fac= (ftime- (float)floor(ftime));
+ fac= (pa->time- (float)floor(pa->time));
pa->co[0]= fac*pa->co[0] + (1.0f-fac)*vec[0];
pa->co[1]= fac*pa->co[1] + (1.0f-fac)*vec[1];
pa->co[2]= fac*pa->co[2] + (1.0f-fac)*vec[2];
- }
- /* start speed: normal */
- if(paf->normfac!=0.0) {
- /* transpose ! */
- vec[0]= imat[0][0]*no[0] + imat[0][1]*no[1] + imat[0][2]*no[2];
- vec[1]= imat[1][0]*no[0] + imat[1][1]*no[1] + imat[1][2]*no[2];
- vec[2]= imat[2][0]*no[0] + imat[2][1]*no[1] + imat[2][2]*no[2];
-
- Normalise(vec);
- VecMulf(vec, paf->normfac);
- VECADD(pa->no, pa->no, vec);
+ /* start speed: normal */
+ if(paf->normfac!=0.0) {
+ /* imat is transpose ! */
+ VECCOPY(vec, no);
+ Mat3MulVecfl(mcnow->imat, vec);
+
+ Normalise(vec);
+ VecMulf(vec, paf->normfac);
+ VECADD(pa->no, pa->no, vec);
+ }
+ }
+ else {
+ if(paf->normfac!=0.0) {
+ VECCOPY(pa->no, no);
+ Normalise(pa->no);
+ VecMulf(pa->no, paf->normfac);
+ }
}
+
pa->lifetime= paf->lifetime;
if(paf->randlife!=0.0) {
pa->lifetime*= 1.0f + paf->randlife*(rng_getFloat(rng) - 0.5f);
}
- pa->mat_nr= 1;
+ pa->mat_nr= paf->omat;
- make_particle_keys(rng, ob, 0, a, paf, pa, force, deform, mtexmove, ob->lay, cfraont);
+ make_particle_keys(rng, ob, 0, a, paf, pa, force, deform, mtexmove, ob->lay);
}
- if(G.f & G_DEBUG) {
- printf("\r Particle: %d / %d \n", totpart, totpart);
- fflush(stdout);
- }
- if(deform) end_latt_deform();
-
- /* restore */
- G.scene->r.cfra= cfraont;
- G.scene->r.framelen= framelenont;
- give_mesh_mvert(0, 0, 0, 0, 0,paf->seed);
-
- /* put hierarchy back */
- par= ob;
- while(par) {
- popfirst(par);
- /* do not do ob->ipo: keep insertkey */
- do_ob_key(par);
-
- if(par->type==OB_ARMATURE) {
- do_all_pose_actions(par); // only does this object actions
- where_is_pose(par);
- }
- par= par->parent;
- }
+ /* free stuff */
+ give_mesh_particle_coord(NULL, NULL, NULL, 0, 0, NULL, NULL);
+ if(voweights) MEM_freeN(voweights);
+ if(foweights) MEM_freeN(foweights);
+ if(mcache) MEM_freeN(mcache);
+ if(deform) end_latt_deform();
+
/* reset deflector cache */
for(base= G.scene->base.first; base; base= base->next) {
if(base->object->sumohandle) {
@@ -1380,10 +1837,6 @@ void build_particle_system(Object *ob)
}
}
- /* restore: AFTER popfirst */
- ob->sf= sfraont;
-
- if(ma) do_mat_ipo(ma); // set back on current time
disable_speed_curve(0);
waitcursor(0);
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 10395326357..38732377e29 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -346,11 +346,11 @@ int sb_detect_collision(float opco[3], float facenormal[3], float *damp,
{
Base *base;
Object *ob;
- int a, deflected=0;
float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3],d_nvect[3], dv1[3], dv2[3],
facedist,n_mag,t,force_mag_norm,
innerfacethickness = -0.5f, outerfacethickness = 0.2f,
ee = 5.0f, ff = 0.1f, fa;
+ int a, deflected=0;
base= G.scene->base.first;
while (base) {
@@ -495,29 +495,27 @@ static int sb_deflect_face(Object *ob,float *actpos, float *futurepos,float *col
{
int deflected;
float s_actpos[3], s_futurepos[3];
+
VECCOPY(s_actpos,actpos);
if(futurepos)
- VECCOPY(s_futurepos,futurepos);
+ VECCOPY(s_futurepos,futurepos);
+
deflected= sb_detect_collision(s_actpos, facenormal, cf, force , ob->lay, ob);
return(deflected);
-
}
-#define USES_FIELD 1
-#define USES_DEFLECT 2
static int is_there_deflection(unsigned int layer)
{
Base *base;
- int retval= 0;
for(base = G.scene->base.first; base; base= base->next) {
if( (base->lay & layer) && base->object->pd) {
- if(base->object->pd->forcefield) retval |= USES_FIELD;
- if(base->object->pd->deflect) retval |= USES_DEFLECT;
+ if(base->object->pd->deflect)
+ return 1;
}
}
- return retval;
+ return 0;
}
static void softbody_calc_forces(Object *ob, float forcetime)
@@ -529,10 +527,10 @@ static void softbody_calc_forces(Object *ob, float forcetime)
BodyPoint *bp;
BodyPoint *bproot;
BodySpring *bs;
- float iks, ks, kd, gravity, actspringlen, forcefactor, sd[3],
- fieldfactor = 1000.0f,
- windfactor = 250.0f;
- int a, b, do_effector;
+ ListBase *do_effector;
+ float iks, ks, kd, gravity, actspringlen, forcefactor, sd[3];
+ float fieldfactor = 1000.0f, windfactor = 250.0f;
+ int a, b, do_deflector;
/* clear forces */
for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
@@ -540,8 +538,11 @@ static void softbody_calc_forces(Object *ob, float forcetime)
}
gravity = sb->grav * sb_grav_force_scale(ob);
+
/* check! */
- do_effector= is_there_deflection(ob->lay);
+ do_deflector= is_there_deflection(ob->lay);
+ do_effector= pdInitEffectors(ob->lay);
+
iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */
bproot= sb->bpoint; /* need this for proper spring addressing */
@@ -581,14 +582,15 @@ static void softbody_calc_forces(Object *ob, float forcetime)
bp->force[2]-= gravity*sb->nodemass; /* individual mass of node here */
/* particle field & vortex */
- if(do_effector & USES_FIELD) {
+ if(do_effector) {
float force[3]= {0.0f, 0.0f, 0.0f};
float speed[3]= {0.0f, 0.0f, 0.0f};
float eval_sb_fric_force_scale = sb_fric_force_scale(ob); // just for calling functio once
- pdDoEffector(bp->pos, force, speed, (float)G.scene->r.cfra, ob->lay,PE_WIND_AS_SPEED);
- // note: now we have wind as motion of media, so we can do anisotropic stuff here,
- // if we had vertex normals here(BM)
+ pdDoEffectors(do_effector, bp->pos, force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED);
+
+ /* note: now we have wind as motion of media, so we can do anisotropic stuff here, */
+ /* if we had vertex normals here(BM) */
/* apply forcefield*/
VecMulf(force,fieldfactor* eval_sb_fric_force_scale);
VECADD(bp->force, bp->force, force);
@@ -616,7 +618,7 @@ static void softbody_calc_forces(Object *ob, float forcetime)
yes, constraints and collision stuff should go here too (read baraff papers on that!)
*/
/* moving collision targets */
- if(do_effector & USES_DEFLECT) {
+ if(do_deflector) {
float defforce[3] = {0.0f,0.0f,0.0f}, collisionpos[3],facenormal[3], cf = 1.0f;
kd = 1.0f;
@@ -689,6 +691,11 @@ static void softbody_calc_forces(Object *ob, float forcetime)
}/*any edges*/
}/*omit on snap */
}/*loop all bp's*/
+
+ /* cleanup */
+ if(do_effector)
+ pdEndEffectors(do_effector);
+
}
static void softbody_apply_forces(Object *ob, float forcetime, int mode, float *err)
@@ -701,11 +708,9 @@ static void softbody_apply_forces(Object *ob, float forcetime, int mode, float *
float dx[3],dv[3];
float timeovermass;
float maxerr = 0.0;
- int a, do_effector;
+ int a;
forcetime *= sb_time_scale(ob);
- /* check! */
- do_effector= is_there_deflection(ob->lay);
// claim a minimum mass for vertex
if (sb->nodemass > 0.09999f) timeovermass = forcetime/sb->nodemass;
@@ -771,6 +776,7 @@ static void softbody_apply_forces(Object *ob, float forcetime, int mode, float *
else { VECADD(bp->pos, bp->pos, dx);}
}//snap
} //for
+
if (err){ /* so step size will be controlled by biggest difference in slope */
*err = maxerr;
}