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:
Diffstat (limited to 'source/blender/blenkernel/intern/particle.c')
-rw-r--r--source/blender/blenkernel/intern/particle.c1038
1 files changed, 538 insertions, 500 deletions
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 6b75f5d417c..5f45e06cfc4 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -46,10 +46,11 @@
#include "DNA_scene_types.h"
#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
#include "BLI_kdtree.h"
#include "BLI_rand.h"
#include "BLI_threads.h"
-#include "BLI_math.h"
#include "BKE_anim.h"
#include "BKE_animsys.h"
@@ -61,7 +62,7 @@
#include "BKE_group.h"
#include "BKE_main.h"
#include "BKE_lattice.h"
-#include "BKE_utildefines.h"
+
#include "BKE_displist.h"
#include "BKE_particle.h"
#include "BKE_object.h"
@@ -196,7 +197,7 @@ void psys_set_current_num(Object *ob, int index)
}
Object *psys_find_object(Scene *scene, ParticleSystem *psys)
{
- Base *base = scene->base.first;
+ Base *base;
ParticleSystem *tpsys;
for(base = scene->base.first; base; base = base->next) {
@@ -272,7 +273,7 @@ int psys_check_enabled(Object *ob, ParticleSystem *psys)
}
psmd= psys_get_modifier(ob, psys);
- if(psys->renderdata) {
+ if(psys->renderdata || G.rendering) {
if(!(psmd->modifier.mode & eModifierMode_Render))
return 0;
}
@@ -380,7 +381,7 @@ void psys_free_settings(ParticleSettings *part)
fluid_free_settings(part->fluid);
}
-void free_hair(Object *ob, ParticleSystem *psys, int dynamics)
+void free_hair(Object *UNUSED(ob), ParticleSystem *psys, int dynamics)
{
PARTICLE_P;
@@ -402,9 +403,10 @@ void free_hair(Object *ob, ParticleSystem *psys, int dynamics)
modifier_free((ModifierData*)psys->clmd);
psys->clmd = NULL;
+ psys->pointcache = BKE_ptcache_add(&psys->ptcaches);
}
else {
- cloth_free_modifier(ob, psys->clmd);
+ cloth_free_modifier(psys->clmd);
}
}
@@ -559,6 +561,9 @@ void psys_free(Object *ob, ParticleSystem * psys)
BLI_freelistN(&psys->targets);
BLI_kdtree_free(psys->tree);
+
+ if(psys->fluid_springs)
+ MEM_freeN(psys->fluid_springs);
pdEndEffectors(&psys->effectors);
@@ -996,6 +1001,8 @@ static float interpolate_particle_value(float v1, float v2, float v3, float v4,
value= w[0]*v1 + w[1]*v2 + w[2]*v3;
if(four)
value += w[3]*v4;
+
+ CLAMP(value, 0.f, 1.f);
return value;
}
@@ -1051,9 +1058,10 @@ typedef struct ParticleInterpolationData {
} ParticleInterpolationData;
/* Assumes pointcache->mem_cache exists, so for disk cached particles call psys_make_temp_pointcache() before use */
/* It uses ParticleInterpolationData->pm to store the current memory cache frame so it's thread safe. */
-static void get_pointcache_keys_for_time(Object *ob, PointCache *cache, PTCacheMem **cur, int index, float t, ParticleKey *key1, ParticleKey *key2)
+static void get_pointcache_keys_for_time(Object *UNUSED(ob), PointCache *cache, PTCacheMem **cur, int index, float t, ParticleKey *key1, ParticleKey *key2)
{
static PTCacheMem *pm = NULL;
+ int index1, index2;
if(index < 0) { /* initialize */
*cur = cache->mem_cache.first;
@@ -1068,15 +1076,19 @@ static void get_pointcache_keys_for_time(Object *ob, PointCache *cache, PTCacheM
pm = *cur;
- BKE_ptcache_make_particle_key(key2, pm->index_array ? pm->index_array[index] - 1 : index, pm->data, (float)pm->frame);
- if(pm->prev->index_array && pm->prev->index_array[index] == 0)
+ index2 = BKE_ptcache_mem_index_find(pm, index);
+ index1 = BKE_ptcache_mem_index_find(pm->prev, index);
+
+ BKE_ptcache_make_particle_key(key2, index2, pm->data, (float)pm->frame);
+ if(index1 < 0)
copy_particle_key(key1, key2, 1);
else
- BKE_ptcache_make_particle_key(key1, pm->prev->index_array ? pm->prev->index_array[index] - 1 : index, pm->prev->data, (float)pm->prev->frame);
+ BKE_ptcache_make_particle_key(key1, index1, pm->prev->data, (float)pm->prev->frame);
}
else if(cache->mem_cache.first) {
pm = cache->mem_cache.first;
- BKE_ptcache_make_particle_key(key2, pm->index_array ? pm->index_array[index] - 1 : index, pm->data, (float)pm->frame);
+ index2 = BKE_ptcache_mem_index_find(pm, index);
+ BKE_ptcache_make_particle_key(key2, index2, pm->data, (float)pm->frame);
copy_particle_key(key1, key2, 1);
}
}
@@ -1087,14 +1099,7 @@ static int get_pointcache_times_for_particle(PointCache *cache, int index, float
int ret = 0;
for(pm=cache->mem_cache.first; pm; pm=pm->next) {
- if(pm->index_array) {
- if(pm->index_array[index]) {
- *start = pm->frame;
- ret++;
- break;
- }
- }
- else {
+ if(BKE_ptcache_mem_index_find(pm, index) >= 0) {
*start = pm->frame;
ret++;
break;
@@ -1102,14 +1107,7 @@ static int get_pointcache_times_for_particle(PointCache *cache, int index, float
}
for(pm=cache->mem_cache.last; pm; pm=pm->prev) {
- if(pm->index_array) {
- if(pm->index_array[index]) {
- *end = pm->frame;
- ret++;
- break;
- }
- }
- else {
+ if(BKE_ptcache_mem_index_find(pm, index) >= 0) {
*end = pm->frame;
ret++;
break;
@@ -1124,13 +1122,8 @@ float psys_get_dietime_from_cache(PointCache *cache, int index) {
int dietime = 10000000; /* some max value so that we can default to pa->time+lifetime */
for(pm=cache->mem_cache.last; pm; pm=pm->prev) {
- if(pm->index_array) {
- if(pm->index_array[index])
- return (float)pm->frame;
- }
- else {
+ if(BKE_ptcache_mem_index_find(pm, index) >= 0)
return (float)pm->frame;
- }
}
return (float)dietime;
@@ -1157,7 +1150,7 @@ static void init_particle_interpolation(Object *ob, ParticleSystem *psys, Partic
pind->dietime = (key + pa->totkey - 1)->time;
}
else if(pind->cache) {
- float start, end;
+ float start=0.0f, end=0.0f;
get_pointcache_keys_for_time(ob, pind->cache, &pind->pm, -1, 0.0f, NULL, NULL);
pind->birthtime = pa ? pa->time : pind->cache->startframe;
pind->dietime = pa ? pa->dietime : pind->cache->endframe;
@@ -1201,12 +1194,12 @@ static void mvert_to_particle(ParticleKey *key, MVert *mvert, HairKey *hkey)
key->time = hkey->time;
}
-static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData *pa, float t, float frs_sec, ParticleInterpolationData *pind, ParticleKey *result)
+static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData *pa, float t, ParticleInterpolationData *pind, ParticleKey *result)
{
PTCacheEditPoint *point = pind->epoint;
ParticleKey keys[4];
int point_vel = (point && point->keys->vel);
- float real_t, dfra, keytime;
+ float real_t, dfra, keytime, invdt;
/* billboards wont fill in all of these, so start cleared */
memset(keys, 0, sizeof(keys));
@@ -1345,11 +1338,12 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
dfra = keys[2].time - keys[1].time;
keytime = (real_t - keys[1].time) / dfra;
+ invdt = dfra * 0.04f * psys->part->timetweak;
/* convert velocity to timestep size */
if(pind->keyed || pind->cache || point_vel){
- mul_v3_fl(keys[1].vel, dfra / frs_sec);
- mul_v3_fl(keys[2].vel, dfra / frs_sec);
+ mul_v3_fl(keys[1].vel, invdt);
+ mul_v3_fl(keys[2].vel, invdt);
interp_qt_qtqt(result->rot,keys[1].rot,keys[2].rot,keytime);
}
@@ -1360,7 +1354,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
/* the velocity needs to be converted back from cubic interpolation */
if(pind->keyed || pind->cache || point_vel)
- mul_v3_fl(result->vel, frs_sec / dfra);
+ mul_v3_fl(result->vel, 1.f/invdt);
}
/************************************************/
/* Particles on a dm */
@@ -1476,7 +1470,7 @@ void psys_interpolate_face(MVert *mvert, MFace *mface, MTFace *tface, float (*or
}
else {
VECCOPY(orco, vec);
- if(ornor)
+ if(ornor && nor)
VECCOPY(ornor, nor);
}
}
@@ -1646,7 +1640,7 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, float *
return DMCACHE_NOTFOUND;
}
-static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache, float *fw, float foffset, int *mapindex, float *mapfw)
+static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache, float *fw, float UNUSED(foffset), int *mapindex, float *mapfw)
{
if(index < 0)
return 0;
@@ -1802,7 +1796,7 @@ ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys)
/* Particles on a shape */
/************************************************/
/* ready for future use */
-static void psys_particle_on_shape(int distr, int index, float *fuv, float *vec, float *nor, float *utan, float *vtan, float *orco, float *ornor)
+static void psys_particle_on_shape(int UNUSED(distr), int UNUSED(index), float *UNUSED(fuv), float *vec, float *nor, float *utan, float *vtan, float *orco, float *ornor)
{
/* TODO */
float zerovec[3]={0.0f,0.0f,0.0f};
@@ -1861,144 +1855,186 @@ static float vert_weight(MDeformVert *dvert, int group)
return 0.0;
}
-static void do_prekink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, short type, short axis, float obmat[][4])
+static void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, float flat, short type, short axis, float obmat[][4], int smooth_start)
{
- float vec[3]={0.0,0.0,0.0}, q1[4]={1,0,0,0},q2[4];
- float t;
+ float kink[3]={1.f,0.f,0.f}, par_vec[3], q1[4]={1.f,0.f,0.f,0.f};
+ float t, dt=1.f, result[3];
+
+ if(par == NULL || type == PART_KINK_NO)
+ return;
- CLAMP(time,0.0,1.0);
+ CLAMP(time, 0.f, 1.f);
if(shape!=0.0f && type!=PART_KINK_BRAID) {
if(shape<0.0f)
- time= (float)pow(time, 1.0+shape);
+ time= (float)pow(time, 1.f+shape);
else
- time= (float)pow(time, 1.0/(1.0-shape));
+ time= (float)pow(time, 1.f/(1.f-shape));
}
- t=time;
+ t = time * freq *(float)M_PI;
+
+ if(smooth_start) {
+ dt = fabs(t);
+ /* smooth the beginning of kink */
+ CLAMP(dt, 0.f, (float)M_PI);
+ dt = sin(dt/2.f);
+ }
+
+ if(type != PART_KINK_RADIAL) {
+ float temp[3];
- t*=(float)M_PI*freq;
+ kink[axis]=1.f;
- if(par==0) return;
+ if(obmat)
+ mul_mat3_m4_v3(obmat, kink);
+
+ if(par_rot)
+ mul_qt_v3(par_rot, kink);
- switch(type){
- case PART_KINK_CURL:
- vec[axis]=1.0;
- if(par_rot)
- QUATCOPY(q2,par_rot)
- else
- vec_to_quat( q2,par->vel,axis,(axis+1)%3);
- mul_qt_v3(q2,vec);
- mul_v3_fl(vec,amplitude);
- VECADD(state->co,state->co,vec);
+ /* make sure kink is normal to strand */
+ project_v3_v3v3(temp, kink, par->vel);
+ sub_v3_v3(kink, temp);
+ normalize_v3(kink);
+ }
- VECSUB(vec,state->co,par->co);
+ copy_v3_v3(result, state->co);
+ sub_v3_v3v3(par_vec, par->co, state->co);
- if(t!=0.0)
- axis_angle_to_quat(q1,par->vel,t);
-
- mul_qt_v3(q1,vec);
-
- VECADD(state->co,par->co,vec);
- break;
- case PART_KINK_RADIAL:
- VECSUB(vec,state->co,par->co);
+ switch(type) {
+ case PART_KINK_CURL:
+ {
+ mul_v3_fl(par_vec, -1.f);
- normalize_v3(vec);
- mul_v3_fl(vec,amplitude*(float)sin(t));
+ if(flat > 0.f) {
+ float proj[3];
+ project_v3_v3v3(proj, par_vec, par->vel);
+ madd_v3_v3fl(par_vec, proj, -flat);
- VECADD(state->co,state->co,vec);
- break;
- case PART_KINK_WAVE:
- vec[axis]=1.0;
- if(obmat)
- mul_mat3_m4_v3(obmat,vec);
+ project_v3_v3v3(proj, par_vec, kink);
+ madd_v3_v3fl(par_vec, proj, -flat);
+ }
- if(par_rot)
- mul_qt_v3(par_rot,vec);
+ axis_angle_to_quat(q1, kink, (float)M_PI/2.f);
- project_v3_v3v3(q1,vec,par->vel);
-
- VECSUB(vec,vec,q1);
- normalize_v3(vec);
+ mul_qt_v3(q1, par_vec);
- mul_v3_fl(vec,amplitude*(float)sin(t));
+ madd_v3_v3fl(par_vec, kink, amplitude);
- VECADD(state->co,state->co,vec);
- break;
- case PART_KINK_BRAID:
- if(par){
- float y_vec[3]={0.0,1.0,0.0};
- float z_vec[3]={0.0,0.0,1.0};
- float vec_from_par[3], vec_one[3], radius, state_co[3];
- float inp_y,inp_z,length;
-
- if(par_rot)
- QUATCOPY(q2,par_rot)
- else
- vec_to_quat(q2,par->vel,axis,(axis+1)%3);
- mul_qt_v3(q2,y_vec);
- mul_qt_v3(q2,z_vec);
-
- VECSUB(vec_from_par,state->co,par->co);
- radius= normalize_v3_v3(vec_one, vec_from_par);
+ /* rotate kink vector around strand tangent */
+ if(t!=0.f) {
+ axis_angle_to_quat(q1, par->vel, t);
+ mul_qt_v3(q1, par_vec);
+ }
- inp_y=dot_v3v3(y_vec,vec_one);
- inp_z=dot_v3v3(z_vec,vec_one);
+ add_v3_v3v3(result, par->co, par_vec);
+ break;
+ }
+ case PART_KINK_RADIAL:
+ {
+ if(flat > 0.f) {
+ float proj[3];
+ /* flatten along strand */
+ project_v3_v3v3(proj, par_vec, par->vel);
+ madd_v3_v3fl(result, proj, flat);
+ }
- if(inp_y>0.5){
- VECCOPY(state_co,y_vec);
+ madd_v3_v3fl(result, par_vec, -amplitude*(float)sin(t));
+ break;
+ }
+ case PART_KINK_WAVE:
+ {
+ madd_v3_v3fl(result, kink, amplitude*(float)sin(t));
- mul_v3_fl(y_vec,amplitude*(float)cos(t));
- mul_v3_fl(z_vec,amplitude/2.0f*(float)sin(2.0f*t));
- }
- else if(inp_z>0.0){
- VECCOPY(state_co,z_vec);
- mul_v3_fl(state_co,(float)sin(M_PI/3.0f));
- VECADDFAC(state_co,state_co,y_vec,-0.5f);
+ if(flat > 0.f) {
+ float proj[3];
+ /* flatten along wave */
+ project_v3_v3v3(proj, par_vec, kink);
+ madd_v3_v3fl(result, proj, flat);
- mul_v3_fl(y_vec,-amplitude*(float)cos(t + M_PI/3.0f));
- mul_v3_fl(z_vec,amplitude/2.0f*(float)cos(2.0f*t + M_PI/6.0f));
- }
- else{
- VECCOPY(state_co,z_vec);
- mul_v3_fl(state_co,-(float)sin(M_PI/3.0f));
- VECADDFAC(state_co,state_co,y_vec,-0.5f);
+ /* flatten along strand */
+ project_v3_v3v3(proj, par_vec, par->vel);
+ madd_v3_v3fl(result, proj, flat);
+ }
+ break;
+ }
+ case PART_KINK_BRAID:
+ {
+ float y_vec[3]={0.f,1.f,0.f};
+ float z_vec[3]={0.f,0.f,1.f};
+ float vec_one[3], state_co[3];
+ float inp_y, inp_z, length;
+
+ if(par_rot) {
+ mul_qt_v3(par_rot, y_vec);
+ mul_qt_v3(par_rot, z_vec);
+ }
+
+ mul_v3_fl(par_vec, -1.f);
+ normalize_v3_v3(vec_one, par_vec);
- mul_v3_fl(y_vec,amplitude*(float)-sin(t+M_PI/6.0f));
- mul_v3_fl(z_vec,amplitude/2.0f*(float)-sin(2.0f*t+M_PI/3.0f));
- }
+ inp_y=dot_v3v3(y_vec, vec_one);
+ inp_z=dot_v3v3(z_vec, vec_one);
- mul_v3_fl(state_co,amplitude);
- VECADD(state_co,state_co,par->co);
- VECSUB(vec_from_par,state->co,state_co);
+ if(inp_y>0.5){
+ copy_v3_v3(state_co, y_vec);
- length=normalize_v3(vec_from_par);
- mul_v3_fl(vec_from_par,MIN2(length,amplitude/2.0f));
+ mul_v3_fl(y_vec, amplitude*(float)cos(t));
+ mul_v3_fl(z_vec, amplitude/2.f*(float)sin(2.f*t));
+ }
+ else if(inp_z>0.0){
+ mul_v3_v3fl(state_co, z_vec, (float)sin(M_PI/3.f));
+ VECADDFAC(state_co,state_co,y_vec,-0.5f);
- VECADD(state_co,par->co,y_vec);
- VECADD(state_co,state_co,z_vec);
- VECADD(state_co,state_co,vec_from_par);
+ mul_v3_fl(y_vec, -amplitude * (float)cos(t + M_PI/3.f));
+ mul_v3_fl(z_vec, amplitude/2.f * (float)cos(2.f*t + M_PI/6.f));
+ }
+ else{
+ mul_v3_v3fl(state_co, z_vec, -(float)sin(M_PI/3.f));
+ madd_v3_v3fl(state_co, y_vec, -0.5f);
- shape=(2.0f*(float)M_PI)*(1.0f+shape);
+ mul_v3_fl(y_vec, amplitude * (float)-sin(t + M_PI/6.f));
+ mul_v3_fl(z_vec, amplitude/2.f * (float)-sin(2.f*t + M_PI/3.f));
+ }
- if(t<shape){
- shape=t/shape;
- shape=(float)sqrt((double)shape);
- interp_v3_v3v3(state->co,state->co,state_co,shape);
- }
- else{
- VECCOPY(state->co,state_co);
- }
- }
- break;
+ mul_v3_fl(state_co, amplitude);
+ add_v3_v3(state_co, par->co);
+ sub_v3_v3v3(par_vec, state->co, state_co);
+
+ length = normalize_v3(par_vec);
+ mul_v3_fl(par_vec, MIN2(length, amplitude/2.f));
+
+ add_v3_v3v3(state_co, par->co, y_vec);
+ add_v3_v3(state_co, z_vec);
+ add_v3_v3(state_co, par_vec);
+
+ shape = 2.f*(float)M_PI * (1.f+shape);
+
+ if(t<shape){
+ shape = t/shape;
+ shape = (float)sqrt((double)shape);
+ interp_v3_v3v3(result, result, state_co, shape);
+ }
+ else{
+ copy_v3_v3(result, state_co);
+ }
+ break;
}
+ }
+
+ /* blend the start of the kink */
+ if(dt < 1.f)
+ interp_v3_v3v3(state->co, state->co, result, dt);
+ else
+ copy_v3_v3(state->co, result);
}
-static void do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump)
+static float do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump)
{
+ float clump = 0.f;
+
if(par && clumpfac!=0.0){
- float clump, cpow;
+ float cpow;
if(clumppow<0.0)
cpow=1.0f+clumppow;
@@ -2009,8 +2045,11 @@ static void do_clump(ParticleKey *state, ParticleKey *par, float time, float clu
clump = -clumpfac*pa_clump*(float)pow(1.0-(double)time,(double)cpow);
else
clump = clumpfac*pa_clump*(float)pow((double)time,(double)cpow);
+
interp_v3_v3v3(state->co,state->co,par->co,clump);
}
+
+ return clump;
}
void precalc_guides(ParticleSimulationData *sim, ListBase *effectors)
{
@@ -2123,7 +2162,7 @@ int do_guides(ListBase *effectors, ParticleKey *state, int index, float time)
}
par.co[0] = par.co[1] = par.co[2] = 0.0f;
VECCOPY(key.co, vec_to_point);
- do_prekink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, pd->kink, pd->kink_axis, 0);
+ do_kink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, 0.f, pd->kink, pd->kink_axis, 0, 0);
do_clump(&key, &par, guidetime, pd->clump_fac, pd->clump_pow, 1.0f);
VECCOPY(vec_to_point, key.co);
@@ -2184,7 +2223,7 @@ static void do_rough_end(float *loc, float mat[4][4], float t, float fac, float
VECADDFAC(state->co,state->co,mat[0],rough[0]);
VECADDFAC(state->co,state->co,mat[1],rough[1]);
}
-static void do_path_effectors(ParticleSimulationData *sim, int i, ParticleCacheKey *ca, int k, int steps, float *rootco, float effector, float dfra, float cfra, float *length, float *vec)
+static void do_path_effectors(ParticleSimulationData *sim, int i, ParticleCacheKey *ca, int k, int steps, float *UNUSED(rootco), float effector, float UNUSED(dfra), float UNUSED(cfra), float *length, float *vec)
{
float force[3] = {0.0f,0.0f,0.0f};
ParticleKey eff_key;
@@ -2207,12 +2246,13 @@ static void do_path_effectors(ParticleSimulationData *sim, int i, ParticleCacheK
normalize_v3(force);
- VECADDFAC(ca->co, (ca-1)->co, force, *length);
-
- if(k < steps) {
+ if(k < steps)
sub_v3_v3v3(vec, (ca+1)->co, ca->co);
+
+ madd_v3_v3v3fl(ca->co, (ca-1)->co, force, *length);
+
+ if(k < steps)
*length = len_v3(vec);
- }
}
static int check_path_length(int k, ParticleCacheKey *keys, ParticleCacheKey *state, float max_length, float *cur_length, float length, float *dvec)
{
@@ -2228,20 +2268,23 @@ static int check_path_length(int k, ParticleCacheKey *keys, ParticleCacheKey *st
return k;
}
}
-static void offset_child(ChildParticle *cpa, ParticleKey *par, ParticleKey *child, float flat, float radius)
+static void offset_child(ChildParticle *cpa, ParticleKey *par, float *par_rot, ParticleKey *child, float flat, float radius)
{
- VECCOPY(child->co,cpa->fuv);
- mul_v3_fl(child->co,radius);
+ copy_v3_v3(child->co, cpa->fuv);
+ mul_v3_fl(child->co, radius);
child->co[0]*=flat;
- VECCOPY(child->vel,par->vel);
-
- mul_qt_v3(par->rot,child->co);
+ copy_v3_v3(child->vel, par->vel);
- QUATCOPY(child->rot,par->rot);
+ if(par_rot) {
+ mul_qt_v3(par_rot, child->co);
+ copy_qt_qt(child->rot, par_rot);
+ }
+ else
+ unit_qt(child->rot);
- VECADD(child->co,child->co,par->co);
+ add_v3_v3(child->co, par->co);
}
float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup)
{
@@ -2371,12 +2414,9 @@ static int psys_threads_init_path(ParticleThread *threads, Scene *scene, float c
if(totchild==0) return 0;
/* init random number generator */
- if(ctx->sim.psys->part->flag & PART_ANIM_BRANCHING)
- seed= 31415926 + ctx->sim.psys->seed + (int)cfra;
- else
- seed= 31415926 + ctx->sim.psys->seed;
+ seed= 31415926 + ctx->sim.psys->seed;
- if(part->flag & PART_BRANCHING || ctx->editupdate || totchild < 10000)
+ if(ctx->editupdate || totchild < 10000)
totthread= 1;
for(i=0; i<totthread; i++) {
@@ -2419,7 +2459,7 @@ static int psys_threads_init_path(ParticleThread *threads, Scene *scene, float c
}
/* note: this function must be thread safe, except for branching! */
-static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, ParticleCacheKey *keys, int i)
+static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, ParticleCacheKey *child_keys, int i)
{
ParticleThreadContext *ctx= thread->ctx;
Object *ob= ctx->sim.ob;
@@ -2427,44 +2467,29 @@ static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle
ParticleSettings *part = psys->part;
ParticleCacheKey **cache= psys->childcache;
ParticleCacheKey **pcache= psys_in_edit_mode(ctx->sim.scene, psys) ? psys->edit->pathcache : psys->pathcache;
- ParticleCacheKey *state, *par = NULL, *key[4];
- ParticleData *pa=NULL;
+ ParticleCacheKey *child, *par = NULL, *key[4];
ParticleTexture ptex;
- float *cpa_fuv=0, *par_rot=0;
- float co[3], orco[3], ornor[3], hairmat[4][4], t, cpa_1st[3], dvec[3];
- float branch_begin, branch_end, branch_prob, rough_rand;
+ float *cpa_fuv=0, *par_rot=0, rot[4];
+ float orco[3], ornor[3], hairmat[4][4], t, dvec[3], off1[4][3], off2[4][3];
float length, max_length = 1.0f, cur_length = 0.0f;
- float eff_length, eff_vec[3];
+ float eff_length, eff_vec[3], weight[4];
int k, cpa_num;
short cpa_from;
if(!pcache)
return;
- if(part->flag & PART_BRANCHING) {
- branch_begin=rng_getFloat(thread->rng_path);
- branch_end=branch_begin+(1.0f-branch_begin)*rng_getFloat(thread->rng_path);
- branch_prob=rng_getFloat(thread->rng_path);
- rough_rand=rng_getFloat(thread->rng_path);
- }
- else {
- branch_begin= 0.0f;
- branch_end= 0.0f;
- branch_prob= 0.0f;
- rough_rand= 0.0f;
- }
-
- if(i<psys->totpart){
- branch_begin=0.0f;
- branch_end=1.0f;
- branch_prob=0.0f;
- }
-
if(ctx->between){
+ ParticleData *pa = psys->particles + cpa->pa[0];
int w, needupdate;
- float foffset;
-
- if(ctx->editupdate && !(part->flag & PART_BRANCHING)) {
+ float foffset, wsum=0.f;
+ float co[3];
+ float p_min = part->parting_min;
+ float p_max = part->parting_max;
+ /* Virtual parents don't work nicely with parting. */
+ float p_fac = part->parents > 0.f ? 0.f : part->parting_fac;
+
+ if(ctx->editupdate) {
needupdate= 0;
w= 0;
while(w<4 && cpa->pa[w]>=0) {
@@ -2478,223 +2503,223 @@ static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle
if(!needupdate)
return;
else
- memset(keys, 0, sizeof(*keys)*(ctx->steps+1));
+ memset(child_keys, 0, sizeof(*child_keys)*(ctx->steps+1));
}
/* get parent paths */
- w= 0;
- while(w<4 && cpa->pa[w]>=0){
- key[w] = pcache[cpa->pa[w]];
- w++;
+ for(w=0; w<4; w++) {
+ if(cpa->pa[w] >= 0) {
+ key[w] = pcache[cpa->pa[w]];
+ weight[w] = cpa->w[w];
+ }
+ else {
+ key[w] = pcache[0];
+ weight[w] = 0.f;
+ }
+ }
+
+ /* modify weights to create parting */
+ if(p_fac > 0.f) {
+ for(w=0; w<4; w++) {
+ if(w && weight[w] > 0.f) {
+ float d;
+ if(part->flag & PART_CHILD_LONG_HAIR) {
+ /* For long hair use tip distance/root distance as parting factor instead of root to tip angle. */
+ float d1 = len_v3v3(key[0]->co, key[w]->co);
+ float d2 = len_v3v3((key[0]+key[0]->steps-1)->co, (key[w]+key[w]->steps-1)->co);
+
+ d = d1 > 0.f ? d2/d1 - 1.f : 10000.f;
+ }
+ else {
+ float v1[3], v2[3];
+ sub_v3_v3v3(v1, (key[0]+key[0]->steps-1)->co, key[0]->co);
+ sub_v3_v3v3(v2, (key[w]+key[w]->steps-1)->co, key[w]->co);
+ normalize_v3(v1);
+ normalize_v3(v2);
+
+ d = saacos(dot_v3v3(v1, v2)) * 180.f / M_PI;
+ }
+
+ if(p_max > p_min)
+ d = (d - p_min)/(p_max - p_min);
+ else
+ d = (d - p_min) <= 0.f ? 0.f : 1.f;
+
+ CLAMP(d, 0.f, 1.f);
+
+ if(d > 0.f)
+ weight[w] *= (1.f - d);
+ }
+ wsum += weight[w];
+ }
+ for(w=0; w<4; w++)
+ weight[w] /= wsum;
+
+ interp_v4_v4v4(weight, cpa->w, weight, p_fac);
}
/* get the original coordinates (orco) for texture usage */
cpa_num = cpa->num;
- foffset= cpa->foffset;
+ foffset = cpa->foffset;
cpa_fuv = cpa->fuv;
cpa_from = PART_FROM_FACE;
psys_particle_on_emitter(ctx->sim.psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa->fuv,foffset,co,ornor,0,0,orco,0);
- if(part->path_start==0.0f) {
- /* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */
- VECCOPY(cpa_1st,co);
- mul_m4_v3(ob->obmat,cpa_1st);
- }
+ mul_m4_v3(ob->obmat, co);
- pa = psys->particles + cpa->pa[0];
+ for(w=0; w<4; w++)
+ sub_v3_v3v3(off1[w], co, key[w]->co);
psys_mat_hair_to_global(ob, ctx->sim.psmd->dm, psys->part->from, pa, hairmat);
-
- pa=0;
}
else{
- if(ctx->editupdate && !(part->flag & PART_BRANCHING)) {
+ ParticleData *pa = psys->particles + cpa->parent;
+ float co[3];
+ if(ctx->editupdate) {
if(!(psys->edit->points[cpa->parent].flag & PEP_EDIT_RECALC))
return;
- memset(keys, 0, sizeof(*keys)*(ctx->steps+1));
+ memset(child_keys, 0, sizeof(*child_keys)*(ctx->steps+1));
}
/* get the parent path */
- key[0]=pcache[cpa->parent];
+ key[0] = pcache[cpa->parent];
/* get the original coordinates (orco) for texture usage */
- pa=psys->particles+cpa->parent;
-
- cpa_from=part->from;
- cpa_num=pa->num;
- cpa_fuv=pa->fuv;
+ cpa_from = part->from;
+ cpa_num = pa->num;
+ cpa_fuv = pa->fuv;
psys_particle_on_emitter(ctx->sim.psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,ornor,0,0,orco,0);
psys_mat_hair_to_global(ob, ctx->sim.psmd->dm, psys->part->from, pa, hairmat);
}
- keys->steps = ctx->steps;
-
- /* correct child ipo timing */
-#if 0 // XXX old animation system
- if((part->flag&PART_ABS_TIME)==0 && part->ipo){
- float dsta=part->end-part->sta;
- calc_ipo(part->ipo, 100.0f*(ctx->cfra-(part->sta+dsta*cpa->rand[1]))/(part->lifetime*(1.0f - part->randlife*cpa->rand[0])));
- execute_ipo((ID *)part, part->ipo);
- }
-#endif // XXX old animation system
+ child_keys->steps = ctx->steps;
/* get different child parameters from textures & vgroups */
get_child_modifier_parameters(part, ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex);
if(ptex.exist < PSYS_FRAND(i + 24)) {
- keys->steps = -1;
+ child_keys->steps = -1;
return;
}
/* create the child path */
- for(k=0,state=keys; k<=ctx->steps; k++,state++){
+ for(k=0,child=child_keys; k<=ctx->steps; k++,child++){
if(ctx->between){
int w=0;
- state->co[0] = state->co[1] = state->co[2] = 0.0f;
- state->vel[0] = state->vel[1] = state->vel[2] = 0.0f;
- state->rot[0] = state->rot[1] = state->rot[2] = state->rot[3] = 0.0f;
+ zero_v3(child->co);
+ zero_v3(child->vel);
+ unit_qt(child->rot);
- //QUATCOPY(state->rot,key[0]->rot);
+ for(w=0; w<4; w++) {
+ copy_v3_v3(off2[w], off1[w]);
- /* child position is the weighted sum of parent positions */
- while(w<4 && cpa->pa[w]>=0){
- state->co[0] += cpa->w[w] * key[w]->co[0];
- state->co[1] += cpa->w[w] * key[w]->co[1];
- state->co[2] += cpa->w[w] * key[w]->co[2];
-
- state->vel[0] += cpa->w[w] * key[w]->vel[0];
- state->vel[1] += cpa->w[w] * key[w]->vel[1];
- state->vel[2] += cpa->w[w] * key[w]->vel[2];
- key[w]++;
- w++;
- }
- if(part->path_start==0.0f) {
- if(k==0){
- /* calculate the offset between actual child root position and first position interpolated from parents */
- VECSUB(cpa_1st,cpa_1st,state->co);
+ if(part->flag & PART_CHILD_LONG_HAIR) {
+ /* Use parent rotation (in addition to emission location) to determine child offset. */
+ if(k)
+ mul_qt_v3((key[w]+k)->rot, off2[w]);
+
+ /* Fade the effect of rotation for even lengths in the end */
+ project_v3_v3v3(dvec, off2[w], (key[w]+k)->vel);
+ madd_v3_v3fl(off2[w], dvec, -(float)k/(float)ctx->steps);
}
- /* apply offset for correct positioning */
- VECADD(state->co,state->co,cpa_1st);
+
+ add_v3_v3(off2[w], (key[w]+k)->co);
}
+
+ /* child position is the weighted sum of parent positions */
+ interp_v3_v3v3v3v3(child->co, off2[0], off2[1], off2[2], off2[3], weight);
+ interp_v3_v3v3v3v3(child->vel, (key[0]+k)->vel, (key[1]+k)->vel, (key[2]+k)->vel, (key[3]+k)->vel, weight);
+
+ copy_qt_qt(child->rot, (key[0]+k)->rot);
}
else{
+ if(k) {
+ mul_qt_qtqt(rot, (key[0]+k)->rot, key[0]->rot);
+ par_rot = rot;
+ }
+ else {
+ par_rot = key[0]->rot;
+ }
/* offset the child from the parent position */
- offset_child(cpa, (ParticleKey*)key[0], (ParticleKey*)state, part->childflat, part->childrad);
-
- key[0]++;
+ offset_child(cpa, (ParticleKey*)(key[0]+k), par_rot, (ParticleKey*)child, part->childflat, part->childrad);
}
}
/* apply effectors */
if(part->flag & PART_CHILD_EFFECT) {
- for(k=0,state=keys; k<=ctx->steps; k++,state++) {
+ for(k=0,child=child_keys; k<=ctx->steps; k++,child++) {
if(k) {
- do_path_effectors(&ctx->sim, cpa->pa[0], state, k, ctx->steps, keys->co, ptex.effector, 0.0f, ctx->cfra, &eff_length, eff_vec);
+ do_path_effectors(&ctx->sim, cpa->pa[0], child, k, ctx->steps, child_keys->co, ptex.effector, 0.0f, ctx->cfra, &eff_length, eff_vec);
}
else {
- sub_v3_v3v3(eff_vec,(state+1)->co,state->co);
- eff_length= len_v3(eff_vec);
+ sub_v3_v3v3(eff_vec, (child+1)->co, child->co);
+ eff_length = len_v3(eff_vec);
}
}
}
- for(k=0,state=keys; k<=ctx->steps; k++,state++){
- t=(float)k/(float)ctx->steps;
+ for(k=0,child=child_keys; k<=ctx->steps; k++,child++){
+ t = (float)k/(float)ctx->steps;
+
+ if(ctx->totparent)
+ /* this is now threadsafe, virtual parents are calculated before rest of children */
+ par = (i >= ctx->totparent) ? cache[cpa->parent] : NULL;
+ else if(cpa->parent >= 0)
+ par = pcache[cpa->parent];
- if(ctx->totparent){
- if(i>=ctx->totparent) {
- /* this is now threadsafe, virtual parents are calculated before rest of children */
- par = cache[cpa->parent] + k;
+ if(par) {
+ if(k) {
+ mul_qt_qtqt(rot, (par+k)->rot, par->rot);
+ par_rot = rot;
}
- else
- par=0;
- }
- else if(cpa->parent>=0){
- par=pcache[cpa->parent]+k;
- par_rot = par->rot;
+ else {
+ par_rot = par->rot;
+ }
+ par += k;
}
/* apply different deformations to the child path */
- do_child_modifiers(&ctx->sim, &ptex, (ParticleKey *)par, par_rot, cpa, orco, hairmat, (ParticleKey *)state, t);
-
- /* TODO: better branching */
- //if(part->flag & PART_BRANCHING && ctx->between == 0 && part->flag & PART_ANIM_BRANCHING)
- // rough_t = t * rough_rand;
- //else
- // rough_t = t;
-
- /* TODO: better branching */
- //if(part->flag & PART_BRANCHING && ctx->between==0){
- // if(branch_prob > part->branch_thres){
- // branchfac=0.0f;
- // }
- // else{
- // if(part->flag & PART_SYMM_BRANCHING){
- // if(t < branch_begin || t > branch_end)
- // branchfac=0.0f;
- // else{
- // if((t-branch_begin)/(branch_end-branch_begin)<0.5)
- // branchfac=2.0f*(t-branch_begin)/(branch_end-branch_begin);
- // else
- // branchfac=2.0f*(branch_end-t)/(branch_end-branch_begin);
-
- // CLAMP(branchfac,0.0f,1.0f);
- // }
- // }
- // else{
- // if(t < branch_begin){
- // branchfac=0.0f;
- // }
- // else{
- // branchfac=(t-branch_begin)/((1.0f-branch_begin)*0.5f);
- // CLAMP(branchfac,0.0f,1.0f);
- // }
- // }
- // }
-
- // if(i<psys->totpart)
- // interp_v3_v3v3(state->co, (pcache[i] + k)->co, state->co, branchfac);
- // else
- // /* this is not threadsafe, but should only happen for
- // * branching particles particles, which are not threaded */
- // interp_v3_v3v3(state->co, (cache[i - psys->totpart] + k)->co, state->co, branchfac);
- //}
+ do_child_modifiers(&ctx->sim, &ptex, (ParticleKey *)par, par_rot, cpa, orco, hairmat, (ParticleKey *)child, t);
/* we have to correct velocity because of kink & clump */
if(k>1){
- VECSUB((state-1)->vel,state->co,(state-2)->co);
- mul_v3_fl((state-1)->vel,0.5);
+ sub_v3_v3v3((child-1)->vel, child->co, (child-2)->co);
+ mul_v3_fl((child-1)->vel, 0.5);
if(ctx->ma && (part->draw & PART_DRAW_MAT_COL))
- get_strand_normal(ctx->ma, ornor, cur_length, (state-1)->vel);
+ get_strand_normal(ctx->ma, ornor, cur_length, (child-1)->vel);
}
if(k == ctx->steps)
- VECSUB(state->vel,state->co,(state-1)->co);
+ sub_v3_v3v3(child->vel, child->co, (child-1)->co);
/* check if path needs to be cut before actual end of data points */
if(k){
- VECSUB(dvec,state->co,(state-1)->co);
- length=1.0f/(float)ctx->steps;
- k=check_path_length(k,keys,state,max_length,&cur_length,length,dvec);
+ sub_v3_v3v3(dvec, child->co, (child-1)->co);
+ length = 1.0f/(float)ctx->steps;
+ k = check_path_length(k, child_keys, child, max_length, &cur_length, length, dvec);
}
else{
/* initialize length calculation */
- max_length= ptex.length;
- cur_length= 0.0f;
+ max_length = ptex.length;
+ cur_length = 0.0f;
}
if(ctx->ma && (part->draw & PART_DRAW_MAT_COL)) {
- VECCOPY(state->col, &ctx->ma->r)
- get_strand_normal(ctx->ma, ornor, cur_length, state->vel);
+ VECCOPY(child->col, &ctx->ma->r)
+ get_strand_normal(ctx->ma, ornor, cur_length, child->vel);
}
}
+
+ /* Hide virtual parents */
+ if(i < ctx->totparent)
+ child_keys->steps = -1;
}
static void *exec_child_path_cache(void *data)
@@ -2720,10 +2745,8 @@ static void *exec_child_path_cache(void *data)
void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupdate)
{
- ParticleSettings *part = sim->psys->part;
ParticleThread *pthreads;
ParticleThreadContext *ctx;
- ParticleCacheKey **cache;
ListBase threads;
int i, totchild, totparent, totthread;
@@ -2741,8 +2764,8 @@ void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupd
totchild= ctx->totchild;
totparent= ctx->totparent;
- if(editupdate && sim->psys->childcache && !(part->flag & PART_BRANCHING) && totchild == sim->psys->totchildcache) {
- cache = sim->psys->childcache;
+ if(editupdate && sim->psys->childcache && totchild == sim->psys->totchildcache) {
+ ; /* just overwrite the existing cache */
}
else {
/* clear out old and create new empty path cache */
@@ -2782,6 +2805,43 @@ void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupd
psys_threads_free(pthreads);
}
+/* figure out incremental rotations along path starting from unit quat */
+static void cache_key_incremental_rotation(ParticleCacheKey *key0, ParticleCacheKey *key1, ParticleCacheKey *key2, float *prev_tangent, int i)
+{
+ float cosangle, angle, tangent[3], normal[3], q[4];
+
+ switch(i) {
+ case 0:
+ /* start from second key */
+ break;
+ case 1:
+ /* calculate initial tangent for incremental rotations */
+ sub_v3_v3v3(prev_tangent, key0->co, key1->co);
+ normalize_v3(prev_tangent);
+ unit_qt(key1->rot);
+ break;
+ default:
+ sub_v3_v3v3(tangent, key0->co, key1->co);
+ normalize_v3(tangent);
+
+ cosangle= dot_v3v3(tangent, prev_tangent);
+
+ /* note we do the comparison on cosangle instead of
+ * angle, since floating point accuracy makes it give
+ * different results across platforms */
+ if(cosangle > 0.999999f) {
+ QUATCOPY(key1->rot, key2->rot);
+ }
+ else {
+ angle= saacos(cosangle);
+ cross_v3_v3v3(normal, prev_tangent, tangent);
+ axis_angle_to_quat( q,normal, angle);
+ mul_qt_qtqt(key1->rot, q, key2->rot);
+ }
+
+ copy_v3_v3(prev_tangent, tangent);
+ }
+}
/* Calculates paths ready for drawing/rendering. */
/* -Usefull for making use of opengl vertex arrays for super fast strand drawing. */
/* -Makes child strands possible and creates them too into the cache. */
@@ -2792,9 +2852,9 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
ParticleEditSettings *pset = &sim->scene->toolsettings->particle;
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
- ParticleCacheKey *ca, **cache= psys->pathcache;
+ ParticleCacheKey *ca, **cache;
- DerivedMesh *hair_dm = psys->hair_out_dm;
+ DerivedMesh *hair_dm = (psys->part->type==PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) ? psys->hair_out_dm : NULL;
ParticleKey result;
@@ -2804,9 +2864,9 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
PARTICLE_P;
float birthtime = 0.0, dietime = 0.0;
- float t, time = 0.0, dfra = 1.0, frs_sec = sim->scene->r.frs_sec;
+ float t, time = 0.0, dfra = 1.0 /* , frs_sec = sim->scene->r.frs_sec*/ /*UNUSED*/;
float col[4] = {0.5f, 0.5f, 0.5f, 1.0f};
- float prev_tangent[3], hairmat[4][4];
+ float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4];
float rotmat[3][3];
int k;
int steps = (int)pow(2.0, (double)(psys->renderdata ? part->ren_step : part->draw_step));
@@ -2827,7 +2887,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
BLI_srandom(psys->seed);
keyed = psys->flag & PSYS_KEYED;
- baked = !hair_dm && psys->pointcache->mem_cache.first;
+ baked = psys->pointcache->mem_cache.first && psys->part->type != PART_HAIR;
/* clear out old and create new empty path cache */
psys_free_path_cache(psys, psys->edit);
@@ -2894,22 +2954,19 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
/*--interpolate actual path from data points--*/
for(k=0, ca=cache[p]; k<=steps; k++, ca++){
time = (float)k / (float)steps;
-
t = birthtime + time * (dietime - birthtime);
-
result.time = -t;
-
- do_particle_interpolation(psys, p, pa, t, frs_sec, &pind, &result);
+ do_particle_interpolation(psys, p, pa, t, &pind, &result);
+ copy_v3_v3(ca->co, result.co);
/* dynamic hair is in object space */
/* keyed and baked are already in global space */
if(hair_dm)
- mul_m4_v3(sim->ob->obmat, result.co);
+ mul_m4_v3(sim->ob->obmat, ca->co);
else if(!keyed && !baked && !(psys->flag & PSYS_GLOBAL_HAIR))
- mul_m4_v3(hairmat, result.co);
+ mul_m4_v3(hairmat, ca->co);
- VECCOPY(ca->co, result.co);
- VECCOPY(ca->col, col);
+ copy_v3_v3(ca->col, col);
}
/*--modify paths and calculate rotation & velocity--*/
@@ -2944,54 +3001,25 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
/* finally do rotation & velocity */
for(k=1, ca=cache[p]+1; k<=steps; k++, ca++) {
- /* figure out rotation */
- float cosangle, angle, tangent[3], normal[3], q[4];
-
- if(k == 1) {
- /* calculate initial tangent for incremental rotations */
- VECSUB(tangent, ca->co, (ca - 1)->co);
- normalize_v3_v3(prev_tangent, tangent);
-
- /* First rotation is based on emitting face orientation. */
- /* This is way better than having flipping rotations resulting */
- /* from using a global axis as a rotation pole (vec_to_quat()). */
- /* It's not an ideal solution though since it disregards the */
- /* initial tangent, but taking that in to account will allow */
- /* the possibility of flipping again. -jahka */
- mat3_to_quat_is_ok( (ca-1)->rot,rotmat);
- }
- else {
- VECSUB(tangent, ca->co, (ca - 1)->co);
- normalize_v3(tangent);
-
- cosangle= dot_v3v3(tangent, prev_tangent);
-
- /* note we do the comparison on cosangle instead of
- * angle, since floating point accuracy makes it give
- * different results across platforms */
- if(cosangle > 0.999999f) {
- QUATCOPY((ca - 1)->rot, (ca - 2)->rot);
- }
- else {
- angle= saacos(cosangle);
- cross_v3_v3v3(normal, prev_tangent, tangent);
- axis_angle_to_quat( q,normal, angle);
- mul_qt_qtqt((ca - 1)->rot, q, (ca - 2)->rot);
- }
-
- VECCOPY(prev_tangent, tangent);
- }
+ cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k);
if(k == steps)
- QUATCOPY(ca->rot, (ca - 1)->rot);
-
+ copy_qt_qt(ca->rot, (ca - 1)->rot);
/* set velocity */
- VECSUB(ca->vel, ca->co, (ca-1)->co);
+ sub_v3_v3v3(ca->vel, ca->co, (ca-1)->co);
if(k==1)
- VECCOPY((ca-1)->vel, ca->vel);
+ copy_v3_v3((ca-1)->vel, ca->vel);
}
+ /* First rotation is based on emitting face orientation.
+ * This is way better than having flipping rotations resulting
+ * from using a global axis as a rotation pole (vec_to_quat()).
+ * It's not an ideal solution though since it disregards the
+ * initial tangent, but taking that in to account will allow
+ * the possibility of flipping again. -jahka
+ */
+ mat3_to_quat_is_ok(cache[p]->rot, rotmat);
}
psys->totcached = totpart;
@@ -3024,7 +3052,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
float birthtime = 0.0, dietime = 0.0;
float t, time = 0.0, keytime = 0.0, frs_sec;
- float hairmat[4][4], rotmat[3][3], prev_tangent[3];
+ float hairmat[4][4], rotmat[3][3], prev_tangent[3] = {0.0f, 0.0f, 0.0f};
int k, i;
int steps = (int)pow(2.0, (double)pset->draw_step);
int totpart = edit->totpoint, recalc_set=0;
@@ -3046,12 +3074,8 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
frs_sec = (psys || edit->pid.flag & PTCACHE_VEL_PER_SEC) ? 25.0f : 1.0f;
- if(pset->brushtype == PE_BRUSH_WEIGHT){
- /* use weight painting colors now... */
-#if 0
- sel_col[0] = sel_col[1] = sel_col[2] = 1.0f;
- nosel_col[0] = nosel_col[1] = nosel_col[2] = 0.0f;
-#endif
+ if(pset->brushtype == PE_BRUSH_WEIGHT) {
+ ;/* use weight painting colors now... */
}
else{
sel_col[0] = (float)edit->sel_col[0] / 255.0f;
@@ -3079,6 +3103,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
/* should init_particle_interpolation set this ? */
if(pset->brushtype==PE_BRUSH_WEIGHT){
pind.hkey[0] = NULL;
+ /* pa != NULL since the weight brush is only available for hair */
pind.hkey[1] = pa->hair;
}
@@ -3092,9 +3117,9 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
if(psys) {
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
- VECCOPY(rotmat[0], hairmat[2]);
- VECCOPY(rotmat[1], hairmat[1]);
- VECCOPY(rotmat[2], hairmat[0]);
+ copy_v3_v3(rotmat[0], hairmat[2]);
+ copy_v3_v3(rotmat[1], hairmat[1]);
+ copy_v3_v3(rotmat[2], hairmat[0]);
}
birthtime = pind.birthtime;
@@ -3108,66 +3133,32 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
/*--interpolate actual path from data points--*/
for(k=0, ca=cache[i]; k<=steps; k++, ca++){
time = (float)k / (float)steps;
-
t = birthtime + time * (dietime - birthtime);
-
result.time = -t;
-
- do_particle_interpolation(psys, i, pa, t, frs_sec, &pind, &result);
+ do_particle_interpolation(psys, i, pa, t, &pind, &result);
+ copy_v3_v3(ca->co, result.co);
/* non-hair points are already in global space */
if(psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- mul_m4_v3(hairmat, result.co);
+ mul_m4_v3(hairmat, ca->co);
- /* create rotations for proper creation of children */
if(k) {
- float cosangle, angle, tangent[3], normal[3], q[4];
-
- if(k == 1) {
- /* calculate initial tangent for incremental rotations */
- VECSUB(tangent, ca->co, (ca - 1)->co);
- normalize_v3_v3(prev_tangent, tangent);
-
- /* First rotation is based on emitting face orientation. */
- /* This is way better than having flipping rotations resulting */
- /* from using a global axis as a rotation pole (vec_to_quat()). */
- /* It's not an ideal solution though since it disregards the */
- /* initial tangent, but taking that in to account will allow */
- /* the possibility of flipping again. -jahka */
- mat3_to_quat_is_ok( (ca-1)->rot,rotmat);
- }
- else {
- VECSUB(tangent, ca->co, (ca - 1)->co);
- normalize_v3(tangent);
-
- cosangle= dot_v3v3(tangent, prev_tangent);
-
- /* note we do the comparison on cosangle instead of
- * angle, since floating point accuracy makes it give
- * different results across platforms */
- if(cosangle > 0.999999f) {
- QUATCOPY((ca - 1)->rot, (ca - 2)->rot);
- }
- else {
- angle= saacos(cosangle);
- cross_v3_v3v3(normal, prev_tangent, tangent);
- axis_angle_to_quat( q,normal, angle);
- mul_qt_qtqt((ca - 1)->rot, q, (ca - 2)->rot);
- }
-
- VECCOPY(prev_tangent, tangent);
- }
+ cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k);
if(k == steps)
- QUATCOPY(ca->rot, (ca - 1)->rot);
- }
-
- }
+ copy_qt_qt(ca->rot, (ca - 1)->rot);
- VECCOPY(ca->co, result.co);
+ /* set velocity */
+ sub_v3_v3v3(ca->vel, ca->co, (ca - 1)->co);
- ca->vel[0] = ca->vel[1] = 0.0f;
- ca->vel[1] = 1.0f;
+ if(k==1)
+ copy_v3_v3((ca - 1)->vel, ca->vel);
+ }
+ }
+ else {
+ ca->vel[0] = ca->vel[1] = 0.0f;
+ ca->vel[1] = 1.0f;
+ }
/* selection coloring in edit mode */
if(pset->brushtype==PE_BRUSH_WEIGHT){
@@ -3215,12 +3206,27 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
ca->time = t;
}
+ if(psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
+ /* First rotation is based on emitting face orientation.
+ * This is way better than having flipping rotations resulting
+ * from using a global axis as a rotation pole (vec_to_quat()).
+ * It's not an ideal solution though since it disregards the
+ * initial tangent, but taking that in to account will allow
+ * the possibility of flipping again. -jahka
+ */
+ mat3_to_quat_is_ok(cache[i]->rot, rotmat);
+ }
}
edit->totcached = totpart;
if(psys) {
- ParticleSimulationData sim = {scene, ob, psys, psys_get_modifier(ob, psys), NULL};
+ ParticleSimulationData sim= {0};
+ sim.scene= scene;
+ sim.ob= ob;
+ sim.psys= psys;
+ sim.psmd= psys_get_modifier(ob, psys);
+
psys_cache_child_paths(&sim, cfra, 1);
}
@@ -3338,7 +3344,7 @@ static void psys_face_mat(Object *ob, DerivedMesh *dm, ParticleData *pa, float m
triatomat(v[0], v[1], v[2], (osface)? osface->uv: NULL, mat);
}
-void psys_mat_hair_to_object(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[][4])
+void psys_mat_hair_to_object(Object *UNUSED(ob), DerivedMesh *dm, short from, ParticleData *pa, float hairmat[][4])
{
float vec[3];
@@ -3380,7 +3386,7 @@ void psys_mat_hair_to_global(Object *ob, DerivedMesh *dm, short from, ParticleDa
/************************************************/
/* ParticleSettings handling */
/************************************************/
-ModifierData *object_add_particle_system(Scene *scene, Object *ob, char *name)
+ModifierData *object_add_particle_system(Scene *scene, Object *ob, const char *name)
{
ParticleSystem *psys;
ModifierData *md;
@@ -3419,7 +3425,7 @@ ModifierData *object_add_particle_system(Scene *scene, Object *ob, char *name)
psys->cfra=bsystem_time(scene,ob,scene->r.cfra+1,0.0);
DAG_scene_sort(G.main, scene);
- DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
return md;
}
@@ -3456,7 +3462,7 @@ void object_remove_particle_system(Scene *scene, Object *ob)
ob->mode &= ~OB_MODE_PARTICLE_EDIT;
DAG_scene_sort(G.main, scene);
- DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
static void default_particle_settings(ParticleSettings *part)
{
@@ -3467,7 +3473,7 @@ static void default_particle_settings(ParticleSettings *part)
part->bb_uv_split=1;
part->bb_align=PART_BB_VIEW;
part->bb_split_offset=PART_BB_OFF_LINEAR;
- part->flag=PART_REACT_MULTIPLE|PART_HAIR_GEOMETRY|PART_EDISTR|PART_TRAND;
+ part->flag=PART_EDISTR|PART_TRAND|PART_HIDE_ADVANCED_HAIR;
part->sta= 1.0;
part->end= 200.0;
@@ -3486,6 +3492,7 @@ static void default_particle_settings(ParticleSettings *part)
part->adapt_angle= 5;
part->adapt_pix= 3;
part->kink_axis= 2;
+ part->kink_amp_clump= 1.f;
part->reactevent= PART_EVENT_DEATH;
part->disp=100;
part->from= PART_FROM_FACE;
@@ -3537,7 +3544,7 @@ static void default_particle_settings(ParticleSettings *part)
}
-ParticleSettings *psys_new_settings(char *name, Main *main)
+ParticleSettings *psys_new_settings(const char *name, Main *main)
{
ParticleSettings *part;
@@ -3817,7 +3824,7 @@ float psys_get_child_time(ParticleSystem *psys, ChildParticle *cpa, float cfra,
return (cfra-time)/life;
}
-float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float cfra, float *pa_time)
+float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float UNUSED(cfra), float *UNUSED(pa_time))
{
ParticleSettings *part = psys->part;
float size; // time XXX
@@ -3898,26 +3905,42 @@ static void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *pte
int i = cpa - sim->psys->child;
int guided = 0;
+ float kink_freq = part->kink_freq;
+ float rough1 = part->rough1;
+ float rough2 = part->rough2;
+ float rough_end = part->rough_end;
+
+ if(ptex) {
+ kink_freq *= ptex->kink;
+ rough1 *= ptex->rough1;
+ rough2 *= ptex->rough2;
+ rough_end *= ptex->roughe;
+ }
+
if(part->flag & PART_CHILD_EFFECT)
/* state is safe to cast, since only co and vel are used */
guided = do_guides(sim->psys->effectors, (ParticleKey*)state, cpa->parent, t);
if(guided==0){
- if(part->kink)
- do_prekink(state, par, par_rot, t, part->kink_freq * ptex->kink, part->kink_shape,
- part->kink_amp, part->kink, part->kink_axis, sim->ob->obmat);
-
- do_clump(state, par, t, part->clumpfac, part->clumppow, ptex->clump);
+ float clump = do_clump(state, par, t, part->clumpfac, part->clumppow, ptex ? ptex->clump : 1.f);
+
+ if(kink_freq != 0.f) {
+ float kink_amp = part->kink_amp * (1.f - part->kink_amp_clump * clump);
+
+ do_kink(state, par, par_rot, t, kink_freq, part->kink_shape,
+ kink_amp, part->kink_flat, part->kink, part->kink_axis,
+ sim->ob->obmat, sim->psys->part->childtype == PART_CHILD_FACES);
+ }
}
- if(part->rough1 != 0.0 && ptex->rough1 != 0.0)
- do_rough(orco, mat, t, ptex->rough1*part->rough1, part->rough1_size, 0.0, state);
+ if(rough1 > 0.f)
+ do_rough(orco, mat, t, rough1, part->rough1_size, 0.0, state);
- if(part->rough2 != 0.0 && ptex->rough2 != 0.0)
- do_rough(sim->psys->frand + ((i + 27) % (PSYS_FRAND_COUNT - 3)), mat, t, ptex->rough2*part->rough2, part->rough2_size, part->rough2_thres, state);
+ if(rough2 > 0.f)
+ do_rough(sim->psys->frand + ((i + 27) % (PSYS_FRAND_COUNT - 3)), mat, t, rough2, part->rough2_size, part->rough2_thres, state);
- if(part->rough_end != 0.0 && ptex->roughe != 0.0)
- do_rough_end(sim->psys->frand + ((i + 27) % (PSYS_FRAND_COUNT - 3)), mat, t, ptex->roughe*part->rough_end, part->rough_end_shape, state);
+ if(rough_end > 0.f)
+ do_rough_end(sim->psys->frand + ((i + 27) % (PSYS_FRAND_COUNT - 3)), mat, t, rough_end, part->rough_end_shape, state);
}
/* get's hair (or keyed) particles state at the "path time" specified in state->time */
void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *state, int vel)
@@ -3933,10 +3956,9 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
ParticleThreadContext ctx; /* fake thread context for child modifiers */
ParticleInterpolationData pind;
- float t, frs_sec = sim->scene->r.frs_sec;
+ float t;
float co[3], orco[3];
float hairmat[4][4];
- int totparent = 0;
int totpart = psys->totpart;
int totchild = psys->totchild;
short between = 0, edit = 0;
@@ -3946,11 +3968,8 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
float *cpa_fuv; int cpa_num; short cpa_from;
- //if(psys_in_edit_mode(scene, psys)){
- // if((psys->edit_path->flag & PSYS_EP_SHOW_CHILD)==0)
- // totchild=0;
- // edit=1;
- //}
+ /* initialize keys to zero */
+ memset(keys, 0, 4*sizeof(ParticleKey));
t=state->time;
CLAMP(t, 0.0, 1.0);
@@ -3965,7 +3984,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
* account when subdividing for instance */
pind.dm = psys_in_edit_mode(sim->scene, psys) ? NULL : psys->hair_out_dm;
init_particle_interpolation(sim->ob, psys, pa, &pind);
- do_particle_interpolation(psys, p, pa, t, frs_sec, &pind, state);
+ do_particle_interpolation(psys, p, pa, t, &pind, state);
if(!keyed && !cached) {
if((pa->flag & PARS_REKEY)==0) {
@@ -3992,11 +4011,6 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
t = psys_get_child_time(psys, cpa, -state->time, NULL, NULL);
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;
}
@@ -4027,7 +4041,10 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
pa = psys->particles + cpa->parent;
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat);
+ if(part->type == PART_HAIR)
+ psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat);
+ else
+ unit_m4(hairmat);
pa=0;
}
@@ -4043,9 +4060,16 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
cpa_num=pa->num;
cpa_fuv=pa->fuv;
- psys_particle_on_emitter(psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,0,0,0,orco,0);
+
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat);
+ if(part->type == PART_HAIR) {
+ psys_particle_on_emitter(psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,0,0,0,orco,0);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat);
+ }
+ else {
+ copy_v3_v3(orco, cpa->fuv);
+ unit_m4(hairmat);
+ }
}
/* correct child ipo timing */
@@ -4086,7 +4110,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
}
else{
/* offset the child from the parent position */
- offset_child(cpa, keys, state, part->childflat, part->childrad);
+ offset_child(cpa, keys, keys->rot, state, part->childflat, part->childrad);
}
par = keys;
@@ -4165,11 +4189,11 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
if(pa) {
if(!always)
- if((pa->alive==PARS_UNBORN && (part->flag & PART_UNBORN)==0)
- || (pa->alive==PARS_DEAD && (part->flag & PART_DIED)==0))
+ if((cfra < pa->time && (part->flag & PART_UNBORN)==0)
+ || (cfra > pa->dietime && (part->flag & PART_DIED)==0))
return 0;
- state->time = MIN2(state->time, pa->dietime);
+ cfra = MIN2(cfra, pa->dietime);
}
if(sim->psys->flag & PSYS_KEYED){
@@ -4179,41 +4203,42 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
}
else{
if(cpa){
+ float mat[4][4];
ParticleKey *key1;
float t = (cfra - pa->time) / pa->lifetime;
key1=&pa->state;
- offset_child(cpa, key1, state, part->childflat, part->childrad);
-
+ offset_child(cpa, key1, key1->rot, state, part->childflat, part->childrad);
+
CLAMP(t,0.0,1.0);
- if(part->kink) /* TODO: part->kink_freq*pa_kink */
- do_prekink(state,key1,key1->rot,t,part->kink_freq,part->kink_shape,part->kink_amp,part->kink,part->kink_axis,sim->ob->obmat);
-
- /* TODO: pa_clump vgroup */
- do_clump(state,key1,t,part->clumpfac,part->clumppow,1.0);
+
+ unit_m4(mat);
+ do_child_modifiers(sim, NULL, key1, key1->rot, cpa, cpa->fuv, mat, state, t);
if(psys->lattice)
calc_latt_deform(sim->psys->lattice, state->co,1.0f);
}
else{
- if(pa->state.time==state->time || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED)
- || pa->prev_state.time <= 0.0f)
+ if(pa->state.time==cfra || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED))
copy_particle_key(state, &pa->state, 1);
- else if(pa->prev_state.time==state->time)
+ else if(pa->prev_state.time==cfra)
copy_particle_key(state, &pa->prev_state, 1);
else {
+ float dfra, frs_sec = sim->scene->r.frs_sec;
/* let's interpolate to try to be as accurate as possible */
- if(pa->state.time + 2.0f > state->time && pa->prev_state.time - 2.0f < state->time) {
- ParticleKey keys[4];
- float dfra, keytime, frs_sec = sim->scene->r.frs_sec;
+ if(pa->state.time + 2.f >= state->time && pa->prev_state.time - 2.f <= state->time) {
+ if(pa->prev_state.time >= pa->state.time || pa->prev_state.time < 0.f) {
+ /* prev_state is wrong so let's not use it, this can happen at frames 1, 0 or particle birth */
+ dfra = state->time - pa->state.time;
- 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);
+ madd_v3_v3v3fl(state->co, state->co, state->vel, dfra/frs_sec);
}
else {
+ ParticleKey keys[4];
+ float keytime;
+
copy_particle_key(keys+1, &pa->prev_state, 1);
copy_particle_key(keys+2, &pa->state, 1);
@@ -4228,12 +4253,21 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
psys_interpolate_particle(-1, keys, keytime, state, 1);
/* convert back to real velocity */
- mul_v3_fl(state->vel, 1.0f / (dfra * timestep));
+ mul_v3_fl(state->vel, 1.f / (dfra * timestep));
interp_v3_v3v3(state->ave, keys[1].ave, keys[2].ave, keytime);
interp_qt_qtqt(state->rot, keys[1].rot, keys[2].rot, keytime);
}
}
+ else if(pa->state.time + 1.f >= state->time && pa->state.time - 1.f <= state->time) {
+ /* linear interpolation using only pa->state */
+
+ dfra = state->time - pa->state.time;
+
+ copy_particle_key(state, &pa->state, 1);
+
+ madd_v3_v3v3fl(state->co, state->co, state->vel, dfra/frs_sec);
+ }
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);
@@ -4248,7 +4282,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
}
}
-void psys_get_dupli_texture(Object *ob, ParticleSettings *part, ParticleSystemModifierData *psmd, ParticleData *pa, ChildParticle *cpa, float *uv, float *orco)
+void psys_get_dupli_texture(Object *UNUSED(ob), ParticleSettings *part, ParticleSystemModifierData *psmd, ParticleData *pa, ChildParticle *cpa, float *uv, float *orco)
{
MFace *mface;
MTFace *mtface;
@@ -4353,7 +4387,7 @@ void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa
normalize_v3(side);
cross_v3_v3v3(nor, vec, side);
- unit_m4(mat);
+ unit_m4(mat);
VECCOPY(mat[0], vec);
VECCOPY(mat[1], side);
VECCOPY(mat[2], nor);
@@ -4448,7 +4482,11 @@ void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3]
void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys) {
- ParticleSimulationData sim = {scene, ob, psys, psys_get_modifier(ob, psys)};
+ ParticleSimulationData sim= {0};
+ sim.scene= scene;
+ sim.ob= ob;
+ sim.psys= psys;
+ sim.psmd= psys_get_modifier(ob, psys);
psys->lattice = psys_get_lattice(&sim);