diff options
author | Ton Roosendaal <ton@blender.org> | 2005-04-04 22:09:47 +0400 |
---|---|---|
committer | Ton Roosendaal <ton@blender.org> | 2005-04-04 22:09:47 +0400 |
commit | 7a377bcb05c2634a872208680aca80cc9e9a0c11 (patch) | |
tree | 787ce3fb287b9206f6a5084b25551c8fb2735979 /source/blender/blenkernel | |
parent | 04e4b72e063702dc16cf41dd97c5776d03742bde (diff) |
- Made SoftBody work with Particle Force Fields.
- Added new (Particle) Deflector; type Wind.
Wind gives constant directional force. It is animatable (Ipos) and reacts
to Object scaling. Also uses FallOff. Works for particles and SoftBody
quick movie check; http://www.blender.org/bf/0001_0250.avi
test file is in download.blender.org/demo/test/wind_soft.blend
- Added MaxDist option for forcefields, to control its influence better.
Is drawn as circle in 3d window.
Forcefields are a bit weak still... should react to scaling, or not; in
that case drawing should indicate it (done for spherical field now).
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/BKE_effect.h | 8 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/effect.c | 122 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/softbody.c | 82 |
3 files changed, 157 insertions, 55 deletions
diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h index 21663b39dd3..a5ca3708a22 100644 --- a/source/blender/blenkernel/BKE_effect.h +++ b/source/blender/blenkernel/BKE_effect.h @@ -61,5 +61,13 @@ void build_particle_system(struct Object *ob); void calc_wave_deform(struct WaveEff *wav, float ctime, float *co); int object_wave(struct Object *ob); +/* particle deflector */ +void pdDoEffector(float *opco, float *force, float *speed, float cur_time, unsigned int par_layer); +int pdDoDeflection(float opco[3], float npco[3], float opno[3], + float npno[3], float life, float force[3], int def_depth, + float cur_time, unsigned int par_layer, int *last_object, + int *last_face, int *same_face); + + #endif diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 6fe6b708f58..d811b5c0fbb 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -380,11 +380,18 @@ static int linetriangle(float p1[3], float p2[3], float v0[3], float v1[3], floa return 1; } -static void get_effector(float opco[], float force[], float speed[], float cur_time, unsigned int par_layer) +/* -------- pdDoEffector() -------- + generic force/speed system, now used for particles and softbodies + opco = global coord, as input + force = force accumulator + speed = speed accumulator + cur_time = in frames + par_layer = layer the caller is in + +*/ +void pdDoEffector(float *opco, float *force, float *speed, float cur_time, unsigned int par_layer) { /* - Particle effector field code - Modifies the force on a particle according to its relation with the effector object Different kind of effectors include: @@ -397,46 +404,75 @@ static void get_effector(float opco[], float force[], float speed[], float cur_t */ Object *ob; Base *base; + PartDeflect *pd; float vect_to_vert[3]; float force_vec[3]; float f_force, distance; - float obloc[3]; + float *obloc; float force_val, ffall_val; short cur_frame; /* Cycle through objects, get total of (1/(gravity_strength * dist^gravity_power)) */ - /* Check for min distance here? */ - base = G.scene->base.first; - while (base) { - if(base->lay & par_layer) { + /* Check for min distance here? (yes would be cool to add that, ton) */ + + for(base = G.scene->base.first; base; base= base->next) { + if( (base->lay & par_layer) && base->object->pd) { ob= base->object; - if(ob->pd && ob->pd->forcefield == PFIELD_FORCE) { - - /* Need to set r.cfra for paths (investigate, ton) */ + pd= ob->pd; + + /* checking if to continue or not */ + if(pd->forcefield==0) continue; + + /* Get IPO force strength and fall off values here */ + if (has_ipo_code(ob->ipo, OB_PD_FSTR)) + force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, cur_time); + else + force_val = pd->f_strength; + + if (has_ipo_code(ob->ipo, OB_PD_FFALL)) + ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, cur_time); + else + ffall_val = pd->f_power; + + + /* Need to set r.cfra for paths (investigate, ton) (uses ob->ctime now, ton) */ + if(ob->ctime!=cur_time) { cur_frame = G.scene->r.cfra; G.scene->r.cfra = (short)cur_time; where_is_object_time(ob, cur_time); G.scene->r.cfra = cur_frame; + } + + /* use center of object for distance calculus */ + obloc= ob->obmat[3]; + VECSUB(vect_to_vert, obloc, opco); + distance = VecLength(vect_to_vert); + + if((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist) + ; /* don't do anything */ + else if(pd->forcefield == PFIELD_WIND) { + VECCOPY(force_vec, ob->obmat[2]); - /* only use center of object */ - obloc[0] = ob->obmat[3][0]; - obloc[1] = ob->obmat[3][1]; - obloc[2] = ob->obmat[3][2]; + /* wind works harder perpendicular to normal, would be nice for softbody later (ton) */ - /* Get IPO force strength and fall off values here */ - if (has_ipo_code(ob->ipo, OB_PD_FSTR)) - force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, cur_time); - else - force_val = ob->pd->f_strength; - - if (has_ipo_code(ob->ipo, OB_PD_FFALL)) - ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, cur_time); - else - ffall_val = ob->pd->f_power; + /* Limit minimum distance to vertex so that */ + /* the force is not too big */ + if (distance < 0.001) distance = 0.001f; + f_force = (force_val)*(1/(1000 * (float)pow((double)distance, (double)ffall_val))); + + force[0] += force_vec[0]*f_force; + force[1] += force_vec[1]*f_force; + force[2] += force_vec[2]*f_force; + + } + else if(pd->forcefield == PFIELD_FORCE) { + + /* only use center of object */ + obloc= ob->obmat[3]; /* Now calculate the gravitational force */ VECSUB(vect_to_vert, obloc, opco); - distance = Normalise(vect_to_vert); + distance = VecLength(vect_to_vert); /* Limit minimum distance to vertex so that */ /* the force is not too big */ @@ -447,33 +483,14 @@ static void get_effector(float opco[], float force[], float speed[], float cur_t force[2] += (vect_to_vert[2] * f_force ); } - else if(ob->pd && ob->pd->forcefield == PFIELD_VORTEX) { - /* Need to set r.cfra for paths (investigate, ton) */ - cur_frame = G.scene->r.cfra; - G.scene->r.cfra = (short)cur_time; - where_is_object_time(ob, cur_time); - G.scene->r.cfra = cur_frame; - - /* only use center of object */ - obloc[0] = ob->obmat[3][0]; - obloc[1] = ob->obmat[3][1]; - obloc[2] = ob->obmat[3][2]; - - /* Get IPO force strength and fall off values here */ - if (has_ipo_code(ob->ipo, OB_PD_FSTR)) - force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, cur_time); - else - force_val = ob->pd->f_strength; + else if(pd->forcefield == PFIELD_VORTEX) { - if (has_ipo_code(ob->ipo, OB_PD_FFALL)) - ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, cur_time); - else - ffall_val = ob->pd->f_power; + /* only use center of object */ + obloc= ob->obmat[3]; /* Now calculate the vortex force */ VECSUB(vect_to_vert, obloc, opco); - - distance = Normalise(vect_to_vert); + distance = VecLength(vect_to_vert); Crossf(force_vec, ob->obmat[2], vect_to_vert); Normalise(force_vec); @@ -488,7 +505,6 @@ static void get_effector(float opco[], float force[], float speed[], float cur_t } } - base = base->next; } } @@ -513,7 +529,7 @@ static void cache_object_vertices(Object *ob) } } -static int get_deflection(float opco[3], float npco[3], float opno[3], +int pdDoDeflection(float opco[3], float npco[3], float opno[3], float npno[3], float life, float force[3], int def_depth, float cur_time, unsigned int par_layer, int *last_object, int *last_face, int *same_face) @@ -875,7 +891,7 @@ void make_particle_keys(int depth, int nr, PartEff *paf, Particle *part, float * /* Check force field */ cur_time = pa->time; - get_effector(opco, new_force, new_speed, cur_time, par_layer); + pdDoEffector(opco, new_force, new_speed, cur_time, par_layer); /* new location */ pa->co[0]= opa->co[0] + deltalife * (opa->no[0] + new_speed[0] + 0.5f*new_force[0]); @@ -910,7 +926,7 @@ void make_particle_keys(int depth, int nr, PartEff *paf, Particle *part, float * /* Bail out if we've done the calculation 10 times - this seems ok */ /* for most scenes I've tested */ while (finish_defs) { - deflected = get_deflection(opco, npco, opno, npno, life, new_force, + deflected = pdDoDeflection(opco, npco, opno, npno, life, new_force, def_count, cur_time, par_layer, &last_ob, &last_fc, &same_fc); if (deflected) { diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 240dfffa438..30e244eee93 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -69,6 +69,7 @@ variables on the UI for now #include "BLI_arithb.h" #include "BKE_displist.h" +#include "BKE_effect.h" #include "BKE_global.h" #include "BKE_object.h" #include "BKE_softbody.h" @@ -268,6 +269,22 @@ static void Vec3PlusStVec(float *v, float s, float *v1) v[2] += s*v1[2]; } +#define USES_FIELD 1 +#define USES_DEFLECT 2 +static int is_there_deflection(unsigned int layer) +{ + Base *base; + int retval= 0; + + for(base = G.scene->base.first; base; base= base->next) { + if( (base->lay & layer) && base->object->pd) { + if(base->object->pd->forcefield) retval |= USES_FIELD; + if(base->object->pd->deflect) retval |= USES_DEFLECT; + } + } + return retval; +} + static void softbody_calc_forces(Object *ob, float dtime) { @@ -276,13 +293,16 @@ static void softbody_calc_forces(Object *ob, float dtime) BodyPoint *bproot; BodySpring *bs; float iks, ks, kd, gravity, actspringlen, forcefactor, sd[3]; - int a, b; + int a, b, do_effector; /* clear forces */ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { bp->force[0]= bp->force[1]= bp->force[2]= 0.0; } + /* check! */ + do_effector= is_there_deflection(ob->lay); + gravity = sb->nodemass * sb->grav * rescale_grav_to_framerate; iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */ bproot= sb->bpoint; /* need this for proper spring addressing */ @@ -334,6 +354,49 @@ static void softbody_calc_forces(Object *ob, float dtime) /* this is the place where other forces can be added yes, constraints and collision stuff should go here too (read baraff papers on that!) */ + + /* particle field & deflectors */ + if(do_effector & USES_FIELD) { + float force[3]= {0.0f, 0.0f, 0.0f}; + float speed[3]= {0.0f, 0.0f, 0.0f}; + + pdDoEffector(bp->pos, force, speed, (float)G.scene->r.cfra, ob->lay); + /* apply force */ + // VecMulf(force, rescale_grav_to_framerate); <- didn't work, made value far too low! + VECADD(bp->force, bp->force, force); + /* apply speed. note; deflector can give 'speed' only.... */ + VecMulf(speed, rescale_grav_to_framerate); + VECADD(bp->vec, bp->vec, speed); + } +#if 0 + /* copied from particles... doesn't work really! */ + if(do_effector & USES_DEFLECT) { + int deflected; + int last_ob = -1; + int last_fc = -1; + int same_fc = 0; + float last[3], lastv[3]; + int finish_defs = 1; + int def_count = 0; + + VecSubf(last, bp->pos, bp->vec); + VECCOPY(lastv, bp->vec); + + while (finish_defs) { + deflected= pdDoDeflection(last, bp->pos, lastv, + bp->vec, dtime, bp->force, 0, + G.scene->r.cfra, ob->lay, &last_ob, &last_fc, &same_fc); + if (deflected) { + def_count = def_count + 1; + //deflection = 1; + if (def_count==10) finish_defs = 0; + } + else { + finish_defs = 0; + } + } + } +#endif /*other forces done*/ /* nice things could be done with anisotropic friction @@ -974,7 +1037,7 @@ void sbObjectReset(Object *ob) bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0f; // no idea about the Heun stuff! (ton) - VECCOPY(bp->prevpos, bp->vec); + VECCOPY(bp->prevpos, bp->pos); VECCOPY(bp->prevvec, bp->vec); VECCOPY(bp->prevdx, bp->vec); VECCOPY(bp->prevdv, bp->vec); @@ -987,6 +1050,7 @@ void sbObjectReset(Object *ob) void sbObjectStep(Object *ob, float framenr) { SoftBody *sb; + Base *base; float dtime; int timescale,t; float ctime, forcetime; @@ -1003,6 +1067,11 @@ void sbObjectStep(Object *ob, float framenr) /* still no points? go away */ if(sb->totpoint==0) return; + /* reset deflector cache, sumohandle is free, but its still sorta abuse... (ton) */ + for(base= G.scene->base.first; base; base= base->next) { + base->object->sumohandle= NULL; + } + /* checking time: */ ctime= bsystem_time(ob, NULL, framenr, 0.0); softbody_scale_time(steptime); // translate frames/sec and lenghts unit to SI system @@ -1124,5 +1193,14 @@ void sbObjectStep(Object *ob, float framenr) // so here it is ! softbody_to_object(ob); } + + /* reset deflector cache */ + for(base= G.scene->base.first; base; base= base->next) { + if(base->object->sumohandle) { + MEM_freeN(base->object->sumohandle); + base->object->sumohandle= NULL; + } + } + } |