diff options
author | Janne Karhu <jhkarh@gmail.com> | 2012-02-12 04:25:52 +0400 |
---|---|---|
committer | Janne Karhu <jhkarh@gmail.com> | 2012-02-12 04:25:52 +0400 |
commit | a7458742b1f87c918fad6e7f0081e5d2b2e94125 (patch) | |
tree | c60197638edd28fd2d135a4e86a7617a357fdba8 /source | |
parent | 0327b9a0cf9cac49936a09a9fc943be5e5337813 (diff) |
Fix [#29265] Particle Instance: Create Along Paths + Children inconsistent with actual children hair particles
* Hair particle rotations weren't calculated properly for particle locations along a path and the "particle on path" calculations were not correct in many other ways too.
* Now the particle's location along a path is interpolated directly from the cached paths if it exist. These paths are always correctly calculated.
* Paths are now cached if a particle instance modifier using the particle system with the path option exists.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/intern/particle.c | 297 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/particle_system.c | 14 |
2 files changed, 190 insertions, 121 deletions
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index cd3933d3c44..8bd5b55e778 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -1365,6 +1365,35 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData if(pind->keyed || pind->cache || point_vel) mul_v3_fl(result->vel, 1.f/invdt); } + +static void interpolate_pathcache(ParticleCacheKey *first, float t, ParticleCacheKey *result) +{ + int i=0; + ParticleCacheKey *cur = first; + + /* scale the requested time to fit the entire path even if the path is cut early */ + t *= (first+first->steps)->time; + + while(i<first->steps && cur->time < t) + cur++; + + if(cur->time == t) + *result = *cur; + else { + float dt = (t-(cur-1)->time)/(cur->time-(cur-1)->time); + interp_v3_v3v3(result->co, (cur-1)->co, cur->co, dt); + interp_v3_v3v3(result->vel, (cur-1)->vel, cur->vel, dt); + interp_qt_qtqt(result->rot, (cur-1)->rot, cur->rot, dt); + result->time = t; + } + + /* first is actual base rotation, others are incremental from first */ + if(cur==first || cur-1==first) + copy_qt_qt(result->rot, first->rot); + else + mul_qt_qtqt(result->rot, first->rot, result->rot); +} + /************************************************/ /* Particles on a dm */ /************************************************/ @@ -2648,6 +2677,8 @@ static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle /* offset the child from the parent position */ offset_child(cpa, (ParticleKey*)(key[0]+k), par_rot, (ParticleKey*)child, part->childflat, part->childrad); } + + child->time = (float)k/(float)ctx->steps; } /* apply effectors */ @@ -3009,6 +3040,8 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra) if(k==1) copy_v3_v3((ca-1)->vel, ca->vel); + + ca->time = (float)k/(float)steps; } /* First rotation is based on emitting face orientation. * This is way better than having flipping rotations resulting @@ -4013,84 +4046,105 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey * CLAMP(t, 0.0f, 1.0f); if(p<totpart){ - pa = psys->particles + p; - pind.keyed = keyed; - pind.cache = cached ? psys->pointcache : NULL; - pind.epoint = NULL; - pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE); - /* pind.dm disabled in editmode means we dont get effectors taken into - * 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, &pind, state); - - if(pind.dm) { - mul_m4_v3(sim->ob->obmat, state->co); - mul_mat3_m4_v3(sim->ob->obmat, state->vel); - } - else if(!keyed && !cached && !(psys->flag & PSYS_GLOBAL_HAIR)) { - if((pa->flag & PARS_REKEY)==0) { - psys_mat_hair_to_global(sim->ob, sim->psmd->dm, part->from, pa, hairmat); - mul_m4_v3(hairmat, state->co); - mul_mat3_m4_v3(hairmat, state->vel); - - if(sim->psys->effectors && (part->flag & PART_CHILD_GUIDE)==0) { - do_guides(sim->psys->effectors, state, p, state->time); - /* TODO: proper velocity handling */ - } + /* interpolate pathcache directly if it exist */ + if(psys->pathcache) { + ParticleCacheKey result; + interpolate_pathcache(psys->pathcache[p], t, &result); + copy_v3_v3(state->co, result.co); + copy_v3_v3(state->vel, result.vel); + copy_qt_qt(state->rot, result.rot); + } + /* otherwise interpolate with other means */ + else { + pa = psys->particles + p; + + pind.keyed = keyed; + pind.cache = cached ? psys->pointcache : NULL; + pind.epoint = NULL; + pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE); + /* pind.dm disabled in editmode means we dont get effectors taken into + * 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, &pind, state); + + if(pind.dm) { + mul_m4_v3(sim->ob->obmat, state->co); + mul_mat3_m4_v3(sim->ob->obmat, state->vel); + } + else if(!keyed && !cached && !(psys->flag & PSYS_GLOBAL_HAIR)) { + if((pa->flag & PARS_REKEY)==0) { + psys_mat_hair_to_global(sim->ob, sim->psmd->dm, part->from, pa, hairmat); + mul_m4_v3(hairmat, state->co); + mul_mat3_m4_v3(hairmat, state->vel); + + if(sim->psys->effectors && (part->flag & PART_CHILD_GUIDE)==0) { + do_guides(sim->psys->effectors, state, p, state->time); + /* TODO: proper velocity handling */ + } - if(psys->lattice && edit==0) - calc_latt_deform(psys->lattice, state->co,1.0f); + if(psys->lattice && edit==0) + calc_latt_deform(psys->lattice, state->co,1.0f); + } } } } else if(totchild){ //invert_m4_m4(imat,ob->obmat); - cpa=psys->child+p-totpart; + /* interpolate childcache directly if it exists */ + if(psys->childcache) { + ParticleCacheKey result; + interpolate_pathcache(psys->childcache[p-totpart], t, &result); + copy_v3_v3(state->co, result.co); + copy_v3_v3(state->vel, result.vel); + copy_qt_qt(state->rot, result.rot); + } + else { + cpa=psys->child+p-totpart; - if(state->time < 0.0f) - t = psys_get_child_time(psys, cpa, -state->time, NULL, NULL); + if(state->time < 0.0f) + t = psys_get_child_time(psys, cpa, -state->time, NULL, NULL); - if(totchild && part->childtype==PART_CHILD_FACES){ - /* part->parents could still be 0 so we can't test with totparent */ - between=1; - } - if(between){ - int w = 0; - float foffset; - - /* get parent states */ - while(w<4 && cpa->pa[w]>=0){ - keys[w].time = state->time; - psys_get_particle_on_path(sim, cpa->pa[w], keys+w, 1); - w++; + if(totchild && part->childtype==PART_CHILD_FACES){ + /* part->parents could still be 0 so we can't test with totparent */ + between=1; } + if(between){ + int w = 0; + float foffset; + + /* get parent states */ + while(w<4 && cpa->pa[w]>=0){ + keys[w].time = state->time; + psys_get_particle_on_path(sim, cpa->pa[w], keys+w, 1); + w++; + } - /* get the original coordinates (orco) for texture usage */ - cpa_num=cpa->num; + /* get the original coordinates (orco) for texture usage */ + cpa_num=cpa->num; - foffset= cpa->foffset; - cpa_fuv = cpa->fuv; - cpa_from = PART_FROM_FACE; + foffset= cpa->foffset; + cpa_fuv = cpa->fuv; + cpa_from = PART_FROM_FACE; - psys_particle_on_emitter(psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa->fuv,foffset,co,0,0,0,orco,0); + psys_particle_on_emitter(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 */ - //copy_v3_v3(cpa_1st,co); + /* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */ + //copy_v3_v3(cpa_1st,co); - //mul_m4_v3(ob->obmat,cpa_1st); + //mul_m4_v3(ob->obmat,cpa_1st); - pa = psys->particles + cpa->parent; + pa = psys->particles + cpa->parent; - if(part->type == PART_HAIR) - psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat); - else - unit_m4(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; - } - else{ + pa=0; + } + else{ /* get the parent state */ keys->time = state->time; psys_get_particle_on_path(sim, cpa->parent, keys,1); @@ -4114,74 +4168,75 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey * } } - /* correct child ipo timing */ -#if 0 // XXX old animation system - if((part->flag&PART_ABS_TIME)==0 && part->ipo){ - calc_ipo(part->ipo, 100.0f*t); - execute_ipo((ID *)part, part->ipo); - } -#endif // XXX old animation system + /* correct child ipo timing */ + #if 0 // XXX old animation system + if((part->flag&PART_ABS_TIME)==0 && part->ipo){ + calc_ipo(part->ipo, 100.0f*t); + execute_ipo((ID *)part, part->ipo); + } + #endif // XXX old animation system - /* get different child parameters from textures & vgroups */ - memset(&ctx, 0, sizeof(ParticleThreadContext)); - ctx.sim = *sim; - ctx.dm = psmd->dm; - ctx.ma = ma; - /* TODO: assign vertex groups */ - get_child_modifier_parameters(part, &ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex); - - if(between){ - int w=0; + /* get different child parameters from textures & vgroups */ + memset(&ctx, 0, sizeof(ParticleThreadContext)); + ctx.sim = *sim; + ctx.dm = psmd->dm; + ctx.ma = ma; + /* TODO: assign vertex groups */ + get_child_modifier_parameters(part, &ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex); + + if(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; + + /* child position is the weighted sum of parent positions */ + while(w<4 && cpa->pa[w]>=0){ + state->co[0] += cpa->w[w] * keys[w].co[0]; + state->co[1] += cpa->w[w] * keys[w].co[1]; + state->co[2] += cpa->w[w] * keys[w].co[2]; + + state->vel[0] += cpa->w[w] * keys[w].vel[0]; + state->vel[1] += cpa->w[w] * keys[w].vel[1]; + state->vel[2] += cpa->w[w] * keys[w].vel[2]; + w++; + } + /* apply offset for correct positioning */ + //add_v3_v3(state->co, cpa_1st); + } + else{ + /* offset the child from the parent position */ + offset_child(cpa, keys, keys->rot, state, part->childflat, part->childrad); + } - state->co[0] = state->co[1] = state->co[2] = 0.0f; - state->vel[0] = state->vel[1] = state->vel[2] = 0.0f; + par = keys; - /* child position is the weighted sum of parent positions */ - while(w<4 && cpa->pa[w]>=0){ - state->co[0] += cpa->w[w] * keys[w].co[0]; - state->co[1] += cpa->w[w] * keys[w].co[1]; - state->co[2] += cpa->w[w] * keys[w].co[2]; - - state->vel[0] += cpa->w[w] * keys[w].vel[0]; - state->vel[1] += cpa->w[w] * keys[w].vel[1]; - state->vel[2] += cpa->w[w] * keys[w].vel[2]; - w++; - } - /* apply offset for correct positioning */ - //add_v3_v3(state->co, cpa_1st); - } - else{ - /* offset the child from the parent position */ - offset_child(cpa, keys, keys->rot, state, part->childflat, part->childrad); - } + if(vel) + copy_particle_key(&tstate, state, 1); - par = keys; + /* apply different deformations to the child path */ + do_child_modifiers(sim, &ptex, par, par->rot, cpa, orco, hairmat, state, t); - if(vel) - copy_particle_key(&tstate, state, 1); + /* try to estimate correct velocity */ + if(vel){ + ParticleKey tstate; + float length = len_v3(state->vel); - /* apply different deformations to the child path */ - do_child_modifiers(sim, &ptex, par, par->rot, cpa, orco, hairmat, state, t); - - /* try to estimate correct velocity */ - if(vel){ - ParticleKey tstate; - float length = len_v3(state->vel); - - if(t>=0.001f){ - tstate.time=t-0.001f; - psys_get_particle_on_path(sim,p,&tstate,0); - sub_v3_v3v3(state->vel,state->co,tstate.co); - normalize_v3(state->vel); - } - else{ - tstate.time=t+0.001f; - psys_get_particle_on_path(sim,p,&tstate,0); - sub_v3_v3v3(state->vel,tstate.co,state->co); - normalize_v3(state->vel); - } + if(t>=0.001f){ + tstate.time=t-0.001f; + psys_get_particle_on_path(sim,p,&tstate,0); + sub_v3_v3v3(state->vel,state->co,tstate.co); + normalize_v3(state->vel); + } + else{ + tstate.time=t+0.001f; + psys_get_particle_on_path(sim,p,&tstate,0); + sub_v3_v3v3(state->vel,tstate.co,state->co); + normalize_v3(state->vel); + } - mul_v3_fl(state->vel, length); + mul_v3_fl(state->vel, length); + } } } } diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 5a64da7354e..e853c0fee19 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -3407,6 +3407,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra) ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; ParticleEditSettings *pset = &sim->scene->toolsettings->particle; + Base *base; int distr=0, alloc=0, skip=0; if((psys->part->childtype && psys->totchild != get_psys_tot_child(sim->scene, psys)) || psys->recalc&PSYS_RECALC_RESET) @@ -3449,6 +3450,19 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra) } } + + /* particle instance modifier with "path" option need cached paths even if particle system doesn't */ + for (base = sim->scene->base.first; base; base= base->next) { + ModifierData *md = modifiers_findByType(base->object, eModifierType_ParticleInstance); + if(md) { + ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; + if(pimd->flag & eParticleInstanceFlag_Path && pimd->ob == sim->ob && pimd->psys == (psys - (ParticleSystem*)sim->ob->particlesystem.first)) { + skip = 0; + break; + } + } + } + if(!skip) { psys_cache_paths(sim, cfra); |