- Regarding the Peach "hair effectors" request in the mailing list I coded quick support so that effectors now can effect combed hair too. Nothing special needed to use, just normal field effectors, although there is a new "stiff" parameter in extras panel. (Note, at least for now this only works with path visualization)

- Keyed particles work again for all visualizations (previously only "path"), they still need some work though to be fully operational.
- Keyed particles weren't saved or loaded correctly.
This commit is contained in:
Janne Karhu 2008-01-17 00:28:14 +00:00
parent 4e4e69050c
commit cb025f95de
8 changed files with 165 additions and 79 deletions

@ -289,6 +289,8 @@ void psys_particle_on_dm(struct Object *ob, struct DerivedMesh *dm, int from, in
void initialize_particle(struct ParticleData *pa, int p, struct Object *ob, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd); void initialize_particle(struct ParticleData *pa, int p, struct Object *ob, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd);
void reset_particle(struct ParticleData *pa, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd, struct Object *ob, float dtime, float cfra, float *vg_vel, float *vg_tan, float *vg_rot); void reset_particle(struct ParticleData *pa, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd, struct Object *ob, float dtime, float cfra, float *vg_vel, float *vg_tan, float *vg_rot);
void do_effectors(int pa_no, struct ParticleData *pa, struct ParticleKey *state, struct Object *ob, struct ParticleSystem *psys, float *force_field, float *vel,float framestep, float cfra);
void psys_calc_dmfaces(struct Object *ob, struct DerivedMesh *dm, struct ParticleSystem *psys); void psys_calc_dmfaces(struct Object *ob, struct DerivedMesh *dm, struct ParticleSystem *psys);
int psys_particle_dm_face_lookup(struct Object *ob, struct DerivedMesh *dm, int index, float *fw, struct LinkNode *node); int psys_particle_dm_face_lookup(struct Object *ob, struct DerivedMesh *dm, int index, float *fw, struct LinkNode *node);

@ -2249,6 +2249,7 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda
char nosel[4], sel[4]; char nosel[4], sel[4];
float sel_col[3]; float sel_col[3];
float nosel_col[3]; float nosel_col[3];
float length, vec[3];
/* we don't have anything valid to create paths from so let's quit here */ /* we don't have anything valid to create paths from so let's quit here */
if((psys->flag & PSYS_HAIR_DONE)==0 && (psys->flag & PSYS_KEYED)==0) if((psys->flag & PSYS_HAIR_DONE)==0 && (psys->flag & PSYS_KEYED)==0)
@ -2417,7 +2418,6 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda
: ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL) : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL)
,keys, keytime, &result); ,keys, keytime, &result);
/* the velocity needs to be converted back from cubic interpolation */ /* the velocity needs to be converted back from cubic interpolation */
if(psys->flag & PSYS_KEYED){ if(psys->flag & PSYS_KEYED){
VecMulf(result.vel, frs_sec / dfra); VecMulf(result.vel, frs_sec / dfra);
@ -2426,11 +2426,48 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda
Mat4MulVecfl(hairmat, result.co); Mat4MulVecfl(hairmat, result.co);
} }
VECCOPY(ca->co, result.co);
}
/*--modify paths--*/
VecSubf(vec,(cache[i]+1)->co,cache[i]->co);
length = VecLength(vec);
for(k=0, ca=cache[i]; k<=steps; k++, ca++) {
/* apply effectors */
if(edit==0 && k) {
float force[3] = {0.0f,0.0f,0.0f}, vel[3] = {0.0f,0.0f,0.0f};
ParticleKey eff_key;
VECCOPY(eff_key.co,(ca-1)->co);
VECCOPY(eff_key.vel,(ca-1)->vel);
QUATCOPY(eff_key.rot,(ca-1)->rot);
do_effectors(i, pa, &eff_key, ob, psys, force, vel, dfra, cfra);
VecMulf(force, pow((float)k / (float)steps, 100.0f * psys->part->eff_hair) * steps);
VecAddf(force, force, vec);
Normalize(force);
if(k < steps) {
VecSubf(vec, (ca+1)->co, ca->co);
length = VecLength(vec);
}
VECADDFAC(ca->co, (ca-1)->co, force, length);
}
/* apply guide curves to path data */ /* apply guide curves to path data */
if(edit==0 && psys->effectors.first && (psys->part->flag & PART_CHILD_GUIDE)==0) if(edit==0 && psys->effectors.first && (psys->part->flag & PART_CHILD_GUIDE)==0)
do_guide(&result, i, time, &psys->effectors); do_guide(&result, i, time, &psys->effectors);
/* apply lattice */
if(psys->lattice && edit==0)
calc_latt_deform(ca->co, 1.0f);
/* figure out rotation */ /* figure out rotation */
if(k) { if(k) {
@ -2439,7 +2476,7 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda
if(k == 1) { if(k == 1) {
float *q2; float *q2;
VECSUB(tangent, result.co, (ca - 1)->co); VECSUB(tangent, ca->co, (ca - 1)->co);
q2 = vectoquat(tangent, OB_POSX, OB_POSZ); q2 = vectoquat(tangent, OB_POSX, OB_POSZ);
@ -2449,7 +2486,7 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda
Normalize(prev_tangent); Normalize(prev_tangent);
} }
else { else {
VECSUB(tangent, result.co, (ca - 1)->co); VECSUB(tangent, ca->co, (ca - 1)->co);
Normalize(tangent); Normalize(tangent);
angle = saacos(Inpf(tangent, prev_tangent)); angle = saacos(Inpf(tangent, prev_tangent));
@ -2470,7 +2507,8 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda
} }
} }
VECCOPY(ca->co, result.co);
/* set velocity */
if(k){ if(k){
VECSUB(ca->vel, ca->co, (ca-1)->co); VECSUB(ca->vel, ca->co, (ca-1)->co);
@ -2512,9 +2550,6 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda
else{ else{
VECCOPY(ca->col, col); VECCOPY(ca->col, col);
} }
if(psys->lattice && edit==0)
calc_latt_deform(ca->co, 1.0f);
} }
} }
@ -3200,11 +3235,11 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle
ParticleData *pa; ParticleData *pa;
ChildParticle *cpa; ChildParticle *cpa;
ParticleTexture ptex; ParticleTexture ptex;
ParticleKey tstate; ParticleKey tstate, *kkey[2] = {NULL, NULL};
HairKey *hkey[2]; HairKey *hkey[2];
ParticleKey *par=0, keys[4]; ParticleKey *par=0, keys[4];
float t, real_t, dfra, keytime; float t, real_t, dfra, keytime, frs_sec = G.scene->r.frs_sec;
float co[3], orco[3]; float co[3], orco[3];
float imat[4][4], hairmat[4][4], cpa_1st[3]; float imat[4][4], hairmat[4][4], cpa_1st[3];
float pa_clump = 0.0, pa_kink = 0.0; float pa_clump = 0.0, pa_kink = 0.0;
@ -3239,11 +3274,29 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle
return; return;
} }
if(psys->flag & PSYS_KEYED) {
kkey[0] = pa->keys;
kkey[1] = kkey[0] + 1;
real_t = kkey[0]->time + t * (kkey[0][pa->totkey-1].time - kkey[0]->time);
}
else {
hkey[0] = pa->hair; hkey[0] = pa->hair;
hkey[1] = pa->hair + 1; hkey[1] = pa->hair + 1;
real_t = hkey[0]->time + (hkey[0][pa->totkey-1].time - hkey[0]->time) * t; real_t = hkey[0]->time + (hkey[0][pa->totkey-1].time - hkey[0]->time) * t;
}
if(psys->flag & PSYS_KEYED) {
while(kkey[1]->time < real_t) {
kkey[1]++;
}
kkey[0] = kkey[1] - 1;
memcpy(keys + 1, kkey[0], sizeof(ParticleKey));
memcpy(keys + 2, kkey[1], sizeof(ParticleKey));
}
else {
while(hkey[1]->time < real_t) while(hkey[1]->time < real_t)
hkey[1]++; hkey[1]++;
@ -3251,7 +3304,9 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle
hair_to_particle(keys + 1, hkey[0]); hair_to_particle(keys + 1, hkey[0]);
hair_to_particle(keys + 2, hkey[1]); hair_to_particle(keys + 2, hkey[1]);
}
if((psys->flag & PSYS_KEYED)==0) {
//if(soft){ //if(soft){
// if(key[0] != sbel.keys) // if(key[0] != sbel.keys)
// DB_copy_key(&k1,key[0]-1); // DB_copy_key(&k1,key[0]-1);
@ -3276,6 +3331,7 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle
hair_to_particle(keys + 3, hkey[1] + 1); hair_to_particle(keys + 3, hkey[1] + 1);
else else
hair_to_particle(keys + 3, hkey[1]); hair_to_particle(keys + 3, hkey[1]);
}
//} //}
//psys_get_particle_on_path(bsys,p,t,bkey,ckey[0]); //psys_get_particle_on_path(bsys,p,t,bkey,ckey[0]);
@ -3296,9 +3352,22 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle
keytime = (real_t - keys[1].time) / dfra; keytime = (real_t - keys[1].time) / dfra;
interpolate_particle((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL /* convert velocity to timestep size */
if(psys->flag & PSYS_KEYED){
VecMulf(keys[1].vel, dfra / frs_sec);
VecMulf(keys[2].vel, dfra / frs_sec);
QuatInterpol(state->rot,keys[1].rot,keys[2].rot,keytime);
}
interpolate_particle((psys->flag & PSYS_KEYED) ? -1 /* signal for cubic interpolation */
: ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL)
,keys, keytime, state); ,keys, keytime, state);
/* the velocity needs to be converted back from cubic interpolation */
if(psys->flag & PSYS_KEYED){
VecMulf(state->vel, frs_sec / dfra);
}
else {
if((pa->flag & PARS_REKEY)==0) { if((pa->flag & PARS_REKEY)==0) {
psys_mat_hair_to_global(ob, psmd->dm, part->from, pa, hairmat); psys_mat_hair_to_global(ob, psmd->dm, part->from, pa, hairmat);
Mat4MulVecfl(hairmat, state->co); Mat4MulVecfl(hairmat, state->co);
@ -3312,8 +3381,9 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle
calc_latt_deform(state->co,1.0f); calc_latt_deform(state->co,1.0f);
} }
} }
}
else if(totchild){ else if(totchild){
Mat4Invert(imat,ob->obmat); //Mat4Invert(imat,ob->obmat);
cpa=psys->child+p-totpart; cpa=psys->child+p-totpart;
@ -3345,19 +3415,9 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle
psys_particle_on_emitter(ob,psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa->fuv,foffset,co,0,0,0,orco,0); psys_particle_on_emitter(ob,psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa->fuv,foffset,co,0,0,0,orco,0);
/* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */ /* 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); //VECCOPY(cpa_1st,co);
//w=0; //Mat4MulVecfl(ob->obmat,cpa_1st);
//while(w<4 && cpa->pa[w]>=0){
// pa=psys->particles+cpa->pa[w];
// psys_particle_on_emitter(ob,psmd,part->from,pa->num,pa->fuv,pa->foffset,vec,0,0,0);
// cpa_1st[0] -= cpa->w[w]*vec[0];
// cpa_1st[1] -= cpa->w[w]*vec[1];
// cpa_1st[2] -= cpa->w[w]*vec[2];
// w++;
//}
Mat4MulVecfl(ob->obmat,cpa_1st);
pa=0; pa=0;
} }
@ -3412,7 +3472,7 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle
w++; w++;
} }
/* apply offset for correct positioning */ /* apply offset for correct positioning */
VECADD(state->co,state->co,cpa_1st); //VECADD(state->co,state->co,cpa_1st);
} }
else{ else{
/* offset the child from the parent position */ /* offset the child from the parent position */
@ -3452,19 +3512,18 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle
if(part->rough_end != 0.0) if(part->rough_end != 0.0)
do_rough_end(cpa->rand, t, part->rough_end, part->rough_end_shape, state, par); do_rough_end(cpa->rand, t, part->rough_end, part->rough_end_shape, state, par);
if(vel){ //if(vel){
if(t>=0.001f){ // if(t>=0.001f){
tstate.time=t-0.001f; // tstate.time=t-0.001f;
psys_get_particle_on_path(ob,psys,p,&tstate,0); // psys_get_particle_on_path(ob,psys,p,&tstate,0);
VECSUB(state->vel,state->co,tstate.co); // VECSUB(state->vel,state->co,tstate.co);
} // }
else{ // else{
tstate.time=t+0.001f; // tstate.time=t+0.001f;
psys_get_particle_on_path(ob,psys,p,&tstate,0); // psys_get_particle_on_path(ob,psys,p,&tstate,0);
VECSUB(state->vel,tstate.co,state->co); // VECSUB(state->vel,tstate.co,state->co);
} // }
} //}
} }
} }
/* gets particle's state at a time, returns 1 if particle exists and can be seen and 0 if not */ /* gets particle's state at a time, returns 1 if particle exists and can be seen and 0 if not */
@ -3505,18 +3564,18 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey
return 0; return 0;
} }
//if(bsys->flag & (BSYS_DONE|BSYS_KEYED)){ if(psys->flag & PSYS_KEYED){
// if(between){ if(between){
// //ChildParticle *cpa=psys->child+p-totpart; ChildParticle *cpa=psys->child+p-totpart;
// //state->time= (cfra-(part->sta+(part->end-part->sta)*cpa->rand[0]))/(part->lifetime*cpa->rand[1]); state->time= (cfra-(part->sta+(part->end-part->sta)*cpa->rand[0]))/(part->lifetime*cpa->rand[1]);
// } }
// else else
// state->time= (cfra-pa->time)/(pa->dietime-pa->time);//pa->lifetime; state->time= (cfra-pa->time)/(pa->dietime-pa->time);
// psys_get_particle_on_path(ob,psys,p,state,1); psys_get_particle_on_path(ob,psys,p,state,1);
// return 1; return 1;
//} }
//else{ else{
//if(psys->totchild && p>=psys->totpart){ //if(psys->totchild && p>=psys->totpart){
// ChildParticle *cpa=psys->child+p-psys->totpart; // ChildParticle *cpa=psys->child+p-psys->totpart;
// ParticleKey *key1, skey; // ParticleKey *key1, skey;
@ -3560,7 +3619,7 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey
//} //}
return 1; return 1;
//} }
} }
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 *ob, ParticleSettings *part, ParticleSystemModifierData *psmd, ParticleData *pa, ChildParticle *cpa, float *uv, float *orco)

