/* -------- pdDoEffectors() -------- * generic force/speed system, now used for particles and softbodies * scene = scene where it runs in, for time and stuff * lb = listbase with objects that take part in effecting * opco = global coord, as input * force = force accumulator * speed = actual current speed which can be altered * cur_time = "external" time in frames, is constant for static particles * loc_time = "local" time in frames, range <0-1> for the lifetime of particle * par_layer = layer the caller is in * flags = only used for softbody wind now * guide = old speed of particle */ void pdDoEffectors(ListBase *effectors, ListBase *colliders, EffectorWeights *weights, EffectedPoint *point, float *force, float *impulse) { /* * Modifies the force on a particle according to its * relation with the effector object * Different kind of effectors include: * Forcefields: Gravity-like attractor * (force power is related to the inverse of distance to the power of a falloff value) * Vortex fields: swirling effectors * (particles rotate around Z-axis of the object. otherwise, same relation as) * (Forcefields, but this is not done through a force/acceleration) * Guide: particles on a path * (particles are guided along a curve bezier or old nurbs) * (is independent of other effectors) */ EffectorCache *eff; EffectorData efd; 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) */ 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, &step); for (; p<tot; p+=step) { if (get_effector_data(eff, &efd, point, 0)) { efd.falloff= effector_falloff(eff, &efd, point, weights); if (efd.falloff > 0.0f) efd.falloff *= eff_calc_visibility(colliders, eff, &efd, point); if (efd.falloff <= 0.0f) { /* don't do anything */ } else if (eff->pd->forcefield == PFIELD_TEXTURE) { do_texture_effector(eff, &efd, point, force); } else { float temp1[3] = {0, 0, 0}, temp2[3]; copy_v3_v3(temp1, force); do_physical_effector(eff, &efd, point, force); /* for softbody backward compatibility */ if (point->flag & PE_WIND_AS_SPEED && impulse) { sub_v3_v3v3(temp2, force, temp1); sub_v3_v3v3(impulse, impulse, temp2); } } } else if (eff->flag & PE_VELOCITY_TO_IMPULSE && impulse) { /* special case for harmonic effector */ add_v3_v3v3(impulse, impulse, efd.vel); } } } }
static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) { BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid*) rule; BoidSettings *boids = bbd->part->boids; BoidParticle *bpa = pa->boid; EffectedPoint epoint; ListBase *effectors = bbd->sim->psys->effectors; EffectorCache *cur, *eff = NULL; EffectorCache temp_eff; EffectorData efd, cur_efd; float mul = (rule->type == eBoidRuleType_Avoid ? 1.0 : -1.0); float priority = 0.0f, len = 0.0f; int ret = 0; pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint); /* 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: 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(cur, &cur_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; } } } /* if the object doesn't have effector data we have to fake it */ if (eff == NULL && gabr->ob) { memset(&temp_eff, 0, sizeof(EffectorCache)); temp_eff.ob = gabr->ob; temp_eff.scene = bbd->sim->scene; eff = &temp_eff; get_effector_data(eff, &efd, &epoint, 0); priority = 1.0f; } /* then use that effector */ if (priority > (rule->type==eBoidRuleType_Avoid ? gabr->fear_factor : 0.0f)) { /* with avoid, factor is "fear factor" */ Object *eob = eff->ob; PartDeflect *pd = eff->pd; float surface = (pd && pd->shape == PFIELD_SHAPE_SURFACE) ? 1.0f : 0.0f; if (gabr->options & BRULE_GOAL_AVOID_PREDICT) { /* estimate future location of target */ get_effector_data(eff, &efd, &epoint, 1); mul_v3_fl(efd.vel, efd.distance / (val->max_speed * bbd->timestep)); add_v3_v3(efd.loc, efd.vel); sub_v3_v3v3(efd.vec_to_point, pa->prev_state.co, efd.loc); efd.distance = len_v3(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; copy_v3_v3(bbd->goal_co, efd.loc); copy_v3_v3(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 */ negate_v3_v3(efd.vec_to_point, bpa->gravity); } copy_v3_v3(bbd->wanted_co, efd.vec_to_point); mul_v3_fl(bbd->wanted_co, mul); bbd->wanted_speed = val->max_speed * priority; /* with goals factor is approach velocity factor */ if (rule->type == eBoidRuleType_Goal && boids->landing_smoothness > 0.0f) { float len2 = 2.0f*len_v3(pa->prev_state.vel); surface *= pa->size * boids->height; if (len2 > 0.0f && efd.distance - surface < len2) { len2 = (efd.distance - surface)/len2; bbd->wanted_speed *= powf(len2, boids->landing_smoothness); } } ret = 1; } return ret; }