diff options
Diffstat (limited to 'source/blender/blenkernel/intern/boids.c')
-rw-r--r-- | source/blender/blenkernel/intern/boids.c | 192 |
1 files changed, 83 insertions, 109 deletions
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index 7c3f3a7876f..712fb13cfc0 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -47,6 +47,7 @@ #include "BLI_blenlib.h" #include "BLI_kdtree.h" #include "BLI_kdopbvh.h" +#include "BKE_collision.h" #include "BKE_effect.h" #include "BKE_boids.h" #include "BKE_particle.h" @@ -72,112 +73,89 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, { BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid*) rule; BoidSettings *boids = bbd->part->boids; - ParticleEffectorCache *ec; - Object *priority_ob = NULL; BoidParticle *bpa = pa->boid; - float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; + EffectedPoint epoint; + ListBase *effectors = bbd->sim->psys->effectors; + EffectorCache *cur, *eff = NULL; + EffectorData efd, cur_efd; float mul = (rule->type == eBoidRuleType_Avoid ? 1.0 : -1.0); float priority = 0.0f, len = 0.0f; int ret = 0; - /* first find out goal/predator with highest priority */ - /* if rule->ob specified use it */ - if(gabr->ob && (rule->type != eBoidRuleType_Goal || gabr->ob != bpa->ground)) { - PartDeflect *pd = gabr->ob->pd; - float vec_to_part[3]; - - if(pd && pd->forcefield == PFIELD_BOID) { - effector_find_co(bbd->sim->scene, pa->prev_state.co, NULL, gabr->ob, pd, loc, vec, NULL, NULL); - - VecSubf(vec_to_part, pa->prev_state.co, loc); - - priority = mul * pd->f_strength * effector_falloff(pd, vec, vec_to_part); - } - else - priority = 1.0; - - priority = 1.0; - priority_ob = gabr->ob; - } - else for(ec=bbd->sim->psys->effectors.first; ec; ec=ec->next) { - if(ec->type & PSYS_EC_EFFECTOR) { - Object *eob = ec->ob; - PartDeflect *pd = eob->pd; - - /* skip current object */ - if(rule->type == eBoidRuleType_Goal && eob == bpa->ground) - continue; - - if(pd->forcefield == PFIELD_BOID && mul * pd->f_strength > 0.0f) { - float vec_to_part[3], temp; - - effector_find_co(bbd->sim->scene, pa->prev_state.co, NULL, eob, pd, loc, vec, NULL, NULL); - - VecSubf(vec_to_part, pa->prev_state.co, loc); + pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint); - temp = mul * pd->f_strength * effector_falloff(pd, vec, vec_to_part); - - if(temp == 0.0f) - ; /* do nothing */ - else if(temp > priority) { - priority = temp; - priority_ob = eob; - len = VecLength(vec_to_part); - } - /* choose closest object with same priority */ - else if(temp == priority) { - float len2 = VecLength(vec_to_part); - - if(len2 < len) { - priority_ob = eob; - len = len2; - } + /* first find out goal/predator with highest priority */ + if(effectors) for(cur = effectors->first; cur; cur=cur->next) { + Object *eob = cur->ob; + PartDeflect *pd = cur->pd; + + if(gabr->ob && (rule->type != eBoidRuleType_Goal || gabr->ob != bpa->ground)) { + if(gabr->ob == eob) { + /* TODO: objects without any effector and effectors with multiple points */ + if(get_effector_data(cur, &efd, &epoint, 0)) { + if(cur->pd && cur->pd->forcefield == PFIELD_BOID) + priority = mul * pd->f_strength * effector_falloff(cur, &efd, &epoint, bbd->part->effector_weights); + else + priority = 1.0; + + eff = cur; } + break; + } + } + else if(rule->type == eBoidRuleType_Goal && eob == bpa->ground) + ; /* skip current object */ + else if(pd->forcefield == PFIELD_BOID && mul * pd->f_strength > 0.0f && get_effector_data(eff, &efd, &epoint, 0)) { + float temp = mul * pd->f_strength * effector_falloff(cur, &cur_efd, &epoint, bbd->part->effector_weights); + + if(temp == 0.0f) + ; /* do nothing */ + else if(temp > priority) { + priority = temp; + eff = cur; + efd = cur_efd; + len = efd.distance; + } + /* choose closest object with same priority */ + else if(temp == priority && efd.distance < len) { + eff = cur; + efd = cur_efd; + len = efd.distance; } } } /* then use that effector */ if(priority > (rule->type==eBoidRuleType_Avoid ? gabr->fear_factor : 0.0f)) { /* with avoid, factor is "fear factor" */ - Object *eob = priority_ob; + Object *eob = eff->ob; PartDeflect *pd = eob->pd; - float vec_to_part[3]; - float surface = 0.0f; - float nor[3]; + float surface = pd->shape == PFIELD_SHAPE_SURFACE ? 1.0f : 0.0f; if(gabr->options & BRULE_GOAL_AVOID_PREDICT) { /* estimate future location of target */ - surface = (float)effector_find_co(bbd->sim->scene, pa->prev_state.co, NULL, eob, pd, loc, nor, vec, NULL); - - VecSubf(vec_to_part, pa->prev_state.co, loc); - len = Normalize(vec_to_part); + get_effector_data(eff, &efd, &epoint, 1); - VecMulf(vec, len / (val->max_speed * bbd->timestep)); - VecAddf(loc, loc, vec); - VecSubf(vec_to_part, pa->prev_state.co, loc); - } - else { - surface = (float)effector_find_co(bbd->sim->scene, pa->prev_state.co, NULL, eob, pd, loc, nor, NULL, NULL); - - VecSubf(vec_to_part, pa->prev_state.co, loc); - len = VecLength(vec_to_part); + VecMulf(efd.vel, efd.distance / (val->max_speed * bbd->timestep)); + VecAddf(efd.loc, efd.loc, efd.vel); + VecSubf(efd.vec_to_point, pa->prev_state.co, efd.loc); + efd.distance = VecLength(efd.vec_to_point); } if(rule->type == eBoidRuleType_Goal && boids->options & BOID_ALLOW_CLIMB && surface!=0.0f) { if(!bbd->goal_ob || bbd->goal_priority < priority) { bbd->goal_ob = eob; - VECCOPY(bbd->goal_co, loc); - VECCOPY(bbd->goal_nor, nor); + VECCOPY(bbd->goal_co, efd.loc); + VECCOPY(bbd->goal_nor, efd.nor); } } else if(rule->type == eBoidRuleType_Avoid && bpa->data.mode == eBoidMode_Climbing && priority > 2.0f * gabr->fear_factor) { /* detach from surface and try to fly away from danger */ - VECCOPY(vec_to_part, bpa->gravity); - VecMulf(vec_to_part, -1.0f); + VECCOPY(efd.vec_to_point, bpa->gravity); + VecMulf(efd.vec_to_point, -1.0f); } - VECCOPY(bbd->wanted_co, vec_to_part); + VECCOPY(bbd->wanted_co, efd.vec_to_point); VecMulf(bbd->wanted_co, mul); bbd->wanted_speed = val->max_speed * priority; @@ -188,8 +166,8 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, surface *= pa->size * boids->height; - if(len2 > 0.0f && len - surface < len2) { - len2 = (len - surface)/len2; + if(len2 > 0.0f && efd.distance - surface < len2) { + len2 = (efd.distance - surface)/len2; bbd->wanted_speed *= pow(len2, boids->landing_smoothness); } } @@ -204,9 +182,9 @@ static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues * { BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision*) rule; KDTreeNearest *ptn = NULL; - ParticleEffectorCache *ec; ParticleTarget *pt; BoidParticle *bpa = pa->boid; + ColliderCache *coll; float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; float co1[3], vel1[3], co2[3], vel2[3]; float len, t, inp, t_min = 2.0f; @@ -214,7 +192,7 @@ static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues * int ret = 0; //check deflector objects first - if(acbr->options & BRULE_ACOLL_WITH_DEFLECTORS) { + if(acbr->options & BRULE_ACOLL_WITH_DEFLECTORS && bbd->sim->colliders) { ParticleCollision col; BVHTreeRayHit hit; float radius = val->personal_space * pa->size, ray_dir[3]; @@ -228,20 +206,16 @@ static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues * hit.dist = col.ray_len = VecLength(ray_dir); /* find out closest deflector object */ - for(ec=bbd->sim->psys->effectors.first; ec; ec=ec->next) { - if(ec->type & PSYS_EC_DEFLECT) { - Object *eob = ec->ob; - - /* don't check with current ground object */ - if(eob == bpa->ground) - continue; + for(coll = bbd->sim->colliders->first; coll; coll=coll->next) { + /* don't check with current ground object */ + if(coll->ob == bpa->ground) + continue; - col.md = ( CollisionModifierData * ) ( modifiers_findByType ( eob, eModifierType_Collision ) ); - col.ob_t = eob; + col.ob = coll->ob; + col.md = coll->collmd; - if(col.md && col.md->bvhtree) - BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, particle_intersect_face, &col); - } + if(col.md && col.md->bvhtree) + BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, particle_intersect_face, &col); } /* then avoid that object */ if(hit.index>=0) { @@ -756,25 +730,28 @@ static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float *gro if(bpa->data.mode == eBoidMode_Climbing) { SurfaceModifierData *surmd = NULL; float x[3], v[3]; - + surmd = (SurfaceModifierData *)modifiers_findByType ( bpa->ground, eModifierType_Surface ); /* take surface velocity into account */ - effector_find_co(bbd->sim->scene, pa->state.co, surmd, NULL, NULL, x, NULL, v, NULL); + closest_point_on_surface(surmd, pa->state.co, x, NULL, v); VecAddf(x, x, v); /* get actual position on surface */ - effector_find_co(bbd->sim->scene, x, surmd, NULL, NULL, ground_co, ground_nor, NULL, NULL); + closest_point_on_surface(surmd, x, ground_co, ground_nor, NULL); return bpa->ground; } else { float zvec[3] = {0.0f, 0.0f, 2000.0f}; ParticleCollision col; + ColliderCache *coll; BVHTreeRayHit hit; - ParticleEffectorCache *ec; float radius = 0.0f, t, ray_dir[3]; + if(!bbd->sim->colliders) + return NULL; + VECCOPY(col.co1, pa->state.co); VECCOPY(col.co2, pa->state.co); VecAddf(col.co1, col.co1, zvec); @@ -785,16 +762,12 @@ static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float *gro hit.dist = col.ray_len = VecLength(ray_dir); /* find out upmost deflector object */ - for(ec=bbd->sim->psys->effectors.first; ec; ec=ec->next) { - if(ec->type & PSYS_EC_DEFLECT) { - Object *eob = ec->ob; + for(coll = bbd->sim->colliders->first; coll; coll = coll->next){ + col.ob = coll->ob; + col.md = coll->collmd; - col.md = ( CollisionModifierData * ) ( modifiers_findByType ( eob, eModifierType_Collision ) ); - col.ob_t = eob; - - if(col.md && col.md->bvhtree) - BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, particle_intersect_face, &col); - } + if(col.md && col.md->bvhtree) + BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, particle_intersect_face, &col); } /* then use that object */ if(hit.index>=0) { @@ -802,7 +775,7 @@ static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float *gro VecLerpf(ground_co, col.co1, col.co2, t); VECCOPY(ground_nor, col.nor); Normalize(ground_nor); - return col.ob; + return col.hit_ob; } else { /* default to z=0 */ @@ -1068,6 +1041,7 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa) BoidSettings *boids = bbd->part->boids; BoidParticle *bpa = pa->boid; BoidValues val; + EffectedPoint epoint; float acc[3] = {0.0f, 0.0f, 0.0f}, tan_acc[3], nor_acc[3]; float dvec[3], bvec[3]; float new_dir[3], new_speed; @@ -1075,9 +1049,8 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa) float wanted_dir[3]; float q[4], mat[3][3]; /* rotation */ float ground_co[3] = {0.0f, 0.0f, 0.0f}, ground_nor[3] = {0.0f, 0.0f, 1.0f}; - float force[3] = {0.0f, 0.0f, 0.0f}, tvel[3] = {0.0f, 0.0f, 1.0f}; + float force[3] = {0.0f, 0.0f, 0.0f}; float pa_mass=bbd->part->mass, dtime=bbd->dfra*bbd->timestep; - int p = pa - bbd->sim->psys->particles; set_boid_values(&val, boids, pa); @@ -1208,7 +1181,8 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa) } /* account for effectors */ - do_effectors(bbd->sim, p, pa, &pa->state, pa->state.co, force, tvel, bbd->dfra, bbd->cfra); + pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint); + pdDoEffectors(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL); if(ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) { float length = Normalize(force); |