diff options
Diffstat (limited to 'source/blender/blenkernel/intern/effect.c')
-rw-r--r-- | source/blender/blenkernel/intern/effect.c | 155 |
1 files changed, 147 insertions, 8 deletions
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 33125ceeb02..fe8f5ebdca6 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -43,6 +43,7 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_object_force.h" +#include "DNA_particle_types.h" #include "DNA_texture_types.h" #include "DNA_scene_types.h" @@ -66,6 +67,7 @@ #include "BKE_library.h" #include "BKE_modifier.h" #include "BKE_object.h" +#include "BKE_particle.h" #include "BKE_scene.h" #include "BKE_smoke.h" @@ -143,11 +145,12 @@ void free_partdeflect(PartDeflect *pd) MEM_freeN(pd); } -static EffectorCache *new_effector_cache(Scene *scene, Object *ob, PartDeflect *pd) +static EffectorCache *new_effector_cache(Scene *scene, Object *ob, ParticleSystem *psys, PartDeflect *pd) { EffectorCache *eff = MEM_callocN(sizeof(EffectorCache), "EffectorCache"); eff->scene = scene; eff->ob = ob; + eff->psys = psys; eff->pd = pd; eff->frame = -1; return eff; @@ -170,16 +173,40 @@ static void add_object_to_effectors(ListBase **effectors, Scene *scene, Effector if (*effectors == NULL) *effectors = MEM_callocN(sizeof(ListBase), "effectors list"); - eff = new_effector_cache(scene, ob, ob->pd); + eff = new_effector_cache(scene, ob, NULL, ob->pd); /* make sure imat is up to date */ invert_m4_m4(ob->imat, ob->obmat); BLI_addtail(*effectors, eff); } +static void add_particles_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, ParticleSystem *psys, ParticleSystem *psys_src, bool for_simulation) +{ + ParticleSettings *part= psys->part; + + if ( !psys_check_enabled(ob, psys, G.is_rendering) ) + return; + + if ( psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0) + return; + + if ( part->pd && part->pd->forcefield && (!for_simulation || weights->weight[part->pd->forcefield] != 0.0f)) { + if (*effectors == NULL) + *effectors = MEM_callocN(sizeof(ListBase), "effectors list"); + + BLI_addtail(*effectors, new_effector_cache(scene, ob, psys, part->pd)); + } + + if (part->pd2 && part->pd2->forcefield && (!for_simulation || weights->weight[part->pd2->forcefield] != 0.0f)) { + if (*effectors == NULL) + *effectors = MEM_callocN(sizeof(ListBase), "effectors list"); + + BLI_addtail(*effectors, new_effector_cache(scene, ob, psys, part->pd2)); + } +} /* returns ListBase handle with objects taking part in the effecting */ -ListBase *pdInitEffectors(Scene *scene, Object *ob_src, +ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src, EffectorWeights *weights, bool for_simulation) { Base *base; @@ -193,6 +220,13 @@ ListBase *pdInitEffectors(Scene *scene, Object *ob_src, if ( (go->ob->lay & layer) ) { if ( go->ob->pd && go->ob->pd->forcefield ) add_object_to_effectors(&effectors, scene, weights, go->ob, ob_src, for_simulation); + + if ( go->ob->particlesystem.first ) { + ParticleSystem *psys= go->ob->particlesystem.first; + + for ( ; psys; psys=psys->next ) + add_particles_to_effectors(&effectors, scene, weights, go->ob, psys, psys_src, for_simulation); + } } } } @@ -201,6 +235,13 @@ ListBase *pdInitEffectors(Scene *scene, Object *ob_src, if ( (base->lay & layer) ) { if ( base->object->pd && base->object->pd->forcefield ) add_object_to_effectors(&effectors, scene, weights, base->object, ob_src, for_simulation); + + if ( base->object->particlesystem.first ) { + ParticleSystem *psys= base->object->particlesystem.first; + + for ( ; psys; psys=psys->next ) + add_particles_to_effectors(&effectors, scene, weights, base->object, psys, psys_src, for_simulation); + } } } } @@ -253,6 +294,8 @@ static void precalculate_effector(EffectorCache *eff) if (eff->ob->type == OB_CURVE) eff->flag |= PE_USE_NORMAL_DATA; } + else if (eff->psys) + psys_update_particle_tree(eff->psys, eff->scene->r.cfra); /* Store object velocity */ if (eff->ob) { @@ -275,6 +318,36 @@ void pdPrecalculateEffectors(ListBase *effectors) } +void pd_point_from_particle(ParticleSimulationData *sim, ParticleData *pa, ParticleKey *state, EffectedPoint *point) +{ + ParticleSettings *part = sim->psys->part; + point->loc = state->co; + point->vel = state->vel; + point->index = pa - sim->psys->particles; + point->size = pa->size; + point->charge = 0.0f; + + if (part->pd && part->pd->forcefield == PFIELD_CHARGE) + point->charge += part->pd->f_strength; + + if (part->pd2 && part->pd2->forcefield == PFIELD_CHARGE) + point->charge += part->pd2->f_strength; + + point->vel_to_sec = 1.0f; + point->vel_to_frame = psys_get_timestep(sim); + + point->flag = 0; + + if (sim->psys->part->flag & PART_ROT_DYN) { + point->ave = state->ave; + point->rot = state->rot; + } + else + point->ave = point->rot = NULL; + + point->psys = sim->psys; +} + void pd_point_from_loc(Scene *scene, float *loc, float *vel, int index, EffectedPoint *point) { point->loc = loc; @@ -288,6 +361,7 @@ void pd_point_from_loc(Scene *scene, float *loc, float *vel, int index, Effected point->flag = 0; point->ave = point->rot = NULL; + point->psys = NULL; } void pd_point_from_soft(Scene *scene, float *loc, float *vel, int index, EffectedPoint *point) { @@ -302,6 +376,8 @@ void pd_point_from_soft(Scene *scene, float *loc, float *vel, int index, Effecte point->flag = PE_WIND_AS_SPEED; point->ave = point->rot = NULL; + + point->psys = NULL; } /************************************************/ /* Effectors */ @@ -414,7 +490,7 @@ static float falloff_func_rad(PartDeflect *pd, float fac) return falloff_func(fac, pd->flag&PFIELD_USEMINR, pd->minrad, pd->flag&PFIELD_USEMAXR, pd->maxrad, pd->f_power_r); } -static float effector_falloff(EffectorCache *eff, EffectorData *efd, EffectedPoint *UNUSED(point), EffectorWeights *weights) +float effector_falloff(EffectorCache *eff, EffectorData *efd, EffectedPoint *UNUSED(point), EffectorWeights *weights) { float temp[3]; float falloff = weights ? weights->weight[0] * weights->weight[eff->pd->forcefield] : 1.0f; @@ -489,6 +565,7 @@ int closest_point_on_surface(SurfaceModifierData *surmd, const float co[3], floa } int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int real_velocity) { + float cfra = eff->scene->r.cfra; int ret = 0; /* In case surface object is in Edit mode when loading the .blend, surface modifier is never executed @@ -525,6 +602,43 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin ret = 1; } } + else if (eff->psys) { + ParticleData *pa = eff->psys->particles + *efd->index; + ParticleKey state; + + /* exclude the particle itself for self effecting particles */ + if (eff->psys == point->psys && *efd->index == point->index) { + /* pass */ + } + else { + ParticleSimulationData sim= {NULL}; + sim.scene= eff->scene; + sim.ob= eff->ob; + sim.psys= eff->psys; + + /* TODO: time from actual previous calculated frame (step might not be 1) */ + state.time = cfra - 1.0f; + ret = psys_get_particle_state(&sim, *efd->index, &state, 0); + + /* TODO */ + //if (eff->pd->forcefiled == PFIELD_HARMONIC && ret==0) { + // if (pa->dietime < eff->psys->cfra) + // eff->flag |= PE_VELOCITY_TO_IMPULSE; + //} + + copy_v3_v3(efd->loc, state.co); + + /* rather than use the velocity use rotated x-axis (defaults to velocity) */ + efd->nor[0] = 1.f; + efd->nor[1] = efd->nor[2] = 0.f; + mul_qt_v3(state.rot, efd->nor); + + if (real_velocity) + copy_v3_v3(efd->vel, state.vel); + + efd->size = pa->size; + } + } else { /* use center of object for distance calculus */ const Object *ob = eff->ob; @@ -576,7 +690,7 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin return ret; } -static void get_effector_tot(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int *tot, int *p) +static void get_effector_tot(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int *tot, int *p, int *step) { *p = 0; efd->index = p; @@ -589,6 +703,31 @@ static void get_effector_tot(EffectorCache *eff, EffectorData *efd, EffectedPoin *tot = *p+1; } } + else if (eff->psys) { + *tot = eff->psys->totpart; + + if (eff->pd->forcefield == PFIELD_CHARGE) { + /* Only the charge of the effected particle is used for + * interaction, not fall-offs. If the fall-offs aren't the + * same this will be unphysical, but for animation this + * could be the wanted behavior. If you want physical + * correctness the fall-off should be spherical 2.0 anyways. + */ + efd->charge = eff->pd->f_strength; + } + else if (eff->pd->forcefield == PFIELD_HARMONIC && (eff->pd->flag & PFIELD_MULTIPLE_SPRINGS)==0) { + /* every particle is mapped to only one harmonic effector particle */ + *p= point->index % eff->psys->totpart; + *tot= *p + 1; + } + + if (eff->psys->part->effector_amount) { + int totpart = eff->psys->totpart; + int amount = eff->psys->part->effector_amount; + + *step = (totpart > amount) ? totpart/amount : 1; + } + } else { *tot = 1; } @@ -854,7 +993,7 @@ void pdDoEffectors(ListBase *effectors, ListBase *colliders, EffectorWeights *we */ EffectorCache *eff; EffectorData efd; - int p=0, tot = 1; + int p=0, tot = 1, step = 1; /* Cycle through collected objects, get total of (1/(gravity_strength * dist^gravity_power)) */ /* Check for min distance here? (yes would be cool to add that, ton) */ @@ -862,9 +1001,9 @@ void pdDoEffectors(ListBase *effectors, ListBase *colliders, EffectorWeights *we if (effectors) for (eff = effectors->first; eff; eff=eff->next) { /* object effectors were fully checked to be OK to evaluate! */ - get_effector_tot(eff, &efd, point, &tot, &p); + get_effector_tot(eff, &efd, point, &tot, &p, &step); - for (; p<tot; p++) { + for (; p<tot; p+=step) { if (get_effector_data(eff, &efd, point, 0)) { efd.falloff= effector_falloff(eff, &efd, point, weights); |