Blender V4.3
boids.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 by Janne Karhu. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cmath>
10#include <cstring>
11
12#include "MEM_guardedalloc.h"
13
15#include "DNA_scene_types.h"
16
17#include "BLI_blenlib.h"
18#include "BLI_kdtree.h"
19#include "BLI_math_base_safe.h"
20#include "BLI_math_rotation.h"
21#include "BLI_math_vector.h"
22#include "BLI_rand.h"
23#include "BLI_utildefines.h"
24
25#include "BKE_boids.h"
26#include "BKE_collision.h"
27#include "BKE_effect.h"
28#include "BKE_particle.h"
29#include "BLI_kdopbvh.h"
30
31#include "BLT_translation.hh"
32
33#include "BKE_modifier.hh"
34
35#include "RNA_enum_types.hh"
36
37static float len_squared_v3v3_with_normal_bias(const float co_search[3],
38 const float co_test[3],
39 const void *user_data)
40{
41 const float *normal = static_cast<const float *>(user_data);
42 float d[3], dist;
43
44 sub_v3_v3v3(d, co_test, co_search);
45
46 dist = len_squared_v3(d);
47
48 /* Avoid head-on collisions. */
49 if (dot_v3v3(d, normal) < 0.0f) {
50 dist *= 10.0f;
51 }
52 return dist;
53}
54
60
61static bool apply_boid_rule(
62 BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness);
63
64static bool rule_none(BoidRule * /*rule*/,
65 BoidBrainData * /*data*/,
66 BoidValues * /*val*/,
67 ParticleData * /*pa*/)
68{
69 return false;
70}
71
73{
75 BoidSettings *boids = bbd->part->boids;
76 BoidParticle *bpa = pa->boid;
77 EffectedPoint epoint;
78 ListBase *effectors = bbd->sim->psys->effectors;
79 EffectorCache *eff = nullptr;
80 EffectorCache temp_eff;
81 EffectorData efd, cur_efd;
82 float mul = (rule->type == eBoidRuleType_Avoid ? 1.0 : -1.0);
83 float priority = 0.0f, len = 0.0f;
84 bool ret = false;
85
86 int p = 0;
87 efd.index = cur_efd.index = &p;
88
89 pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
90
91 /* first find out goal/predator with highest priority */
92 if (effectors) {
93 LISTBASE_FOREACH (EffectorCache *, cur, effectors) {
94 Object *eob = cur->ob;
95 PartDeflect *pd = cur->pd;
96
97 if (gabr->ob && (rule->type != eBoidRuleType_Goal || gabr->ob != bpa->ground)) {
98 if (gabr->ob == eob) {
99 /* TODO: effectors with multiple points */
100 if (get_effector_data(cur, &efd, &epoint, 0)) {
101 if (cur->pd && cur->pd->forcefield == PFIELD_BOID) {
102 priority = mul * pd->f_strength *
103 effector_falloff(cur, &efd, &epoint, bbd->part->effector_weights);
104 }
105 else {
106 priority = 1.0;
107 }
108
109 eff = cur;
110 }
111 break;
112 }
113 }
114 else if (rule->type == eBoidRuleType_Goal && eob == bpa->ground) {
115 /* skip current object */
116 }
117 else if (pd->forcefield == PFIELD_BOID && mul * pd->f_strength > 0.0f &&
118 get_effector_data(cur, &cur_efd, &epoint, 0))
119 {
120 float temp = mul * pd->f_strength *
121 effector_falloff(cur, &cur_efd, &epoint, bbd->part->effector_weights);
122
123 if (temp == 0.0f) {
124 /* do nothing */
125 }
126 else if (temp > priority) {
127 priority = temp;
128 eff = cur;
129 efd = cur_efd;
130 len = efd.distance;
131 }
132 /* choose closest object with same priority */
133 else if (temp == priority && efd.distance < len) {
134 eff = cur;
135 efd = cur_efd;
136 len = efd.distance;
137 }
138 }
139 }
140 }
141
142 /* if the object doesn't have effector data we have to fake it */
143 if (eff == nullptr && gabr->ob) {
144 memset(&temp_eff, 0, sizeof(EffectorCache));
145 temp_eff.ob = gabr->ob;
146 temp_eff.depsgraph = bbd->sim->depsgraph;
147 temp_eff.scene = bbd->sim->scene;
148 eff = &temp_eff;
149 get_effector_data(eff, &efd, &epoint, 0);
150 priority = 1.0f;
151 }
152
153 /* Then use that effector. */
154
155 /* With avoid, factor is "fear factor". */
156 if (priority > (rule->type == eBoidRuleType_Avoid ? gabr->fear_factor : 0.0f)) {
157 Object *eob = eff->ob;
158 PartDeflect *pd = eff->pd;
159 float surface = (pd && pd->shape == PFIELD_SHAPE_SURFACE) ? 1.0f : 0.0f;
160
161 if (gabr->options & BRULE_GOAL_AVOID_PREDICT) {
162 /* estimate future location of target */
163 get_effector_data(eff, &efd, &epoint, 1);
164
165 mul_v3_fl(efd.vel, efd.distance / (val->max_speed * bbd->timestep));
166 add_v3_v3(efd.loc, efd.vel);
168 efd.distance = len_v3(efd.vec_to_point);
169 }
170
171 if (rule->type == eBoidRuleType_Goal && boids->options & BOID_ALLOW_CLIMB && surface != 0.0f) {
172 if (!bbd->goal_ob || bbd->goal_priority < priority) {
173 bbd->goal_ob = eob;
174 copy_v3_v3(bbd->goal_co, efd.loc);
175 copy_v3_v3(bbd->goal_nor, efd.nor);
176 }
177 }
178 else if ((rule->type == eBoidRuleType_Avoid) && (bpa->data.mode == eBoidMode_Climbing) &&
179 (priority > 2.0f * gabr->fear_factor))
180 {
181 /* detach from surface and try to fly away from danger */
183 }
184
186 mul_v3_fl(bbd->wanted_co, mul);
187
188 bbd->wanted_speed = val->max_speed * priority;
189
190 /* with goals factor is approach velocity factor */
191 if (rule->type == eBoidRuleType_Goal && boids->landing_smoothness > 0.0f) {
192 float len2 = 2.0f * len_v3(pa->prev_state.vel);
193
194 surface *= pa->size * boids->height;
195
196 if (len2 > 0.0f && efd.distance - surface < len2) {
197 len2 = (efd.distance - surface) / len2;
198 bbd->wanted_speed *= powf(len2, boids->landing_smoothness);
199 }
200 }
201
202 ret = true;
203 }
204
205 return ret;
206}
207
209 BoidBrainData *bbd,
210 BoidValues *val,
211 ParticleData *pa)
212{
213 const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT;
215 KDTreeNearest_3d *ptn = nullptr;
216 BoidParticle *bpa = pa->boid;
217 float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
218 float co1[3], vel1[3], co2[3], vel2[3];
219 float len, t, inp, t_min = 2.0f;
220 int n, neighbors = 0, nearest = 0;
221 bool ret = false;
222
223 /* Check deflector objects first. */
224 if (acbr->options & BRULE_ACOLL_WITH_DEFLECTORS && bbd->sim->colliders) {
226 BVHTreeRayHit hit;
227 float radius = val->personal_space * pa->size, ray_dir[3];
228
229 memset(&col, 0, sizeof(ParticleCollision));
230
231 copy_v3_v3(col.co1, pa->prev_state.co);
232 add_v3_v3v3(col.co2, pa->prev_state.co, pa->prev_state.vel);
233 sub_v3_v3v3(ray_dir, col.co2, col.co1);
234 mul_v3_fl(ray_dir, acbr->look_ahead);
235 col.f = 0.0f;
236 hit.index = -1;
237 hit.dist = col.original_ray_length = normalize_v3(ray_dir);
238
239 /* find out closest deflector object */
241 /* don't check with current ground object */
242 if (coll->ob == bpa->ground) {
243 continue;
244 }
245
246 col.current = coll->ob;
247 col.md = coll->collmd;
248
249 if (col.md && col.md->bvhtree) {
250 BLI_bvhtree_ray_cast_ex(col.md->bvhtree,
251 col.co1,
252 ray_dir,
253 radius,
254 &hit,
256 &col,
257 raycast_flag);
258 }
259 }
260 /* then avoid that object */
261 if (hit.index >= 0) {
262 t = hit.dist / col.original_ray_length;
263
264 /* avoid head-on collision */
265 if (dot_v3v3(col.pce.nor, pa->prev_state.ave) < -0.99f) {
266 /* don't know why, but uneven range [0.0, 1.0] */
267 /* works much better than even [-1.0, 1.0] */
268 bbd->wanted_co[0] = BLI_rng_get_float(bbd->rng);
269 bbd->wanted_co[1] = BLI_rng_get_float(bbd->rng);
270 bbd->wanted_co[2] = BLI_rng_get_float(bbd->rng);
271 }
272 else {
273 copy_v3_v3(bbd->wanted_co, col.pce.nor);
274 }
275
276 mul_v3_fl(bbd->wanted_co, (1.0f - t) * val->personal_space * pa->size);
277
278 bbd->wanted_speed = sqrtf(t) * len_v3(pa->prev_state.vel);
279 bbd->wanted_speed = std::max(bbd->wanted_speed, val->min_speed);
280
281 return true;
282 }
283 }
284
285 /* Check boids in their own system. */
286 if (acbr->options & BRULE_ACOLL_WITH_BOIDS) {
287 neighbors = BLI_kdtree_3d_range_search_with_len_squared_cb(bbd->sim->psys->tree,
288 pa->prev_state.co,
289 &ptn,
290 acbr->look_ahead *
291 len_v3(pa->prev_state.vel),
293 pa->prev_state.ave);
294 if (neighbors > 1) {
295 for (n = 1; n < neighbors; n++) {
296 copy_v3_v3(co1, pa->prev_state.co);
297 copy_v3_v3(vel1, pa->prev_state.vel);
298 copy_v3_v3(co2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.co);
299 copy_v3_v3(vel2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.vel);
300
301 sub_v3_v3v3(loc, co1, co2);
302
303 sub_v3_v3v3(vec, vel1, vel2);
304
305 inp = dot_v3v3(vec, vec);
306
307 /* velocities not parallel */
308 if (inp != 0.0f) {
309 t = -dot_v3v3(loc, vec) / inp;
310 /* cpa is not too far in the future so investigate further */
311 if (t > 0.0f && t < t_min) {
312 madd_v3_v3fl(co1, vel1, t);
313 madd_v3_v3fl(co2, vel2, t);
314
315 sub_v3_v3v3(vec, co2, co1);
316
317 len = normalize_v3(vec);
318
319 /* distance of cpa is close enough */
320 if (len < 2.0f * val->personal_space * pa->size) {
321 t_min = t;
322
323 mul_v3_fl(vec, len_v3(vel1));
324 mul_v3_fl(vec, (2.0f - t) / 2.0f);
325 sub_v3_v3v3(bbd->wanted_co, vel1, vec);
326 bbd->wanted_speed = len_v3(bbd->wanted_co);
327 ret = true;
328 }
329 }
330 }
331 }
332 }
333 }
334 MEM_SAFE_FREE(ptn);
335
336 /* check boids in other systems */
338 ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
339
340 if (epsys) {
341 BLI_assert(epsys->tree != nullptr);
342 neighbors = BLI_kdtree_3d_range_search_with_len_squared_cb(epsys->tree,
343 pa->prev_state.co,
344 &ptn,
345 acbr->look_ahead *
346 len_v3(pa->prev_state.vel),
348 pa->prev_state.ave);
349
350 if (neighbors > 0) {
351 for (n = 0; n < neighbors; n++) {
352 copy_v3_v3(co1, pa->prev_state.co);
353 copy_v3_v3(vel1, pa->prev_state.vel);
354 copy_v3_v3(co2, (epsys->particles + ptn[n].index)->prev_state.co);
355 copy_v3_v3(vel2, (epsys->particles + ptn[n].index)->prev_state.vel);
356
357 sub_v3_v3v3(loc, co1, co2);
358
359 sub_v3_v3v3(vec, vel1, vel2);
360
361 inp = dot_v3v3(vec, vec);
362
363 /* velocities not parallel */
364 if (inp != 0.0f) {
365 t = -dot_v3v3(loc, vec) / inp;
366 /* cpa is not too far in the future so investigate further */
367 if (t > 0.0f && t < t_min) {
368 madd_v3_v3fl(co1, vel1, t);
369 madd_v3_v3fl(co2, vel2, t);
370
371 sub_v3_v3v3(vec, co2, co1);
372
373 len = normalize_v3(vec);
374
375 /* distance of cpa is close enough */
376 if (len < 2.0f * val->personal_space * pa->size) {
377 t_min = t;
378
379 mul_v3_fl(vec, len_v3(vel1));
380 mul_v3_fl(vec, (2.0f - t) / 2.0f);
381 sub_v3_v3v3(bbd->wanted_co, vel1, vec);
382 bbd->wanted_speed = len_v3(bbd->wanted_co);
383 ret = true;
384 }
385 }
386 }
387 }
388 }
389
390 MEM_SAFE_FREE(ptn);
391 }
392 }
393
394 if (ptn && nearest == 0) {
395 MEM_freeN(ptn);
396 }
397
398 return ret;
399}
400static bool rule_separate(BoidRule * /*rule*/,
401 BoidBrainData *bbd,
402 BoidValues *val,
403 ParticleData *pa)
404{
405 KDTreeNearest_3d *ptn = nullptr;
406 float len = 2.0f * val->personal_space * pa->size + 1.0f;
407 float vec[3] = {0.0f, 0.0f, 0.0f};
408 int neighbors = BLI_kdtree_3d_range_search(
409 bbd->sim->psys->tree, pa->prev_state.co, &ptn, 2.0f * val->personal_space * pa->size);
410 bool ret = false;
411
412 if (neighbors > 1 && ptn[1].dist != 0.0f) {
413 sub_v3_v3v3(vec, pa->prev_state.co, bbd->sim->psys->particles[ptn[1].index].state.co);
414 mul_v3_fl(vec, (2.0f * val->personal_space * pa->size - ptn[1].dist) / ptn[1].dist);
415 add_v3_v3(bbd->wanted_co, vec);
416 bbd->wanted_speed = val->max_speed;
417 len = ptn[1].dist;
418 ret = true;
419 }
420 MEM_SAFE_FREE(ptn);
421
422 /* check other boid systems */
424 ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
425
426 if (epsys) {
427 neighbors = BLI_kdtree_3d_range_search(
428 epsys->tree, pa->prev_state.co, &ptn, 2.0f * val->personal_space * pa->size);
429
430 if (neighbors > 0 && ptn[0].dist < len) {
431 sub_v3_v3v3(vec, pa->prev_state.co, ptn[0].co);
432 mul_v3_fl(vec, (2.0f * val->personal_space * pa->size - ptn[0].dist) / ptn[1].dist);
433 add_v3_v3(bbd->wanted_co, vec);
434 bbd->wanted_speed = val->max_speed;
435 len = ptn[0].dist;
436 ret = true;
437 }
438
439 MEM_SAFE_FREE(ptn);
440 }
441 }
442 return ret;
443}
444static bool rule_flock(BoidRule * /*rule*/,
445 BoidBrainData *bbd,
446 BoidValues * /*val*/,
447 ParticleData *pa)
448{
449 KDTreeNearest_3d ptn[11];
450 float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
451 int neighbors = BLI_kdtree_3d_find_nearest_n_with_len_squared_cb(
452 bbd->sim->psys->tree,
453 pa->state.co,
454 ptn,
455 ARRAY_SIZE(ptn),
457 pa->prev_state.ave);
458 int n;
459 bool ret = false;
460
461 if (neighbors > 1) {
462 for (n = 1; n < neighbors; n++) {
463 add_v3_v3(loc, bbd->sim->psys->particles[ptn[n].index].prev_state.co);
464 add_v3_v3(vec, bbd->sim->psys->particles[ptn[n].index].prev_state.vel);
465 }
466
467 mul_v3_fl(loc, 1.0f / (float(neighbors) - 1.0f));
468 mul_v3_fl(vec, 1.0f / (float(neighbors) - 1.0f));
469
470 sub_v3_v3(loc, pa->prev_state.co);
471 sub_v3_v3(vec, pa->prev_state.vel);
472
473 add_v3_v3(bbd->wanted_co, vec);
474 add_v3_v3(bbd->wanted_co, loc);
475 bbd->wanted_speed = len_v3(bbd->wanted_co);
476
477 ret = true;
478 }
479 return ret;
480}
481static bool rule_follow_leader(BoidRule *rule,
482 BoidBrainData *bbd,
483 BoidValues *val,
484 ParticleData *pa)
485{
487 float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
488 float mul, len;
489 const int n = (flbr->queue_size <= 1) ? bbd->sim->psys->totpart : flbr->queue_size;
491 const int p = int(pa - bbd->sim->psys->particles);
492 int i;
493 bool ret = false;
494
495 if (flbr->ob) {
496 float vec2[3], t;
497
498 /* first check we're not blocking the leader */
499 sub_v3_v3v3(vec, flbr->loc, flbr->oloc);
500 mul_v3_fl(vec, 1.0f / bbd->timestep);
501
502 sub_v3_v3v3(loc, pa->prev_state.co, flbr->oloc);
503
504 mul = dot_v3v3(vec, vec);
505
506 /* leader is not moving */
507 if (mul < 0.01f) {
508 len = len_v3(loc);
509 /* too close to leader */
510 if (len < 2.0f * val->personal_space * pa->size) {
511 copy_v3_v3(bbd->wanted_co, loc);
512 bbd->wanted_speed = val->max_speed;
513 return true;
514 }
515 }
516 else {
517 t = dot_v3v3(loc, vec) / mul;
518
519 /* possible blocking of leader in near future */
520 if (t > 0.0f && t < 3.0f) {
521 copy_v3_v3(vec2, vec);
522 mul_v3_fl(vec2, t);
523
524 sub_v3_v3v3(vec2, loc, vec2);
525
526 len = len_v3(vec2);
527
528 if (len < 2.0f * val->personal_space * pa->size) {
529 copy_v3_v3(bbd->wanted_co, vec2);
530 bbd->wanted_speed = val->max_speed * (3.0f - t) / 3.0f;
531 return true;
532 }
533 }
534 }
535
536 /* not blocking so try to follow leader */
537 if (p && flbr->options & BRULE_LEADER_IN_LINE) {
538 copy_v3_v3(vec, bbd->sim->psys->particles[p - 1].prev_state.vel);
539 copy_v3_v3(loc, bbd->sim->psys->particles[p - 1].prev_state.co);
540 }
541 else {
542 copy_v3_v3(loc, flbr->oloc);
543 sub_v3_v3v3(vec, flbr->loc, flbr->oloc);
544 mul_v3_fl(vec, 1.0f / bbd->timestep);
545 }
546
547 /* fac is seconds behind leader */
548 madd_v3_v3fl(loc, vec, -flbr->distance);
549
550 sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co);
551 bbd->wanted_speed = len_v3(bbd->wanted_co);
552
553 ret = true;
554 }
555 else if (p % n) {
556 float vec2[3], t, t_min = 3.0f;
557
558 /* first check we're not blocking any leaders */
559 for (i = 0; i < bbd->sim->psys->totpart; i += n) {
560 copy_v3_v3(vec, bbd->sim->psys->particles[i].prev_state.vel);
561
562 sub_v3_v3v3(loc, pa->prev_state.co, bbd->sim->psys->particles[i].prev_state.co);
563
564 mul = dot_v3v3(vec, vec);
565
566 /* leader is not moving */
567 if (mul < 0.01f) {
568 len = len_v3(loc);
569 /* too close to leader */
570 if (len < 2.0f * val->personal_space * pa->size) {
571 copy_v3_v3(bbd->wanted_co, loc);
572 bbd->wanted_speed = val->max_speed;
573 return true;
574 }
575 }
576 else {
577 t = dot_v3v3(loc, vec) / mul;
578
579 /* possible blocking of leader in near future */
580 if (t > 0.0f && t < t_min) {
581 copy_v3_v3(vec2, vec);
582 mul_v3_fl(vec2, t);
583
584 sub_v3_v3v3(vec2, loc, vec2);
585
586 len = len_v3(vec2);
587
588 if (len < 2.0f * val->personal_space * pa->size) {
589 t_min = t;
590 copy_v3_v3(bbd->wanted_co, loc);
591 bbd->wanted_speed = val->max_speed * (3.0f - t) / 3.0f;
592 ret = true;
593 }
594 }
595 }
596 }
597
598 if (ret) {
599 return true;
600 }
601
602 /* not blocking so try to follow leader */
603 if (flbr->options & BRULE_LEADER_IN_LINE) {
604 copy_v3_v3(vec, bbd->sim->psys->particles[p - 1].prev_state.vel);
605 copy_v3_v3(loc, bbd->sim->psys->particles[p - 1].prev_state.co);
606 }
607 else {
608 copy_v3_v3(vec, bbd->sim->psys->particles[p - p % n].prev_state.vel);
609 copy_v3_v3(loc, bbd->sim->psys->particles[p - p % n].prev_state.co);
610 }
611
612 /* fac is seconds behind leader */
613 madd_v3_v3fl(loc, vec, -flbr->distance);
614
615 sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co);
616 bbd->wanted_speed = len_v3(bbd->wanted_co);
617
618 ret = true;
619 }
620
621 return ret;
622}
623static bool rule_average_speed(BoidRule *rule,
624 BoidBrainData *bbd,
625 BoidValues *val,
626 ParticleData *pa)
627{
628 BoidParticle *bpa = pa->boid;
630 float vec[3] = {0.0f, 0.0f, 0.0f};
631
632 if (asbr->wander > 0.0f) {
633 /* abuse pa->r_ave for wandering */
634 bpa->wander[0] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng));
635 bpa->wander[1] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng));
636 bpa->wander[2] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng));
637
638 normalize_v3(bpa->wander);
639
640 copy_v3_v3(vec, bpa->wander);
641
642 mul_qt_v3(pa->prev_state.rot, vec);
643
645
646 mul_v3_fl(bbd->wanted_co, 1.1f);
647
648 add_v3_v3(bbd->wanted_co, vec);
649
650 /* leveling */
651 if (asbr->level > 0.0f && psys_uses_gravity(bbd->sim)) {
653 mul_v3_fl(vec, asbr->level);
654 sub_v3_v3(bbd->wanted_co, vec);
655 }
656 }
657 else {
659
660 /* may happen at birth */
661 if (dot_v2v2(bbd->wanted_co, bbd->wanted_co) == 0.0f) {
662 bbd->wanted_co[0] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
663 bbd->wanted_co[1] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
664 bbd->wanted_co[2] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
665 }
666
667 /* leveling */
668 if (asbr->level > 0.0f && psys_uses_gravity(bbd->sim)) {
670 mul_v3_fl(vec, asbr->level);
671 sub_v3_v3(bbd->wanted_co, vec);
672 }
673 }
674 bbd->wanted_speed = asbr->speed * val->max_speed;
675
676 return true;
677}
678static bool rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
679{
680 BoidRuleFight *fbr = (BoidRuleFight *)rule;
681 KDTreeNearest_3d *ptn = nullptr;
682 ParticleData *epars;
683 ParticleData *enemy_pa = nullptr;
684 BoidParticle *bpa;
685 /* friends & enemies */
686 float closest_enemy[3] = {0.0f, 0.0f, 0.0f};
687 float closest_dist = fbr->distance + 1.0f;
688 float f_strength = 0.0f, e_strength = 0.0f;
689 float health = 0.0f;
690 int n;
691 bool ret = false;
692
693 /* calculate its own group strength */
694 int neighbors = BLI_kdtree_3d_range_search(
695 bbd->sim->psys->tree, pa->prev_state.co, &ptn, fbr->distance);
696 for (n = 0; n < neighbors; n++) {
697 bpa = bbd->sim->psys->particles[ptn[n].index].boid;
698 health += bpa->data.health;
699 }
700
701 f_strength += bbd->part->boids->strength * health;
702
703 MEM_SAFE_FREE(ptn);
704
705 /* add other friendlies and calculate enemy strength and find closest enemy */
707 ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
708 if (epsys && epsys->part->boids) {
709 epars = epsys->particles;
710
711 neighbors = BLI_kdtree_3d_range_search(epsys->tree, pa->prev_state.co, &ptn, fbr->distance);
712
713 health = 0.0f;
714
715 for (n = 0; n < neighbors; n++) {
716 bpa = epars[ptn[n].index].boid;
717 health += bpa->data.health;
718
719 if (n == 0 && pt->mode == PTARGET_MODE_ENEMY && ptn[n].dist < closest_dist) {
720 copy_v3_v3(closest_enemy, ptn[n].co);
721 closest_dist = ptn[n].dist;
722 enemy_pa = epars + ptn[n].index;
723 }
724 }
725 if (pt->mode == PTARGET_MODE_ENEMY) {
726 e_strength += epsys->part->boids->strength * health;
727 }
728 else if (pt->mode == PTARGET_MODE_FRIEND) {
729 f_strength += epsys->part->boids->strength * health;
730 }
731
732 MEM_SAFE_FREE(ptn);
733 }
734 }
735 /* decide action if enemy presence found */
736 if (e_strength > 0.0f) {
737 sub_v3_v3v3(bbd->wanted_co, closest_enemy, pa->prev_state.co);
738
739 /* attack if in range */
740 if (closest_dist <= bbd->part->boids->range + pa->size + enemy_pa->size) {
741 float damage = BLI_rng_get_float(bbd->rng);
742 float enemy_dir[3];
743
744 normalize_v3_v3(enemy_dir, bbd->wanted_co);
745
746 /* fight mode */
747 bbd->wanted_speed = 0.0f;
748
749 /* must face enemy to fight */
750 if (dot_v3v3(pa->prev_state.ave, enemy_dir) > 0.5f) {
751 bpa = enemy_pa->boid;
752 bpa->data.health -= bbd->part->boids->strength * bbd->timestep *
753 ((1.0f - bbd->part->boids->accuracy) * damage +
754 bbd->part->boids->accuracy);
755 }
756 }
757 else {
758 /* approach mode */
759 bbd->wanted_speed = val->max_speed;
760 }
761
762 /* check if boid doesn't want to fight */
763 bpa = pa->boid;
764 if (bpa->data.health / bbd->part->boids->health * bbd->part->boids->aggression <
765 e_strength / f_strength)
766 {
767 /* decide to flee */
768 if (closest_dist < fbr->flee_distance * fbr->distance) {
769 negate_v3(bbd->wanted_co);
770 bbd->wanted_speed = val->max_speed;
771 }
772 else { /* wait for better odds */
773 bbd->wanted_speed = 0.0f;
774 }
775 }
776
777 ret = true;
778 }
779
780 return ret;
781}
782
783using boid_rule_cb = bool (*)(BoidRule *rule,
785 BoidValues *val,
786 ParticleData *pa);
787
789 rule_none,
798#if 0
799 rule_help,
800 rule_protect,
801 rule_hide,
802 rule_follow_path,
803 rule_follow_wall,
804#endif
805};
806
808{
809 BoidParticle *bpa = pa->boid;
810
812 val->max_speed = boids->land_max_speed * bpa->data.health / boids->health;
813 val->max_acc = boids->land_max_acc * val->max_speed;
814 val->max_ave = boids->land_max_ave * float(M_PI) * bpa->data.health / boids->health;
815 val->min_speed = 0.0f; /* no minimum speed on land */
817 val->jump_speed = boids->land_jump_speed * bpa->data.health / boids->health;
818 }
819 else {
820 val->max_speed = boids->air_max_speed * bpa->data.health / boids->health;
821 val->max_acc = boids->air_max_acc * val->max_speed;
822 val->max_ave = boids->air_max_ave * float(M_PI) * bpa->data.health / boids->health;
823 val->min_speed = boids->air_min_speed * boids->air_max_speed;
825 val->jump_speed = 0.0f; /* no jumping in air */
826 }
827}
828
830 ParticleData *pa,
831 float ground_co[3],
832 float ground_nor[3])
833{
834 const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT;
835 BoidParticle *bpa = pa->boid;
836
837 if (bpa->data.mode == eBoidMode_Climbing) {
838 SurfaceModifierData *surmd = nullptr;
839 float x[3], v[3];
840
842
843 /* take surface velocity into account */
844 closest_point_on_surface(surmd, pa->state.co, x, nullptr, v);
845 add_v3_v3(x, v);
846
847 /* get actual position on surface */
848 closest_point_on_surface(surmd, x, ground_co, ground_nor, nullptr);
849
850 return bpa->ground;
851 }
852
853 const float zvec[3] = {0.0f, 0.0f, 2000.0f};
855 BVHTreeRayHit hit;
856 float radius = 0.0f, t, ray_dir[3];
857
858 if (!bbd->sim->colliders) {
859 return nullptr;
860 }
861
862 memset(&col, 0, sizeof(ParticleCollision));
863
864 /* first try to find below boid */
865 copy_v3_v3(col.co1, pa->state.co);
866 sub_v3_v3v3(col.co2, pa->state.co, zvec);
867 sub_v3_v3v3(ray_dir, col.co2, col.co1);
868 col.f = 0.0f;
869 hit.index = -1;
870 hit.dist = col.original_ray_length = normalize_v3(ray_dir);
871 col.pce.inside = 0;
872
874 col.current = coll->ob;
875 col.md = coll->collmd;
876 col.fac1 = col.fac2 = 0.0f;
877
878 if (col.md && col.md->bvhtree) {
879 BLI_bvhtree_ray_cast_ex(col.md->bvhtree,
880 col.co1,
881 ray_dir,
882 radius,
883 &hit,
885 &col,
886 raycast_flag);
887 }
888 }
889 /* then use that object */
890 if (hit.index >= 0) {
891 t = hit.dist / col.original_ray_length;
892 interp_v3_v3v3(ground_co, col.co1, col.co2, t);
893 normalize_v3_v3(ground_nor, col.pce.nor);
894 return col.hit;
895 }
896
897 /* couldn't find below, so find upmost deflector object */
898 add_v3_v3v3(col.co1, pa->state.co, zvec);
899 sub_v3_v3v3(col.co2, pa->state.co, zvec);
900 sub_v3_v3(col.co2, zvec);
901 sub_v3_v3v3(ray_dir, col.co2, col.co1);
902 col.f = 0.0f;
903 hit.index = -1;
904 hit.dist = col.original_ray_length = normalize_v3(ray_dir);
905
907 col.current = coll->ob;
908 col.md = coll->collmd;
909
910 if (col.md && col.md->bvhtree) {
911 BLI_bvhtree_ray_cast_ex(col.md->bvhtree,
912 col.co1,
913 ray_dir,
914 radius,
915 &hit,
917 &col,
918 raycast_flag);
919 }
920 }
921 /* then use that object */
922 if (hit.index >= 0) {
923 t = hit.dist / col.original_ray_length;
924 interp_v3_v3v3(ground_co, col.co1, col.co2, t);
925 normalize_v3_v3(ground_nor, col.pce.nor);
926 return col.hit;
927 }
928
929 /* default to z=0 */
930 copy_v3_v3(ground_co, pa->state.co);
931 ground_co[2] = 0;
932 ground_nor[0] = ground_nor[1] = 0.0f;
933 ground_nor[2] = 1.0f;
934 return nullptr;
935}
936static bool boid_rule_applies(ParticleData *pa, BoidSettings * /*boids*/, BoidRule *rule)
937{
938 BoidParticle *bpa = pa->boid;
939
940 if (rule == nullptr) {
941 return false;
942 }
943
945 {
946 return true;
947 }
948
949 if (bpa->data.mode == eBoidMode_InAir && rule->flag & BOIDRULE_IN_AIR) {
950 return true;
951 }
952
953 return false;
954}
956{
957 LISTBASE_FOREACH (BoidState *, state, &part->boids->states) {
958 LISTBASE_FOREACH (BoidRule *, rule, &state->rules) {
959 if (rule->type == eBoidRuleType_FollowLeader) {
961
962 if (flbr->ob && flbr->cfra != cfra) {
963 /* save object locations for velocity calculations */
964 copy_v3_v3(flbr->oloc, flbr->loc);
965 copy_v3_v3(flbr->loc, flbr->ob->object_to_world().location());
966 flbr->cfra = cfra;
967 }
968 }
969 }
970 }
971}
972static void boid_climb(BoidSettings *boids,
973 ParticleData *pa,
974 float *surface_co,
975 float *surface_nor)
976{
977 BoidParticle *bpa = pa->boid;
978 float nor[3], vel[3];
979 copy_v3_v3(nor, surface_nor);
980
981 /* gather apparent gravity */
982 madd_v3_v3fl(bpa->gravity, surface_nor, -1.0f);
983 normalize_v3(bpa->gravity);
984
985 /* raise boid it's size from surface */
986 mul_v3_fl(nor, pa->size * boids->height);
987 add_v3_v3v3(pa->state.co, surface_co, nor);
988
989 /* remove normal component from velocity */
990 project_v3_v3v3(vel, pa->state.vel, surface_nor);
991 sub_v3_v3v3(pa->state.vel, pa->state.vel, vel);
992}
993static float boid_goal_signed_dist(float *boid_co, float *goal_co, float *goal_nor)
994{
995 float vec[3];
996
997 sub_v3_v3v3(vec, boid_co, goal_co);
998
999 return dot_v3v3(vec, goal_nor);
1000}
1001/* wanted_co is relative to boid location */
1003 BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness)
1004{
1005 if (rule == nullptr) {
1006 return false;
1007 }
1008
1009 if (!boid_rule_applies(pa, bbd->part->boids, rule)) {
1010 return false;
1011 }
1012
1013 if (!boid_rules[rule->type](rule, bbd, val, pa)) {
1014 return false;
1015 }
1016
1017 if (fuzziness < 0.0f || compare_len_v3v3(bbd->wanted_co,
1018 pa->prev_state.vel,
1019 fuzziness * len_v3(pa->prev_state.vel)) == 0)
1020 {
1021 return true;
1022 }
1023 return false;
1024}
1026{
1027 BoidState *state = static_cast<BoidState *>(boids->states.first);
1028 BoidParticle *bpa = pa->boid;
1029
1030 for (; state; state = state->next) {
1031 if (state->id == bpa->data.state_id) {
1032 return state;
1033 }
1034 }
1035
1036 /* for some reason particle isn't at a valid state */
1037 state = static_cast<BoidState *>(boids->states.first);
1038 if (state) {
1039 bpa->data.state_id = state->id;
1040 }
1041
1042 return state;
1043}
1044
1045#if 0 /* TODO */
1046static int boid_condition_is_true(BoidCondition *cond)
1047{
1048 return 0;
1049}
1050#endif
1051
1053{
1054 BoidRule *rule;
1055 BoidSettings *boids = bbd->part->boids;
1056 BoidValues val;
1057 BoidState *state = get_boid_state(boids, pa);
1058 BoidParticle *bpa = pa->boid;
1059 ParticleSystem *psys = bbd->sim->psys;
1060 int rand;
1061
1062 if (bpa->data.health <= 0.0f) {
1063 pa->alive = PARS_DYING;
1064 pa->dietime = bbd->cfra;
1065 return;
1066 }
1067
1068/* Planned for near future. */
1069#if 0
1070 BoidCondition *cond = state->conditions.first;
1071 for (; cond; cond = cond->next) {
1072 if (boid_condition_is_true(cond)) {
1073 pa->boid->state_id = cond->state_id;
1074 state = get_boid_state(boids, pa);
1075 break; /* only first true condition is used */
1076 }
1077 }
1078#endif
1079
1080 zero_v3(bbd->wanted_co);
1081 bbd->wanted_speed = 0.0f;
1082
1083 /* create random seed for every particle & frame */
1084 rand = int(psys_frand(psys, psys->seed + p) * 1000);
1085 rand = int(psys_frand(psys, int(bbd->cfra) + rand) * 1000);
1086
1087 set_boid_values(&val, bbd->part->boids, pa);
1088
1089 /* go through rules */
1090 switch (state->ruleset_type) {
1092 LISTBASE_FOREACH (BoidRule *, rule, &state->rules) {
1093 if (apply_boid_rule(bbd, rule, &val, pa, state->rule_fuzziness)) {
1094 break; /* only first nonzero rule that comes through fuzzy rule is applied */
1095 }
1096 }
1097 break;
1098 }
1100 /* use random rule for each particle (always same for same particle though) */
1101 const int n = BLI_listbase_count(&state->rules);
1102 if (n) {
1103 rule = static_cast<BoidRule *>(BLI_findlink(&state->rules, rand % n));
1104 apply_boid_rule(bbd, rule, &val, pa, -1.0);
1105 }
1106 break;
1107 }
1109 float wanted_co[3] = {0.0f, 0.0f, 0.0f}, wanted_speed = 0.0f;
1110 int n = 0;
1111 LISTBASE_FOREACH (BoidRule *, rule, &state->rules) {
1112 if (apply_boid_rule(bbd, rule, &val, pa, -1.0f)) {
1113 add_v3_v3(wanted_co, bbd->wanted_co);
1114 wanted_speed += bbd->wanted_speed;
1115 n++;
1116 zero_v3(bbd->wanted_co);
1117 bbd->wanted_speed = 0.0f;
1118 }
1119 }
1120
1121 if (n > 1) {
1122 mul_v3_fl(wanted_co, 1.0f / float(n));
1123 wanted_speed /= float(n);
1124 }
1125
1126 copy_v3_v3(bbd->wanted_co, wanted_co);
1127 bbd->wanted_speed = wanted_speed;
1128 break;
1129 }
1130 }
1131
1132 /* decide on jumping & liftoff */
1133 if (bpa->data.mode == eBoidMode_OnLand) {
1134 /* Fuzziness makes boids capable of misjudgment. */
1135 float mul = 1.0f + state->rule_fuzziness;
1136
1137 if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) {
1138 float cvel[3], dir[3];
1139
1140 copy_v3_v3(dir, pa->prev_state.ave);
1141 normalize_v2(dir);
1142
1143 copy_v3_v3(cvel, bbd->wanted_co);
1144 normalize_v2(cvel);
1145
1146 if (dot_v2v2(cvel, dir) > 0.95f / mul) {
1148 }
1149 }
1150 else if (val.jump_speed > 0.0f) {
1151 float jump_v[3];
1152 int jump = 0;
1153
1154 /* jump to get to a location */
1155 if (bbd->wanted_co[2] > 0.0f) {
1156 float cvel[3], dir[3];
1157 float z_v, ground_v, cur_v;
1158 float len;
1159
1160 copy_v3_v3(dir, pa->prev_state.ave);
1161 normalize_v2(dir);
1162
1163 copy_v3_v3(cvel, bbd->wanted_co);
1164 normalize_v2(cvel);
1165
1166 len = len_v2(pa->prev_state.vel);
1167
1168 /* first of all, are we going in a suitable direction? */
1169 /* or at a suitably slow speed */
1170 if (dot_v2v2(cvel, dir) > 0.95f / mul || len <= state->rule_fuzziness) {
1171 /* try to reach goal at highest point of the parabolic path */
1172 cur_v = len_v2(pa->prev_state.vel);
1173 z_v = safe_sqrtf(-2.0f * bbd->sim->scene->physics_settings.gravity[2] *
1174 bbd->wanted_co[2]);
1175 ground_v = len_v2(bbd->wanted_co) *
1176 safe_sqrtf(-0.5f * bbd->sim->scene->physics_settings.gravity[2] /
1177 bbd->wanted_co[2]);
1178
1179 len = safe_sqrtf((ground_v - cur_v) * (ground_v - cur_v) + z_v * z_v);
1180
1181 if (len < val.jump_speed * mul || bbd->part->boids->options & BOID_ALLOW_FLIGHT) {
1182 jump = 1;
1183
1184 len = std::min(len, val.jump_speed);
1185
1186 copy_v3_v3(jump_v, dir);
1187 jump_v[2] = z_v;
1188 mul_v3_fl(jump_v, ground_v);
1189
1190 normalize_v3(jump_v);
1191 mul_v3_fl(jump_v, len);
1192 add_v2_v2v2(jump_v, jump_v, pa->prev_state.vel);
1193 }
1194 }
1195 }
1196
1197 /* jump to go faster */
1198 if (jump == 0 && val.jump_speed > val.max_speed && bbd->wanted_speed > val.max_speed) {
1199 /* pass */
1200 }
1201
1202 if (jump) {
1203 copy_v3_v3(pa->prev_state.vel, jump_v);
1205 }
1206 }
1207 }
1208}
1210{
1211 BoidSettings *boids = bbd->part->boids;
1212 BoidParticle *bpa = pa->boid;
1213 BoidValues val;
1214 EffectedPoint epoint;
1215 float acc[3] = {0.0f, 0.0f, 0.0f}, tan_acc[3], nor_acc[3];
1216 float dvec[3], bvec[3];
1217 float new_dir[3], new_speed;
1218 float old_dir[3], old_speed;
1219 float wanted_dir[3];
1220 float q[4], mat[3][3]; /* rotation */
1221 float ground_co[3] = {0.0f, 0.0f, 0.0f}, ground_nor[3] = {0.0f, 0.0f, 1.0f};
1222 float force[3] = {0.0f, 0.0f, 0.0f};
1223 float pa_mass = bbd->part->mass, dtime = bbd->dfra * bbd->timestep;
1224
1225 set_boid_values(&val, boids, pa);
1226
1227 /* make sure there's something in new velocity, location & rotation */
1228 copy_particle_key(&pa->state, &pa->prev_state, 0);
1229
1230 if (bbd->part->flag & PART_SIZEMASS) {
1231 pa_mass *= pa->size;
1232 }
1233
1234 /* if boids can't fly they fall to the ground */
1235 if ((boids->options & BOID_ALLOW_FLIGHT) == 0 &&
1237 psys_uses_gravity(bbd->sim))
1238 {
1240 }
1241
1242 if (bpa->data.mode == eBoidMode_Falling) {
1243 /* Falling boids are only effected by gravity. */
1244 acc[2] = bbd->sim->scene->physics_settings.gravity[2];
1245 }
1246 else {
1247 /* figure out acceleration */
1248 float landing_level = 2.0f;
1249 float level = landing_level + 1.0f;
1250 float new_vel[3];
1251
1252 if (bpa->data.mode == eBoidMode_Liftoff) {
1253 bpa->data.mode = eBoidMode_InAir;
1254 bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
1255 }
1256 else if (bpa->data.mode == eBoidMode_InAir && boids->options & BOID_ALLOW_LAND) {
1257 /* auto-leveling & landing if close to ground */
1258
1259 bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
1260
1261 /* level = how many particle sizes above ground */
1262 level = (pa->prev_state.co[2] - ground_co[2]) / (2.0f * pa->size) - 0.5f;
1263
1264 landing_level = -boids->landing_smoothness * pa->prev_state.vel[2] * pa_mass;
1265
1266 if (pa->prev_state.vel[2] < 0.0f) {
1267 if (level < 1.0f) {
1268 bbd->wanted_co[0] = bbd->wanted_co[1] = bbd->wanted_co[2] = 0.0f;
1269 bbd->wanted_speed = 0.0f;
1271 }
1272 else if (level < landing_level) {
1273 bbd->wanted_speed *= (level - 1.0f) / landing_level;
1274 bbd->wanted_co[2] *= (level - 1.0f) / landing_level;
1275 }
1276 }
1277 }
1278
1279 copy_v3_v3(old_dir, pa->prev_state.ave);
1280 new_speed = normalize_v3_v3(wanted_dir, bbd->wanted_co);
1281
1282 /* first check if we have valid direction we want to go towards */
1283 if (new_speed == 0.0f) {
1284 copy_v3_v3(new_dir, old_dir);
1285 }
1286 else {
1287 float old_dir2[2], wanted_dir2[2], nor[3], angle;
1288 copy_v2_v2(old_dir2, old_dir);
1289 normalize_v2(old_dir2);
1290 copy_v2_v2(wanted_dir2, wanted_dir);
1291 normalize_v2(wanted_dir2);
1292
1293 /* choose random direction to turn if wanted velocity */
1294 /* is directly behind regardless of z-coordinate */
1295 if (dot_v2v2(old_dir2, wanted_dir2) < -0.99f) {
1296 wanted_dir[0] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
1297 wanted_dir[1] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
1298 wanted_dir[2] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
1299 normalize_v3(wanted_dir);
1300 }
1301
1302 /* constrain direction with maximum angular velocity */
1303 angle = safe_acosf(dot_v3v3(old_dir, wanted_dir));
1304 angle = min_ff(angle, val.max_ave);
1305
1306 cross_v3_v3v3(nor, old_dir, wanted_dir);
1307 axis_angle_to_quat(q, nor, angle);
1308 copy_v3_v3(new_dir, old_dir);
1309 mul_qt_v3(q, new_dir);
1310 normalize_v3(new_dir);
1311
1312 /* save direction in case resulting velocity too small */
1313 axis_angle_to_quat(q, nor, angle * dtime);
1314 copy_v3_v3(pa->state.ave, old_dir);
1315 mul_qt_v3(q, pa->state.ave);
1316 normalize_v3(pa->state.ave);
1317 }
1318
1319 /* constrain speed with maximum acceleration */
1320 old_speed = len_v3(pa->prev_state.vel);
1321
1322 if (bbd->wanted_speed < old_speed) {
1323 new_speed = std::max(bbd->wanted_speed, old_speed - val.max_acc);
1324 }
1325 else {
1326 new_speed = std::min(bbd->wanted_speed, old_speed + val.max_acc);
1327 }
1328
1329 /* combine direction and speed */
1330 copy_v3_v3(new_vel, new_dir);
1331 mul_v3_fl(new_vel, new_speed);
1332
1333 /* maintain minimum flying velocity if not landing */
1334 if (level >= landing_level) {
1335 float len2 = dot_v2v2(new_vel, new_vel);
1336 float root;
1337
1338 len2 = std::max(len2, val.min_speed * val.min_speed);
1339 root = safe_sqrtf(new_speed * new_speed - len2);
1340
1341 new_vel[2] = new_vel[2] < 0.0f ? -root : root;
1342
1343 normalize_v2(new_vel);
1344 mul_v2_fl(new_vel, safe_sqrtf(len2));
1345 }
1346
1347 /* finally constrain speed to max speed */
1348 new_speed = normalize_v3(new_vel);
1349 mul_v3_fl(new_vel, std::min(new_speed, val.max_speed));
1350
1351 /* get acceleration from difference of velocities */
1352 sub_v3_v3v3(acc, new_vel, pa->prev_state.vel);
1353
1354 /* break acceleration to components */
1355 project_v3_v3v3(tan_acc, acc, pa->prev_state.ave);
1356 sub_v3_v3v3(nor_acc, acc, tan_acc);
1357 }
1358
1359 /* account for effectors */
1360 pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
1362 bbd->sim->colliders,
1363 bbd->part->effector_weights,
1364 &epoint,
1365 force,
1366 nullptr,
1367 nullptr);
1368
1370 float length = normalize_v3(force);
1371
1372 length = std::max(0.0f, length - boids->land_stick_force);
1373
1374 mul_v3_fl(force, length);
1375 }
1376
1377 add_v3_v3(acc, force);
1378
1379 /* store smoothed acceleration for nice banking etc. */
1380 madd_v3_v3fl(bpa->data.acc, acc, dtime);
1381 mul_v3_fl(bpa->data.acc, 1.0f / (1.0f + dtime));
1382
1383 /* integrate new location & velocity */
1384
1385 /* by regarding the acceleration as a force at this stage we
1386 * can get better control although it's a bit unphysical */
1387 mul_v3_fl(acc, 1.0f / pa_mass);
1388
1389 copy_v3_v3(dvec, acc);
1390 mul_v3_fl(dvec, dtime * dtime * 0.5f);
1391
1392 copy_v3_v3(bvec, pa->prev_state.vel);
1393 mul_v3_fl(bvec, dtime);
1394 add_v3_v3(dvec, bvec);
1395 add_v3_v3(pa->state.co, dvec);
1396
1397 madd_v3_v3fl(pa->state.vel, acc, dtime);
1398
1399 // if (bpa->data.mode != eBoidMode_InAir)
1400 bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
1401
1402 /* change modes, constrain movement & keep track of down vector */
1403 switch (bpa->data.mode) {
1404 case eBoidMode_InAir: {
1405 float grav[3];
1406
1407 grav[0] = 0.0f;
1408 grav[1] = 0.0f;
1409 grav[2] = bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f;
1410
1411 /* don't take forward acceleration into account (better banking) */
1412 if (dot_v3v3(bpa->data.acc, pa->state.vel) > 0.0f) {
1413 project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel);
1414 sub_v3_v3v3(dvec, bpa->data.acc, dvec);
1415 }
1416 else {
1417 copy_v3_v3(dvec, bpa->data.acc);
1418 }
1419
1420 /* gather apparent gravity */
1421 madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking);
1422 normalize_v3(bpa->gravity);
1423
1424 /* stick boid on goal when close enough */
1425 if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <=
1426 pa->size * boids->height)
1427 {
1429 bpa->ground = bbd->goal_ob;
1430 boid_find_ground(bbd, pa, ground_co, ground_nor);
1431 boid_climb(boids, pa, ground_co, ground_nor);
1432 }
1433 else if (pa->state.co[2] <= ground_co[2] + pa->size * boids->height) {
1434 /* land boid when below ground */
1435 if (boids->options & BOID_ALLOW_LAND) {
1436 pa->state.co[2] = ground_co[2] + pa->size * boids->height;
1437 pa->state.vel[2] = 0.0f;
1438 bpa->data.mode = eBoidMode_OnLand;
1439 }
1440 /* fly above ground */
1441 else if (bpa->ground) {
1442 pa->state.co[2] = ground_co[2] + pa->size * boids->height;
1443 pa->state.vel[2] = 0.0f;
1444 }
1445 }
1446 break;
1447 }
1448 case eBoidMode_Falling: {
1449 float grav[3];
1450
1451 grav[0] = 0.0f;
1452 grav[1] = 0.0f;
1453 grav[2] = bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f;
1454
1455 /* gather apparent gravity */
1456 madd_v3_v3fl(bpa->gravity, grav, dtime);
1457 normalize_v3(bpa->gravity);
1458
1459 if (boids->options & BOID_ALLOW_LAND) {
1460 /* stick boid on goal when close enough */
1461 if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <=
1462 pa->size * boids->height)
1463 {
1465 bpa->ground = bbd->goal_ob;
1466 boid_find_ground(bbd, pa, ground_co, ground_nor);
1467 boid_climb(boids, pa, ground_co, ground_nor);
1468 }
1469 /* land boid when really near ground */
1470 else if (pa->state.co[2] <= ground_co[2] + 1.01f * pa->size * boids->height) {
1471 pa->state.co[2] = ground_co[2] + pa->size * boids->height;
1472 pa->state.vel[2] = 0.0f;
1473 bpa->data.mode = eBoidMode_OnLand;
1474 }
1475 /* if we're falling, can fly and want to go upwards lets fly */
1476 else if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) {
1477 bpa->data.mode = eBoidMode_InAir;
1478 }
1479 }
1480 else {
1481 bpa->data.mode = eBoidMode_InAir;
1482 }
1483 break;
1484 }
1485 case eBoidMode_Climbing: {
1486 boid_climb(boids, pa, ground_co, ground_nor);
1487#if 0
1488 float nor[3];
1489 copy_v3_v3(nor, ground_nor);
1490
1491 /* Gather apparent gravity to r_ve. */
1492 madd_v3_v3fl(pa->r_ve, ground_nor, -1.0);
1493 normalize_v3(pa->r_ve);
1494
1495 /* Raise boid it's size from surface. */
1496 mul_v3_fl(nor, pa->size * boids->height);
1497 add_v3_v3v3(pa->state.co, ground_co, nor);
1498
1499 /* Remove normal component from velocity. */
1500 project_v3_v3v3(v, pa->state.vel, ground_nor);
1501 sub_v3_v3v3(pa->state.vel, pa->state.vel, v);
1502#endif
1503 break;
1504 }
1505 case eBoidMode_OnLand: {
1506 /* stick boid on goal when close enough */
1507 if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <=
1508 pa->size * boids->height)
1509 {
1511 bpa->ground = bbd->goal_ob;
1512 boid_find_ground(bbd, pa, ground_co, ground_nor);
1513 boid_climb(boids, pa, ground_co, ground_nor);
1514 }
1515 /* ground is too far away so boid falls */
1516 else if (pa->state.co[2] - ground_co[2] > 1.1f * pa->size * boids->height) {
1518 }
1519 else {
1520 /* constrain to surface */
1521 pa->state.co[2] = ground_co[2] + pa->size * boids->height;
1522 pa->state.vel[2] = 0.0f;
1523 }
1524
1525 if (boids->banking > 0.0f) {
1526 float grav[3];
1527 /* Don't take gravity's strength in to account, */
1528 /* otherwise amount of banking is hard to control. */
1529 negate_v3_v3(grav, ground_nor);
1530
1531 project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel);
1532 sub_v3_v3v3(dvec, bpa->data.acc, dvec);
1533
1534 /* gather apparent gravity */
1535 madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking);
1536 normalize_v3(bpa->gravity);
1537 }
1538 else {
1539 /* gather negative surface normal */
1540 madd_v3_v3fl(bpa->gravity, ground_nor, -1.0f);
1541 normalize_v3(bpa->gravity);
1542 }
1543 break;
1544 }
1545 }
1546
1547 /* save direction to state.ave unless the boid is falling */
1548 /* (boids can't effect their direction when falling) */
1549 if (bpa->data.mode != eBoidMode_Falling && len_v3(pa->state.vel) > 0.1f * pa->size) {
1550 copy_v3_v3(pa->state.ave, pa->state.vel);
1551 pa->state.ave[2] *= bbd->part->boids->pitch;
1552 normalize_v3(pa->state.ave);
1553 }
1554
1555 /* apply damping */
1557 mul_v3_fl(pa->state.vel, 1.0f - 0.2f * bbd->part->dampfac);
1558 }
1559
1560 /* calculate rotation matrix based on forward & down vectors */
1561 if (bpa->data.mode == eBoidMode_InAir) {
1562 copy_v3_v3(mat[0], pa->state.ave);
1563
1564 project_v3_v3v3(dvec, bpa->gravity, pa->state.ave);
1565 sub_v3_v3v3(mat[2], bpa->gravity, dvec);
1566 normalize_v3(mat[2]);
1567 }
1568 else {
1569 project_v3_v3v3(dvec, pa->state.ave, bpa->gravity);
1570 sub_v3_v3v3(mat[0], pa->state.ave, dvec);
1571 normalize_v3(mat[0]);
1572
1573 copy_v3_v3(mat[2], bpa->gravity);
1574 }
1575 negate_v3(mat[2]);
1576 cross_v3_v3v3(mat[1], mat[2], mat[0]);
1577
1578 /* apply rotation */
1579 mat3_to_quat_legacy(q, mat);
1580 copy_qt_qt(pa->state.rot, q);
1581}
1582
1584{
1585 BoidRule *rule = nullptr;
1586 if (type <= 0) {
1587 return nullptr;
1588 }
1589
1590 switch (type) {
1591 case eBoidRuleType_Goal:
1593 rule = static_cast<BoidRule *>(MEM_callocN(sizeof(BoidRuleGoalAvoid), "BoidRuleGoalAvoid"));
1594 break;
1596 rule = static_cast<BoidRule *>(
1597 MEM_callocN(sizeof(BoidRuleAvoidCollision), "BoidRuleAvoidCollision"));
1598 ((BoidRuleAvoidCollision *)rule)->look_ahead = 2.0f;
1599 break;
1601 rule = static_cast<BoidRule *>(
1602 MEM_callocN(sizeof(BoidRuleFollowLeader), "BoidRuleFollowLeader"));
1603 ((BoidRuleFollowLeader *)rule)->distance = 1.0f;
1604 break;
1606 rule = static_cast<BoidRule *>(
1607 MEM_callocN(sizeof(BoidRuleAverageSpeed), "BoidRuleAverageSpeed"));
1608 ((BoidRuleAverageSpeed *)rule)->speed = 0.5f;
1609 break;
1611 rule = static_cast<BoidRule *>(MEM_callocN(sizeof(BoidRuleFight), "BoidRuleFight"));
1612 ((BoidRuleFight *)rule)->distance = 100.0f;
1613 ((BoidRuleFight *)rule)->flee_distance = 100.0f;
1614 break;
1615 default:
1616 rule = static_cast<BoidRule *>(MEM_callocN(sizeof(BoidRule), "BoidRule"));
1617 break;
1618 }
1619
1620 rule->type = type;
1622 STRNCPY_UTF8(rule->name, DATA_(rna_enum_boidrule_type_items[type - 1].name));
1623
1624 return rule;
1625}
1627{
1628 boids->air_max_speed = 10.0f;
1629 boids->air_max_acc = 0.5f;
1630 boids->air_max_ave = 0.5f;
1631 boids->air_personal_space = 1.0f;
1632
1633 boids->land_max_speed = 5.0f;
1634 boids->land_max_acc = 0.5f;
1635 boids->land_max_ave = 0.5f;
1636 boids->land_personal_space = 1.0f;
1637
1638 boids->options = BOID_ALLOW_FLIGHT;
1639
1640 boids->landing_smoothness = 3.0f;
1641 boids->banking = 1.0f;
1642 boids->pitch = 1.0f;
1643 boids->height = 1.0f;
1644
1645 boids->health = 1.0f;
1646 boids->accuracy = 1.0f;
1647 boids->aggression = 2.0f;
1648 boids->range = 1.0f;
1649 boids->strength = 0.1f;
1650}
1651
1653{
1654 BoidState *state = static_cast<BoidState *>(MEM_callocN(sizeof(BoidState), "BoidState"));
1655
1656 state->id = boids->last_state_id++;
1657 if (state->id) {
1658 SNPRINTF(state->name, "State %i", state->id);
1659 }
1660 else {
1661 STRNCPY(state->name, "State");
1662 }
1663
1664 state->rule_fuzziness = 0.5;
1665 state->volume = 1.0f;
1666 state->channels |= ~0;
1667
1668 return state;
1669}
1670
1672{
1673 BoidState *staten = static_cast<BoidState *>(MEM_dupallocN(state));
1674
1675 BLI_duplicatelist(&staten->rules, &state->rules);
1676 BLI_duplicatelist(&staten->conditions, &state->conditions);
1677 BLI_duplicatelist(&staten->actions, &state->actions);
1678
1679 staten->id = boids->last_state_id++;
1680
1681 return staten;
1682}
1684{
1685 if (boids) {
1686 BoidState *state = static_cast<BoidState *>(boids->states.first);
1687
1688 for (; state; state = state->next) {
1689 BLI_freelistN(&state->rules);
1690 BLI_freelistN(&state->conditions);
1691 BLI_freelistN(&state->actions);
1692 }
1693
1694 BLI_freelistN(&boids->states);
1695
1696 MEM_freeN(boids);
1697 }
1698}
1700{
1701 BoidSettings *nboids = nullptr;
1702
1703 if (boids) {
1705 BoidState *nstate;
1706
1707 nboids = static_cast<BoidSettings *>(MEM_dupallocN(boids));
1708
1709 BLI_duplicatelist(&nboids->states, &boids->states);
1710
1711 state = static_cast<BoidState *>(boids->states.first);
1712 nstate = static_cast<BoidState *>(nboids->states.first);
1713 for (; state; state = state->next, nstate = nstate->next) {
1714 BLI_duplicatelist(&nstate->rules, &state->rules);
1715 BLI_duplicatelist(&nstate->conditions, &state->conditions);
1716 BLI_duplicatelist(&nstate->actions, &state->actions);
1717 }
1718 }
1719
1720 return nboids;
1721}
1723{
1724 BoidState *state = static_cast<BoidState *>(boids->states.first);
1725
1726 for (; state; state = state->next) {
1727 if (state->flag & BOIDSTATE_CURRENT) {
1728 break;
1729 }
1730 }
1731
1732 return state;
1733}
float effector_falloff(struct EffectorCache *eff, struct EffectorData *efd, struct EffectedPoint *point, struct EffectorWeights *weights)
Definition effect.cc:589
void BKE_effectors_apply(struct ListBase *effectors, struct ListBase *colliders, struct EffectorWeights *weights, struct EffectedPoint *point, float *force, float *wind_force, float *impulse)
Definition effect.cc:1110
bool get_effector_data(struct EffectorCache *eff, struct EffectorData *efd, struct EffectedPoint *point, int real_velocity)
Definition effect.cc:674
bool closest_point_on_surface(struct SurfaceModifierData *surmd, const float co[3], float surface_co[3], float surface_nor[3], float surface_vel[3])
Definition effect.cc:638
void pd_point_from_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, struct EffectedPoint *point)
Definition effect.cc:381
ModifierData * BKE_modifiers_findby_type(const Object *ob, ModifierType type)
void copy_particle_key(struct ParticleKey *to, struct ParticleKey *from, int time)
Definition particle.cc:3741
void BKE_psys_collision_neartest_cb(void *userdata, int index, const struct BVHTreeRay *ray, struct BVHTreeRayHit *hit)
int psys_uses_gravity(struct ParticleSimulationData *sim)
Definition particle.cc:826
struct ParticleSystem * psys_get_target_system(struct Object *ob, struct ParticleTarget *pt)
BLI_INLINE float psys_frand(ParticleSystem *psys, unsigned int seed)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BVH_RAYCAST_DEFAULT
Definition BLI_kdopbvh.h:91
int BLI_bvhtree_ray_cast_ex(const BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata, int flag)
A KD-tree for nearest neighbor search.
#define LISTBASE_FOREACH(type, var, list)
void void void void void void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float min_ff(float a, float b)
#define M_PI
MINLINE float safe_sqrtf(float a)
MINLINE float safe_acosf(float a)
void axis_angle_to_quat(float r[4], const float axis[3], float angle)
void mul_qt_v3(const float q[4], float r[3])
void mat3_to_quat_legacy(float q[4], const float wmat[3][3])
void copy_qt_qt(float q[4], const float a[4])
MINLINE float len_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition math_vector.c:36
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v3(float r[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v2(float n[2])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE bool compare_len_v3v3(const float v1[3], const float v2[3], float limit) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
Random number functions.
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition rand.cc:93
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
#define STRNCPY_UTF8(dst, src)
#define ARRAY_SIZE(arr)
#define ARRAY_HAS_ITEM(arr_item, arr_start, arr_len)
#define ELEM(...)
#define DATA_(msgid)
#define BOIDSTATE_CURRENT
@ BOIDRULE_IN_AIR
@ BOIDRULE_ON_LAND
@ eBoidMode_OnLand
@ eBoidMode_Liftoff
@ eBoidMode_Climbing
@ eBoidMode_Falling
@ eBoidMode_InAir
#define BRULE_LEADER_IN_LINE
@ eBoidRulesetType_Average
@ eBoidRulesetType_Fuzzy
@ eBoidRulesetType_Random
@ BOID_ALLOW_FLIGHT
@ BOID_ALLOW_LAND
@ BOID_ALLOW_CLIMB
@ BRULE_ACOLL_WITH_DEFLECTORS
@ BRULE_ACOLL_WITH_BOIDS
@ eBoidRuleType_Goal
@ eBoidRuleType_Fight
@ eBoidRuleType_Avoid
@ eBoidRuleType_FollowLeader
@ eBoidRuleType_AvoidCollision
@ eBoidRuleType_AverageSpeed
@ BRULE_GOAL_AVOID_PREDICT
@ eModifierType_Surface
@ PFIELD_SHAPE_SURFACE
@ PTARGET_MODE_ENEMY
@ PTARGET_MODE_FRIEND
@ PART_SIZEMASS
@ PARS_DYING
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT const BMVert * v
void boid_free_settings(BoidSettings *boids)
Definition boids.cc:1683
BoidRule * boid_new_rule(int type)
Definition boids.cc:1583
BoidSettings * boid_copy_settings(const BoidSettings *boids)
Definition boids.cc:1699
static bool rule_flock(BoidRule *, BoidBrainData *bbd, BoidValues *, ParticleData *pa)
Definition boids.cc:444
static bool rule_average_speed(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
Definition boids.cc:623
BoidState * boid_get_current_state(BoidSettings *boids)
Definition boids.cc:1722
BoidState * boid_new_state(BoidSettings *boids)
Definition boids.cc:1652
static bool rule_follow_leader(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
Definition boids.cc:481
static void boid_climb(BoidSettings *boids, ParticleData *pa, float *surface_co, float *surface_nor)
Definition boids.cc:972
static bool apply_boid_rule(BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness)
Definition boids.cc:1002
void boid_body(BoidBrainData *bbd, ParticleData *pa)
Definition boids.cc:1209
static bool rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
Definition boids.cc:72
void boids_precalc_rules(ParticleSettings *part, float cfra)
Definition boids.cc:955
static bool rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
Definition boids.cc:208
static bool rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
Definition boids.cc:678
static BoidState * get_boid_state(BoidSettings *boids, ParticleData *pa)
Definition boids.cc:1025
static float boid_goal_signed_dist(float *boid_co, float *goal_co, float *goal_nor)
Definition boids.cc:993
static float len_squared_v3v3_with_normal_bias(const float co_search[3], const float co_test[3], const void *user_data)
Definition boids.cc:37
void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
Definition boids.cc:1052
static bool boid_rule_applies(ParticleData *pa, BoidSettings *, BoidRule *rule)
Definition boids.cc:936
BoidState * boid_duplicate_state(BoidSettings *boids, BoidState *state)
Definition boids.cc:1671
static boid_rule_cb boid_rules[]
Definition boids.cc:788
static bool rule_separate(BoidRule *, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
Definition boids.cc:400
static bool rule_none(BoidRule *, BoidBrainData *, BoidValues *, ParticleData *)
Definition boids.cc:64
bool(*)(BoidRule *rule, BoidBrainData *data, BoidValues *val, ParticleData *pa) boid_rule_cb
Definition boids.cc:783
static void set_boid_values(BoidValues *val, BoidSettings *boids, ParticleData *pa)
Definition boids.cc:807
void boid_default_settings(BoidSettings *boids)
Definition boids.cc:1626
static Object * boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float ground_co[3], float ground_nor[3])
Definition boids.cc:829
void jump(const btVector3 &v=btVector3(0, 0, 0))
static void mul(btAlignedObjectArray< T > &items, const Q &value)
#define powf(x, y)
#define sqrtf(x)
int len
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uint col
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
static ulong state[N]
Frequency::GEOMETRY nor[]
return ret
const EnumPropertyItem rna_enum_boidrule_type_items[]
Definition rna_boid.cc:28
float wanted_co[3]
Definition BKE_boids.h:27
float goal_nor[3]
Definition BKE_boids.h:32
struct ParticleSettings * part
Definition BKE_boids.h:25
struct Object * goal_ob
Definition BKE_boids.h:30
struct RNG * rng
Definition BKE_boids.h:35
float timestep
Definition BKE_boids.h:26
float wanted_speed
Definition BKE_boids.h:27
float goal_priority
Definition BKE_boids.h:33
struct ParticleSimulationData * sim
Definition BKE_boids.h:24
float goal_co[3]
Definition BKE_boids.h:31
float acc[3]
struct Object * ground
struct BoidData data
struct Object * ob
struct Object * ob
char name[32]
struct ListBase states
float landing_smoothness
float air_personal_space
float land_personal_space
ListBase conditions
ListBase actions
ListBase rules
struct BoidState * next
float personal_space
Definition boids.cc:58
float min_speed
Definition boids.cc:57
float max_ave
Definition boids.cc:57
float max_speed
Definition boids.cc:56
float max_acc
Definition boids.cc:56
float jump_speed
Definition boids.cc:58
struct Scene * scene
Definition BKE_effect.h:75
struct PartDeflect * pd
Definition BKE_effect.h:80
struct Object * ob
Definition BKE_effect.h:76
struct Depsgraph * depsgraph
Definition BKE_effect.h:74
float loc[3]
Definition BKE_effect.h:54
float distance
Definition BKE_effect.h:59
float vec_to_point[3]
Definition BKE_effect.h:58
float nor[3]
Definition BKE_effect.h:55
float vel[3]
Definition BKE_effect.h:56
void * first
BoidParticle * boid
ParticleKey state
ParticleKey prev_state
struct BoidSettings * boids
struct EffectorWeights * effector_weights
struct Depsgraph * depsgraph
struct Scene * scene
struct ParticleSystem * psys
struct Object * ob
struct ListBase * colliders
ParticleData * particles
struct ListBase targets
ParticleSettings * part
struct ListBase * effectors
struct KDTree_3d * tree
struct PhysicsSettings physics_settings