Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2009 by Janne Karhu. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): none yet. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 #include <string.h> 00034 #include <math.h> 00035 00036 #include "MEM_guardedalloc.h" 00037 00038 #include "DNA_object_force.h" 00039 #include "DNA_scene_types.h" 00040 00041 #include "BLI_rand.h" 00042 #include "BLI_math.h" 00043 #include "BLI_blenlib.h" 00044 #include "BLI_kdtree.h" 00045 #include "BLI_utildefines.h" 00046 00047 #include "BKE_collision.h" 00048 #include "BKE_effect.h" 00049 #include "BKE_boids.h" 00050 #include "BKE_particle.h" 00051 00052 #include "BKE_modifier.h" 00053 00054 #include "RNA_enum_types.h" 00055 00056 typedef struct BoidValues { 00057 float max_speed, max_acc; 00058 float max_ave, min_speed; 00059 float personal_space, jump_speed; 00060 } BoidValues; 00061 00062 static int apply_boid_rule(BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness); 00063 00064 static int rule_none(BoidRule *UNUSED(rule), BoidBrainData *UNUSED(data), BoidValues *UNUSED(val), ParticleData *UNUSED(pa)) 00065 { 00066 return 0; 00067 } 00068 00069 static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) 00070 { 00071 BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid*) rule; 00072 BoidSettings *boids = bbd->part->boids; 00073 BoidParticle *bpa = pa->boid; 00074 EffectedPoint epoint; 00075 ListBase *effectors = bbd->sim->psys->effectors; 00076 EffectorCache *cur, *eff = NULL; 00077 EffectorCache temp_eff; 00078 EffectorData efd, cur_efd; 00079 float mul = (rule->type == eBoidRuleType_Avoid ? 1.0 : -1.0); 00080 float priority = 0.0f, len = 0.0f; 00081 int ret = 0; 00082 00083 pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint); 00084 00085 /* first find out goal/predator with highest priority */ 00086 if(effectors) for(cur = effectors->first; cur; cur=cur->next) { 00087 Object *eob = cur->ob; 00088 PartDeflect *pd = cur->pd; 00089 00090 if(gabr->ob && (rule->type != eBoidRuleType_Goal || gabr->ob != bpa->ground)) { 00091 if(gabr->ob == eob) { 00092 /* TODO: effectors with multiple points */ 00093 if(get_effector_data(cur, &efd, &epoint, 0)) { 00094 if(cur->pd && cur->pd->forcefield == PFIELD_BOID) 00095 priority = mul * pd->f_strength * effector_falloff(cur, &efd, &epoint, bbd->part->effector_weights); 00096 else 00097 priority = 1.0; 00098 00099 eff = cur; 00100 } 00101 break; 00102 } 00103 } 00104 else if(rule->type == eBoidRuleType_Goal && eob == bpa->ground) 00105 ; /* skip current object */ 00106 else if(pd->forcefield == PFIELD_BOID && mul * pd->f_strength > 0.0f && get_effector_data(cur, &cur_efd, &epoint, 0)) { 00107 float temp = mul * pd->f_strength * effector_falloff(cur, &cur_efd, &epoint, bbd->part->effector_weights); 00108 00109 if(temp == 0.0f) 00110 ; /* do nothing */ 00111 else if(temp > priority) { 00112 priority = temp; 00113 eff = cur; 00114 efd = cur_efd; 00115 len = efd.distance; 00116 } 00117 /* choose closest object with same priority */ 00118 else if(temp == priority && efd.distance < len) { 00119 eff = cur; 00120 efd = cur_efd; 00121 len = efd.distance; 00122 } 00123 } 00124 } 00125 00126 /* if the object doesn't have effector data we have to fake it */ 00127 if(eff == NULL && gabr->ob) { 00128 memset(&temp_eff, 0, sizeof(EffectorCache)); 00129 temp_eff.ob = gabr->ob; 00130 temp_eff.scene = bbd->sim->scene; 00131 eff = &temp_eff; 00132 get_effector_data(eff, &efd, &epoint, 0); 00133 priority = 1.0f; 00134 } 00135 00136 /* then use that effector */ 00137 if(priority > (rule->type==eBoidRuleType_Avoid ? gabr->fear_factor : 0.0f)) { /* with avoid, factor is "fear factor" */ 00138 Object *eob = eff->ob; 00139 PartDeflect *pd = eff->pd; 00140 float surface = (pd && pd->shape == PFIELD_SHAPE_SURFACE) ? 1.0f : 0.0f; 00141 00142 if(gabr->options & BRULE_GOAL_AVOID_PREDICT) { 00143 /* estimate future location of target */ 00144 get_effector_data(eff, &efd, &epoint, 1); 00145 00146 mul_v3_fl(efd.vel, efd.distance / (val->max_speed * bbd->timestep)); 00147 add_v3_v3(efd.loc, efd.vel); 00148 sub_v3_v3v3(efd.vec_to_point, pa->prev_state.co, efd.loc); 00149 efd.distance = len_v3(efd.vec_to_point); 00150 } 00151 00152 if(rule->type == eBoidRuleType_Goal && boids->options & BOID_ALLOW_CLIMB && surface!=0.0f) { 00153 if(!bbd->goal_ob || bbd->goal_priority < priority) { 00154 bbd->goal_ob = eob; 00155 copy_v3_v3(bbd->goal_co, efd.loc); 00156 copy_v3_v3(bbd->goal_nor, efd.nor); 00157 } 00158 } 00159 else if(rule->type == eBoidRuleType_Avoid && bpa->data.mode == eBoidMode_Climbing && 00160 priority > 2.0f * gabr->fear_factor) { 00161 /* detach from surface and try to fly away from danger */ 00162 negate_v3_v3(efd.vec_to_point, bpa->gravity); 00163 } 00164 00165 copy_v3_v3(bbd->wanted_co, efd.vec_to_point); 00166 mul_v3_fl(bbd->wanted_co, mul); 00167 00168 bbd->wanted_speed = val->max_speed * priority; 00169 00170 /* with goals factor is approach velocity factor */ 00171 if(rule->type == eBoidRuleType_Goal && boids->landing_smoothness > 0.0f) { 00172 float len2 = 2.0f*len_v3(pa->prev_state.vel); 00173 00174 surface *= pa->size * boids->height; 00175 00176 if(len2 > 0.0f && efd.distance - surface < len2) { 00177 len2 = (efd.distance - surface)/len2; 00178 bbd->wanted_speed *= powf(len2, boids->landing_smoothness); 00179 } 00180 } 00181 00182 ret = 1; 00183 } 00184 00185 return ret; 00186 } 00187 00188 static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) 00189 { 00190 BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision*) rule; 00191 KDTreeNearest *ptn = NULL; 00192 ParticleTarget *pt; 00193 BoidParticle *bpa = pa->boid; 00194 ColliderCache *coll; 00195 float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; 00196 float co1[3], vel1[3], co2[3], vel2[3]; 00197 float len, t, inp, t_min = 2.0f; 00198 int n, neighbors = 0, nearest = 0; 00199 int ret = 0; 00200 00201 //check deflector objects first 00202 if(acbr->options & BRULE_ACOLL_WITH_DEFLECTORS && bbd->sim->colliders) { 00203 ParticleCollision col; 00204 BVHTreeRayHit hit; 00205 float radius = val->personal_space * pa->size, ray_dir[3]; 00206 00207 copy_v3_v3(col.co1, pa->prev_state.co); 00208 add_v3_v3v3(col.co2, pa->prev_state.co, pa->prev_state.vel); 00209 sub_v3_v3v3(ray_dir, col.co2, col.co1); 00210 mul_v3_fl(ray_dir, acbr->look_ahead); 00211 col.f = 0.0f; 00212 hit.index = -1; 00213 hit.dist = col.original_ray_length = len_v3(ray_dir); 00214 00215 /* find out closest deflector object */ 00216 for(coll = bbd->sim->colliders->first; coll; coll=coll->next) { 00217 /* don't check with current ground object */ 00218 if(coll->ob == bpa->ground) 00219 continue; 00220 00221 col.current = coll->ob; 00222 col.md = coll->collmd; 00223 00224 if(col.md && col.md->bvhtree) 00225 BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, BKE_psys_collision_neartest_cb, &col); 00226 } 00227 /* then avoid that object */ 00228 if(hit.index>=0) { 00229 t = hit.dist/col.original_ray_length; 00230 00231 /* avoid head-on collision */ 00232 if(dot_v3v3(col.pce.nor, pa->prev_state.ave) < -0.99f) { 00233 /* don't know why, but uneven range [0.0,1.0] */ 00234 /* works much better than even [-1.0,1.0] */ 00235 bbd->wanted_co[0] = BLI_frand(); 00236 bbd->wanted_co[1] = BLI_frand(); 00237 bbd->wanted_co[2] = BLI_frand(); 00238 } 00239 else { 00240 copy_v3_v3(bbd->wanted_co, col.pce.nor); 00241 } 00242 00243 mul_v3_fl(bbd->wanted_co, (1.0f - t) * val->personal_space * pa->size); 00244 00245 bbd->wanted_speed = sqrtf(t) * len_v3(pa->prev_state.vel); 00246 bbd->wanted_speed = MAX2(bbd->wanted_speed, val->min_speed); 00247 00248 return 1; 00249 } 00250 } 00251 00252 //check boids in own system 00253 if(acbr->options & BRULE_ACOLL_WITH_BOIDS) 00254 { 00255 neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, acbr->look_ahead * len_v3(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn); 00256 if(neighbors > 1) for(n=1; n<neighbors; n++) { 00257 copy_v3_v3(co1, pa->prev_state.co); 00258 copy_v3_v3(vel1, pa->prev_state.vel); 00259 copy_v3_v3(co2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.co); 00260 copy_v3_v3(vel2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.vel); 00261 00262 sub_v3_v3v3(loc, co1, co2); 00263 00264 sub_v3_v3v3(vec, vel1, vel2); 00265 00266 inp = dot_v3v3(vec,vec); 00267 00268 /* velocities not parallel */ 00269 if(inp != 0.0f) { 00270 t = -dot_v3v3(loc, vec)/inp; 00271 /* cpa is not too far in the future so investigate further */ 00272 if(t > 0.0f && t < t_min) { 00273 madd_v3_v3fl(co1, vel1, t); 00274 madd_v3_v3fl(co2, vel2, t); 00275 00276 sub_v3_v3v3(vec, co2, co1); 00277 00278 len = normalize_v3(vec); 00279 00280 /* distance of cpa is close enough */ 00281 if(len < 2.0f * val->personal_space * pa->size) { 00282 t_min = t; 00283 00284 mul_v3_fl(vec, len_v3(vel1)); 00285 mul_v3_fl(vec, (2.0f - t)/2.0f); 00286 sub_v3_v3v3(bbd->wanted_co, vel1, vec); 00287 bbd->wanted_speed = len_v3(bbd->wanted_co); 00288 ret = 1; 00289 } 00290 } 00291 } 00292 } 00293 } 00294 if(ptn){ MEM_freeN(ptn); ptn=NULL; } 00295 00296 /* check boids in other systems */ 00297 for(pt=bbd->sim->psys->targets.first; pt; pt=pt->next) { 00298 ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt); 00299 00300 if(epsys) { 00301 neighbors = BLI_kdtree_range_search(epsys->tree, acbr->look_ahead * len_v3(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn); 00302 if(neighbors > 0) for(n=0; n<neighbors; n++) { 00303 copy_v3_v3(co1, pa->prev_state.co); 00304 copy_v3_v3(vel1, pa->prev_state.vel); 00305 copy_v3_v3(co2, (epsys->particles + ptn[n].index)->prev_state.co); 00306 copy_v3_v3(vel2, (epsys->particles + ptn[n].index)->prev_state.vel); 00307 00308 sub_v3_v3v3(loc, co1, co2); 00309 00310 sub_v3_v3v3(vec, vel1, vel2); 00311 00312 inp = dot_v3v3(vec,vec); 00313 00314 /* velocities not parallel */ 00315 if(inp != 0.0f) { 00316 t = -dot_v3v3(loc, vec)/inp; 00317 /* cpa is not too far in the future so investigate further */ 00318 if(t > 0.0f && t < t_min) { 00319 madd_v3_v3fl(co1, vel1, t); 00320 madd_v3_v3fl(co2, vel2, t); 00321 00322 sub_v3_v3v3(vec, co2, co1); 00323 00324 len = normalize_v3(vec); 00325 00326 /* distance of cpa is close enough */ 00327 if(len < 2.0f * val->personal_space * pa->size) { 00328 t_min = t; 00329 00330 mul_v3_fl(vec, len_v3(vel1)); 00331 mul_v3_fl(vec, (2.0f - t)/2.0f); 00332 sub_v3_v3v3(bbd->wanted_co, vel1, vec); 00333 bbd->wanted_speed = len_v3(bbd->wanted_co); 00334 ret = 1; 00335 } 00336 } 00337 } 00338 } 00339 00340 if(ptn){ MEM_freeN(ptn); ptn=NULL; } 00341 } 00342 } 00343 00344 00345 if(ptn && nearest==0) 00346 MEM_freeN(ptn); 00347 00348 return ret; 00349 } 00350 static int rule_separate(BoidRule *UNUSED(rule), BoidBrainData *bbd, BoidValues *val, ParticleData *pa) 00351 { 00352 KDTreeNearest *ptn = NULL; 00353 ParticleTarget *pt; 00354 float len = 2.0f * val->personal_space * pa->size + 1.0f; 00355 float vec[3] = {0.0f, 0.0f, 0.0f}; 00356 int neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, 2.0f * val->personal_space * pa->size, pa->prev_state.co, NULL, &ptn); 00357 int ret = 0; 00358 00359 if(neighbors > 1 && ptn[1].dist!=0.0f) { 00360 sub_v3_v3v3(vec, pa->prev_state.co, bbd->sim->psys->particles[ptn[1].index].state.co); 00361 mul_v3_fl(vec, (2.0f * val->personal_space * pa->size - ptn[1].dist) / ptn[1].dist); 00362 add_v3_v3(bbd->wanted_co, vec); 00363 bbd->wanted_speed = val->max_speed; 00364 len = ptn[1].dist; 00365 ret = 1; 00366 } 00367 if(ptn){ MEM_freeN(ptn); ptn=NULL; } 00368 00369 /* check other boid systems */ 00370 for(pt=bbd->sim->psys->targets.first; pt; pt=pt->next) { 00371 ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt); 00372 00373 if(epsys) { 00374 neighbors = BLI_kdtree_range_search(epsys->tree, 2.0f * val->personal_space * pa->size, pa->prev_state.co, NULL, &ptn); 00375 00376 if(neighbors > 0 && ptn[0].dist < len) { 00377 sub_v3_v3v3(vec, pa->prev_state.co, ptn[0].co); 00378 mul_v3_fl(vec, (2.0f * val->personal_space * pa->size - ptn[0].dist) / ptn[1].dist); 00379 add_v3_v3(bbd->wanted_co, vec); 00380 bbd->wanted_speed = val->max_speed; 00381 len = ptn[0].dist; 00382 ret = 1; 00383 } 00384 00385 if(ptn){ MEM_freeN(ptn); ptn=NULL; } 00386 } 00387 } 00388 return ret; 00389 } 00390 static int rule_flock(BoidRule *UNUSED(rule), BoidBrainData *bbd, BoidValues *UNUSED(val), ParticleData *pa) 00391 { 00392 KDTreeNearest ptn[11]; 00393 float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; 00394 int neighbors = BLI_kdtree_find_n_nearest(bbd->sim->psys->tree, 11, pa->state.co, pa->prev_state.ave, ptn); 00395 int n; 00396 int ret = 0; 00397 00398 if(neighbors > 1) { 00399 for(n=1; n<neighbors; n++) { 00400 add_v3_v3(loc, bbd->sim->psys->particles[ptn[n].index].prev_state.co); 00401 add_v3_v3(vec, bbd->sim->psys->particles[ptn[n].index].prev_state.vel); 00402 } 00403 00404 mul_v3_fl(loc, 1.0f/((float)neighbors - 1.0f)); 00405 mul_v3_fl(vec, 1.0f/((float)neighbors - 1.0f)); 00406 00407 sub_v3_v3(loc, pa->prev_state.co); 00408 sub_v3_v3(vec, pa->prev_state.vel); 00409 00410 add_v3_v3(bbd->wanted_co, vec); 00411 add_v3_v3(bbd->wanted_co, loc); 00412 bbd->wanted_speed = len_v3(bbd->wanted_co); 00413 00414 ret = 1; 00415 } 00416 return ret; 00417 } 00418 static int rule_follow_leader(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) 00419 { 00420 BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*) rule; 00421 float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; 00422 float mul, len; 00423 int n = (flbr->queue_size <= 1) ? bbd->sim->psys->totpart : flbr->queue_size; 00424 int i, ret = 0, p = pa - bbd->sim->psys->particles; 00425 00426 if(flbr->ob) { 00427 float vec2[3], t; 00428 00429 /* first check we're not blocking the leader*/ 00430 sub_v3_v3v3(vec, flbr->loc, flbr->oloc); 00431 mul_v3_fl(vec, 1.0f/bbd->timestep); 00432 00433 sub_v3_v3v3(loc, pa->prev_state.co, flbr->oloc); 00434 00435 mul = dot_v3v3(vec, vec); 00436 00437 /* leader is not moving */ 00438 if(mul < 0.01f) { 00439 len = len_v3(loc); 00440 /* too close to leader */ 00441 if(len < 2.0f * val->personal_space * pa->size) { 00442 copy_v3_v3(bbd->wanted_co, loc); 00443 bbd->wanted_speed = val->max_speed; 00444 return 1; 00445 } 00446 } 00447 else { 00448 t = dot_v3v3(loc, vec)/mul; 00449 00450 /* possible blocking of leader in near future */ 00451 if(t > 0.0f && t < 3.0f) { 00452 copy_v3_v3(vec2, vec); 00453 mul_v3_fl(vec2, t); 00454 00455 sub_v3_v3v3(vec2, loc, vec2); 00456 00457 len = len_v3(vec2); 00458 00459 if(len < 2.0f * val->personal_space * pa->size) { 00460 copy_v3_v3(bbd->wanted_co, vec2); 00461 bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f; 00462 return 1; 00463 } 00464 } 00465 } 00466 00467 /* not blocking so try to follow leader */ 00468 if(p && flbr->options & BRULE_LEADER_IN_LINE) { 00469 copy_v3_v3(vec, bbd->sim->psys->particles[p-1].prev_state.vel); 00470 copy_v3_v3(loc, bbd->sim->psys->particles[p-1].prev_state.co); 00471 } 00472 else { 00473 copy_v3_v3(loc, flbr->oloc); 00474 sub_v3_v3v3(vec, flbr->loc, flbr->oloc); 00475 mul_v3_fl(vec, 1.0f/bbd->timestep); 00476 } 00477 00478 /* fac is seconds behind leader */ 00479 madd_v3_v3fl(loc, vec, -flbr->distance); 00480 00481 sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co); 00482 bbd->wanted_speed = len_v3(bbd->wanted_co); 00483 00484 ret = 1; 00485 } 00486 else if(p % n) { 00487 float vec2[3], t, t_min = 3.0f; 00488 00489 /* first check we're not blocking any leaders */ 00490 for(i = 0; i< bbd->sim->psys->totpart; i+=n){ 00491 copy_v3_v3(vec, bbd->sim->psys->particles[i].prev_state.vel); 00492 00493 sub_v3_v3v3(loc, pa->prev_state.co, bbd->sim->psys->particles[i].prev_state.co); 00494 00495 mul = dot_v3v3(vec, vec); 00496 00497 /* leader is not moving */ 00498 if(mul < 0.01f) { 00499 len = len_v3(loc); 00500 /* too close to leader */ 00501 if(len < 2.0f * val->personal_space * pa->size) { 00502 copy_v3_v3(bbd->wanted_co, loc); 00503 bbd->wanted_speed = val->max_speed; 00504 return 1; 00505 } 00506 } 00507 else { 00508 t = dot_v3v3(loc, vec)/mul; 00509 00510 /* possible blocking of leader in near future */ 00511 if(t > 0.0f && t < t_min) { 00512 copy_v3_v3(vec2, vec); 00513 mul_v3_fl(vec2, t); 00514 00515 sub_v3_v3v3(vec2, loc, vec2); 00516 00517 len = len_v3(vec2); 00518 00519 if(len < 2.0f * val->personal_space * pa->size) { 00520 t_min = t; 00521 copy_v3_v3(bbd->wanted_co, loc); 00522 bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f; 00523 ret = 1; 00524 } 00525 } 00526 } 00527 } 00528 00529 if(ret) return 1; 00530 00531 /* not blocking so try to follow leader */ 00532 if(flbr->options & BRULE_LEADER_IN_LINE) { 00533 copy_v3_v3(vec, bbd->sim->psys->particles[p-1].prev_state.vel); 00534 copy_v3_v3(loc, bbd->sim->psys->particles[p-1].prev_state.co); 00535 } 00536 else { 00537 copy_v3_v3(vec, bbd->sim->psys->particles[p - p%n].prev_state.vel); 00538 copy_v3_v3(loc, bbd->sim->psys->particles[p - p%n].prev_state.co); 00539 } 00540 00541 /* fac is seconds behind leader */ 00542 madd_v3_v3fl(loc, vec, -flbr->distance); 00543 00544 sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co); 00545 bbd->wanted_speed = len_v3(bbd->wanted_co); 00546 00547 ret = 1; 00548 } 00549 00550 return ret; 00551 } 00552 static int rule_average_speed(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) 00553 { 00554 BoidParticle *bpa = pa->boid; 00555 BoidRuleAverageSpeed *asbr = (BoidRuleAverageSpeed*)rule; 00556 float vec[3] = {0.0f, 0.0f, 0.0f}; 00557 00558 if(asbr->wander > 0.0f) { 00559 /* abuse pa->r_ave for wandering */ 00560 bpa->wander[0] += asbr->wander * (-1.0f + 2.0f * BLI_frand()); 00561 bpa->wander[1] += asbr->wander * (-1.0f + 2.0f * BLI_frand()); 00562 bpa->wander[2] += asbr->wander * (-1.0f + 2.0f * BLI_frand()); 00563 00564 normalize_v3(bpa->wander); 00565 00566 copy_v3_v3(vec, bpa->wander); 00567 00568 mul_qt_v3(pa->prev_state.rot, vec); 00569 00570 copy_v3_v3(bbd->wanted_co, pa->prev_state.ave); 00571 00572 mul_v3_fl(bbd->wanted_co, 1.1f); 00573 00574 add_v3_v3(bbd->wanted_co, vec); 00575 00576 /* leveling */ 00577 if(asbr->level > 0.0f && psys_uses_gravity(bbd->sim)) { 00578 project_v3_v3v3(vec, bbd->wanted_co, bbd->sim->scene->physics_settings.gravity); 00579 mul_v3_fl(vec, asbr->level); 00580 sub_v3_v3(bbd->wanted_co, vec); 00581 } 00582 } 00583 else { 00584 copy_v3_v3(bbd->wanted_co, pa->prev_state.ave); 00585 00586 /* may happen at birth */ 00587 if(dot_v2v2(bbd->wanted_co,bbd->wanted_co)==0.0f) { 00588 bbd->wanted_co[0] = 2.0f*(0.5f - BLI_frand()); 00589 bbd->wanted_co[1] = 2.0f*(0.5f - BLI_frand()); 00590 bbd->wanted_co[2] = 2.0f*(0.5f - BLI_frand()); 00591 } 00592 00593 /* leveling */ 00594 if(asbr->level > 0.0f && psys_uses_gravity(bbd->sim)) { 00595 project_v3_v3v3(vec, bbd->wanted_co, bbd->sim->scene->physics_settings.gravity); 00596 mul_v3_fl(vec, asbr->level); 00597 sub_v3_v3(bbd->wanted_co, vec); 00598 } 00599 00600 } 00601 bbd->wanted_speed = asbr->speed * val->max_speed; 00602 00603 return 1; 00604 } 00605 static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) 00606 { 00607 BoidRuleFight *fbr = (BoidRuleFight*)rule; 00608 KDTreeNearest *ptn = NULL; 00609 ParticleTarget *pt; 00610 ParticleData *epars; 00611 ParticleData *enemy_pa = NULL; 00612 BoidParticle *bpa; 00613 /* friends & enemies */ 00614 float closest_enemy[3] = {0.0f,0.0f,0.0f}; 00615 float closest_dist = fbr->distance + 1.0f; 00616 float f_strength = 0.0f, e_strength = 0.0f; 00617 float health = 0.0f; 00618 int n, ret = 0; 00619 00620 /* calculate own group strength */ 00621 int neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, fbr->distance, pa->prev_state.co, NULL, &ptn); 00622 for(n=0; n<neighbors; n++) { 00623 bpa = bbd->sim->psys->particles[ptn[n].index].boid; 00624 health += bpa->data.health; 00625 } 00626 00627 f_strength += bbd->part->boids->strength * health; 00628 00629 if(ptn){ MEM_freeN(ptn); ptn=NULL; } 00630 00631 /* add other friendlies and calculate enemy strength and find closest enemy */ 00632 for(pt=bbd->sim->psys->targets.first; pt; pt=pt->next) { 00633 ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt); 00634 if(epsys) { 00635 epars = epsys->particles; 00636 00637 neighbors = BLI_kdtree_range_search(epsys->tree, fbr->distance, pa->prev_state.co, NULL, &ptn); 00638 00639 health = 0.0f; 00640 00641 for(n=0; n<neighbors; n++) { 00642 bpa = epars[ptn[n].index].boid; 00643 health += bpa->data.health; 00644 00645 if(n==0 && pt->mode==PTARGET_MODE_ENEMY && ptn[n].dist < closest_dist) { 00646 copy_v3_v3(closest_enemy, ptn[n].co); 00647 closest_dist = ptn[n].dist; 00648 enemy_pa = epars + ptn[n].index; 00649 } 00650 } 00651 if(pt->mode==PTARGET_MODE_ENEMY) 00652 e_strength += epsys->part->boids->strength * health; 00653 else if(pt->mode==PTARGET_MODE_FRIEND) 00654 f_strength += epsys->part->boids->strength * health; 00655 00656 if(ptn){ MEM_freeN(ptn); ptn=NULL; } 00657 } 00658 } 00659 /* decide action if enemy presence found */ 00660 if(e_strength > 0.0f) { 00661 sub_v3_v3v3(bbd->wanted_co, closest_enemy, pa->prev_state.co); 00662 00663 /* attack if in range */ 00664 if(closest_dist <= bbd->part->boids->range + pa->size + enemy_pa->size) { 00665 float damage = BLI_frand(); 00666 float enemy_dir[3]; 00667 00668 normalize_v3_v3(enemy_dir, bbd->wanted_co); 00669 00670 /* fight mode */ 00671 bbd->wanted_speed = 0.0f; 00672 00673 /* must face enemy to fight */ 00674 if(dot_v3v3(pa->prev_state.ave, enemy_dir)>0.5f) { 00675 bpa = enemy_pa->boid; 00676 bpa->data.health -= bbd->part->boids->strength * bbd->timestep * ((1.0f-bbd->part->boids->accuracy)*damage + bbd->part->boids->accuracy); 00677 } 00678 } 00679 else { 00680 /* approach mode */ 00681 bbd->wanted_speed = val->max_speed; 00682 } 00683 00684 /* check if boid doesn't want to fight */ 00685 bpa = pa->boid; 00686 if(bpa->data.health/bbd->part->boids->health * bbd->part->boids->aggression < e_strength / f_strength) { 00687 /* decide to flee */ 00688 if(closest_dist < fbr->flee_distance * fbr->distance) { 00689 negate_v3(bbd->wanted_co); 00690 bbd->wanted_speed = val->max_speed; 00691 } 00692 else { /* wait for better odds */ 00693 bbd->wanted_speed = 0.0f; 00694 } 00695 } 00696 00697 ret = 1; 00698 } 00699 00700 return ret; 00701 } 00702 00703 typedef int (*boid_rule_cb)(BoidRule *rule, BoidBrainData *data, BoidValues *val, ParticleData *pa); 00704 00705 static boid_rule_cb boid_rules[] = { 00706 rule_none, 00707 rule_goal_avoid, 00708 rule_goal_avoid, 00709 rule_avoid_collision, 00710 rule_separate, 00711 rule_flock, 00712 rule_follow_leader, 00713 rule_average_speed, 00714 rule_fight, 00715 //rule_help, 00716 //rule_protect, 00717 //rule_hide, 00718 //rule_follow_path, 00719 //rule_follow_wall 00720 }; 00721 00722 static void set_boid_values(BoidValues *val, BoidSettings *boids, ParticleData *pa) 00723 { 00724 BoidParticle *bpa = pa->boid; 00725 00726 if(ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) { 00727 val->max_speed = boids->land_max_speed * bpa->data.health/boids->health; 00728 val->max_acc = boids->land_max_acc * val->max_speed; 00729 val->max_ave = boids->land_max_ave * (float)M_PI * bpa->data.health/boids->health; 00730 val->min_speed = 0.0f; /* no minimum speed on land */ 00731 val->personal_space = boids->land_personal_space; 00732 val->jump_speed = boids->land_jump_speed * bpa->data.health/boids->health; 00733 } 00734 else { 00735 val->max_speed = boids->air_max_speed * bpa->data.health/boids->health; 00736 val->max_acc = boids->air_max_acc * val->max_speed; 00737 val->max_ave = boids->air_max_ave * (float)M_PI * bpa->data.health/boids->health; 00738 val->min_speed = boids->air_min_speed * boids->air_max_speed; 00739 val->personal_space = boids->air_personal_space; 00740 val->jump_speed = 0.0f; /* no jumping in air */ 00741 } 00742 } 00743 00744 static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float ground_co[3], float ground_nor[3]) 00745 { 00746 BoidParticle *bpa = pa->boid; 00747 00748 if(bpa->data.mode == eBoidMode_Climbing) { 00749 SurfaceModifierData *surmd = NULL; 00750 float x[3], v[3]; 00751 00752 surmd = (SurfaceModifierData *)modifiers_findByType ( bpa->ground, eModifierType_Surface ); 00753 00754 /* take surface velocity into account */ 00755 closest_point_on_surface(surmd, pa->state.co, x, NULL, v); 00756 add_v3_v3(x, v); 00757 00758 /* get actual position on surface */ 00759 closest_point_on_surface(surmd, x, ground_co, ground_nor, NULL); 00760 00761 return bpa->ground; 00762 } 00763 else { 00764 float zvec[3] = {0.0f, 0.0f, 2000.0f}; 00765 ParticleCollision col; 00766 ColliderCache *coll; 00767 BVHTreeRayHit hit; 00768 float radius = 0.0f, t, ray_dir[3]; 00769 00770 if(!bbd->sim->colliders) 00771 return NULL; 00772 00773 /* first try to find below boid */ 00774 copy_v3_v3(col.co1, pa->state.co); 00775 sub_v3_v3v3(col.co2, pa->state.co, zvec); 00776 sub_v3_v3v3(ray_dir, col.co2, col.co1); 00777 col.f = 0.0f; 00778 hit.index = -1; 00779 hit.dist = col.original_ray_length = len_v3(ray_dir); 00780 col.pce.inside = 0; 00781 00782 for(coll = bbd->sim->colliders->first; coll; coll = coll->next){ 00783 col.current = coll->ob; 00784 col.md = coll->collmd; 00785 col.fac1 = col.fac2 = 0.f; 00786 00787 if(col.md && col.md->bvhtree) 00788 BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, BKE_psys_collision_neartest_cb, &col); 00789 } 00790 /* then use that object */ 00791 if(hit.index>=0) { 00792 t = hit.dist/col.original_ray_length; 00793 interp_v3_v3v3(ground_co, col.co1, col.co2, t); 00794 normalize_v3_v3(ground_nor, col.pce.nor); 00795 return col.hit; 00796 } 00797 00798 /* couldn't find below, so find upmost deflector object */ 00799 add_v3_v3v3(col.co1, pa->state.co, zvec); 00800 sub_v3_v3v3(col.co2, pa->state.co, zvec); 00801 sub_v3_v3(col.co2, zvec); 00802 sub_v3_v3v3(ray_dir, col.co2, col.co1); 00803 col.f = 0.0f; 00804 hit.index = -1; 00805 hit.dist = col.original_ray_length = len_v3(ray_dir); 00806 00807 for(coll = bbd->sim->colliders->first; coll; coll = coll->next){ 00808 col.current = coll->ob; 00809 col.md = coll->collmd; 00810 00811 if(col.md && col.md->bvhtree) 00812 BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, BKE_psys_collision_neartest_cb, &col); 00813 } 00814 /* then use that object */ 00815 if(hit.index>=0) { 00816 t = hit.dist/col.original_ray_length; 00817 interp_v3_v3v3(ground_co, col.co1, col.co2, t); 00818 normalize_v3_v3(ground_nor, col.pce.nor); 00819 return col.hit; 00820 } 00821 00822 /* default to z=0 */ 00823 copy_v3_v3(ground_co, pa->state.co); 00824 ground_co[2] = 0; 00825 ground_nor[0] = ground_nor[1] = 0.0f; 00826 ground_nor[2] = 1.0f; 00827 return NULL; 00828 } 00829 } 00830 static int boid_rule_applies(ParticleData *pa, BoidSettings *UNUSED(boids), BoidRule *rule) 00831 { 00832 BoidParticle *bpa = pa->boid; 00833 00834 if(rule==NULL) 00835 return 0; 00836 00837 if(ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing) && rule->flag & BOIDRULE_ON_LAND) 00838 return 1; 00839 00840 if(bpa->data.mode==eBoidMode_InAir && rule->flag & BOIDRULE_IN_AIR) 00841 return 1; 00842 00843 return 0; 00844 } 00845 void boids_precalc_rules(ParticleSettings *part, float cfra) 00846 { 00847 BoidState *state = part->boids->states.first; 00848 BoidRule *rule; 00849 for(; state; state=state->next) { 00850 for(rule = state->rules.first; rule; rule=rule->next) { 00851 if(rule->type==eBoidRuleType_FollowLeader) { 00852 BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*) rule; 00853 00854 if(flbr->ob && flbr->cfra != cfra) { 00855 /* save object locations for velocity calculations */ 00856 copy_v3_v3(flbr->oloc, flbr->loc); 00857 copy_v3_v3(flbr->loc, flbr->ob->obmat[3]); 00858 flbr->cfra = cfra; 00859 } 00860 } 00861 } 00862 } 00863 } 00864 static void boid_climb(BoidSettings *boids, ParticleData *pa, float *surface_co, float *surface_nor) 00865 { 00866 BoidParticle *bpa = pa->boid; 00867 float nor[3], vel[3]; 00868 copy_v3_v3(nor, surface_nor); 00869 00870 /* gather apparent gravity */ 00871 madd_v3_v3fl(bpa->gravity, surface_nor, -1.0f); 00872 normalize_v3(bpa->gravity); 00873 00874 /* raise boid it's size from surface */ 00875 mul_v3_fl(nor, pa->size * boids->height); 00876 add_v3_v3v3(pa->state.co, surface_co, nor); 00877 00878 /* remove normal component from velocity */ 00879 project_v3_v3v3(vel, pa->state.vel, surface_nor); 00880 sub_v3_v3v3(pa->state.vel, pa->state.vel, vel); 00881 } 00882 static float boid_goal_signed_dist(float *boid_co, float *goal_co, float *goal_nor) 00883 { 00884 float vec[3]; 00885 00886 sub_v3_v3v3(vec, boid_co, goal_co); 00887 00888 return dot_v3v3(vec, goal_nor); 00889 } 00890 /* wanted_co is relative to boid location */ 00891 static int apply_boid_rule(BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness) 00892 { 00893 if(rule==NULL) 00894 return 0; 00895 00896 if(boid_rule_applies(pa, bbd->part->boids, rule)==0) 00897 return 0; 00898 00899 if(boid_rules[rule->type](rule, bbd, val, pa)==0) 00900 return 0; 00901 00902 if(fuzziness < 0.0f || compare_len_v3v3(bbd->wanted_co, pa->prev_state.vel, fuzziness * len_v3(pa->prev_state.vel))==0) 00903 return 1; 00904 else 00905 return 0; 00906 } 00907 static BoidState *get_boid_state(BoidSettings *boids, ParticleData *pa) 00908 { 00909 BoidState *state = boids->states.first; 00910 BoidParticle *bpa = pa->boid; 00911 00912 for(; state; state=state->next) { 00913 if(state->id==bpa->data.state_id) 00914 return state; 00915 } 00916 00917 /* for some reason particle isn't at a valid state */ 00918 state = boids->states.first; 00919 if(state) 00920 bpa->data.state_id = state->id; 00921 00922 return state; 00923 } 00924 //static int boid_condition_is_true(BoidCondition *cond) { 00925 // /* TODO */ 00926 // return 0; 00927 //} 00928 00929 /* determines the velocity the boid wants to have */ 00930 void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa) 00931 { 00932 BoidRule *rule; 00933 BoidSettings *boids = bbd->part->boids; 00934 BoidValues val; 00935 BoidState *state = get_boid_state(boids, pa); 00936 BoidParticle *bpa = pa->boid; 00937 ParticleSystem *psys = bbd->sim->psys; 00938 int rand; 00939 //BoidCondition *cond; 00940 00941 if(bpa->data.health <= 0.0f) { 00942 pa->alive = PARS_DYING; 00943 pa->dietime = bbd->cfra; 00944 return; 00945 } 00946 00947 //planned for near future 00948 //cond = state->conditions.first; 00949 //for(; cond; cond=cond->next) { 00950 // if(boid_condition_is_true(cond)) { 00951 // pa->boid->state_id = cond->state_id; 00952 // state = get_boid_state(boids, pa); 00953 // break; /* only first true condition is used */ 00954 // } 00955 //} 00956 00957 bbd->wanted_co[0]=bbd->wanted_co[1]=bbd->wanted_co[2]=bbd->wanted_speed=0.0f; 00958 00959 /* create random seed for every particle & frame */ 00960 rand = (int)(PSYS_FRAND(psys->seed + p) * 1000); 00961 rand = (int)(PSYS_FRAND((int)bbd->cfra + rand) * 1000); 00962 00963 set_boid_values(&val, bbd->part->boids, pa); 00964 00965 /* go through rules */ 00966 switch(state->ruleset_type) { 00967 case eBoidRulesetType_Fuzzy: 00968 { 00969 for(rule = state->rules.first; rule; rule = rule->next) { 00970 if(apply_boid_rule(bbd, rule, &val, pa, state->rule_fuzziness)) 00971 break; /* only first nonzero rule that comes through fuzzy rule is applied */ 00972 } 00973 break; 00974 } 00975 case eBoidRulesetType_Random: 00976 { 00977 /* use random rule for each particle (allways same for same particle though) */ 00978 rule = BLI_findlink(&state->rules, rand % BLI_countlist(&state->rules)); 00979 00980 apply_boid_rule(bbd, rule, &val, pa, -1.0); 00981 } 00982 case eBoidRulesetType_Average: 00983 { 00984 float wanted_co[3] = {0.0f, 0.0f, 0.0f}, wanted_speed = 0.0f; 00985 int n = 0; 00986 for(rule = state->rules.first; rule; rule=rule->next) { 00987 if(apply_boid_rule(bbd, rule, &val, pa, -1.0f)) { 00988 add_v3_v3(wanted_co, bbd->wanted_co); 00989 wanted_speed += bbd->wanted_speed; 00990 n++; 00991 bbd->wanted_co[0]=bbd->wanted_co[1]=bbd->wanted_co[2]=bbd->wanted_speed=0.0f; 00992 } 00993 } 00994 00995 if(n > 1) { 00996 mul_v3_fl(wanted_co, 1.0f/(float)n); 00997 wanted_speed /= (float)n; 00998 } 00999 01000 copy_v3_v3(bbd->wanted_co, wanted_co); 01001 bbd->wanted_speed = wanted_speed; 01002 break; 01003 } 01004 01005 } 01006 01007 /* decide on jumping & liftoff */ 01008 if(bpa->data.mode == eBoidMode_OnLand) { 01009 /* fuzziness makes boids capable of misjudgement */ 01010 float mul = 1.0f + state->rule_fuzziness; 01011 01012 if(boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) { 01013 float cvel[3], dir[3]; 01014 01015 copy_v3_v3(dir, pa->prev_state.ave); 01016 normalize_v2(dir); 01017 01018 copy_v3_v3(cvel, bbd->wanted_co); 01019 normalize_v2(cvel); 01020 01021 if(dot_v2v2(cvel, dir) > 0.95f / mul) 01022 bpa->data.mode = eBoidMode_Liftoff; 01023 } 01024 else if(val.jump_speed > 0.0f) { 01025 float jump_v[3]; 01026 int jump = 0; 01027 01028 /* jump to get to a location */ 01029 if(bbd->wanted_co[2] > 0.0f) { 01030 float cvel[3], dir[3]; 01031 float z_v, ground_v, cur_v; 01032 float len; 01033 01034 copy_v3_v3(dir, pa->prev_state.ave); 01035 normalize_v2(dir); 01036 01037 copy_v3_v3(cvel, bbd->wanted_co); 01038 normalize_v2(cvel); 01039 01040 len = len_v2(pa->prev_state.vel); 01041 01042 /* first of all, are we going in a suitable direction? */ 01043 /* or at a suitably slow speed */ 01044 if(dot_v2v2(cvel, dir) > 0.95f / mul || len <= state->rule_fuzziness) { 01045 /* try to reach goal at highest point of the parabolic path */ 01046 cur_v = len_v2(pa->prev_state.vel); 01047 z_v = sasqrt(-2.0f * bbd->sim->scene->physics_settings.gravity[2] * bbd->wanted_co[2]); 01048 ground_v = len_v2(bbd->wanted_co)*sasqrt(-0.5f * bbd->sim->scene->physics_settings.gravity[2] / bbd->wanted_co[2]); 01049 01050 len = sasqrt((ground_v-cur_v)*(ground_v-cur_v) + z_v*z_v); 01051 01052 if(len < val.jump_speed * mul || bbd->part->boids->options & BOID_ALLOW_FLIGHT) { 01053 jump = 1; 01054 01055 len = MIN2(len, val.jump_speed); 01056 01057 copy_v3_v3(jump_v, dir); 01058 jump_v[2] = z_v; 01059 mul_v3_fl(jump_v, ground_v); 01060 01061 normalize_v3(jump_v); 01062 mul_v3_fl(jump_v, len); 01063 add_v2_v2v2(jump_v, jump_v, pa->prev_state.vel); 01064 } 01065 } 01066 } 01067 01068 /* jump to go faster */ 01069 if(jump == 0 && val.jump_speed > val.max_speed && bbd->wanted_speed > val.max_speed) { 01070 01071 } 01072 01073 if(jump) { 01074 copy_v3_v3(pa->prev_state.vel, jump_v); 01075 bpa->data.mode = eBoidMode_Falling; 01076 } 01077 } 01078 } 01079 } 01080 /* tries to realize the wanted velocity taking all constraints into account */ 01081 void boid_body(BoidBrainData *bbd, ParticleData *pa) 01082 { 01083 BoidSettings *boids = bbd->part->boids; 01084 BoidParticle *bpa = pa->boid; 01085 BoidValues val; 01086 EffectedPoint epoint; 01087 float acc[3] = {0.0f, 0.0f, 0.0f}, tan_acc[3], nor_acc[3]; 01088 float dvec[3], bvec[3]; 01089 float new_dir[3], new_speed; 01090 float old_dir[3], old_speed; 01091 float wanted_dir[3]; 01092 float q[4], mat[3][3]; /* rotation */ 01093 float ground_co[3] = {0.0f, 0.0f, 0.0f}, ground_nor[3] = {0.0f, 0.0f, 1.0f}; 01094 float force[3] = {0.0f, 0.0f, 0.0f}; 01095 float pa_mass=bbd->part->mass, dtime=bbd->dfra*bbd->timestep; 01096 01097 set_boid_values(&val, boids, pa); 01098 01099 /* make sure there's something in new velocity, location & rotation */ 01100 copy_particle_key(&pa->state,&pa->prev_state,0); 01101 01102 if(bbd->part->flag & PART_SIZEMASS) 01103 pa_mass*=pa->size; 01104 01105 /* if boids can't fly they fall to the ground */ 01106 if((boids->options & BOID_ALLOW_FLIGHT)==0 && ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)==0 && psys_uses_gravity(bbd->sim)) 01107 bpa->data.mode = eBoidMode_Falling; 01108 01109 if(bpa->data.mode == eBoidMode_Falling) { 01110 /* Falling boids are only effected by gravity. */ 01111 acc[2] = bbd->sim->scene->physics_settings.gravity[2]; 01112 } 01113 else { 01114 /* figure out acceleration */ 01115 float landing_level = 2.0f; 01116 float level = landing_level + 1.0f; 01117 float new_vel[3]; 01118 01119 if(bpa->data.mode == eBoidMode_Liftoff) { 01120 bpa->data.mode = eBoidMode_InAir; 01121 bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor); 01122 } 01123 else if(bpa->data.mode == eBoidMode_InAir && boids->options & BOID_ALLOW_LAND) { 01124 /* auto-leveling & landing if close to ground */ 01125 01126 bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor); 01127 01128 /* level = how many particle sizes above ground */ 01129 level = (pa->prev_state.co[2] - ground_co[2])/(2.0f * pa->size) - 0.5f; 01130 01131 landing_level = - boids->landing_smoothness * pa->prev_state.vel[2] * pa_mass; 01132 01133 if(pa->prev_state.vel[2] < 0.0f) { 01134 if(level < 1.0f) { 01135 bbd->wanted_co[0] = bbd->wanted_co[1] = bbd->wanted_co[2] = 0.0f; 01136 bbd->wanted_speed = 0.0f; 01137 bpa->data.mode = eBoidMode_Falling; 01138 } 01139 else if(level < landing_level) { 01140 bbd->wanted_speed *= (level - 1.0f)/landing_level; 01141 bbd->wanted_co[2] *= (level - 1.0f)/landing_level; 01142 } 01143 } 01144 } 01145 01146 copy_v3_v3(old_dir, pa->prev_state.ave); 01147 new_speed = normalize_v3_v3(wanted_dir, bbd->wanted_co); 01148 01149 /* first check if we have valid direction we want to go towards */ 01150 if(new_speed == 0.0f) { 01151 copy_v3_v3(new_dir, old_dir); 01152 } 01153 else { 01154 float old_dir2[2], wanted_dir2[2], nor[3], angle; 01155 copy_v2_v2(old_dir2, old_dir); 01156 normalize_v2(old_dir2); 01157 copy_v2_v2(wanted_dir2, wanted_dir); 01158 normalize_v2(wanted_dir2); 01159 01160 /* choose random direction to turn if wanted velocity */ 01161 /* is directly behind regardless of z-coordinate */ 01162 if(dot_v2v2(old_dir2, wanted_dir2) < -0.99f) { 01163 wanted_dir[0] = 2.0f*(0.5f - BLI_frand()); 01164 wanted_dir[1] = 2.0f*(0.5f - BLI_frand()); 01165 wanted_dir[2] = 2.0f*(0.5f - BLI_frand()); 01166 normalize_v3(wanted_dir); 01167 } 01168 01169 /* constrain direction with maximum angular velocity */ 01170 angle = saacos(dot_v3v3(old_dir, wanted_dir)); 01171 angle = MIN2(angle, val.max_ave); 01172 01173 cross_v3_v3v3(nor, old_dir, wanted_dir); 01174 axis_angle_to_quat( q,nor, angle); 01175 copy_v3_v3(new_dir, old_dir); 01176 mul_qt_v3(q, new_dir); 01177 normalize_v3(new_dir); 01178 01179 /* save direction in case resulting velocity too small */ 01180 axis_angle_to_quat( q,nor, angle*dtime); 01181 copy_v3_v3(pa->state.ave, old_dir); 01182 mul_qt_v3(q, pa->state.ave); 01183 normalize_v3(pa->state.ave); 01184 } 01185 01186 /* constrain speed with maximum acceleration */ 01187 old_speed = len_v3(pa->prev_state.vel); 01188 01189 if(bbd->wanted_speed < old_speed) 01190 new_speed = MAX2(bbd->wanted_speed, old_speed - val.max_acc); 01191 else 01192 new_speed = MIN2(bbd->wanted_speed, old_speed + val.max_acc); 01193 01194 /* combine direction and speed */ 01195 copy_v3_v3(new_vel, new_dir); 01196 mul_v3_fl(new_vel, new_speed); 01197 01198 /* maintain minimum flying velocity if not landing */ 01199 if(level >= landing_level) { 01200 float len2 = dot_v2v2(new_vel,new_vel); 01201 float root; 01202 01203 len2 = MAX2(len2, val.min_speed*val.min_speed); 01204 root = sasqrt(new_speed*new_speed - len2); 01205 01206 new_vel[2] = new_vel[2] < 0.0f ? -root : root; 01207 01208 normalize_v2(new_vel); 01209 mul_v2_fl(new_vel, sasqrt(len2)); 01210 } 01211 01212 /* finally constrain speed to max speed */ 01213 new_speed = normalize_v3(new_vel); 01214 mul_v3_fl(new_vel, MIN2(new_speed, val.max_speed)); 01215 01216 /* get acceleration from difference of velocities */ 01217 sub_v3_v3v3(acc, new_vel, pa->prev_state.vel); 01218 01219 /* break acceleration to components */ 01220 project_v3_v3v3(tan_acc, acc, pa->prev_state.ave); 01221 sub_v3_v3v3(nor_acc, acc, tan_acc); 01222 } 01223 01224 /* account for effectors */ 01225 pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint); 01226 pdDoEffectors(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL); 01227 01228 if(ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) { 01229 float length = normalize_v3(force); 01230 01231 length = MAX2(0.0f, length - boids->land_stick_force); 01232 01233 mul_v3_fl(force, length); 01234 } 01235 01236 add_v3_v3(acc, force); 01237 01238 /* store smoothed acceleration for nice banking etc. */ 01239 madd_v3_v3fl(bpa->data.acc, acc, dtime); 01240 mul_v3_fl(bpa->data.acc, 1.0f / (1.0f + dtime)); 01241 01242 /* integrate new location & velocity */ 01243 01244 /* by regarding the acceleration as a force at this stage we*/ 01245 /* can get better control allthough it's a bit unphysical */ 01246 mul_v3_fl(acc, 1.0f/pa_mass); 01247 01248 copy_v3_v3(dvec, acc); 01249 mul_v3_fl(dvec, dtime*dtime*0.5f); 01250 01251 copy_v3_v3(bvec, pa->prev_state.vel); 01252 mul_v3_fl(bvec, dtime); 01253 add_v3_v3(dvec, bvec); 01254 add_v3_v3(pa->state.co, dvec); 01255 01256 madd_v3_v3fl(pa->state.vel, acc, dtime); 01257 01258 //if(bpa->data.mode != eBoidMode_InAir) 01259 bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor); 01260 01261 /* change modes, constrain movement & keep track of down vector */ 01262 switch(bpa->data.mode) { 01263 case eBoidMode_InAir: 01264 { 01265 float grav[3]; 01266 01267 grav[0]= 0.0f; 01268 grav[1]= 0.0f; 01269 grav[2]= bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f; 01270 01271 /* don't take forward acceleration into account (better banking) */ 01272 if(dot_v3v3(bpa->data.acc, pa->state.vel) > 0.0f) { 01273 project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel); 01274 sub_v3_v3v3(dvec, bpa->data.acc, dvec); 01275 } 01276 else { 01277 copy_v3_v3(dvec, bpa->data.acc); 01278 } 01279 01280 /* gather apparent gravity */ 01281 madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking); 01282 normalize_v3(bpa->gravity); 01283 01284 /* stick boid on goal when close enough */ 01285 if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) { 01286 bpa->data.mode = eBoidMode_Climbing; 01287 bpa->ground = bbd->goal_ob; 01288 boid_find_ground(bbd, pa, ground_co, ground_nor); 01289 boid_climb(boids, pa, ground_co, ground_nor); 01290 } 01291 else if(pa->state.co[2] <= ground_co[2] + pa->size * boids->height) { 01292 /* land boid when below ground */ 01293 if(boids->options & BOID_ALLOW_LAND) { 01294 pa->state.co[2] = ground_co[2] + pa->size * boids->height; 01295 pa->state.vel[2] = 0.0f; 01296 bpa->data.mode = eBoidMode_OnLand; 01297 } 01298 /* fly above ground */ 01299 else if(bpa->ground) { 01300 pa->state.co[2] = ground_co[2] + pa->size * boids->height; 01301 pa->state.vel[2] = 0.0f; 01302 } 01303 } 01304 break; 01305 } 01306 case eBoidMode_Falling: 01307 { 01308 float grav[3]; 01309 01310 grav[0]= 0.0f; 01311 grav[1]= 0.0f; 01312 grav[2]= bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f; 01313 01314 01315 /* gather apparent gravity */ 01316 madd_v3_v3fl(bpa->gravity, grav, dtime); 01317 normalize_v3(bpa->gravity); 01318 01319 if(boids->options & BOID_ALLOW_LAND) { 01320 /* stick boid on goal when close enough */ 01321 if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) { 01322 bpa->data.mode = eBoidMode_Climbing; 01323 bpa->ground = bbd->goal_ob; 01324 boid_find_ground(bbd, pa, ground_co, ground_nor); 01325 boid_climb(boids, pa, ground_co, ground_nor); 01326 } 01327 /* land boid when really near ground */ 01328 else if(pa->state.co[2] <= ground_co[2] + 1.01f * pa->size * boids->height){ 01329 pa->state.co[2] = ground_co[2] + pa->size * boids->height; 01330 pa->state.vel[2] = 0.0f; 01331 bpa->data.mode = eBoidMode_OnLand; 01332 } 01333 /* if we're falling, can fly and want to go upwards lets fly */ 01334 else if(boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) 01335 bpa->data.mode = eBoidMode_InAir; 01336 } 01337 else 01338 bpa->data.mode = eBoidMode_InAir; 01339 break; 01340 } 01341 case eBoidMode_Climbing: 01342 { 01343 boid_climb(boids, pa, ground_co, ground_nor); 01344 //float nor[3]; 01345 //copy_v3_v3(nor, ground_nor); 01346 01348 //madd_v3_v3fl(pa->r_ve, ground_nor, -1.0); 01349 //normalize_v3(pa->r_ve); 01350 01352 //mul_v3_fl(nor, pa->size * boids->height); 01353 //add_v3_v3v3(pa->state.co, ground_co, nor); 01354 01356 //project_v3_v3v3(v, pa->state.vel, ground_nor); 01357 //sub_v3_v3v3(pa->state.vel, pa->state.vel, v); 01358 break; 01359 } 01360 case eBoidMode_OnLand: 01361 { 01362 /* stick boid on goal when close enough */ 01363 if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) { 01364 bpa->data.mode = eBoidMode_Climbing; 01365 bpa->ground = bbd->goal_ob; 01366 boid_find_ground(bbd, pa, ground_co, ground_nor); 01367 boid_climb(boids, pa, ground_co, ground_nor); 01368 } 01369 /* ground is too far away so boid falls */ 01370 else if(pa->state.co[2]-ground_co[2] > 1.1f * pa->size * boids->height) 01371 bpa->data.mode = eBoidMode_Falling; 01372 else { 01373 /* constrain to surface */ 01374 pa->state.co[2] = ground_co[2] + pa->size * boids->height; 01375 pa->state.vel[2] = 0.0f; 01376 } 01377 01378 if(boids->banking > 0.0f) { 01379 float grav[3]; 01380 /* Don't take gravity's strength in to account, */ 01381 /* otherwise amount of banking is hard to control. */ 01382 negate_v3_v3(grav, ground_nor); 01383 01384 project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel); 01385 sub_v3_v3v3(dvec, bpa->data.acc, dvec); 01386 01387 /* gather apparent gravity */ 01388 madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking); 01389 normalize_v3(bpa->gravity); 01390 } 01391 else { 01392 /* gather negative surface normal */ 01393 madd_v3_v3fl(bpa->gravity, ground_nor, -1.0f); 01394 normalize_v3(bpa->gravity); 01395 } 01396 break; 01397 } 01398 } 01399 01400 /* save direction to state.ave unless the boid is falling */ 01401 /* (boids can't effect their direction when falling) */ 01402 if(bpa->data.mode!=eBoidMode_Falling && len_v3(pa->state.vel) > 0.1f*pa->size) { 01403 copy_v3_v3(pa->state.ave, pa->state.vel); 01404 pa->state.ave[2] *= bbd->part->boids->pitch; 01405 normalize_v3(pa->state.ave); 01406 } 01407 01408 /* apply damping */ 01409 if(ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) 01410 mul_v3_fl(pa->state.vel, 1.0f - 0.2f*bbd->part->dampfac); 01411 01412 /* calculate rotation matrix based on forward & down vectors */ 01413 if(bpa->data.mode == eBoidMode_InAir) { 01414 copy_v3_v3(mat[0], pa->state.ave); 01415 01416 project_v3_v3v3(dvec, bpa->gravity, pa->state.ave); 01417 sub_v3_v3v3(mat[2], bpa->gravity, dvec); 01418 normalize_v3(mat[2]); 01419 } 01420 else { 01421 project_v3_v3v3(dvec, pa->state.ave, bpa->gravity); 01422 sub_v3_v3v3(mat[0], pa->state.ave, dvec); 01423 normalize_v3(mat[0]); 01424 01425 copy_v3_v3(mat[2], bpa->gravity); 01426 } 01427 negate_v3(mat[2]); 01428 cross_v3_v3v3(mat[1], mat[2], mat[0]); 01429 01430 /* apply rotation */ 01431 mat3_to_quat_is_ok( q,mat); 01432 copy_qt_qt(pa->state.rot, q); 01433 } 01434 01435 BoidRule *boid_new_rule(int type) 01436 { 01437 BoidRule *rule = NULL; 01438 if(type <= 0) 01439 return NULL; 01440 01441 switch(type) { 01442 case eBoidRuleType_Goal: 01443 case eBoidRuleType_Avoid: 01444 rule = MEM_callocN(sizeof(BoidRuleGoalAvoid), "BoidRuleGoalAvoid"); 01445 break; 01446 case eBoidRuleType_AvoidCollision: 01447 rule = MEM_callocN(sizeof(BoidRuleAvoidCollision), "BoidRuleAvoidCollision"); 01448 ((BoidRuleAvoidCollision*)rule)->look_ahead = 2.0f; 01449 break; 01450 case eBoidRuleType_FollowLeader: 01451 rule = MEM_callocN(sizeof(BoidRuleFollowLeader), "BoidRuleFollowLeader"); 01452 ((BoidRuleFollowLeader*)rule)->distance = 1.0f; 01453 break; 01454 case eBoidRuleType_AverageSpeed: 01455 rule = MEM_callocN(sizeof(BoidRuleAverageSpeed), "BoidRuleAverageSpeed"); 01456 ((BoidRuleAverageSpeed*)rule)->speed = 0.5f; 01457 break; 01458 case eBoidRuleType_Fight: 01459 rule = MEM_callocN(sizeof(BoidRuleFight), "BoidRuleFight"); 01460 ((BoidRuleFight*)rule)->distance = 100.0f; 01461 ((BoidRuleFight*)rule)->flee_distance = 100.0f; 01462 break; 01463 default: 01464 rule = MEM_callocN(sizeof(BoidRule), "BoidRule"); 01465 break; 01466 } 01467 01468 rule->type = type; 01469 rule->flag |= BOIDRULE_IN_AIR|BOIDRULE_ON_LAND; 01470 BLI_strncpy(rule->name, boidrule_type_items[type-1].name, sizeof(rule->name)); 01471 01472 return rule; 01473 } 01474 void boid_default_settings(BoidSettings *boids) 01475 { 01476 boids->air_max_speed = 10.0f; 01477 boids->air_max_acc = 0.5f; 01478 boids->air_max_ave = 0.5f; 01479 boids->air_personal_space = 1.0f; 01480 01481 boids->land_max_speed = 5.0f; 01482 boids->land_max_acc = 0.5f; 01483 boids->land_max_ave = 0.5f; 01484 boids->land_personal_space = 1.0f; 01485 01486 boids->options = BOID_ALLOW_FLIGHT; 01487 01488 boids->landing_smoothness = 3.0f; 01489 boids->banking = 1.0f; 01490 boids->pitch = 1.0f; 01491 boids->height = 1.0f; 01492 01493 boids->health = 1.0f; 01494 boids->accuracy = 1.0f; 01495 boids->aggression = 2.0f; 01496 boids->range = 1.0f; 01497 boids->strength = 0.1f; 01498 } 01499 01500 BoidState *boid_new_state(BoidSettings *boids) 01501 { 01502 BoidState *state = MEM_callocN(sizeof(BoidState), "BoidState"); 01503 01504 state->id = boids->last_state_id++; 01505 if(state->id) 01506 BLI_snprintf(state->name, sizeof(state->name), "State %i", state->id); 01507 else 01508 strcpy(state->name, "State"); 01509 01510 state->rule_fuzziness = 0.5; 01511 state->volume = 1.0f; 01512 state->channels |= ~0; 01513 01514 return state; 01515 } 01516 01517 BoidState *boid_duplicate_state(BoidSettings *boids, BoidState *state) 01518 { 01519 BoidState *staten = MEM_dupallocN(state); 01520 01521 BLI_duplicatelist(&staten->rules, &state->rules); 01522 BLI_duplicatelist(&staten->conditions, &state->conditions); 01523 BLI_duplicatelist(&staten->actions, &state->actions); 01524 01525 staten->id = boids->last_state_id++; 01526 01527 return staten; 01528 } 01529 void boid_free_settings(BoidSettings *boids) 01530 { 01531 if(boids) { 01532 BoidState *state = boids->states.first; 01533 01534 for(; state; state=state->next) { 01535 BLI_freelistN(&state->rules); 01536 BLI_freelistN(&state->conditions); 01537 BLI_freelistN(&state->actions); 01538 } 01539 01540 BLI_freelistN(&boids->states); 01541 01542 MEM_freeN(boids); 01543 } 01544 } 01545 BoidSettings *boid_copy_settings(BoidSettings *boids) 01546 { 01547 BoidSettings *nboids = NULL; 01548 01549 if(boids) { 01550 BoidState *state; 01551 BoidState *nstate; 01552 01553 nboids = MEM_dupallocN(boids); 01554 01555 BLI_duplicatelist(&nboids->states, &boids->states); 01556 01557 state = boids->states.first; 01558 nstate = nboids->states.first; 01559 for(; state; state=state->next, nstate=nstate->next) { 01560 BLI_duplicatelist(&nstate->rules, &state->rules); 01561 BLI_duplicatelist(&nstate->conditions, &state->conditions); 01562 BLI_duplicatelist(&nstate->actions, &state->actions); 01563 } 01564 } 01565 01566 return nboids; 01567 } 01568 BoidState *boid_get_current_state(BoidSettings *boids) 01569 { 01570 BoidState *state = boids->states.first; 01571 01572 for(; state; state=state->next) { 01573 if(state->flag & BOIDSTATE_CURRENT) 01574 break; 01575 } 01576 01577 return state; 01578 } 01579