@ -2607,7 +2607,7 @@ static void precalc_effectors(Object *ob, ParticleSystem *psys, ParticleSystemMo
/* calculate forces that all effectors apply to a particle*/ /* calculate forces that all effectors apply to a particle*/
static void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, ParticleSystem *psys, float *force_field, float *vel,float framestep, float cfra) void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, ParticleSystem *psys, float *force_field, float *vel,float framestep, float cfra)
{ {
Object *eob; Object *eob;
ParticleSystem *epsys; ParticleSystem *epsys;
@ -4054,7 +4054,11 @@ static void dynamics_step(Object *ob, ParticleSystem *psys, ParticleSystemModifi
if(cfra <= pa->time) if(cfra <= pa->time)
pa->alive = PARS_UNBORN; pa->alive = PARS_UNBORN;
/* without dynamics the state is allways known so no need to kill */ /* without dynamics the state is allways known so no need to kill */
else if(ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED)==0) else if(ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)){
if(cfra < pa->dietime)
pa->alive = PARS_ALIVE;
}
else
pa->alive = PARS_KILLED; pa->alive = PARS_KILLED;
} }
} }
@ -4398,7 +4402,9 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier
return; return;
} }
} }
else if(part->phystype != PART_PHYS_NO) { /* cache shouldn't be used for none physics */ else if(ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED))
; /* cache shouldn't be used for "none" or "keyed" physics */
else {
if(psys->recalc && (psys->flag & PSYS_PROTECT_CACHE) == 0) if(psys->recalc && (psys->flag & PSYS_PROTECT_CACHE) == 0)
clear_particles_from_cache(ob,psys,(int)cfra); clear_particles_from_cache(ob,psys,(int)cfra);
else if(get_particles_from_cache(ob, psys, (int)cfra)) { else if(get_particles_from_cache(ob, psys, (int)cfra)) {
@ -4502,7 +4508,10 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier
psys->recalc = 0; psys->recalc = 0;
psys->cfra = cfra; psys->cfra = cfra;
if(part->type!=PART_HAIR) if(part->type == PART_HAIR || part->phystype == PART_PHYS_NO
|| (part->phystype == PART_PHYS_KEYED && psys->flag & PSYS_FIRST_KEYED))
; /* cache shouldn't be used for hair or "none" or "first keyed" physics */
else
write_particles_to_cache(ob, psys, cfra); write_particles_to_cache(ob, psys, cfra);
/* for keyed particles the path is allways known so it can be drawn */ /* for keyed particles the path is allways known so it can be drawn */

@ -2526,6 +2526,11 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
for(a=0; a<psys->totpart; a++, pa++) for(a=0; a<psys->totpart; a++, pa++)
pa->hair=newdataadr(fd,pa->hair); pa->hair=newdataadr(fd,pa->hair);
} }
if(psys->particles && psys->particles->keys){
ParticleData *pa = psys->particles;
for(a=0; a<psys->totpart; a++, pa++)
pa->keys=newdataadr(fd,pa->keys);
}
psys->child=newdataadr(fd,psys->child); psys->child=newdataadr(fd,psys->child);
psys->effectors.first=psys->effectors.last=0; psys->effectors.first=psys->effectors.last=0;

@ -558,6 +558,13 @@ static void write_particlesystems(WriteData *wd, ListBase *particles)
for(a=0; a<psys->totpart; a++, pa++) for(a=0; a<psys->totpart; a++, pa++)
writestruct(wd, DATA, "HairKey", pa->totkey, pa->hair); writestruct(wd, DATA, "HairKey", pa->totkey, pa->hair);
} }
if(psys->particles->keys) {
ParticleData *pa = psys->particles;
for(a=0; a<psys->totpart; a++, pa++)
writestruct(wd, DATA, "ParticleKey", pa->totkey, pa->keys);
}
} }
if(psys->child) writestruct(wd, DATA, "ChildParticle", psys->totchild ,psys->child); if(psys->child) writestruct(wd, DATA, "ChildParticle", psys->totchild ,psys->child);
writestruct(wd, DATA, "SoftBody", 1, psys->soft); writestruct(wd, DATA, "SoftBody", 1, psys->soft);

