diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index d92e8bad1f9..399f67b7288 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -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 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); int psys_particle_dm_face_lookup(struct Object *ob, struct DerivedMesh *dm, int index, float *fw, struct LinkNode *node); diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 0ac60e6da4e..8b6d6126124 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -2249,6 +2249,7 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda char nosel[4], sel[4]; float sel_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 */ 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) ,keys, keytime, &result); - /* the velocity needs to be converted back from cubic interpolation */ if(psys->flag & PSYS_KEYED){ VecMulf(result.vel, frs_sec / dfra); @@ -2425,12 +2425,49 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda else if(soft==NULL) { /* softbody and keyed are allready in global space */ 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 */ if(edit==0 && psys->effectors.first && (psys->part->flag & PART_CHILD_GUIDE)==0) do_guide(&result, i, time, &psys->effectors); + /* apply lattice */ + if(psys->lattice && edit==0) + calc_latt_deform(ca->co, 1.0f); + /* figure out rotation */ if(k) { @@ -2439,7 +2476,7 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda if(k == 1) { float *q2; - VECSUB(tangent, result.co, (ca - 1)->co); + VECSUB(tangent, ca->co, (ca - 1)->co); 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); } else { - VECSUB(tangent, result.co, (ca - 1)->co); + VECSUB(tangent, ca->co, (ca - 1)->co); Normalize(tangent); angle = saacos(Inpf(tangent, prev_tangent)); @@ -2470,8 +2507,9 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda } } - VECCOPY(ca->co, result.co); + /* set velocity */ + if(k){ 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{ 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; ChildParticle *cpa; ParticleTexture ptex; - ParticleKey tstate; + ParticleKey tstate, *kkey[2] = {NULL, NULL}; HairKey *hkey[2]; 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 imat[4][4], hairmat[4][4], cpa_1st[3]; float pa_clump = 0.0, pa_kink = 0.0; @@ -3239,19 +3274,39 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle return; } - hkey[0] = pa->hair; - hkey[1] = pa->hair + 1; + if(psys->flag & PSYS_KEYED) { + kkey[0] = pa->keys; + kkey[1] = kkey[0] + 1; - real_t = hkey[0]->time + (hkey[0][pa->totkey-1].time - hkey[0]->time) * t; + real_t = kkey[0]->time + t * (kkey[0][pa->totkey-1].time - kkey[0]->time); + } + else { + hkey[0] = pa->hair; + hkey[1] = pa->hair + 1; - while(hkey[1]->time < real_t) - hkey[1]++; + real_t = hkey[0]->time + (hkey[0][pa->totkey-1].time - hkey[0]->time) * t; + } - hkey[0] = hkey[1] - 1; + if(psys->flag & PSYS_KEYED) { + while(kkey[1]->time < real_t) { + kkey[1]++; + } + kkey[0] = kkey[1] - 1; - hair_to_particle(keys + 1, hkey[0]); - hair_to_particle(keys + 2, hkey[1]); + memcpy(keys + 1, kkey[0], sizeof(ParticleKey)); + memcpy(keys + 2, kkey[1], sizeof(ParticleKey)); + } + else { + while(hkey[1]->time < real_t) + hkey[1]++; + hkey[0] = hkey[1] - 1; + + hair_to_particle(keys + 1, hkey[0]); + hair_to_particle(keys + 2, hkey[1]); + } + + if((psys->flag & PSYS_KEYED)==0) { //if(soft){ // if(key[0] != sbel.keys) // 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); else hair_to_particle(keys + 3, hkey[1]); + } //} //psys_get_particle_on_path(bsys,p,t,bkey,ckey[0]); @@ -3296,24 +3352,38 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle 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); - if((pa->flag & PARS_REKEY)==0) { - psys_mat_hair_to_global(ob, psmd->dm, part->from, pa, hairmat); - Mat4MulVecfl(hairmat, state->co); + /* 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) { + psys_mat_hair_to_global(ob, psmd->dm, part->from, pa, hairmat); + Mat4MulVecfl(hairmat, state->co); - if(psys->effectors.first && (part->flag & PART_CHILD_GUIDE)==0) { - do_guide(state, p, state->time, &psys->effectors); - /* TODO: proper velocity handling */ + if(psys->effectors.first && (part->flag & PART_CHILD_GUIDE)==0) { + do_guide(state, p, state->time, &psys->effectors); + /* TODO: proper velocity handling */ + } + + if(psys->lattice && edit==0) + calc_latt_deform(state->co,1.0f); } - - if(psys->lattice && edit==0) - calc_latt_deform(state->co,1.0f); } } else if(totchild){ - Mat4Invert(imat,ob->obmat); + //Mat4Invert(imat,ob->obmat); 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); /* 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; - //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); + //Mat4MulVecfl(ob->obmat,cpa_1st); pa=0; } @@ -3412,7 +3472,7 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle w++; } /* apply offset for correct positioning */ - VECADD(state->co,state->co,cpa_1st); + //VECADD(state->co,state->co,cpa_1st); } else{ /* 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) do_rough_end(cpa->rand, t, part->rough_end, part->rough_end_shape, state, par); - if(vel){ - if(t>=0.001f){ - tstate.time=t-0.001f; - psys_get_particle_on_path(ob,psys,p,&tstate,0); - VECSUB(state->vel,state->co,tstate.co); - } - else{ - tstate.time=t+0.001f; - psys_get_particle_on_path(ob,psys,p,&tstate,0); - VECSUB(state->vel,tstate.co,state->co); - } - } - + //if(vel){ + // if(t>=0.001f){ + // tstate.time=t-0.001f; + // psys_get_particle_on_path(ob,psys,p,&tstate,0); + // VECSUB(state->vel,state->co,tstate.co); + // } + // else{ + // tstate.time=t+0.001f; + // psys_get_particle_on_path(ob,psys,p,&tstate,0); + // 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 */ @@ -3505,18 +3564,18 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey return 0; } - //if(bsys->flag & (BSYS_DONE|BSYS_KEYED)){ - // if(between){ - // //ChildParticle *cpa=psys->child+p-totpart; - // //state->time= (cfra-(part->sta+(part->end-part->sta)*cpa->rand[0]))/(part->lifetime*cpa->rand[1]); - // } - // else - // state->time= (cfra-pa->time)/(pa->dietime-pa->time);//pa->lifetime; + if(psys->flag & PSYS_KEYED){ + if(between){ + ChildParticle *cpa=psys->child+p-totpart; + state->time= (cfra-(part->sta+(part->end-part->sta)*cpa->rand[0]))/(part->lifetime*cpa->rand[1]); + } + else + state->time= (cfra-pa->time)/(pa->dietime-pa->time); - // psys_get_particle_on_path(ob,psys,p,state,1); - // return 1; - //} - //else{ + psys_get_particle_on_path(ob,psys,p,state,1); + return 1; + } + else{ //if(psys->totchild && p>=psys->totpart){ // ChildParticle *cpa=psys->child+p-psys->totpart; // ParticleKey *key1, skey; @@ -3560,7 +3619,7 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey //} return 1; - //} + } } void psys_get_dupli_texture(Object *ob, ParticleSettings *part, ParticleSystemModifierData *psmd, ParticleData *pa, ChildParticle *cpa, float *uv, float *orco) diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index f69e7bcd05f..94cfdadbb16 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -2607,7 +2607,7 @@ static void precalc_effectors(Object *ob, ParticleSystem *psys, ParticleSystemMo /* 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; ParticleSystem *epsys; @@ -4050,12 +4050,16 @@ static void dynamics_step(Object *ob, ParticleSystem *psys, ParticleSystemModifi pa->alive=PARS_UNBORN; } else{ - pa->loop=0; - if(cfra<=pa->time) - pa->alive=PARS_UNBORN; + pa->loop = 0; + if(cfra <= pa->time) + pa->alive = PARS_UNBORN; /* without dynamics the state is allways known so no need to kill */ - else if(ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED)==0) - pa->alive=PARS_KILLED; + else if(ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)){ + if(cfra < pa->dietime) + pa->alive = PARS_ALIVE; + } + else + pa->alive = PARS_KILLED; } } @@ -4398,7 +4402,9 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier 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) clear_particles_from_cache(ob,psys,(int)cfra); else if(get_particles_from_cache(ob, psys, (int)cfra)) { @@ -4500,9 +4506,12 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier dynamics_step(ob,psys,psmd,cfra,vg_vel,vg_tan,vg_rot,vg_size); 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); /* for keyed particles the path is allways known so it can be drawn */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 4812d7e3904..6a2e3aa481a 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2526,6 +2526,11 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles) for(a=0; atotpart; a++, pa++) pa->hair=newdataadr(fd,pa->hair); } + if(psys->particles && psys->particles->keys){ + ParticleData *pa = psys->particles; + for(a=0; atotpart; a++, pa++) + pa->keys=newdataadr(fd,pa->keys); + } psys->child=newdataadr(fd,psys->child); psys->effectors.first=psys->effectors.last=0; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 9c013fbc1d0..fdea98c7ab2 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -558,6 +558,13 @@ static void write_particlesystems(WriteData *wd, ListBase *particles) for(a=0; atotpart; a++, pa++) writestruct(wd, DATA, "HairKey", pa->totkey, pa->hair); } + + if(psys->particles->keys) { + ParticleData *pa = psys->particles; + + for(a=0; atotpart; a++, pa++) + writestruct(wd, DATA, "ParticleKey", pa->totkey, pa->keys); + } } if(psys->child) writestruct(wd, DATA, "ChildParticle", psys->totchild ,psys->child); writestruct(wd, DATA, "SoftBody", 1, psys->soft); diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index f83c2a59799..d39fbbbc679 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -128,7 +128,7 @@ typedef struct ParticleSettings { /* general values */ float sta, end, lifetime, randlife; - float timetweak, jitfac, keyed_time; + float timetweak, jitfac, keyed_time, eff_hair, rt; int totpart, userjit, grid_res; /* initial velocity factors */ diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 1815fdd06f2..5443aa1de5e 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -3912,9 +3912,13 @@ static void object_panel_particle_extra(Object *ob) 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"); + 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 */ - 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"); 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"); diff --git a/source/blender/src/drawobject.c b/source/blender/src/drawobject.c index 2ae272cd5ba..3e154298517 100644 --- a/source/blender/src/drawobject.c +++ b/source/blender/src/drawobject.c @@ -3037,7 +3037,7 @@ static void draw_new_particle_system(Base *base, ParticleSystem *psys) psys->flag|=PSYS_DRAWING; - if(!psys->childcache) + if(part->type==PART_HAIR && !psys->childcache) totchild=0; else totchild=psys->totchild*part->disp/100;