@ -128,7 +128,7 @@ typedef struct ParticleSettings {
/* general values */ /* general values */
float sta, end, lifetime, randlife; float sta, end, lifetime, randlife;
float timetweak, jitfac, keyed_time; float timetweak, jitfac, keyed_time, eff_hair, rt;
int totpart, userjit, grid_res; int totpart, userjit, grid_res;
/* initial velocity factors */ /* initial velocity factors */

@ -3912,9 +3912,13 @@ static void object_panel_particle_extra(Object *ob)
buty=butx=160; buty=butx=160;
uiDefButI(block, NUM, B_PART_DISTR, "Seed:", butx,(buty-=buth),butw,buth, &psys->seed, 0.0, 255.0, 1, 0, "Set an offset in the random table"); uiDefButI(block, NUM, B_PART_DISTR, "Seed:", butx,(buty-=buth),butw,buth, &psys->seed, 0.0, 255.0, 1, 0, "Set an offset in the random table");
if(part->type == PART_HAIR && psys->flag & PSYS_EDITED)
uiDefButF(block, NUM, B_PART_RECALC, "Stiff:", butx,(buty-=buth),butw,buth, &part->eff_hair, 0.0, 1.0, 0, 0, "Hair stiffness for effectors");
else
buty-=buth;
/* size changes must create a recalc event always so that sizes are updated properly */ /* size changes must create a recalc event always so that sizes are updated properly */
uiDefButF(block, NUM, B_PART_RECALC, "Size:", butx,(buty-=2*buth),butw,buth, &part->size, 0.01, 100, 10, 1, "The size of the particles"); uiDefButF(block, NUM, B_PART_RECALC, "Size:", butx,(buty-=buth),butw,buth, &part->size, 0.01, 100, 10, 1, "The size of the particles");
uiDefButF(block, NUM, B_PART_RECALC, "Rand:", butx,(buty-=buth),butw,buth, &part->randsize, 0.0, 2.0, 10, 1, "Give the particle size a random variation"); uiDefButF(block, NUM, B_PART_RECALC, "Rand:", butx,(buty-=buth),butw,buth, &part->randsize, 0.0, 2.0, 10, 1, "Give the particle size a random variation");
uiDefButBitI(block, TOG, PART_SIZEMASS, B_PART_RECALC, "Mass from size", butx,(buty-=buth),butw,buth, &part->flag, 0, 0, 0, 0, "Multiply mass with particle size"); uiDefButBitI(block, TOG, PART_SIZEMASS, B_PART_RECALC, "Mass from size", butx,(buty-=buth),butw,buth, &part->flag, 0, 0, 0, 0, "Multiply mass with particle size");

@ -3037,7 +3037,7 @@ static void draw_new_particle_system(Base *base, ParticleSystem *psys)
psys->flag|=PSYS_DRAWING; psys->flag|=PSYS_DRAWING;
if(!psys->childcache) if(part->type==PART_HAIR && !psys->childcache)
totchild=0; totchild=0;
else else
totchild=psys->totchild*part->disp/100; totchild=psys->totchild*part->disp/100;