Blender V5.0
particle_system.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2007 Janne Karhu. All rights reserved.
2 * SPDX-FileCopyrightText: 2011-2012 AutoCRC (adaptive time step, Classical SPH).
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later */
5
9
10#include <algorithm>
11#include <cmath>
12#include <cstddef>
13#include <cstdlib>
14#include <cstring>
15
16#include "MEM_guardedalloc.h"
17
18#include "DNA_boid_types.h"
19#include "DNA_cloth_types.h"
20#include "DNA_listBase.h"
21#include "DNA_mesh_types.h"
22#include "DNA_meshdata_types.h"
23#include "DNA_modifier_types.h"
25#include "DNA_object_types.h"
26#include "DNA_particle_types.h"
27#include "DNA_scene_types.h"
28#include "DNA_texture_types.h"
29
30#include "BLI_kdopbvh.hh"
31#include "BLI_kdtree.h"
32#include "BLI_linklist.h"
33#include "BLI_listbase.h"
34#include "BLI_math_base_safe.h"
35#include "BLI_math_matrix.h"
36#include "BLI_math_rotation.h"
37#include "BLI_math_vector.h"
38#include "BLI_rand.h"
39#include "BLI_string.h"
40#include "BLI_string_utils.hh"
41#include "BLI_task.h"
42#include "BLI_threads.h"
43#include "BLI_utildefines.h"
44#include "BLI_vector.hh"
45
46#include "BKE_animsys.h"
47#include "BKE_boids.h"
48#include "BKE_collision.h"
49#include "BKE_colortools.hh"
50#include "BKE_customdata.hh"
51#include "BKE_effect.h"
52#include "BKE_lib_id.hh"
53#include "BKE_lib_query.hh"
55#include "BKE_particle.h"
56
57#include "BKE_cloth.hh"
58#include "BKE_material.hh"
59#include "BKE_mesh.hh"
60#include "BKE_modifier.hh"
61#include "BKE_object.hh"
62#include "BKE_pointcache.h"
63#include "BKE_scene.hh"
64
65#include "DEG_depsgraph.hh"
67
68/* FLUID sim particle import */
69#ifdef WITH_FLUID
70# include "DNA_fluid_types.h"
71# include "manta_fluid_API.h"
72#endif // WITH_FLUID
73
75
76/************************************************/
77/* Reacting to system events */
78/************************************************/
79
81{
82 if (psys->pointcache->flag & PTCACHE_BAKED) {
83 return 0;
84 }
85
86 if (psys->part->type == PART_HAIR) {
87 return psys->flag & PSYS_HAIR_DYNAMICS;
88 }
89
91}
92
93float psys_get_current_display_percentage(ParticleSystem *psys, const bool use_render_params)
94{
95 ParticleSettings *part = psys->part;
96
97 if ((use_render_params &&
98 !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */
99 (part->child_percent && part->childtype) || /* display percentage applies to children */
100 (psys->pointcache->flag & PTCACHE_BAKING)) /* baking is always done with full amount */
101 {
102 return 1.0f;
103 }
104
105 return psys->part->disp / 100.0f;
106}
107
109{
110 if (pid && psys->pointcache->flag & PTCACHE_EXTERNAL) {
111 return pid->cache->totpoint;
112 }
113 if (psys->part->distr == PART_DISTR_GRID && psys->part->from != PART_FROM_VERT) {
114 return psys->part->grid_res * psys->part->grid_res * psys->part->grid_res - psys->totunexist;
115 }
116
117 return psys->part->totpart - psys->totunexist;
118}
119
120void psys_reset(ParticleSystem *psys, int mode)
121{
123
125 if (mode == PSYS_RESET_ALL || !(psys->flag & PSYS_EDITED)) {
126 /* don't free if not absolutely necessary */
127 if (psys->totpart != tot_particles(psys, nullptr)) {
129 psys->totpart = 0;
130 }
131
132 psys->totkeyed = 0;
133 psys->flag &= ~(PSYS_HAIR_DONE | PSYS_KEYED);
134
135 if (psys->edit && psys->free_edit) {
136 psys->free_edit(psys->edit);
137 psys->edit = nullptr;
138 psys->free_edit = nullptr;
139 }
140 }
141 }
142 else if (mode == PSYS_RESET_CACHE_MISS) {
143 /* set all particles to be skipped */
145 {
146 pa->flag |= PARS_NO_DISP;
147 }
148 }
149
150 /* reset children */
151 MEM_SAFE_FREE(psys->child);
152
153 psys->totchild = 0;
154
155 /* reset path cache */
156 psys_free_path_cache(psys, psys->edit);
157
158 /* reset point cache */
160
162
163 psys->tot_fluidsprings = psys->alloc_fluidsprings = 0;
164}
165
166void psys_unique_name(Object *object, ParticleSystem *psys, const char *defname)
167{
169 psys,
170 defname,
171 '.',
173 sizeof(psys->name));
174}
175
176static void realloc_particles(ParticleSimulationData *sim, int new_totpart)
177{
178 ParticleSystem *psys = sim->psys;
179 ParticleSettings *part = psys->part;
180 ParticleData *newpars = nullptr;
181 BoidParticle *newboids = nullptr;
183 int totpart, totsaved = 0;
184
185 if (new_totpart < 0) {
186 if ((part->distr == PART_DISTR_GRID) && (part->from != PART_FROM_VERT)) {
187 totpart = part->grid_res;
188 totpart *= totpart * totpart;
189 }
190 else {
191 totpart = part->totpart;
192 }
193 }
194 else {
195 totpart = new_totpart;
196 }
197
198 if (totpart != psys->totpart) {
199 if (psys->edit && psys->free_edit) {
200 psys->free_edit(psys->edit);
201 psys->edit = nullptr;
202 psys->free_edit = nullptr;
203 }
204
205 if (totpart) {
206 newpars = MEM_calloc_arrayN<ParticleData>(totpart, "particles");
207 if (newpars == nullptr) {
208 return;
209 }
210
211 if (psys->part->phystype == PART_PHYS_BOIDS) {
212 newboids = MEM_calloc_arrayN<BoidParticle>(totpart, "boid particles");
213
214 if (newboids == nullptr) {
215 /* allocation error! */
216 if (newpars) {
217 MEM_freeN(newpars);
218 }
219 return;
220 }
221 }
222 }
223
224 if (psys->particles) {
225 totsaved = std::min(psys->totpart, totpart);
226 /* Save old pars. */
227 if (totsaved) {
228 memcpy(newpars, psys->particles, totsaved * sizeof(ParticleData));
229
230 if (psys->particles->boid) {
231 memcpy(newboids, psys->particles->boid, totsaved * sizeof(BoidParticle));
232 }
233 }
234
235 if (psys->particles->keys) {
236 MEM_freeN(psys->particles->keys);
237 }
238
239 if (psys->particles->boid) {
240 MEM_freeN(psys->particles->boid);
241 }
242
243 for (p = 0, pa = newpars; p < totsaved; p++, pa++) {
244 if (pa->keys) {
245 pa->keys = nullptr;
246 pa->totkey = 0;
247 }
248 }
249
250 for (p = totsaved, pa = psys->particles + totsaved; p < psys->totpart; p++, pa++) {
251 if (pa->hair) {
252 MEM_freeN(pa->hair);
253 }
254 }
255
256 MEM_freeN(psys->particles);
257 psys_free_pdd(psys);
258 }
259
260 psys->particles = newpars;
261 psys->totpart = totpart;
262
263 if (newboids) {
265 {
266 pa->boid = newboids++;
267 }
268 }
269 }
270
271 if (psys->child) {
272 MEM_freeN(psys->child);
273 psys->child = nullptr;
274 psys->totchild = 0;
275 }
276}
277
278int psys_get_child_number(Scene *scene, ParticleSystem *psys, const bool use_render_params)
279{
280 int child_num;
281
282 if (!psys->part->childtype) {
283 return 0;
284 }
285
286 if (use_render_params) {
287 child_num = psys->part->child_render_percent;
288 }
289 else {
290 child_num = psys->part->child_percent;
291 }
292
293 return get_render_child_particle_number(&scene->r, child_num, use_render_params);
294}
295
296int psys_get_tot_child(Scene *scene, ParticleSystem *psys, const bool use_render_params)
297{
298 return psys->totpart * psys_get_child_number(scene, psys, use_render_params);
299}
300
301/************************************************/
302/* Distribution */
303/************************************************/
304
305void psys_calc_dmcache(Object *ob, Mesh *mesh_final, Mesh *mesh_original, ParticleSystem *psys)
306{
307 /* use for building derived mesh mapping info:
308 *
309 * node: the allocated links - total derived mesh element count
310 * nodearray: the array of nodes aligned with the base mesh's elements, so
311 * each original elements can reference its derived elements
312 */
313 Mesh *mesh = (Mesh *)ob->data;
314 bool use_modifier_stack = psys->part->use_modifier_stack;
316
317 /* CACHE LOCATIONS */
318 if (!mesh_final->runtime->deformed_only) {
319 /* Will use later to speed up subsurf/evaluated mesh. */
320 LinkNode *node, *nodedmelem, **nodearray;
321 int totdmelem, totelem, i;
322 const int *origindex;
323 const int *origindex_poly = nullptr;
324 if (psys->part->from == PART_FROM_VERT) {
325 totdmelem = mesh_final->verts_num;
326
327 if (use_modifier_stack) {
328 totelem = totdmelem;
329 origindex = nullptr;
330 }
331 else {
332 totelem = mesh->verts_num;
333 origindex = static_cast<const int *>(
335 }
336 }
337 else { /* FROM_FACE/FROM_VOLUME */
338 totdmelem = mesh_final->totface_legacy;
339
340 if (use_modifier_stack) {
341 totelem = totdmelem;
342 origindex = nullptr;
343 origindex_poly = nullptr;
344 }
345 else {
346 totelem = mesh_original->totface_legacy;
347 origindex = static_cast<const int *>(
349
350 /* for face lookups we need the poly origindex too */
351 origindex_poly = static_cast<const int *>(
353 if (origindex_poly == nullptr) {
354 origindex = nullptr;
355 }
356 }
357 }
358
359 nodedmelem = MEM_calloc_arrayN<LinkNode>(totdmelem, "psys node elems");
360 nodearray = MEM_calloc_arrayN<LinkNode *>(totelem, "psys node array");
361
362 for (i = 0, node = nodedmelem; i < totdmelem; i++, node++) {
363 int origindex_final;
364 node->link = POINTER_FROM_INT(i);
365
366 /* may be vertex or face origindex */
367 if (use_modifier_stack) {
368 origindex_final = i;
369 }
370 else {
371 origindex_final = origindex ? origindex[i] : ORIGINDEX_NONE;
372
373 /* if we have a poly source, do an index lookup */
374 if (origindex_poly && origindex_final != ORIGINDEX_NONE) {
375 origindex_final = origindex_poly[origindex_final];
376 }
377 }
378
379 if (origindex_final != ORIGINDEX_NONE && origindex_final < totelem) {
380 if (nodearray[origindex_final]) {
381 /* prepend */
382 node->next = nodearray[origindex_final];
383 nodearray[origindex_final] = node;
384 }
385 else {
386 nodearray[origindex_final] = node;
387 }
388 }
389 }
390
391 /* cache the verts/faces! */
393 {
394 if (pa->num < 0) {
395 pa->num_dmcache = DMCACHE_NOTFOUND;
396 continue;
397 }
398
399 if (use_modifier_stack) {
400 if (pa->num < totelem) {
401 pa->num_dmcache = DMCACHE_ISCHILD;
402 }
403 else {
404 pa->num_dmcache = DMCACHE_NOTFOUND;
405 }
406 }
407 else {
408 if (psys->part->from == PART_FROM_VERT) {
409 if (pa->num < totelem && nodearray[pa->num]) {
410 pa->num_dmcache = POINTER_AS_INT(nodearray[pa->num]->link);
411 }
412 else {
413 pa->num_dmcache = DMCACHE_NOTFOUND;
414 }
415 }
416 else { /* FROM_FACE/FROM_VOLUME */
417 pa->num_dmcache = psys_particle_dm_face_lookup(
418 mesh_final, mesh_original, pa->num, pa->fuv, nodearray);
419 }
420 }
421 }
422
423 MEM_freeN(nodearray);
424 MEM_freeN(nodedmelem);
425 }
426 else {
427 /* TODO_PARTICLE: make the following line unnecessary, each function
428 * should know to use the num or num_dmcache, set the num_dmcache to
429 * an invalid value, just in case. */
430
432 {
433 pa->num_dmcache = DMCACHE_NOTFOUND;
434 }
435 }
436}
437
439{
440 memset(ctx, 0, sizeof(ParticleThreadContext));
441 ctx->sim = *sim;
442 ctx->mesh = ctx->sim.psmd->mesh_final;
443 ctx->ma = BKE_object_material_get(sim->ob, sim->psys->part->omat);
444}
445
447 int startpart,
448 int endpart)
449{
450 int numtasks = min_ii(BLI_system_thread_count() * 4, endpart - startpart);
451 int particles_per_task = numtasks > 0 ? (endpart - startpart) / numtasks : 0;
452 int remainder = numtasks > 0 ? (endpart - startpart) - particles_per_task * numtasks : 0;
453
454 blender::Vector<ParticleTask> tasks(numtasks);
455
456 int p = startpart;
457 for (int i = 0; i < numtasks; i++) {
458 tasks[i].ctx = ctx;
459 tasks[i].begin = p;
460 p = p + particles_per_task + (i < remainder ? 1 : 0);
461 tasks[i].end = p;
462 }
463
464 /* Verify that all particles are accounted for. */
465 if (numtasks > 0) {
466 BLI_assert(tasks[numtasks - 1].end == endpart);
467 }
468
469 return tasks;
470}
471
473{
474 /* threads */
475 for (ParticleTask &task : tasks) {
476 if (task.rng) {
477 BLI_rng_free(task.rng);
478 }
479 if (task.rng_path) {
480 BLI_rng_free(task.rng_path);
481 }
482 }
483
484 tasks.clear();
485}
486
488{
489 /* path caching */
490 if (ctx->vg_length) {
491 MEM_freeN(ctx->vg_length);
492 }
493 if (ctx->vg_clump) {
494 MEM_freeN(ctx->vg_clump);
495 }
496 if (ctx->vg_kink) {
497 MEM_freeN(ctx->vg_kink);
498 }
499 if (ctx->vg_rough1) {
500 MEM_freeN(ctx->vg_rough1);
501 }
502 if (ctx->vg_rough2) {
503 MEM_freeN(ctx->vg_rough2);
504 }
505 if (ctx->vg_roughe) {
506 MEM_freeN(ctx->vg_roughe);
507 }
508 if (ctx->vg_twist) {
509 MEM_freeN(ctx->vg_twist);
510 }
511
512 psys_sim_data_free(&ctx->sim);
513
514 /* distribution */
515 if (ctx->jit) {
516 MEM_freeN(ctx->jit);
517 }
518 if (ctx->jitoff) {
519 MEM_freeN(ctx->jitoff);
520 }
521 if (ctx->weight) {
522 MEM_freeN(ctx->weight);
523 }
524 if (ctx->index) {
525 MEM_freeN(ctx->index);
526 }
527 if (ctx->seams) {
528 MEM_freeN(ctx->seams);
529 }
530 // if (ctx->vertpart) MEM_freeN(ctx->vertpart);
531 BLI_kdtree_3d_free(ctx->tree);
532
533 if (ctx->clumpcurve != nullptr) {
535 }
536 if (ctx->roughcurve != nullptr) {
538 }
539 if (ctx->twistcurve != nullptr) {
541 }
542}
543
545{
546 ParticleSystem *psys = sim->psys;
547 ParticleSettings *part = psys->part;
548 ParticleTexture ptex;
549
550 psys_get_texture(sim, pa, &ptex, PAMAP_INIT, 0.0f);
551
552 switch (part->type) {
553 case PART_EMITTER:
554 if (ptex.exist < psys_frand(psys, p + 125)) {
555 pa->flag |= PARS_UNEXIST;
556 }
557 pa->time = part->sta + (part->end - part->sta) * ptex.time;
558 break;
559 case PART_HAIR:
560 if (ptex.exist < psys_frand(psys, p + 125)) {
561 pa->flag |= PARS_UNEXIST;
562 }
563 pa->time = 0.0f;
564 break;
565 }
566}
567
569{
570 ParticleSettings *part = sim->psys->part;
571 float birth_time = float(pa - sim->psys->particles) / float(sim->psys->totpart);
572
573 pa->flag &= ~PARS_UNEXIST;
574 pa->time = part->sta + (part->end - part->sta) * birth_time;
575
576 pa->hair_index = 0;
577 /* We can't reset to -1 anymore since we've figured out correct index in #distribute_particles
578 * usage other than straight after distribute has to handle this index by itself - jahka. */
579 // pa->num_dmcache = DMCACHE_NOTFOUND; /* assume we don't have a derived mesh face */
580}
581
583{
584 ParticleSystem *psys = sim->psys;
585 ParticleSettings *part = psys->part;
586 /* Grid distribution-sets UNEXIST flag, need to take care of
587 * it here because later this flag is being reset.
588 *
589 * We can't do it for any distribution, because it'll then
590 * conflict with texture influence, which does not free
591 * unexisting particles and only sets flag.
592 *
593 * It's not so bad, because only grid distribution sets
594 * UNEXIST flag.
595 */
596 const bool emit_from_volume_grid = (part->distr == PART_DISTR_GRID) &&
600 {
601 if (!(emit_from_volume_grid && (pa->flag & PARS_UNEXIST) != 0)) {
602 init_particle(sim, pa);
603 }
604 }
605}
606
608{
609 ParticleSystem *psys = sim->psys;
611
612 psys->totunexist = 0;
613
615 {
616 if (pa->flag & PARS_UNEXIST) {
617 psys->totunexist++;
618 }
619 }
620
621 if (psys->totpart && psys->totunexist == psys->totpart) {
622 if (psys->particles->boid) {
623 MEM_freeN(psys->particles->boid);
624 }
625
626 MEM_freeN(psys->particles);
627 psys->particles = nullptr;
628 psys->totpart = psys->totunexist = 0;
629 }
630
631 if (psys->totunexist) {
632 int newtotpart = psys->totpart - psys->totunexist;
633 ParticleData *npa, *newpars;
634
635 npa = newpars = MEM_calloc_arrayN<ParticleData>(newtotpart, "particles");
636
637 for (p = 0, pa = psys->particles; p < newtotpart; p++, pa++, npa++) {
638 while (pa->flag & PARS_UNEXIST) {
639 pa++;
640 }
641
642 memcpy(npa, pa, sizeof(ParticleData));
643 }
644
645 if (psys->particles->boid) {
646 MEM_freeN(psys->particles->boid);
647 }
648 MEM_freeN(psys->particles);
649 psys->particles = newpars;
650 psys->totpart -= psys->totunexist;
651
652 if (psys->particles->boid) {
653 BoidParticle *newboids = MEM_calloc_arrayN<BoidParticle>(psys->totpart, "boid particles");
654
656 {
657 pa->boid = newboids++;
658 }
659 }
660 }
661}
662
663static void get_angular_velocity_vector(short avemode, ParticleKey *state, float vec[3])
664{
665 switch (avemode) {
667 copy_v3_v3(vec, state->vel);
668 break;
669 case PART_AVE_HORIZONTAL: {
670 float zvec[3];
671 zvec[0] = zvec[1] = 0;
672 zvec[2] = 1.0f;
673 cross_v3_v3v3(vec, state->vel, zvec);
674 break;
675 }
676 case PART_AVE_VERTICAL: {
677 float zvec[3], temp[3];
678 zvec[0] = zvec[1] = 0;
679 zvec[2] = 1.0f;
680 cross_v3_v3v3(temp, state->vel, zvec);
681 cross_v3_v3v3(vec, temp, state->vel);
682 break;
683 }
685 vec[0] = 1.0f;
686 vec[1] = vec[2] = 0;
687 break;
689 vec[1] = 1.0f;
690 vec[0] = vec[2] = 0;
691 break;
693 vec[2] = 1.0f;
694 vec[0] = vec[1] = 0;
695 break;
696 }
697}
698
700 ParticleSimulationData *sim, ParticleData *pa, ParticleKey *state, float dtime, float cfra)
701{
702 Object *ob = sim->ob;
703 ParticleSystem *psys = sim->psys;
704 ParticleSettings *part = psys->part;
705 ParticleTexture ptex;
706 float fac, phasefac, nor[3] = {0, 0, 0}, loc[3], vel[3] = {0.0, 0.0, 0.0}, rot[4], q2[4];
707 float r_vel[3], r_ave[3], r_rot[4], vec[3], p_vel[3] = {0.0, 0.0, 0.0};
708 float x_vec[3] = {1.0, 0.0, 0.0}, utan[3] = {0.0, 1.0, 0.0}, vtan[3] = {0.0, 0.0, 1.0},
709 rot_vec[3] = {0.0, 0.0, 0.0};
710 float q_phase[4];
711
712 const bool use_boids = ((part->phystype == PART_PHYS_BOIDS) && (pa->boid != nullptr));
713 const bool use_tangents = ((use_boids == false) &&
714 ((part->tanfac != 0.0f) || (part->rotmode == PART_ROT_NOR_TAN)));
715
716 int p = pa - psys->particles;
717
718 /* get birth location from object */
719 if (use_tangents) {
721 part->from,
722 pa->num,
723 pa->num_dmcache,
724 pa->fuv,
725 pa->foffset,
726 loc,
727 nor,
728 utan,
729 vtan,
730 nullptr);
731 }
732 else {
734 part->from,
735 pa->num,
736 pa->num_dmcache,
737 pa->fuv,
738 pa->foffset,
739 loc,
740 nor,
741 nullptr,
742 nullptr,
743 nullptr);
744 }
745
746 /* get possible textural influence */
747 psys_get_texture(sim, pa, &ptex, PAMAP_IVEL, cfra);
748
749 /* particles live in global space so */
750 /* let's convert: */
751 /* -location */
752 mul_m4_v3(ob->object_to_world().ptr(), loc);
753
754 /* -normal */
755 mul_mat3_m4_v3(ob->object_to_world().ptr(), nor);
757
758 /* -tangent */
759 if (use_tangents) {
760#if 0
761 float phase = vg_rot ?
762 2.0f *
763 (psys_particle_value_from_verts(sim->psmd->dm, part->from, pa, vg_rot) -
764 0.5f) :
765 0.0f;
766#else
767 float phase = 0.0f;
768#endif
769 mul_v3_fl(vtan, -cosf(float(M_PI) * (part->tanphase + phase)));
770 fac = -sinf(float(M_PI) * (part->tanphase + phase));
771 madd_v3_v3fl(vtan, utan, fac);
772
773 mul_mat3_m4_v3(ob->object_to_world().ptr(), vtan);
774
775 copy_v3_v3(utan, nor);
776 mul_v3_fl(utan, dot_v3v3(vtan, nor));
777 sub_v3_v3(vtan, utan);
778
779 normalize_v3(vtan);
780 }
781
782 /* -velocity (boids need this even if there's no random velocity) */
783 if (part->randfac != 0.0f || (part->phystype == PART_PHYS_BOIDS && pa->boid)) {
784 r_vel[0] = 2.0f * (psys_frand(psys, p + 10) - 0.5f);
785 r_vel[1] = 2.0f * (psys_frand(psys, p + 11) - 0.5f);
786 r_vel[2] = 2.0f * (psys_frand(psys, p + 12) - 0.5f);
787
788 mul_mat3_m4_v3(ob->object_to_world().ptr(), r_vel);
789 normalize_v3(r_vel);
790 }
791
792 /* -angular velocity */
793 if (part->avemode == PART_AVE_RAND) {
794 r_ave[0] = 2.0f * (psys_frand(psys, p + 13) - 0.5f);
795 r_ave[1] = 2.0f * (psys_frand(psys, p + 14) - 0.5f);
796 r_ave[2] = 2.0f * (psys_frand(psys, p + 15) - 0.5f);
797
798 mul_mat3_m4_v3(ob->object_to_world().ptr(), r_ave);
799 normalize_v3(r_ave);
800 }
801
802 /* -rotation */
803 if (part->randrotfac != 0.0f) {
804 r_rot[0] = 2.0f * (psys_frand(psys, p + 16) - 0.5f);
805 r_rot[1] = 2.0f * (psys_frand(psys, p + 17) - 0.5f);
806 r_rot[2] = 2.0f * (psys_frand(psys, p + 18) - 0.5f);
807 r_rot[3] = 2.0f * (psys_frand(psys, p + 19) - 0.5f);
808 normalize_qt(r_rot);
809
810 mat4_to_quat(rot, ob->object_to_world().ptr());
811 mul_qt_qtqt(r_rot, r_rot, rot);
812 }
813
814 if (use_boids) {
815 float dvec[3], q[4], mat[3][3];
816
817 copy_v3_v3(state->co, loc);
818
819 /* boids don't get any initial velocity. */
820 zero_v3(state->vel);
821
822 /* boids store direction in ave */
823 if (fabsf(nor[2]) == 1.0f) {
824 sub_v3_v3v3(state->ave, loc, ob->object_to_world().location());
825 normalize_v3(state->ave);
826 }
827 else {
828 copy_v3_v3(state->ave, nor);
829 }
830
831 /* calculate rotation matrix */
832 project_v3_v3v3(dvec, r_vel, state->ave);
833 sub_v3_v3v3(mat[0], state->ave, dvec);
834 normalize_v3(mat[0]);
835 negate_v3_v3(mat[2], r_vel);
836 normalize_v3(mat[2]);
837 cross_v3_v3v3(mat[1], mat[2], mat[0]);
838
839 /* apply rotation */
840 mat3_to_quat_legacy(q, mat);
841 copy_qt_qt(state->rot, q);
842 }
843 else {
844 /* conversion done so now we apply new: */
845 /* -velocity from: */
846
847 /* *reactions */
848 if (dtime > 0.0f) {
849 sub_v3_v3v3(vel, pa->state.vel, pa->prev_state.vel);
850 }
851
852 /* *emitter velocity */
853 if (dtime != 0.0f && part->obfac != 0.0f) {
854 sub_v3_v3v3(vel, loc, state->co);
855 mul_v3_fl(vel, part->obfac / dtime);
856 }
857
858 /* *emitter normal */
859 if (part->normfac != 0.0f) {
860 madd_v3_v3fl(vel, nor, part->normfac);
861 }
862
863 /* *emitter tangent */
864 if (sim->psmd && part->tanfac != 0.0f) {
865 madd_v3_v3fl(vel, vtan, part->tanfac);
866 }
867
868 /* *emitter object orientation */
869 if (part->ob_vel[0] != 0.0f) {
870 normalize_v3_v3(vec, ob->object_to_world().ptr()[0]);
871 madd_v3_v3fl(vel, vec, part->ob_vel[0]);
872 }
873 if (part->ob_vel[1] != 0.0f) {
874 normalize_v3_v3(vec, ob->object_to_world().ptr()[1]);
875 madd_v3_v3fl(vel, vec, part->ob_vel[1]);
876 }
877 if (part->ob_vel[2] != 0.0f) {
878 normalize_v3_v3(vec, ob->object_to_world().ptr()[2]);
879 madd_v3_v3fl(vel, vec, part->ob_vel[2]);
880 }
881
882 /* *texture */
883 /* TODO */
884
885 /* *random */
886 if (part->randfac != 0.0f) {
887 madd_v3_v3fl(vel, r_vel, part->randfac);
888 }
889
890 /* *particle */
891 if (part->partfac != 0.0f) {
892 madd_v3_v3fl(vel, p_vel, part->partfac);
893 }
894
895 mul_v3_v3fl(state->vel, vel, ptex.ivel);
896
897 /* -location from emitter */
898 copy_v3_v3(state->co, loc);
899
900 /* -rotation */
901 unit_qt(state->rot);
902
903 if (part->rotmode) {
904 bool use_global_space;
905
906 /* create vector into which rotation is aligned */
907 switch (part->rotmode) {
908 case PART_ROT_NOR:
909 case PART_ROT_NOR_TAN:
910 copy_v3_v3(rot_vec, nor);
911 use_global_space = false;
912 break;
913 case PART_ROT_VEL:
914 copy_v3_v3(rot_vec, vel);
915 use_global_space = true;
916 break;
917 case PART_ROT_GLOB_X:
918 case PART_ROT_GLOB_Y:
919 case PART_ROT_GLOB_Z:
920 rot_vec[part->rotmode - PART_ROT_GLOB_X] = 1.0f;
921 use_global_space = true;
922 break;
923 case PART_ROT_OB_X:
924 case PART_ROT_OB_Y:
925 case PART_ROT_OB_Z:
926 copy_v3_v3(rot_vec, ob->object_to_world().ptr()[part->rotmode - PART_ROT_OB_X]);
927 use_global_space = false;
928 break;
929 default:
930 use_global_space = true;
931 break;
932 }
933
934 /* create rotation quat */
935
936 if (use_global_space) {
937 negate_v3(rot_vec);
938 vec_to_quat(q2, rot_vec, OB_POSX, OB_POSZ);
939
940 /* randomize rotation quat */
941 if (part->randrotfac != 0.0f) {
942 interp_qt_qtqt(rot, q2, r_rot, part->randrotfac);
943 }
944 else {
945 copy_qt_qt(rot, q2);
946 }
947 }
948 else {
949 /* calculate rotation in local-space */
950 float q_obmat[4];
951 float q_imat[4];
952
953 mat4_to_quat(q_obmat, ob->object_to_world().ptr());
954 invert_qt_qt_normalized(q_imat, q_obmat);
955
956 if (part->rotmode != PART_ROT_NOR_TAN) {
957 float rot_vec_local[3];
958
959 /* rot_vec */
960 negate_v3(rot_vec);
961 copy_v3_v3(rot_vec_local, rot_vec);
962 mul_qt_v3(q_imat, rot_vec_local);
963 normalize_v3(rot_vec_local);
964
965 vec_to_quat(q2, rot_vec_local, OB_POSX, OB_POSZ);
966 }
967 else {
968 /* (part->rotmode == PART_ROT_NOR_TAN) */
969 float tmat[3][3];
970
971 /* NOTE: utan_local is not taken from 'utan', we calculate from rot_vec/vtan. */
972 /* NOTE(@ideasman42): it looks like rotation phase may be applied twice
973 * (once with vtan, again below) however this isn't the case. */
974 float *rot_vec_local = tmat[0];
975 float *vtan_local = tmat[1];
976 float *utan_local = tmat[2];
977
978 /* use tangents */
979 BLI_assert(use_tangents == true);
980
981 /* rot_vec */
982 copy_v3_v3(rot_vec_local, rot_vec);
983 mul_qt_v3(q_imat, rot_vec_local);
984
985 /* vtan_local */
986 copy_v3_v3(vtan_local, vtan); /* flips, can't use */
987 mul_qt_v3(q_imat, vtan_local);
988
989 /* ensure orthogonal matrix (rot_vec aligned) */
990 cross_v3_v3v3(utan_local, vtan_local, rot_vec_local);
991 cross_v3_v3v3(vtan_local, utan_local, rot_vec_local);
992
993 /* NOTE: no need to normalize. */
994 mat3_to_quat(q2, tmat);
995 }
996
997 /* randomize rotation quat */
998 if (part->randrotfac != 0.0f) {
999 mul_qt_qtqt(r_rot, r_rot, q_imat);
1000 interp_qt_qtqt(rot, q2, r_rot, part->randrotfac);
1001 }
1002 else {
1003 copy_qt_qt(rot, q2);
1004 }
1005
1006 mul_qt_qtqt(rot, q_obmat, rot);
1007 }
1008
1009 /* rotation phase */
1010 phasefac = part->phasefac;
1011 if (part->randphasefac != 0.0f) {
1012 phasefac += part->randphasefac * psys_frand(psys, p + 20);
1013 }
1014 axis_angle_to_quat(q_phase, x_vec, phasefac * float(M_PI));
1015
1016 /* combine base rotation & phase */
1017 mul_qt_qtqt(state->rot, rot, q_phase);
1018 }
1019
1020 /* -angular velocity */
1021
1022 zero_v3(state->ave);
1023
1024 if (part->avemode) {
1025 if (part->avemode == PART_AVE_RAND) {
1026 copy_v3_v3(state->ave, r_ave);
1027 }
1028 else {
1030 }
1031
1032 normalize_v3(state->ave);
1033 mul_v3_fl(state->ave, part->avefac);
1034 }
1035 }
1036}
1037
1038/* recursively evaluate emitter parent anim at cfra */
1039static void evaluate_emitter_anim(Depsgraph *depsgraph, Scene *scene, Object *ob, float cfra)
1040{
1041 if (ob->parent) {
1042 evaluate_emitter_anim(depsgraph, scene, ob->parent, cfra);
1043 }
1044
1045 BKE_object_where_is_calc_time(depsgraph, scene, ob, cfra);
1046}
1047
1048void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, float cfra)
1049{
1050 ParticleSystem *psys = sim->psys;
1051 ParticleSettings *part;
1052 ParticleTexture ptex;
1053 int p = pa - psys->particles;
1054 part = psys->part;
1055
1056 /* get precise emitter matrix if particle is born */
1057 if (part->type != PART_HAIR && dtime > 0.0f && pa->time < cfra && pa->time >= sim->psys->cfra) {
1058 evaluate_emitter_anim(sim->depsgraph, sim->scene, sim->ob, pa->time);
1059
1060 psys->flag |= PSYS_OB_ANIM_RESTORE;
1061 }
1062
1063 psys_get_birth_coords(sim, pa, &pa->state, dtime, cfra);
1064
1065 /* Initialize particle settings which depends on texture.
1066 *
1067 * We could only do it now because we'll need to know coordinate
1068 * before sampling the texture.
1069 */
1070 init_particle_texture(sim, pa, p);
1071
1072 if (part->phystype == PART_PHYS_BOIDS && pa->boid) {
1073 BoidParticle *bpa = pa->boid;
1074
1075 /* and gravity in r_ve */
1076 bpa->gravity[0] = bpa->gravity[1] = 0.0f;
1077 bpa->gravity[2] = -1.0f;
1079 (sim->scene->physics_settings.gravity[2] != 0.0f))
1080 {
1081 bpa->gravity[2] = sim->scene->physics_settings.gravity[2];
1082 }
1083
1084 bpa->data.health = part->boids->health;
1085 bpa->data.mode = eBoidMode_InAir;
1086 bpa->data.state_id = ((BoidState *)part->boids->states.first)->id;
1087 bpa->data.acc[0] = bpa->data.acc[1] = bpa->data.acc[2] = 0.0f;
1088 }
1089
1090 if (part->type == PART_HAIR) {
1091 pa->lifetime = 100.0f;
1092 }
1093 else {
1094 /* initialize the lifetime, in case the texture coordinates
1095 * are from Particles/Strands, which would cause undefined values
1096 */
1097 pa->lifetime = part->lifetime * (1.0f - part->randlife * psys_frand(psys, p + 21));
1098 pa->dietime = pa->time + pa->lifetime;
1099
1100 /* get possible textural influence */
1101 psys_get_texture(sim, pa, &ptex, PAMAP_LIFE, cfra);
1102
1103 pa->lifetime = part->lifetime * ptex.life;
1104
1105 if (part->randlife != 0.0f) {
1106 pa->lifetime *= 1.0f - part->randlife * psys_frand(psys, p + 21);
1107 }
1108 }
1109
1110 pa->dietime = pa->time + pa->lifetime;
1111
1112 if ((sim->psys->pointcache) && (sim->psys->pointcache->flag & PTCACHE_BAKED) &&
1113 (sim->psys->pointcache->mem_cache.first))
1114 {
1115 float dietime = psys_get_dietime_from_cache(sim->psys->pointcache, p);
1116 pa->dietime = std::min(pa->dietime, dietime);
1117 }
1118
1119 if (pa->time > cfra) {
1120 pa->alive = PARS_UNBORN;
1121 }
1122 else if (pa->dietime <= cfra) {
1123 pa->alive = PARS_DEAD;
1124 }
1125 else {
1126 pa->alive = PARS_ALIVE;
1127 }
1128
1129 pa->state.time = cfra;
1130}
1131static void reset_all_particles(ParticleSimulationData *sim, float dtime, float cfra, int from)
1132{
1133 ParticleData *pa;
1134 int p, totpart = sim->psys->totpart;
1135
1136 for (p = from, pa = sim->psys->particles + from; p < totpart; p++, pa++) {
1137 reset_particle(sim, pa, dtime, cfra);
1138 }
1139}
1140
1141/************************************************/
1142/* Particle targets */
1143/************************************************/
1144
1146{
1147 ParticleSystem *psys = nullptr;
1148
1149 if (ELEM(pt->ob, nullptr, ob)) {
1150 psys = static_cast<ParticleSystem *>(BLI_findlink(&ob->particlesystem, pt->psys - 1));
1151 }
1152 else {
1153 psys = static_cast<ParticleSystem *>(BLI_findlink(&pt->ob->particlesystem, pt->psys - 1));
1154 }
1155
1156 if (psys) {
1157 pt->flag |= PTARGET_VALID;
1158 }
1159 else {
1160 pt->flag &= ~PTARGET_VALID;
1161 }
1162
1163 return psys;
1164}
1165
1166/************************************************/
1167/* Keyed particles */
1168/************************************************/
1169
1171{
1172 ParticleSystem *psys = sim->psys, *kpsys;
1173 ParticleTarget *pt = static_cast<ParticleTarget *>(psys->targets.first);
1174 int keys_valid = 1;
1175 psys->totkeyed = 0;
1176
1177 for (; pt; pt = pt->next) {
1178 kpsys = psys_get_target_system(sim->ob, pt);
1179
1180 if (kpsys && kpsys->totpart) {
1181 psys->totkeyed += keys_valid;
1182 if (psys->flag & PSYS_KEYED_TIMING && pt->duration != 0.0f) {
1183 psys->totkeyed += 1;
1184 }
1185 }
1186 else {
1187 keys_valid = 0;
1188 }
1189 }
1190
1191 psys->totkeyed *= psys->flag & PSYS_KEYED_TIMING ? 1 : psys->part->keyed_loops;
1192}
1193
1195{
1196 ParticleSystem *psys = sim->psys;
1197 ParticleSimulationData ksim = {nullptr};
1198 ParticleTarget *pt;
1199 PARTICLE_P;
1200 ParticleKey *key;
1201 int totpart = psys->totpart, k, totkeys = psys->totkeyed;
1202 int keyed_flag = 0;
1203
1204 ksim.depsgraph = sim->depsgraph;
1205 ksim.scene = sim->scene;
1206
1207 /* no proper targets so let's clear and bail out */
1208 if (psys->totkeyed == 0) {
1209 free_keyed_keys(psys);
1210 psys->flag &= ~PSYS_KEYED;
1211 return;
1212 }
1213
1214 if (totpart && psys->particles->totkey != totkeys) {
1215 free_keyed_keys(psys);
1216
1217 key = MEM_calloc_arrayN<ParticleKey>(size_t(totpart) * size_t(totkeys), "Keyed keys");
1218
1220 {
1221 pa->keys = key;
1222 pa->totkey = totkeys;
1223 key += totkeys;
1224 }
1225 }
1226
1227 psys->flag &= ~PSYS_KEYED;
1228
1229 pt = static_cast<ParticleTarget *>(psys->targets.first);
1230 for (k = 0; k < totkeys; k++) {
1231 ksim.ob = pt->ob ? pt->ob : sim->ob;
1232 ksim.psys = static_cast<ParticleSystem *>(
1233 BLI_findlink(&ksim.ob->particlesystem, pt->psys - 1));
1234 keyed_flag = (ksim.psys->flag & PSYS_KEYED);
1235 ksim.psys->flag &= ~PSYS_KEYED;
1236
1238 {
1239 key = pa->keys + k;
1240 key->time = -1.0; /* use current time */
1241
1242 const int p_ksim = (ksim.psys->totpart) ? p % ksim.psys->totpart : 0;
1243 psys_get_particle_state(&ksim, p_ksim, key, true);
1244
1245 if (psys->flag & PSYS_KEYED_TIMING) {
1246 key->time = pa->time + pt->time;
1247 if (pt->duration != 0.0f && k + 1 < totkeys) {
1248 copy_particle_key(key + 1, key, 1);
1249 (key + 1)->time = pa->time + pt->time + pt->duration;
1250 }
1251 }
1252 else if (totkeys > 1) {
1253 key->time = pa->time + float(k) / float(totkeys - 1) * pa->lifetime;
1254 }
1255 else {
1256 key->time = pa->time;
1257 }
1258 }
1259
1260 if (psys->flag & PSYS_KEYED_TIMING && pt->duration != 0.0f) {
1261 k++;
1262 }
1263
1264 ksim.psys->flag |= keyed_flag;
1265
1266 pt = static_cast<ParticleTarget *>(
1267 (pt->next && pt->next->flag & PTARGET_VALID) ? pt->next : psys->targets.first);
1268 }
1269
1270 psys->flag |= PSYS_KEYED;
1271}
1272
1273/************************************************/
1274/* Point Cache */
1275/************************************************/
1276
1278{
1279 PointCache *cache = psys->pointcache;
1280
1281 if (cache->flag & PTCACHE_DISK_CACHE && BLI_listbase_is_empty(&cache->mem_cache)) {
1282 PTCacheID pid;
1283 BKE_ptcache_id_from_particles(&pid, ob, psys);
1284 cache->flag &= ~PTCACHE_DISK_CACHE;
1286 cache->flag |= PTCACHE_DISK_CACHE;
1287 }
1288}
1290{
1291 if (psys->pointcache->flag & PTCACHE_DISK_CACHE) {
1293 }
1294}
1295void psys_get_pointcache_start_end(Scene *scene, ParticleSystem *psys, int *sfra, int *efra)
1296{
1297 ParticleSettings *part = psys->part;
1298
1299 *sfra = max_ii(1, int(part->sta));
1300 *efra = min_ii(int(part->end + part->lifetime + 1.0f), max_ii(scene->r.pefra, scene->r.efra));
1301}
1302
1303/* BVH tree balancing inside a mutex lock must be run in isolation. Balancing
1304 * is multithreaded, and we do not want the current thread to start another task
1305 * that may involve acquiring the same mutex lock that it is waiting for. */
1306static void bvhtree_balance_isolated(void *userdata)
1307{
1308 BLI_bvhtree_balance((BVHTree *)userdata);
1309}
1310
1311/************************************************/
1312/* Effectors */
1313/************************************************/
1314
1315static void psys_update_particle_bvhtree(ParticleSystem *psys, float cfra)
1316{
1317 if (psys) {
1318 PARTICLE_P;
1319 int totpart = 0;
1320 bool need_rebuild;
1321
1323 need_rebuild = !psys->bvhtree || psys->bvhtree_frame != cfra;
1325
1326 if (need_rebuild) {
1328 {
1329 totpart++;
1330 }
1331
1333
1335 psys->bvhtree = BLI_bvhtree_new(totpart, 0.0, 4, 6);
1336
1338 {
1339 if (pa->alive == PARS_ALIVE) {
1340 if (pa->state.time == cfra) {
1341 BLI_bvhtree_insert(psys->bvhtree, p, pa->prev_state.co, 1);
1342 }
1343 else {
1344 BLI_bvhtree_insert(psys->bvhtree, p, pa->state.co, 1);
1345 }
1346 }
1347 }
1348
1350
1351 psys->bvhtree_frame = cfra;
1352
1354 }
1355 }
1356}
1358{
1359 if (psys) {
1360 PARTICLE_P;
1361
1362 if (!psys->tree || psys->tree_frame != cfra) {
1363 int totpart = 0;
1365 {
1366 if (pa->alive == PARS_ALIVE) {
1367 totpart++;
1368 }
1369 }
1370
1371 BLI_kdtree_3d_free(psys->tree);
1372 psys->tree = BLI_kdtree_3d_new(totpart);
1373
1375 {
1376 if (pa->alive == PARS_ALIVE) {
1377 const float *co = (pa->state.time == cfra) ? pa->prev_state.co : pa->state.co;
1378 BLI_kdtree_3d_insert(psys->tree, p, co);
1379 }
1380 }
1381 BLI_kdtree_3d_balance(psys->tree);
1382
1383 psys->tree_frame = cfra;
1384 }
1385 }
1386}
1387
1389{
1391 bool use_rotation = (sim->psys->part->flag & PART_ROT_DYN) != 0;
1393 sim->depsgraph, sim->ob, sim->psys, sim->psys->part->effector_weights, use_rotation);
1394 precalc_guides(sim, sim->psys->effectors);
1395}
1396
1398 ParticleSettings *part,
1399 ParticleData *pa,
1400 float dtime,
1401 float *external_acceleration,
1402 void (*force_func)(void *forcedata, ParticleKey *state, float *force, float *impulse),
1403 void *forcedata)
1404{
1405#define ZERO_F43 \
1406 { \
1407 {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f} \
1408 }
1409
1410 ParticleKey states[5];
1411 float force[3], acceleration[3], impulse[3], dx[4][3] = ZERO_F43, dv[4][3] = ZERO_F43, oldpos[3];
1412 float pa_mass = (part->flag & PART_SIZEMASS) ? (part->mass * pa->size) : part->mass;
1413 int i, steps = 1;
1414 int integrator = part->integrator;
1415
1416#undef ZERO_F43
1417
1418 copy_v3_v3(oldpos, pa->state.co);
1419
1420 /* Verlet integration behaves strangely with moving emitters, so do first step with euler. */
1421 if (pa->prev_state.time < 0.0f && integrator == PART_INT_VERLET) {
1422 integrator = PART_INT_EULER;
1423 }
1424
1425 switch (integrator) {
1426 case PART_INT_EULER:
1427 steps = 1;
1428 break;
1429 case PART_INT_MIDPOINT:
1430 steps = 2;
1431 break;
1432 case PART_INT_RK4:
1433 steps = 4;
1434 break;
1435 case PART_INT_VERLET:
1436 steps = 1;
1437 break;
1438 }
1439
1440 for (i = 0; i < steps; i++) {
1441 copy_particle_key(states + i, &pa->state, 1);
1442 }
1443
1444 states->time = 0.0f;
1445
1446 for (i = 0; i < steps; i++) {
1447 zero_v3(force);
1448 zero_v3(impulse);
1449
1450 force_func(forcedata, states + i, force, impulse);
1451
1452 /* Force to acceleration. */
1453 mul_v3_v3fl(acceleration, force, 1.0f / pa_mass);
1454
1455 if (external_acceleration) {
1456 add_v3_v3(acceleration, external_acceleration);
1457 }
1458
1459 /* calculate next state */
1460 add_v3_v3(states[i].vel, impulse);
1461
1462 switch (integrator) {
1463 case PART_INT_EULER:
1464 madd_v3_v3v3fl(pa->state.co, states->co, states->vel, dtime);
1465 madd_v3_v3v3fl(pa->state.vel, states->vel, acceleration, dtime);
1466 break;
1467 case PART_INT_MIDPOINT:
1468 if (i == 0) {
1469 madd_v3_v3v3fl(states[1].co, states->co, states->vel, dtime * 0.5f);
1470 madd_v3_v3v3fl(states[1].vel, states->vel, acceleration, dtime * 0.5f);
1471 states[1].time = dtime * 0.5f;
1472 // fra = sim->psys->cfra + 0.5f * dfra;
1473 }
1474 else {
1475 madd_v3_v3v3fl(pa->state.co, states->co, states[1].vel, dtime);
1476 madd_v3_v3v3fl(pa->state.vel, states->vel, acceleration, dtime);
1477 }
1478 break;
1479 case PART_INT_RK4:
1480 switch (i) {
1481 case 0:
1482 copy_v3_v3(dx[0], states->vel);
1483 mul_v3_fl(dx[0], dtime);
1484 copy_v3_v3(dv[0], acceleration);
1485 mul_v3_fl(dv[0], dtime);
1486
1487 madd_v3_v3v3fl(states[1].co, states->co, dx[0], 0.5f);
1488 madd_v3_v3v3fl(states[1].vel, states->vel, dv[0], 0.5f);
1489 states[1].time = dtime * 0.5f;
1490 // fra = sim->psys->cfra + 0.5f * dfra;
1491 break;
1492 case 1:
1493 madd_v3_v3v3fl(dx[1], states->vel, dv[0], 0.5f);
1494 mul_v3_fl(dx[1], dtime);
1495 copy_v3_v3(dv[1], acceleration);
1496 mul_v3_fl(dv[1], dtime);
1497
1498 madd_v3_v3v3fl(states[2].co, states->co, dx[1], 0.5f);
1499 madd_v3_v3v3fl(states[2].vel, states->vel, dv[1], 0.5f);
1500 states[2].time = dtime * 0.5f;
1501 break;
1502 case 2:
1503 madd_v3_v3v3fl(dx[2], states->vel, dv[1], 0.5f);
1504 mul_v3_fl(dx[2], dtime);
1505 copy_v3_v3(dv[2], acceleration);
1506 mul_v3_fl(dv[2], dtime);
1507
1508 add_v3_v3v3(states[3].co, states->co, dx[2]);
1509 add_v3_v3v3(states[3].vel, states->vel, dv[2]);
1510 states[3].time = dtime;
1511 // fra = cfra;
1512 break;
1513 case 3:
1514 add_v3_v3v3(dx[3], states->vel, dv[2]);
1515 mul_v3_fl(dx[3], dtime);
1516 copy_v3_v3(dv[3], acceleration);
1517 mul_v3_fl(dv[3], dtime);
1518
1519 madd_v3_v3v3fl(pa->state.co, states->co, dx[0], 1.0f / 6.0f);
1520 madd_v3_v3fl(pa->state.co, dx[1], 1.0f / 3.0f);
1521 madd_v3_v3fl(pa->state.co, dx[2], 1.0f / 3.0f);
1522 madd_v3_v3fl(pa->state.co, dx[3], 1.0f / 6.0f);
1523
1524 madd_v3_v3v3fl(pa->state.vel, states->vel, dv[0], 1.0f / 6.0f);
1525 madd_v3_v3fl(pa->state.vel, dv[1], 1.0f / 3.0f);
1526 madd_v3_v3fl(pa->state.vel, dv[2], 1.0f / 3.0f);
1527 madd_v3_v3fl(pa->state.vel, dv[3], 1.0f / 6.0f);
1528 }
1529 break;
1530 case PART_INT_VERLET: /* Verlet integration */
1531 madd_v3_v3v3fl(pa->state.vel, pa->prev_state.vel, acceleration, dtime);
1532 madd_v3_v3v3fl(pa->state.co, pa->prev_state.co, pa->state.vel, dtime);
1533
1534 sub_v3_v3v3(pa->state.vel, pa->state.co, oldpos);
1535 mul_v3_fl(pa->state.vel, 1.0f / dtime);
1536 break;
1537 }
1538 }
1539}
1540
1541/* -------------------------------------------------------------------- */
1555
1556#define PSYS_FLUID_SPRINGS_INITIAL_SIZE 256
1558{
1559 /* Are more refs required? */
1560 if (psys->alloc_fluidsprings == 0 || psys->fluid_springs == nullptr) {
1563 "Particle Fluid Springs");
1564 }
1565 else if (psys->tot_fluidsprings == psys->alloc_fluidsprings) {
1566 /* Double the number of refs allocated */
1567 psys->alloc_fluidsprings *= 2;
1569 psys->fluid_springs, psys->alloc_fluidsprings * sizeof(ParticleSpring));
1570 }
1571
1572 memcpy(psys->fluid_springs + psys->tot_fluidsprings, spring, sizeof(ParticleSpring));
1573 psys->tot_fluidsprings++;
1574
1575 return psys->fluid_springs + psys->tot_fluidsprings - 1;
1576}
1577static void sph_spring_delete(ParticleSystem *psys, int j)
1578{
1579 if (j != psys->tot_fluidsprings - 1) {
1580 psys->fluid_springs[j] = psys->fluid_springs[psys->tot_fluidsprings - 1];
1581 }
1582
1583 psys->tot_fluidsprings--;
1584
1585 if (psys->tot_fluidsprings < psys->alloc_fluidsprings / 2 &&
1587 {
1588 psys->alloc_fluidsprings /= 2;
1590 psys->fluid_springs, psys->alloc_fluidsprings * sizeof(ParticleSpring));
1591 }
1592}
1593static void sph_springs_modify(ParticleSystem *psys, float dtime)
1594{
1595 SPHFluidSettings *fluid = psys->part->fluid;
1596 ParticleData *pa1, *pa2;
1597 ParticleSpring *spring = psys->fluid_springs;
1598
1599 float h, d, Rij[3], rij, Lij;
1600 int i;
1601
1602 float yield_ratio = fluid->yield_ratio;
1603 float plasticity = fluid->plasticity_constant;
1604 /* scale things according to dtime */
1605 float timefix = 25.0f * dtime;
1606
1607 if ((fluid->flag & SPH_VISCOELASTIC_SPRINGS) == 0 || fluid->spring_k == 0.0f) {
1608 return;
1609 }
1610
1611 /* Loop through the springs */
1612 for (i = 0; i < psys->tot_fluidsprings; i++, spring++) {
1613 pa1 = psys->particles + spring->particle_index[0];
1614 pa2 = psys->particles + spring->particle_index[1];
1615
1616 sub_v3_v3v3(Rij, pa2->prev_state.co, pa1->prev_state.co);
1617 rij = normalize_v3(Rij);
1618
1619 /* adjust rest length */
1620 Lij = spring->rest_length;
1621 d = yield_ratio * timefix * Lij;
1622
1623 if (rij > Lij + d) { /* Stretch */
1624 spring->rest_length += plasticity * (rij - Lij - d) * timefix;
1625 }
1626 else if (rij < Lij - d) { /* Compress */
1627 spring->rest_length -= plasticity * (Lij - d - rij) * timefix;
1628 }
1629
1630 h = 4.0f * pa1->size;
1631
1632 if (spring->rest_length > h) {
1633 spring->delete_flag = 1;
1634 }
1635 }
1636
1637 /* Loop through springs backwards - for efficient delete function. */
1638 for (i = psys->tot_fluidsprings - 1; i >= 0; i--) {
1639 if (psys->fluid_springs[i].delete_flag) {
1640 sph_spring_delete(psys, i);
1641 }
1642 }
1643}
1645{
1647 springhash.reserve(psys->tot_fluidsprings);
1648
1649 ParticleSpring *spring;
1650 int i = 0;
1651
1652 for (i = 0, spring = psys->fluid_springs; i < psys->tot_fluidsprings; i++, spring++) {
1653 springhash.add({spring->particle_index[0], spring->particle_index[1]}, i + 1);
1654 }
1655
1656 return springhash;
1657}
1658
1659#define SPH_NEIGHBORS 512
1664
1679
1681 ParticleSystem **psys,
1682 const float co[3],
1683 SPHRangeData *pfr,
1684 float interaction_radius,
1685 BVHTree_RangeQuery callback)
1686{
1687 int i;
1688
1689 pfr->tot_neighbors = 0;
1690
1691 for (i = 0; i < 10 && psys[i]; i++) {
1692 pfr->npsys = psys[i];
1693 pfr->massfac = psys[i]->part->mass / pfr->mass;
1694 pfr->use_size = psys[i]->part->flag & PART_SIZEMASS;
1695
1696 if (tree) {
1697 BLI_bvhtree_range_query(tree, co, interaction_radius, callback, pfr);
1698 break;
1699 }
1700
1702
1703 BLI_bvhtree_range_query(psys[i]->bvhtree, co, interaction_radius, callback, pfr);
1704
1706 }
1707}
1708static void sph_density_accum_cb(void *userdata, int index, const float co[3], float squared_dist)
1709{
1710 SPHRangeData *pfr = (SPHRangeData *)userdata;
1711 ParticleData *npa = pfr->npsys->particles + index;
1712 float q;
1713 float dist;
1714
1715 UNUSED_VARS(co);
1716
1717 if (npa == pfr->pa || squared_dist < FLT_EPSILON) {
1718 return;
1719 }
1720
1721 /* Ugh! One particle has too many neighbors! If some aren't taken into
1722 * account, the forces will be biased by the tree search order. This
1723 * effectively adds energy to the system, and results in a churning motion.
1724 * But, we have to stop somewhere, and it's not the end of the world.
1725 * - jahka and z0r
1726 */
1727 if (pfr->tot_neighbors >= SPH_NEIGHBORS) {
1728 return;
1729 }
1730
1731 pfr->neighbors[pfr->tot_neighbors].index = index;
1732 pfr->neighbors[pfr->tot_neighbors].psys = pfr->npsys;
1733 pfr->tot_neighbors++;
1734
1735 dist = sqrtf(squared_dist);
1736 q = (1.0f - dist / pfr->h) * pfr->massfac;
1737
1738 if (pfr->use_size) {
1739 q *= npa->size;
1740 }
1741
1742 pfr->data[0] += q * q;
1743 pfr->data[1] += q * q * q;
1744}
1745
1746/*
1747 * Find the Courant number for an SPH particle (used for adaptive time step).
1748 */
1749static void sph_particle_courant(SPHData *sphdata, SPHRangeData *pfr)
1750{
1751 ParticleData *pa, *npa;
1752 int i;
1753 float flow[3], offset[3], dist;
1754
1755 zero_v3(flow);
1756
1757 dist = 0.0f;
1758 if (pfr->tot_neighbors > 0) {
1759 pa = pfr->pa;
1760 for (i = 0; i < pfr->tot_neighbors; i++) {
1761 npa = pfr->neighbors[i].psys->particles + pfr->neighbors[i].index;
1762 sub_v3_v3v3(offset, pa->prev_state.co, npa->prev_state.co);
1763 dist += len_v3(offset);
1764 add_v3_v3(flow, npa->prev_state.vel);
1765 }
1766 dist += sphdata->psys[0]->part->fluid->radius; /* TODO(@z0r): remove this? */
1767 sphdata->element_size = dist / pfr->tot_neighbors;
1768 mul_v3_v3fl(sphdata->flow, flow, 1.0f / pfr->tot_neighbors);
1769 }
1770 else {
1771 sphdata->element_size = FLT_MAX;
1772 copy_v3_v3(sphdata->flow, flow);
1773 }
1774}
1775static void sph_force_cb(void *sphdata_v, ParticleKey *state, float *force, float * /*impulse*/)
1776{
1777 SPHData *sphdata = (SPHData *)sphdata_v;
1778 ParticleSystem **psys = sphdata->psys;
1779 ParticleData *pa = sphdata->pa;
1780 SPHFluidSettings *fluid = psys[0]->part->fluid;
1781 ParticleSpring *spring = nullptr;
1782 SPHRangeData pfr;
1783 SPHNeighbor *pfn;
1784 const float *gravity = sphdata->gravity;
1785 const blender::Map<blender::OrderedEdge, int> *springhash = sphdata->eh;
1786
1787 float q, u, rij, dv[3];
1788 float pressure, near_pressure;
1789
1790 float visc = fluid->viscosity_omega;
1791 float stiff_visc = fluid->viscosity_beta *
1792 (fluid->flag & SPH_FAC_VISCOSITY ? fluid->viscosity_omega : 1.0f);
1793
1794 float inv_mass = 1.0f / sphdata->mass;
1795 float spring_constant = fluid->spring_k;
1796
1797 /* 4.0 seems to be a pretty good value */
1798 float interaction_radius = fluid->radius *
1799 (fluid->flag & SPH_FAC_RADIUS ? 4.0f * pa->size : 1.0f);
1800 float h = interaction_radius * sphdata->hfac;
1801 /* 4.77 is an experimentally determined density factor */
1802 float rest_density = fluid->rest_density * (fluid->flag & SPH_FAC_DENSITY ? 4.77f : 1.0f);
1803 float rest_length = fluid->rest_length *
1804 (fluid->flag & SPH_FAC_REST_LENGTH ? 2.588f * pa->size : 1.0f);
1805
1806 float stiffness = fluid->stiffness_k;
1807 float stiffness_near_fac = fluid->stiffness_knear *
1808 (fluid->flag & SPH_FAC_REPULSION ? fluid->stiffness_k : 1.0f);
1809
1810 ParticleData *npa;
1811 float vec[3];
1812 float vel[3];
1813 float co[3];
1814 float data[2];
1815 float density, near_density;
1816
1817 int i, spring_index, index = pa - psys[0]->particles;
1818
1819 data[0] = data[1] = 0;
1820 pfr.data = data;
1821 pfr.h = h;
1822 pfr.pa = pa;
1823 pfr.mass = sphdata->mass;
1824
1825 sph_evaluate_func(nullptr, psys, state->co, &pfr, interaction_radius, sph_density_accum_cb);
1826
1827 density = data[0];
1828 near_density = data[1];
1829
1830 pressure = stiffness * (density - rest_density);
1831 near_pressure = stiffness_near_fac * near_density;
1832
1833 pfn = pfr.neighbors;
1834 for (i = 0; i < pfr.tot_neighbors; i++, pfn++) {
1835 npa = pfn->psys->particles + pfn->index;
1836
1837 madd_v3_v3v3fl(co, npa->prev_state.co, npa->prev_state.vel, state->time);
1838
1839 sub_v3_v3v3(vec, co, state->co);
1840 rij = normalize_v3(vec);
1841
1842 q = (1.0f - rij / h) * pfn->psys->part->mass * inv_mass;
1843
1844 if (pfn->psys->part->flag & PART_SIZEMASS) {
1845 q *= npa->size;
1846 }
1847
1848 copy_v3_v3(vel, npa->prev_state.vel);
1849
1850 /* Double Density Relaxation */
1851 madd_v3_v3fl(force, vec, -(pressure + near_pressure * q) * q);
1852
1853 /* Viscosity */
1854 if (visc > 0.0f || stiff_visc > 0.0f) {
1855 sub_v3_v3v3(dv, vel, state->vel);
1856 u = dot_v3v3(vec, dv);
1857
1858 if (u < 0.0f && visc > 0.0f) {
1859 madd_v3_v3fl(force, vec, 0.5f * q * visc * u);
1860 }
1861
1862 if (u > 0.0f && stiff_visc > 0.0f) {
1863 madd_v3_v3fl(force, vec, 0.5f * q * stiff_visc * u);
1864 }
1865 }
1866
1867 if (spring_constant > 0.0f) {
1868 /* Viscoelastic spring force */
1869 if (pfn->psys == psys[0] && fluid->flag & SPH_VISCOELASTIC_SPRINGS && springhash) {
1870 spring_index = springhash->lookup_default({index, pfn->index}, 0);
1871
1872 if (spring_index) {
1873 spring = psys[0]->fluid_springs + spring_index - 1;
1874
1875 madd_v3_v3fl(force,
1876 vec,
1877 -10.0f * spring_constant * (1.0f - rij / h) * (spring->rest_length - rij));
1878 }
1879 else if (fluid->spring_frames == 0 ||
1880 (pa->prev_state.time - pa->time) <= fluid->spring_frames)
1881 {
1882 ParticleSpring temp_spring;
1883 temp_spring.particle_index[0] = index;
1884 temp_spring.particle_index[1] = pfn->index;
1885 temp_spring.rest_length = (fluid->flag & SPH_CURRENT_REST_LENGTH) ? rij : rest_length;
1886 temp_spring.delete_flag = 0;
1887
1888 sphdata->new_springs.append(temp_spring);
1889 }
1890 }
1891 else { /* PART_SPRING_HOOKES - Hooke's spring force */
1893 force, vec, -10.0f * spring_constant * (1.0f - rij / h) * (rest_length - rij));
1894 }
1895 }
1896 }
1897
1898 /* Artificial buoyancy force in negative gravity direction. */
1899 if (fluid->buoyancy > 0.0f && gravity) {
1900 madd_v3_v3fl(force, gravity, fluid->buoyancy * (density - rest_density));
1901 }
1902
1903 if (sphdata->pass == 0 && psys[0]->part->time_flag & PART_TIME_AUTOSF) {
1904 sph_particle_courant(sphdata, &pfr);
1905 }
1906 sphdata->pass++;
1907}
1908
1909static void sphclassical_density_accum_cb(void *userdata,
1910 int index,
1911 const float co[3],
1912 float /*squared_dist*/)
1913{
1914 SPHRangeData *pfr = (SPHRangeData *)userdata;
1915 ParticleData *npa = pfr->npsys->particles + index;
1916 float q;
1917 float qfac = 21.0f / (256.0f * float(M_PI));
1918 float rij, rij_h;
1919 float vec[3];
1920
1921 /* Exclude particles that are more than 2h away. Can't use squared_dist here
1922 * because it is not accurate enough. Use current state, i.e. the output of
1923 * basic_integrate() - z0r */
1924 sub_v3_v3v3(vec, npa->state.co, co);
1925 rij = len_v3(vec);
1926 rij_h = rij / pfr->h;
1927 if (rij_h > 2.0f) {
1928 return;
1929 }
1930
1931 /* Smoothing factor. Utilize the Wendland kernel. `gnuplot`:
1932 * q1(x) = (2.0 - x)**4 * ( 1.0 + 2.0 * x)
1933 * plot [0:2] q1(x) */
1934 q = qfac / pow3f(pfr->h) * pow4f(2.0f - rij_h) * (1.0f + 2.0f * rij_h);
1935 q *= pfr->npsys->part->mass;
1936
1937 if (pfr->use_size) {
1938 q *= pfr->pa->size;
1939 }
1940
1941 pfr->data[0] += q;
1942 pfr->data[1] += q / npa->sphdensity;
1943}
1944
1945static void sphclassical_neighbor_accum_cb(void *userdata,
1946 int index,
1947 const float co[3],
1948 float /*squared_dist*/)
1949{
1950 SPHRangeData *pfr = (SPHRangeData *)userdata;
1951 ParticleData *npa = pfr->npsys->particles + index;
1952 float rij, rij_h;
1953 float vec[3];
1954
1955 if (pfr->tot_neighbors >= SPH_NEIGHBORS) {
1956 return;
1957 }
1958
1959 /* Exclude particles that are more than 2h away. Can't use squared_dist here
1960 * because it is not accurate enough. Use current state, i.e. the output of
1961 * basic_integrate() - z0r */
1962 sub_v3_v3v3(vec, npa->state.co, co);
1963 rij = len_v3(vec);
1964 rij_h = rij / pfr->h;
1965 if (rij_h > 2.0f) {
1966 return;
1967 }
1968
1969 pfr->neighbors[pfr->tot_neighbors].index = index;
1970 pfr->neighbors[pfr->tot_neighbors].psys = pfr->npsys;
1971 pfr->tot_neighbors++;
1972}
1973static void sphclassical_force_cb(void *sphdata_v,
1975 float *force,
1976 float * /*impulse*/)
1977{
1978 SPHData *sphdata = (SPHData *)sphdata_v;
1979 ParticleSystem **psys = sphdata->psys;
1980 ParticleData *pa = sphdata->pa;
1981 SPHFluidSettings *fluid = psys[0]->part->fluid;
1982 SPHRangeData pfr;
1983 SPHNeighbor *pfn;
1984 const float *gravity = sphdata->gravity;
1985
1986 float dq, u, rij, dv[3];
1987 float pressure, npressure;
1988
1989 float visc = fluid->viscosity_omega;
1990
1991 float interaction_radius;
1992 float h, hinv;
1993 /* 4.77 is an experimentally determined density factor */
1994 float rest_density = fluid->rest_density * (fluid->flag & SPH_FAC_DENSITY ? 4.77f : 1.0f);
1995
1996 /* Use speed of sound squared */
1997 float stiffness = pow2f(fluid->stiffness_k);
1998
1999 ParticleData *npa;
2000 float vec[3];
2001 float co[3];
2002 float pressureTerm;
2003
2004 int i;
2005
2006 float qfac2 = 42.0f / (256.0f * float(M_PI));
2007 float rij_h;
2008
2009 /* 4.0 here is to be consistent with previous formulation/interface */
2010 interaction_radius = fluid->radius * (fluid->flag & SPH_FAC_RADIUS ? 4.0f * pa->size : 1.0f);
2011 h = interaction_radius * sphdata->hfac;
2012 hinv = 1.0f / h;
2013
2014 pfr.h = h;
2015 pfr.pa = pa;
2016
2018 nullptr, psys, state->co, &pfr, interaction_radius, sphclassical_neighbor_accum_cb);
2019 pressure = stiffness * (pow7f(pa->sphdensity / rest_density) - 1.0f);
2020
2021 /* Multiply by mass so that we return a force, not acceleration. */
2022 qfac2 *= sphdata->mass / pow3f(pfr.h);
2023
2024 pfn = pfr.neighbors;
2025 for (i = 0; i < pfr.tot_neighbors; i++, pfn++) {
2026 npa = pfn->psys->particles + pfn->index;
2027 if (npa == pa) {
2028 /* we do not contribute to ourselves */
2029 continue;
2030 }
2031
2032 /* Find vector to neighbor. Exclude particles that are more than 2h
2033 * away. Can't use current state here because it may have changed on
2034 * another thread - so do own mini integration. Unlike basic_integrate,
2035 * SPH integration depends on neighboring particles. - z0r */
2036 madd_v3_v3v3fl(co, npa->prev_state.co, npa->prev_state.vel, state->time);
2037 sub_v3_v3v3(vec, co, state->co);
2038 rij = normalize_v3(vec);
2039 rij_h = rij / pfr.h;
2040 if (rij_h > 2.0f) {
2041 continue;
2042 }
2043
2044 npressure = stiffness * (pow7f(npa->sphdensity / rest_density) - 1.0f);
2045
2046 /* First derivative of smoothing factor. Utilize the Wendland kernel.
2047 * `gnuplot`:
2048 * q2(x) = 2.0 * (2.0 - x)**4 - 4.0 * (2.0 - x)**3 * (1.0 + 2.0 * x)
2049 * plot [0:2] q2(x)
2050 * Particles > 2h away are excluded above. */
2051 dq = qfac2 * (2.0f * pow4f(2.0f - rij_h) - 4.0f * pow3f(2.0f - rij_h) * (1.0f + 2.0f * rij_h));
2052
2053 if (pfn->psys->part->flag & PART_SIZEMASS) {
2054 dq *= npa->size;
2055 }
2056
2057 pressureTerm = pressure / pow2f(pa->sphdensity) + npressure / pow2f(npa->sphdensity);
2058
2059 /* Note that 'minus' is removed, because vec = vecBA, not vecAB.
2060 * This applies to the viscosity calculation below, too. */
2061 madd_v3_v3fl(force, vec, pressureTerm * dq);
2062
2063 /* Viscosity */
2064 if (visc > 0.0f) {
2065 sub_v3_v3v3(dv, npa->prev_state.vel, pa->prev_state.vel);
2066 u = dot_v3v3(vec, dv);
2067 /* Apply parameters */
2068 u *= -dq * hinv * visc / (0.5f * npa->sphdensity + 0.5f * pa->sphdensity);
2069 madd_v3_v3fl(force, vec, u);
2070 }
2071 }
2072
2073 /* Artificial buoyancy force in negative gravity direction. */
2074 if (fluid->buoyancy > 0.0f && gravity) {
2075 madd_v3_v3fl(force, gravity, fluid->buoyancy * (pa->sphdensity - rest_density));
2076 }
2077
2078 if (sphdata->pass == 0 && psys[0]->part->time_flag & PART_TIME_AUTOSF) {
2079 sph_particle_courant(sphdata, &pfr);
2080 }
2081 sphdata->pass++;
2082}
2083
2084static void sphclassical_calc_dens(ParticleData *pa, float /*dfra*/, SPHData *sphdata)
2085{
2086 ParticleSystem **psys = sphdata->psys;
2087 SPHFluidSettings *fluid = psys[0]->part->fluid;
2088 /* 4.0 seems to be a pretty good value */
2089 float interaction_radius = fluid->radius *
2090 (fluid->flag & SPH_FAC_RADIUS ? 4.0f * psys[0]->part->size : 1.0f);
2091 SPHRangeData pfr;
2092 float data[2];
2093
2094 data[0] = 0;
2095 data[1] = 0;
2096 pfr.data = data;
2097 pfr.h = interaction_radius * sphdata->hfac;
2098 pfr.pa = pa;
2099 pfr.mass = sphdata->mass;
2100
2102 nullptr, psys, pa->state.co, &pfr, interaction_radius, sphclassical_density_accum_cb);
2103 pa->sphdensity = min_ff(max_ff(data[0], fluid->rest_density * 0.9f), fluid->rest_density * 1.1f);
2104}
2105
2107 SPHData *sphdata,
2109{
2110 ParticleTarget *pt;
2111 int i;
2112
2113 /* Add other coupled particle systems. */
2114 sphdata->psys[0] = sim->psys;
2115 for (i = 1, pt = static_cast<ParticleTarget *>(sim->psys->targets.first); i < 10;
2116 i++, pt = (pt ? pt->next : nullptr))
2117 {
2118 sphdata->psys[i] = pt ? psys_get_target_system(sim->ob, pt) : nullptr;
2119 }
2120
2121 if (psys_uses_gravity(sim)) {
2122 sphdata->gravity = sim->scene->physics_settings.gravity;
2123 }
2124 else {
2125 sphdata->gravity = nullptr;
2126 }
2127 r_eh = sph_springhash_build(sim->psys);
2128 sphdata->eh = &r_eh;
2129
2130 /* These per-particle values should be overridden later, but just for
2131 * completeness we give them default values now. */
2132 sphdata->pa = nullptr;
2133 sphdata->mass = 1.0f;
2134
2135 if (sim->psys->part->fluid->solver == SPH_SOLVER_DDR) {
2136 sphdata->force_cb = sph_force_cb;
2138 sphdata->hfac = 1.0f;
2139 }
2140 else {
2141 /* SPH_SOLVER_CLASSICAL */
2144 sphdata->hfac = 0.5f;
2145 }
2146}
2147
2148static void psys_sph_flush_springs(SPHData *sphdata)
2149{
2150 for (int i = 0; i < sphdata->new_springs.size(); i++) {
2151 /* sph_spring_add is not thread-safe. - z0r */
2152 sph_spring_add(sphdata->psys[0], &sphdata->new_springs[i]);
2153 }
2154
2155 sphdata->new_springs.clear_and_shrink();
2156}
2157
2159{
2160 psys_sph_flush_springs(sphdata);
2161}
2162
2163void psys_sph_density(BVHTree *tree, SPHData *sphdata, float co[3], float vars[2])
2164{
2165 ParticleSystem **psys = sphdata->psys;
2166 SPHFluidSettings *fluid = psys[0]->part->fluid;
2167 /* 4.0 seems to be a pretty good value */
2168 float interaction_radius = fluid->radius *
2169 (fluid->flag & SPH_FAC_RADIUS ? 4.0f * psys[0]->part->size : 1.0f);
2170 SPHRangeData pfr;
2171 float density[2];
2172
2173 density[0] = density[1] = 0.0f;
2174 pfr.data = density;
2175 pfr.h = interaction_radius * sphdata->hfac;
2176 pfr.mass = sphdata->mass;
2177
2178 sph_evaluate_func(tree, psys, co, &pfr, interaction_radius, sphdata->density_cb);
2179
2180 vars[0] = pfr.data[0];
2181 vars[1] = pfr.data[1];
2182}
2183
2185 ParticleData *pa,
2186 float dfra,
2187 SPHData *sphdata)
2188{
2189 ParticleSettings *part = sim->psys->part;
2190 // float timestep = psys_get_timestep(sim); /* UNUSED */
2191 float pa_mass = part->mass * ((part->flag & PART_SIZEMASS) ? pa->size : 1.0f);
2192 float dtime = dfra * psys_get_timestep(sim);
2193 // int steps = 1; // UNUSED
2194 float effector_acceleration[3];
2195
2196 sphdata->pa = pa;
2197 sphdata->mass = pa_mass;
2198 sphdata->pass = 0;
2199 /* #sphdata.element_size and #sphdata.flow are set in the callback. */
2200
2201 /* Restore previous state and treat gravity & effectors as external acceleration. */
2202 sub_v3_v3v3(effector_acceleration, pa->state.vel, pa->prev_state.vel);
2203 mul_v3_fl(effector_acceleration, 1.0f / dtime);
2204
2205 copy_particle_key(&pa->state, &pa->prev_state, 0);
2206
2207 integrate_particle(part, pa, dtime, effector_acceleration, sphdata->force_cb, sphdata);
2208}
2209
2211
2212/************************************************/
2213/* Basic physics */
2214/************************************************/
2215
2221static void basic_force_cb(void *efdata_v, ParticleKey *state, float *force, float *impulse)
2222{
2223 EfData *efdata = (EfData *)efdata_v;
2224 ParticleSimulationData *sim = efdata->sim;
2225 ParticleSettings *part = sim->psys->part;
2226 ParticleData *pa = efdata->pa;
2227 EffectedPoint epoint;
2228 RNG *rng = sim->rng;
2229
2230 /* add effectors */
2231 pd_point_from_particle(efdata->sim, efdata->pa, state, &epoint);
2232 if (part->type != PART_HAIR || part->effector_weights->flag & EFF_WEIGHT_DO_HAIR) {
2234 sim->colliders,
2235 part->effector_weights,
2236 &epoint,
2237 force,
2238 nullptr,
2239 impulse);
2240 }
2241
2242 mul_v3_fl(force, efdata->ptex.field);
2243 mul_v3_fl(impulse, efdata->ptex.field);
2244
2245 /* calculate air-particle interaction */
2246 if (part->dragfac != 0.0f) {
2247 madd_v3_v3fl(force, state->vel, -part->dragfac * pa->size * pa->size * len_v3(state->vel));
2248 }
2249
2250 /* brownian force */
2251 if (part->brownfac != 0.0f) {
2252 force[0] += (BLI_rng_get_float(rng) - 0.5f) * part->brownfac;
2253 force[1] += (BLI_rng_get_float(rng) - 0.5f) * part->brownfac;
2254 force[2] += (BLI_rng_get_float(rng) - 0.5f) * part->brownfac;
2255 }
2256
2257 if (part->flag & PART_ROT_DYN && epoint.ave) {
2258 copy_v3_v3(pa->state.ave, epoint.ave);
2259 }
2260}
2261/* gathers all forces that effect particles and calculates a new state for the particle */
2262static void basic_integrate(ParticleSimulationData *sim, int p, float dfra, float cfra)
2263{
2264 ParticleSettings *part = sim->psys->part;
2265 ParticleData *pa = sim->psys->particles + p;
2266 ParticleKey tkey;
2267 float dtime = dfra * psys_get_timestep(sim), time;
2268 float *gravity = nullptr, gr[3];
2269 EfData efdata;
2270
2271 psys_get_texture(sim, pa, &efdata.ptex, PAMAP_PHYSICS, cfra);
2272
2273 efdata.pa = pa;
2274 efdata.sim = sim;
2275
2276 /* add global acceleration (gravitation) */
2277 if (psys_uses_gravity(sim) &&
2278 /* normal gravity is too strong for hair so it's disabled by default */
2279 (part->type != PART_HAIR || part->effector_weights->flag & EFF_WEIGHT_DO_HAIR))
2280 {
2281 zero_v3(gr);
2282 madd_v3_v3fl(gr,
2285 gravity = gr;
2286 }
2287
2288 /* maintain angular velocity */
2289 copy_v3_v3(pa->state.ave, pa->prev_state.ave);
2290
2291 integrate_particle(part, pa, dtime, gravity, basic_force_cb, &efdata);
2292
2293 /* damp affects final velocity */
2294 if (part->dampfac != 0.0f) {
2295 mul_v3_fl(pa->state.vel, 1.0f - part->dampfac * efdata.ptex.damp * 25.0f * dtime);
2296 }
2297
2298 // copy_v3_v3(pa->state.ave, states->ave);
2299
2300 /* finally we do guides */
2301 time = (cfra - pa->time) / pa->lifetime;
2302 CLAMP(time, 0.0f, 1.0f);
2303
2304 copy_v3_v3(tkey.co, pa->state.co);
2305 copy_v3_v3(tkey.vel, pa->state.vel);
2306 tkey.time = pa->state.time;
2307
2308 if (part->type != PART_HAIR) {
2309 if (do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, &tkey, p, time)) {
2310 copy_v3_v3(pa->state.co, tkey.co);
2311 /* guides don't produce valid velocity */
2312 sub_v3_v3v3(pa->state.vel, tkey.co, pa->prev_state.co);
2313 mul_v3_fl(pa->state.vel, 1.0f / dtime);
2314 pa->state.time = tkey.time;
2315 }
2316 }
2317}
2318static void basic_rotate(ParticleSettings *part, ParticleData *pa, float dfra, float timestep)
2319{
2320 float rotfac, rot1[4], rot2[4] = {1.0, 0.0, 0.0, 0.0}, dtime = dfra * timestep, extrotfac;
2321
2322 if ((part->flag & PART_ROTATIONS) == 0) {
2323 unit_qt(pa->state.rot);
2324 return;
2325 }
2326
2327 if (part->flag & PART_ROT_DYN) {
2328 extrotfac = len_v3(pa->state.ave);
2329 }
2330 else {
2331 extrotfac = 0.0f;
2332 }
2333
2334 if ((part->flag & PART_ROT_DYN) &&
2336 {
2337 float angle;
2338 float len1 = len_v3(pa->prev_state.vel);
2339 float len2 = len_v3(pa->state.vel);
2340 float vec[3];
2341
2342 if (len1 == 0.0f || len2 == 0.0f) {
2343 zero_v3(pa->state.ave);
2344 }
2345 else {
2346 cross_v3_v3v3(pa->state.ave, pa->prev_state.vel, pa->state.vel);
2347 normalize_v3(pa->state.ave);
2348 angle = dot_v3v3(pa->prev_state.vel, pa->state.vel) / (len1 * len2);
2349 mul_v3_fl(pa->state.ave, safe_acosf(angle) / dtime);
2350 }
2351
2352 get_angular_velocity_vector(part->avemode, &pa->state, vec);
2353 axis_angle_to_quat(rot2, vec, dtime * part->avefac);
2354 }
2355
2356 rotfac = len_v3(pa->state.ave);
2357 if (rotfac == 0.0f || (part->flag & PART_ROT_DYN) == 0 || extrotfac == 0.0f) {
2358 unit_qt(rot1);
2359 }
2360 else {
2361 axis_angle_to_quat(rot1, pa->state.ave, rotfac * dtime);
2362 }
2363 mul_qt_qtqt(pa->state.rot, rot1, pa->prev_state.rot);
2364 mul_qt_qtqt(pa->state.rot, rot2, pa->state.rot);
2365
2366 /* keep rotation quat in good health */
2367 normalize_qt(pa->state.rot);
2368}
2369
2370/************************************************
2371 * Collisions
2372 *
2373 * The algorithm is roughly:
2374 * 1. Use a BVH tree to search for faces that a particle may collide with.
2375 * 2. Use Newton's method to find the exact time at which the collision occurs.
2376 * https://en.wikipedia.org/wiki/Newton's_method
2377 *
2378 ************************************************/
2379#define COLLISION_MIN_RADIUS 0.001f
2380#define COLLISION_MIN_DISTANCE 0.0001f
2381#define COLLISION_ZERO 0.00001f
2382#define COLLISION_INIT_STEP 0.00008f
2383using NRDistanceFunc = float (*)(float *p,
2384 float radius,
2386 float *nor);
2387static float nr_signed_distance_to_plane(float *p,
2388 float radius,
2390 float *nor)
2391{
2392 float p0[3], e1[3], e2[3], d;
2393
2394 sub_v3_v3v3(e1, pce->x1, pce->x0);
2395 sub_v3_v3v3(e2, pce->x2, pce->x0);
2396 sub_v3_v3v3(p0, p, pce->x0);
2397
2398 cross_v3_v3v3(nor, e1, e2);
2400
2401 d = dot_v3v3(p0, nor);
2402
2403 if (pce->inv_nor == -1) {
2404 if (d < 0.0f) {
2405 pce->inv_nor = 1;
2406 }
2407 else {
2408 pce->inv_nor = 0;
2409 }
2410 }
2411
2412 if (pce->inv_nor == 1) {
2413 negate_v3(nor);
2414 d = -d;
2415 }
2416
2417 return d - radius;
2418}
2419static float nr_distance_to_edge(float *p,
2420 float radius,
2422 float * /*nor*/)
2423{
2424 float v0[3], v1[3], v2[3], c[3];
2425
2426 sub_v3_v3v3(v0, pce->x1, pce->x0);
2427 sub_v3_v3v3(v1, p, pce->x0);
2428 sub_v3_v3v3(v2, p, pce->x1);
2429
2430 cross_v3_v3v3(c, v1, v2);
2431
2432 return fabsf(len_v3(c) / len_v3(v0)) - radius;
2433}
2434static float nr_distance_to_vert(float *p,
2435 float radius,
2437 float * /*nor*/)
2438{
2439 return len_v3v3(p, pce->x0) - radius;
2440}
2441
2448 float t,
2449 float fac,
2451{
2452 float f = fac + t * (1.0f - fac);
2453 float mul = col->fac1 + f * (col->fac2 - col->fac1);
2454 if (pce->tot > 0) {
2455 madd_v3_v3v3fl(pce->x0, pce->x[0], pce->v[0], mul);
2456
2457 if (pce->tot > 1) {
2458 madd_v3_v3v3fl(pce->x1, pce->x[1], pce->v[1], mul);
2459
2460 if (pce->tot > 2) {
2461 madd_v3_v3v3fl(pce->x2, pce->x[2], pce->v[2], mul);
2462 }
2463 }
2464 }
2465}
2467{
2468 float v[3];
2469
2470 copy_v3_v3(pce->vel, pce->v[0]);
2471
2472 if (pce->tot > 1) {
2473 sub_v3_v3v3(v, pce->v[1], pce->v[0]);
2474 madd_v3_v3fl(pce->vel, v, pce->uv[0]);
2475
2476 if (pce->tot > 2) {
2477 sub_v3_v3v3(v, pce->v[2], pce->v[0]);
2478 madd_v3_v3fl(pce->vel, v, pce->uv[1]);
2479 }
2480 }
2481}
2483 float p[3], ParticleCollisionElement *pce, float fac, ParticleCollision *col, float *nor)
2484{
2485 if (fac >= 0.0f) {
2486 collision_interpolate_element(pce, 0.0f, fac, col);
2487 }
2488
2489 switch (pce->tot) {
2490 case 1: {
2491 sub_v3_v3v3(nor, p, pce->x0);
2492 return normalize_v3(nor);
2493 }
2494 case 2: {
2495 float u, e[3], vec[3];
2496 sub_v3_v3v3(e, pce->x1, pce->x0);
2497 sub_v3_v3v3(vec, p, pce->x0);
2498 u = dot_v3v3(vec, e) / dot_v3v3(e, e);
2499
2500 madd_v3_v3v3fl(nor, vec, e, -u);
2501 return normalize_v3(nor);
2502 }
2503 case 3:
2504 return nr_signed_distance_to_plane(p, 0.0f, pce, nor);
2505 }
2506 return 0;
2507}
2509 const float p[3], ParticleCollisionElement *pce, float fac, ParticleCollision *col, float *co)
2510{
2511 collision_interpolate_element(pce, 0.0f, fac, col);
2512
2513 switch (pce->tot) {
2514 case 1: {
2515 sub_v3_v3v3(co, p, pce->x0);
2516 normalize_v3(co);
2517 madd_v3_v3v3fl(co, pce->x0, co, col->radius);
2518 break;
2519 }
2520 case 2: {
2521 float u, e[3], vec[3], nor[3];
2522 sub_v3_v3v3(e, pce->x1, pce->x0);
2523 sub_v3_v3v3(vec, p, pce->x0);
2524 u = dot_v3v3(vec, e) / dot_v3v3(e, e);
2525
2526 madd_v3_v3v3fl(nor, vec, e, -u);
2528
2529 madd_v3_v3v3fl(co, pce->x0, e, pce->uv[0]);
2530 madd_v3_v3fl(co, nor, col->radius);
2531 break;
2532 }
2533 case 3: {
2534 float p0[3], e1[3], e2[3], nor[3];
2535
2536 sub_v3_v3v3(e1, pce->x1, pce->x0);
2537 sub_v3_v3v3(e2, pce->x2, pce->x0);
2538 sub_v3_v3v3(p0, p, pce->x0);
2539
2540 cross_v3_v3v3(nor, e1, e2);
2542
2543 if (pce->inv_nor == 1) {
2544 negate_v3(nor);
2545 }
2546
2547 madd_v3_v3v3fl(co, pce->x0, nor, col->radius);
2548 madd_v3_v3fl(co, e1, pce->uv[0]);
2549 madd_v3_v3fl(co, e2, pce->uv[1]);
2550 break;
2551 }
2552 }
2553}
2554/* find first root in range [0-1] starting from 0 */
2556 float radius,
2558 NRDistanceFunc distance_func)
2559{
2560 float t0, t1, dt_init, d0, d1, dd, n[3];
2561 int iter;
2562
2563 pce->inv_nor = -1;
2564
2565 if (col->inv_total_time > 0.0f) {
2566 /* Initial step size should be small, but not too small or floating point
2567 * precision errors will appear. - z0r */
2568 dt_init = COLLISION_INIT_STEP * col->inv_total_time;
2569 }
2570 else {
2571 dt_init = 0.001f;
2572 }
2573
2574 /* start from the beginning */
2575 t0 = 0.0f;
2577 d0 = distance_func(col->co1, radius, pce, n);
2578 t1 = dt_init;
2579 d1 = 0.0f;
2580
2581 for (iter = 0; iter < 10; iter++) { //, itersum++) {
2582 /* get current location */
2584 interp_v3_v3v3(pce->p, col->co1, col->co2, t1);
2585
2586 d1 = distance_func(pce->p, radius, pce, n);
2587
2588 /* particle already inside face, so report collision */
2589 if (iter == 0 && d0 < 0.0f && d0 > -radius) {
2590 copy_v3_v3(pce->p, col->co1);
2591 copy_v3_v3(pce->nor, n);
2592 pce->inside = 1;
2593 return 0.0f;
2594 }
2595
2596 /* Zero gradient (no movement relative to element). Can't step from
2597 * here. */
2598 if (d1 == d0) {
2599 /* If first iteration, try from other end where the gradient may be
2600 * greater. NOTE: code duplicated below. */
2601 if (iter == 0) {
2602 t0 = 1.0f;
2604 d0 = distance_func(col->co2, radius, pce, n);
2605 t1 = 1.0f - dt_init;
2606 d1 = 0.0f;
2607 continue;
2608 }
2609
2610 return -1.0f;
2611 }
2612
2613 dd = (t1 - t0) / (d1 - d0);
2614
2615 t0 = t1;
2616 d0 = d1;
2617
2618 t1 -= d1 * dd;
2619
2620 /* Particle moving away from plane could also mean a strangely rotating
2621 * face, so check from end. NOTE: code duplicated above. */
2622 if (iter == 0 && t1 < 0.0f) {
2623 t0 = 1.0f;
2625 d0 = distance_func(col->co2, radius, pce, n);
2626 t1 = 1.0f - dt_init;
2627 d1 = 0.0f;
2628 continue;
2629 }
2630 if (iter == 1 && (t1 < -COLLISION_ZERO || t1 > 1.0f)) {
2631 return -1.0f;
2632 }
2633
2634 if (d1 <= COLLISION_ZERO && d1 >= -COLLISION_ZERO) {
2635 if (t1 >= -COLLISION_ZERO && t1 <= 1.0f) {
2636 if (distance_func == nr_signed_distance_to_plane) {
2637 copy_v3_v3(pce->nor, n);
2638 }
2639
2640 CLAMP(t1, 0.0f, 1.0f);
2641
2642 return t1;
2643 }
2644
2645 return -1.0f;
2646 }
2647 }
2648 return -1.0;
2649}
2651 float radius,
2653 float *t)
2654{
2656 float ct, u, v;
2657
2658 pce->inv_nor = -1;
2659 pce->inside = 0;
2660
2662
2663 if (ct >= 0.0f && ct < *t && (result->inside == 0 || pce->inside == 1)) {
2664 float e1[3], e2[3], p0[3];
2665 float e1e1, e1e2, e1p0, e2e2, e2p0, inv;
2666
2667 sub_v3_v3v3(e1, pce->x1, pce->x0);
2668 sub_v3_v3v3(e2, pce->x2, pce->x0);
2669 /* XXX: add radius correction here? */
2670 sub_v3_v3v3(p0, pce->p, pce->x0);
2671
2672 e1e1 = dot_v3v3(e1, e1);
2673 e1e2 = dot_v3v3(e1, e2);
2674 e1p0 = dot_v3v3(e1, p0);
2675 e2e2 = dot_v3v3(e2, e2);
2676 e2p0 = dot_v3v3(e2, p0);
2677
2678 inv = 1.0f / (e1e1 * e2e2 - e1e2 * e1e2);
2679 u = (e2e2 * e1p0 - e1e2 * e2p0) * inv;
2680 v = (e1e1 * e2p0 - e1e2 * e1p0) * inv;
2681
2682 if (u >= 0.0f && u <= 1.0f && v >= 0.0f && u + v <= 1.0f) {
2683 *result = *pce;
2684
2685 /* normal already calculated in pce */
2686
2687 result->uv[0] = u;
2688 result->uv[1] = v;
2689
2690 *t = ct;
2691 return 1;
2692 }
2693 }
2694 return 0;
2695}
2697 float radius,
2699 float *t)
2700{
2701 ParticleCollisionElement edge[3], *cur = nullptr, *hit = nullptr;
2703
2704 float ct;
2705 int i;
2706
2707 for (i = 0; i < 3; i++) {
2708 cur = edge + i;
2709 cur->x[0] = pce->x[i];
2710 cur->x[1] = pce->x[(i + 1) % 3];
2711 cur->v[0] = pce->v[i];
2712 cur->v[1] = pce->v[(i + 1) % 3];
2713 cur->tot = 2;
2714 cur->inside = 0;
2715
2717
2718 if (ct >= 0.0f && ct < *t) {
2719 float u, e[3], vec[3];
2720
2721 sub_v3_v3v3(e, cur->x1, cur->x0);
2722 sub_v3_v3v3(vec, cur->p, cur->x0);
2723 u = dot_v3v3(vec, e) / dot_v3v3(e, e);
2724
2725 if (u < 0.0f || u > 1.0f) {
2726 break;
2727 }
2728
2729 *result = *cur;
2730
2731 madd_v3_v3v3fl(result->nor, vec, e, -u);
2732 normalize_v3(result->nor);
2733
2734 result->uv[0] = u;
2735
2736 hit = cur;
2737 *t = ct;
2738 }
2739 }
2740
2741 return hit != nullptr;
2742}
2744 float radius,
2746 float *t)
2747{
2748 ParticleCollisionElement vert[3], *cur = nullptr, *hit = nullptr;
2750
2751 float ct;
2752 int i;
2753
2754 for (i = 0; i < 3; i++) {
2755 cur = vert + i;
2756 cur->x[0] = pce->x[i];
2757 cur->v[0] = pce->v[i];
2758 cur->tot = 1;
2759 cur->inside = 0;
2760
2762
2763 if (ct >= 0.0f && ct < *t) {
2764 *result = *cur;
2765
2766 sub_v3_v3v3(result->nor, cur->p, cur->x0);
2767 normalize_v3(result->nor);
2768
2769 hit = cur;
2770 *t = ct;
2771 }
2772 }
2773
2774 return hit != nullptr;
2775}
2777 int index,
2778 const BVHTreeRay *ray,
2779 BVHTreeRayHit *hit)
2780{
2783 const blender::int3 vert_tri = &col->md->vert_tris[index];
2784 float (*x)[3] = col->md->x;
2785 float (*v)[3] = col->md->current_v;
2786 float t = hit->dist / col->original_ray_length;
2787 int collision = 0;
2788
2789 pce.x[0] = x[vert_tri[0]];
2790 pce.x[1] = x[vert_tri[1]];
2791 pce.x[2] = x[vert_tri[2]];
2792
2793 pce.v[0] = v[vert_tri[0]];
2794 pce.v[1] = v[vert_tri[1]];
2795 pce.v[2] = v[vert_tri[2]];
2796
2797 pce.tot = 3;
2798 pce.inside = 0;
2799 pce.index = index;
2800
2801 collision = collision_sphere_to_tri(col, ray->radius, &pce, &t);
2802 if (col->pce.inside == 0) {
2803 collision += collision_sphere_to_edges(col, ray->radius, &pce, &t);
2804 collision += collision_sphere_to_verts(col, ray->radius, &pce, &t);
2805 }
2806
2807 if (collision) {
2808 hit->dist = col->original_ray_length * t;
2809 hit->index = index;
2810
2812
2813 col->hit = col->current;
2814 }
2815}
2818 BVHTreeRayHit *hit,
2819 ListBase *colliders)
2820{
2821 const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT;
2822 float ray_dir[3];
2823
2824 if (BLI_listbase_is_empty(colliders)) {
2825 return 0;
2826 }
2827
2828 sub_v3_v3v3(ray_dir, col->co2, col->co1);
2829 hit->index = -1;
2830 hit->dist = col->original_ray_length = normalize_v3(ray_dir);
2831 col->pce.inside = 0;
2832
2833 /* even if particle is stationary we want to check for moving colliders */
2834 /* if hit.dist is zero the bvhtree_ray_cast will just ignore everything */
2835 if (hit->dist == 0.0f) {
2836 hit->dist = col->original_ray_length = 0.000001f;
2837 }
2838
2839 LISTBASE_FOREACH (ColliderCache *, coll, colliders) {
2840 /* for boids: don't check with current ground object; also skip if permeated */
2841 bool skip = false;
2842
2843 for (int i = 0; i < col->skip_count; i++) {
2844 if (coll->ob == col->skip[i]) {
2845 skip = true;
2846 break;
2847 }
2848 }
2849
2850 if (skip) {
2851 continue;
2852 }
2853
2854 /* particles should not collide with emitter at birth */
2855 if (coll->ob == col->emitter && pa->time < col->cfra && pa->time >= col->old_cfra) {
2856 continue;
2857 }
2858
2859 col->current = coll->ob;
2860 col->md = coll->collmd;
2861 col->fac1 = (col->old_cfra - coll->collmd->time_x) /
2862 (coll->collmd->time_xnew - coll->collmd->time_x);
2863 col->fac2 = (col->cfra - coll->collmd->time_x) /
2864 (coll->collmd->time_xnew - coll->collmd->time_x);
2865
2866 if (col->md && col->md->bvhtree) {
2867 BLI_bvhtree_ray_cast_ex(col->md->bvhtree,
2868 col->co1,
2869 ray_dir,
2870 col->radius,
2871 hit,
2873 col,
2874 raycast_flag);
2875 }
2876 }
2877
2878 return hit->index >= 0;
2879}
2881 ParticleData *pa,
2883 BVHTreeRayHit *hit,
2884 int kill,
2885 int dynamic_rotation)
2886{
2887 ParticleCollisionElement *pce = &col->pce;
2888 PartDeflect *pd = col->hit->pd;
2889 RNG *rng = sim->rng;
2890 /* point of collision */
2891 float co[3];
2892 /* location factor of collision between this iteration */
2893 float x = hit->dist / col->original_ray_length;
2894 /* time factor of collision between timestep */
2895 float f = col->f + x * (1.0f - col->f);
2896 /* time since previous collision (in seconds) */
2897 float dt1 = (f - col->f) * col->total_time;
2898 /* time left after collision (in seconds) */
2899 float dt2 = (1.0f - f) * col->total_time;
2900 /* did particle pass through the collision surface? */
2901 int through = (BLI_rng_get_float(rng) < pd->pdef_perm) ? 1 : 0;
2902
2903 /* calculate exact collision location */
2904 interp_v3_v3v3(co, col->co1, col->co2, x);
2905
2906 /* particle dies in collision */
2907 if (through == 0 && (kill || pd->flag & PDEFLE_KILL_PART)) {
2908 pa->alive = PARS_DYING;
2909 pa->dietime = col->old_cfra + (col->cfra - col->old_cfra) * f;
2910
2911 copy_v3_v3(pa->state.co, co);
2912 interp_v3_v3v3(pa->state.vel, pa->prev_state.vel, pa->state.vel, f);
2913 interp_qt_qtqt(pa->state.rot, pa->prev_state.rot, pa->state.rot, f);
2914 interp_v3_v3v3(pa->state.ave, pa->prev_state.ave, pa->state.ave, f);
2915
2916 /* particle is dead so we don't need to calculate further */
2917 return 0;
2918 }
2919 /* figure out velocity and other data after collision */
2920
2921 /* velocity directly before collision to be modified into velocity directly after collision */
2922 float v0[3];
2923 /* normal component of v0 */
2924 float v0_nor[3];
2925 /* tangential component of v0 */
2926 float v0_tan[3];
2927 /* tangential component of collision surface velocity */
2928 float vc_tan[3];
2929 float v0_dot, vc_dot;
2930 float damp = pd->pdef_damp + pd->pdef_rdamp * 2 * (BLI_rng_get_float(rng) - 0.5f);
2931 float frict = pd->pdef_frict + pd->pdef_rfrict * 2 * (BLI_rng_get_float(rng) - 0.5f);
2932 float distance, nor[3], dot;
2933
2934 CLAMP(damp, 0.0f, 1.0f);
2935 CLAMP(frict, 0.0f, 1.0f);
2936
2937 /* get exact velocity right before collision */
2938 madd_v3_v3v3fl(v0, col->ve1, col->acc, dt1);
2939
2940 /* Convert collider velocity from `1/frame_step` to `1/s` TODO:
2941 * here we assume 1 frame step for collision modifier. */
2942 mul_v3_fl(pce->vel, col->inv_timestep);
2943
2944 /* calculate tangential particle velocity */
2945 v0_dot = dot_v3v3(pce->nor, v0);
2946 madd_v3_v3v3fl(v0_tan, v0, pce->nor, -v0_dot);
2947
2948 /* calculate tangential collider velocity */
2949 vc_dot = dot_v3v3(pce->nor, pce->vel);
2950 madd_v3_v3v3fl(vc_tan, pce->vel, pce->nor, -vc_dot);
2951
2952 /* handle friction effects (tangential and angular velocity) */
2953 if (frict > 0.0f) {
2954 /* angular <-> linear velocity */
2955 if (dynamic_rotation) {
2956 float vr_tan[3], v1_tan[3], ave[3];
2957
2958 /* linear velocity of particle surface */
2959 cross_v3_v3v3(vr_tan, pce->nor, pa->state.ave);
2960 mul_v3_fl(vr_tan, pa->size);
2961
2962 /* change to coordinates that move with the collision plane */
2963 sub_v3_v3v3(v1_tan, v0_tan, vc_tan);
2964
2965 /* The resulting velocity is a weighted average of particle cm & surface
2966 * velocity. This weight (related to particle's moment of inertia) could
2967 * be made a parameter for angular <-> linear conversion.
2968 */
2969 madd_v3_v3fl(v1_tan, vr_tan, -0.4);
2970 mul_v3_fl(v1_tan, 1.0f / 1.4f); /* 1/(1+0.4) */
2971
2972 /* rolling friction is around 0.01 of sliding friction
2973 * (could be made a parameter) */
2974 mul_v3_fl(v1_tan, 1.0f - 0.01f * frict);
2975
2976 /* surface_velocity is opposite to cm velocity */
2977 negate_v3_v3(vr_tan, v1_tan);
2978
2979 /* get back to global coordinates */
2980 add_v3_v3(v1_tan, vc_tan);
2981
2982 /* Convert to angular velocity. */
2983 cross_v3_v3v3(ave, vr_tan, pce->nor);
2984 mul_v3_fl(ave, 1.0f / std::max(pa->size, 0.001f));
2985
2986 /* only friction will cause change in linear & angular velocity */
2987 interp_v3_v3v3(pa->state.ave, pa->state.ave, ave, frict);
2988 interp_v3_v3v3(v0_tan, v0_tan, v1_tan, frict);
2989 }
2990 else {
2991 /* Just basic friction (nonphysical due to the friction model used in Blender). */
2992 interp_v3_v3v3(v0_tan, v0_tan, vc_tan, frict);
2993 }
2994 }
2995
2996 /* Stickiness was possibly added before,
2997 * so cancel that before calculating new normal velocity.
2998 * Otherwise particles go flying out of the surface
2999 * because of high reversed sticky velocity. */
3000 if (v0_dot < 0.0f) {
3001 v0_dot += pd->pdef_stickness;
3002 v0_dot = std::min(v0_dot, 0.0f);
3003 }
3004
3005 /* damping and flipping of velocity around normal */
3006 v0_dot *= 1.0f - damp;
3007 vc_dot *= through ? damp : 1.0f;
3008
3009 /* calculate normal particle velocity */
3010 /* special case for object hitting the particle from behind */
3011 if (through == 0 && ((vc_dot > 0.0f && v0_dot > 0.0f && vc_dot > v0_dot) ||
3012 (vc_dot < 0.0f && v0_dot < 0.0f && vc_dot < v0_dot)))
3013 {
3014 mul_v3_v3fl(v0_nor, pce->nor, vc_dot);
3015 }
3016 else if (v0_dot > 0.0f) {
3017 mul_v3_v3fl(v0_nor, pce->nor, vc_dot + v0_dot);
3018 }
3019 else {
3020 mul_v3_v3fl(v0_nor, pce->nor, vc_dot + (through ? 1.0f : -1.0f) * v0_dot);
3021 }
3022
3023 /* combine components together again */
3024 add_v3_v3v3(v0, v0_nor, v0_tan);
3025
3026 if (col->boid) {
3027 /* keep boids above ground */
3028 BoidParticle *bpa = pa->boid;
3029 if (bpa->data.mode == eBoidMode_OnLand || co[2] <= col->boid_z) {
3030 co[2] = col->boid_z;
3031 v0[2] = 0.0f;
3032 }
3033 }
3034
3035 /* re-apply acceleration to final location and velocity */
3036 madd_v3_v3v3fl(pa->state.co, co, v0, dt2);
3037 madd_v3_v3fl(pa->state.co, col->acc, 0.5f * dt2 * dt2);
3038 madd_v3_v3v3fl(pa->state.vel, v0, col->acc, dt2);
3039
3040 /* make sure particle stays on the right side of the surface */
3041 if (!through) {
3043
3046 }
3047
3048 dot = dot_v3v3(nor, v0);
3049 if (dot < 0.0f) {
3050 madd_v3_v3fl(v0, nor, -dot);
3051 }
3052
3054
3057 }
3058
3059 dot = dot_v3v3(nor, pa->state.vel);
3060 if (dot < 0.0f) {
3061 madd_v3_v3fl(pa->state.vel, nor, -dot);
3062 }
3063 }
3064
3065 /* add stickiness to surface */
3066 madd_v3_v3fl(pa->state.vel, pce->nor, -pd->pdef_stickness);
3067
3068 /* set coordinates for next iteration */
3069 copy_v3_v3(col->co1, co);
3070 copy_v3_v3(col->co2, pa->state.co);
3071
3072 copy_v3_v3(col->ve1, v0);
3073 copy_v3_v3(col->ve2, pa->state.vel);
3074
3075 col->f = f;
3076
3077 /* if permeability random roll succeeded, disable collider for this sim step */
3078 if (through) {
3079 col->skip[col->skip_count++] = col->hit;
3080 }
3081
3082 return 1;
3083}
3085{
3086 /* final chance to prevent total failure, so stick to the surface and hope for the best */
3087 collision_point_on_surface(col->co1, &col->pce, 1.0f, col, pa->state.co);
3088
3089 copy_v3_v3(pa->state.vel, col->pce.vel);
3090 mul_v3_fl(pa->state.vel, col->inv_timestep);
3091
3092 // printf("max iterations\n");
3093}
3094
3095/* Particle - Mesh collision detection and response
3096 * Features:
3097 * -friction and damping
3098 * -angular momentum <-> linear momentum
3099 * -high accuracy by re-applying particle acceleration after collision
3100 * -handles moving, rotating and deforming meshes
3101 * -uses Newton-Rhapson iteration to find the collisions
3102 * -handles spherical particles and (nearly) point like particles
3103 */
3104static void collision_check(ParticleSimulationData *sim, int p, float dfra, float cfra)
3105{
3106 ParticleSettings *part = sim->psys->part;
3107 ParticleData *pa = sim->psys->particles + p;
3109 BVHTreeRayHit hit;
3110 int collision_count = 0;
3111
3112 float timestep = psys_get_timestep(sim);
3113
3114 memset(&col, 0, sizeof(ParticleCollision));
3115
3116 col.total_time = timestep * dfra;
3117 col.inv_total_time = 1.0f / col.total_time;
3118 col.inv_timestep = 1.0f / timestep;
3119
3120 col.cfra = cfra;
3121 col.old_cfra = sim->psys->cfra;
3122
3123 /* Get acceleration (from gravity, force-fields etc. to be re-applied in collision response). */
3124 sub_v3_v3v3(col.acc, pa->state.vel, pa->prev_state.vel);
3125 mul_v3_fl(col.acc, 1.0f / col.total_time);
3126
3127 /* set values for first iteration */
3128 copy_v3_v3(col.co1, pa->prev_state.co);
3129 copy_v3_v3(col.co2, pa->state.co);
3130 copy_v3_v3(col.ve1, pa->prev_state.vel);
3131 copy_v3_v3(col.ve2, pa->state.vel);
3132 col.f = 0.0f;
3133
3134 col.radius = ((part->flag & PART_SIZE_DEFL) || (part->phystype == PART_PHYS_BOIDS)) ?
3135 pa->size :
3137
3138 /* override for boids */
3139 if (part->phystype == PART_PHYS_BOIDS && part->boids->options & BOID_ALLOW_LAND) {
3140 col.boid = 1;
3141 col.boid_z = pa->state.co[2];
3142 col.skip[col.skip_count++] = pa->boid->ground;
3143 }
3144
3145 /* 10 iterations to catch multiple collisions */
3146 while (collision_count < PARTICLE_COLLISION_MAX_COLLISIONS) {
3147 if (collision_detect(pa, &col, &hit, sim->colliders)) {
3148
3149 collision_count++;
3150
3151 if (collision_count == PARTICLE_COLLISION_MAX_COLLISIONS) {
3152 collision_fail(pa, &col);
3153 }
3154 else if (collision_response(
3155 sim, pa, &col, &hit, part->flag & PART_DIE_ON_COL, part->flag & PART_ROT_DYN) ==
3156 0)
3157 {
3158 return;
3159 }
3160 }
3161 else {
3162 return;
3163 }
3164 }
3165}
3166
3167/************************************************/
3168/* Hair */
3169/************************************************/
3170
3175 float cfra,
3176 const bool use_render_params)
3177{
3178 ParticleSystem *psys = sim->psys;
3179 ParticleSettings *part = psys->part;
3181 int distr = 0, alloc = 0, skip = 0;
3182
3183 if ((psys->part->childtype &&
3184 psys->totchild != psys_get_tot_child(sim->scene, psys, use_render_params)) ||
3186 {
3187 alloc = 1;
3188 }
3189
3190 if (alloc || psys->recalc & ID_RECALC_PSYS_CHILD ||
3191 (psys->vgroup[PSYS_VG_DENSITY] && (sim->ob && sim->ob->mode & OB_MODE_WEIGHT_PAINT)))
3192 {
3193 distr = 1;
3194 }
3195
3196 if (distr) {
3197 if (alloc) {
3198 realloc_particles(sim, sim->psys->totpart);
3199 }
3200
3201 if (psys_get_tot_child(sim->scene, psys, use_render_params)) {
3202 /* don't generate children while computing the hair keys */
3203 if (!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) {
3205
3206 if (part->childtype == PART_CHILD_FACES && part->parents != 0.0f) {
3207 psys_find_parents(sim, use_render_params);
3208 }
3209 }
3210 }
3211 else {
3212 psys_free_children(psys);
3213 }
3214 }
3215
3216 if ((part->type == PART_HAIR || psys->flag & PSYS_KEYED ||
3217 psys->pointcache->flag & PTCACHE_BAKED) == 0)
3218 {
3219 skip = 1; /* only hair, keyed and baked stuff can have paths */
3220 }
3221 else if (part->ren_as != PART_DRAW_PATH &&
3222 !(part->type == PART_HAIR && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)))
3223 {
3224 skip = 1; /* particle visualization must be set as path */
3225 }
3226 else if (DEG_get_mode(sim->depsgraph) != DAG_EVAL_RENDER) {
3227 if (part->draw_as != PART_DRAW_REND) {
3228 skip = 1; /* draw visualization */
3229 }
3230 else if (psys->pointcache->flag & PTCACHE_BAKING) {
3231 skip = 1; /* no need to cache paths while baking dynamics */
3232 }
3233 else if (psys_in_edit_mode(sim->depsgraph, psys)) {
3234 if ((pset->flag & PE_DRAW_PART) == 0) {
3235 skip = 1;
3236 }
3237 else if (part->childtype == 0 &&
3238 (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) == 0)
3239 {
3240 skip = 1; /* in edit mode paths are needed for child particles and dynamic hair */
3241 }
3242 }
3243 }
3244
3245 if (!skip) {
3246 psys_cache_paths(sim, cfra, use_render_params);
3247
3248 /* for render, child particle paths are computed on the fly */
3249 if (part->childtype) {
3250 if (!psys->totchild) {
3251 skip = 1;
3252 }
3253 else if (psys->part->type == PART_HAIR && (psys->flag & PSYS_HAIR_DONE) == 0) {
3254 skip = 1;
3255 }
3256
3257 if (!skip) {
3258 psys_cache_child_paths(sim, cfra, false, use_render_params);
3259 }
3260 }
3261 }
3262 else if (psys->pathcache) {
3263 psys_free_path_cache(psys, nullptr);
3264 }
3265}
3266
3267static bool psys_hair_use_simulation(ParticleData *pa, float max_length)
3268{
3269 /* Minimum segment length relative to average length.
3270 * Hairs with segments below this length will be excluded from the simulation,
3271 * because otherwise the solver will become unstable.
3272 * The hair system should always make sure the hair segments have reasonable length ratios,
3273 * but this can happen in old files when e.g. cutting hair.
3274 */
3275 const float min_length = 0.1f * max_length;
3276
3277 HairKey *key;
3278 int k;
3279
3280 if (pa->totkey < 2) {
3281 return false;
3282 }
3283
3284 for (k = 1, key = pa->hair + 1; k < pa->totkey; k++, key++) {
3285 float length = len_v3v3(key->co, (key - 1)->co);
3286 if (length < min_length) {
3287 return false;
3288 }
3289 }
3290
3291 return true;
3292}
3293
3294static MDeformVert *hair_set_pinning(MDeformVert *dvert, float weight)
3295{
3296 if (dvert) {
3297 if (!dvert->totweight) {
3298 dvert->dw = MEM_callocN<MDeformWeight>("deformWeight");
3299 dvert->totweight = 1;
3300 }
3301
3302 dvert->dw->weight = weight;
3303 dvert++;
3304 }
3305 return dvert;
3306}
3307
3309 int totpoint,
3310 int totedge,
3311 Mesh **r_mesh)
3312{
3313 ParticleSystem *psys = sim->psys;
3314 ParticleSettings *part = psys->part;
3315 Mesh *mesh;
3316 MDeformVert *dvert;
3317 HairKey *key;
3318 PARTICLE_P;
3319 int k, hair_index;
3320 float hairmat[4][4];
3321 float max_length;
3322 float hair_radius;
3323
3324 mesh = *r_mesh;
3325 if (!mesh) {
3326 *r_mesh = mesh = BKE_mesh_new_nomain(totpoint, totedge, 0, 0);
3327 }
3328 blender::MutableSpan<blender::float3> positions = mesh->vert_positions_for_write();
3329 blender::int2 *edge = mesh->edges_for_write().data();
3330 dvert = mesh->deform_verts_for_write().data();
3331
3332 if (psys->clmd->hairdata == nullptr) {
3333 psys->clmd->hairdata = MEM_malloc_arrayN<ClothHairData>(size_t(totpoint), "hair data");
3334 }
3335
3336 /* calculate maximum segment length */
3337 max_length = 0.0f;
3339 {
3340 if (!(pa->flag & PARS_UNEXIST)) {
3341 for (k = 1, key = pa->hair + 1; k < pa->totkey; k++, key++) {
3342 float length = len_v3v3(key->co, (key - 1)->co);
3343 max_length = std::max(max_length, length);
3344 }
3345 }
3346 }
3347
3348 psys->clmd->sim_parms->vgroup_mass = 1;
3349
3350 int vert_index = 0;
3351
3352 /* XXX placeholder for more flexible future hair settings */
3353 hair_radius = part->size;
3354
3355 /* Make vgroup for pin roots etc. */
3356 hair_index = 1;
3358 {
3359 if (!(pa->flag & PARS_UNEXIST)) {
3360 float root_mat[4][4];
3361 float bending_stiffness;
3362 bool use_hair;
3363
3364 pa->hair_index = hair_index;
3365 use_hair = psys_hair_use_simulation(pa, max_length);
3366
3367 psys_mat_hair_to_object(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
3368 mul_m4_m4m4(root_mat, sim->ob->object_to_world().ptr(), hairmat);
3369 normalize_m4(root_mat);
3370
3371 bending_stiffness = std::clamp(
3372 1.0f - part->bending_random * psys_frand(psys, p + 666), 0.0f, 1.0f);
3373
3374 for (k = 0, key = pa->hair; k < pa->totkey; k++, key++) {
3375 ClothHairData *hair;
3376 float *co, *co_next;
3377
3378 co = key->co;
3379 co_next = (key + 1)->co;
3380
3381 /* create fake root before actual root to resist bending */
3382 if (k == 0) {
3383 hair = &psys->clmd->hairdata[pa->hair_index - 1];
3384 copy_v3_v3(hair->loc, root_mat[3]);
3385 copy_m3_m4(hair->rot, root_mat);
3386
3387 hair->radius = hair_radius;
3388 hair->bending_stiffness = bending_stiffness;
3389
3390 add_v3_v3v3(positions[vert_index], co, co);
3391 sub_v3_v3(positions[vert_index], co_next);
3392 mul_m4_v3(hairmat, positions[vert_index]);
3393
3394 edge->x = pa->hair_index - 1;
3395 edge->y = pa->hair_index;
3396
3397 dvert = hair_set_pinning(dvert, 1.0f);
3398
3399 vert_index++;
3400 edge++;
3401 }
3402
3403 /* store root transform in cloth data */
3404 hair = &psys->clmd->hairdata[pa->hair_index + k];
3405 copy_v3_v3(hair->loc, root_mat[3]);
3406 copy_m3_m4(hair->rot, root_mat);
3407
3408 hair->radius = hair_radius;
3409 hair->bending_stiffness = bending_stiffness;
3410
3411 copy_v3_v3(positions[vert_index], co);
3412 mul_m4_v3(hairmat, positions[vert_index]);
3413
3414 if (k) {
3415 edge->x = pa->hair_index + k - 1;
3416 edge->y = pa->hair_index + k;
3417 }
3418
3419 /* roots and disabled hairs should be 1.0, the rest can be anything from 0.0 to 1.0 */
3420 if (use_hair) {
3421 dvert = hair_set_pinning(dvert, key->weight);
3422 }
3423 else {
3424 dvert = hair_set_pinning(dvert, 1.0f);
3425 }
3426
3427 vert_index++;
3428 if (k) {
3429 edge++;
3430 }
3431 }
3432
3433 hair_index += pa->totkey + 1;
3434 }
3435 }
3436}
3437
3439{
3440 ParticleSystem *psys = sim->psys;
3441 PARTICLE_P;
3442 EffectorWeights *clmd_effweights;
3443 int totpoint;
3444 int totedge;
3445 bool realloc_roots;
3446
3447 if (!psys->clmd) {
3449 psys->clmd->sim_parms->goalspring = 0.0f;
3452 }
3453
3454 /* count simulated points */
3455 totpoint = 0;
3456 totedge = 0;
3458 {
3459 if (!(pa->flag & PARS_UNEXIST)) {
3460 /* "out" dm contains all hairs */
3461 totedge += pa->totkey;
3462 totpoint += pa->totkey + 1; /* +1 for virtual root point */
3463 }
3464 }
3465
3466 /* whether hair root info array has to be reallocated */
3467 realloc_roots = false;
3468 if (psys->hair_in_mesh) {
3469 Mesh *mesh = psys->hair_in_mesh;
3470 if (totpoint != mesh->verts_num || totedge != mesh->edges_num) {
3471 BKE_id_free(nullptr, mesh);
3472 psys->hair_in_mesh = nullptr;
3473 realloc_roots = true;
3474 }
3475 }
3476
3477 if (!psys->hair_in_mesh || !psys->clmd->hairdata || realloc_roots) {
3478 if (psys->clmd->hairdata) {
3479 MEM_freeN(psys->clmd->hairdata);
3480 psys->clmd->hairdata = nullptr;
3481 }
3482 }
3483
3484 /* Free hair_out_mesh before modifying hair_in_mesh in hair_create_input_mesh() to avoid copying
3485 * on write since they share some data */
3486 if (psys->hair_out_mesh) {
3487 BKE_id_free(nullptr, psys->hair_out_mesh);
3488 }
3489
3490 hair_create_input_mesh(sim, totpoint, totedge, &psys->hair_in_mesh);
3491
3492 psys->clmd->point_cache = psys->pointcache;
3493 /* for hair sim we replace the internal cloth effector weights temporarily
3494 * to use the particle settings
3495 */
3496 clmd_effweights = psys->clmd->sim_parms->effector_weights;
3498
3500 nullptr, &psys->hair_in_mesh->id, (ID **)&psys->hair_out_mesh, LIB_ID_COPY_LOCALIZE);
3501
3503 psys->clmd,
3504 sim->depsgraph,
3505 sim->scene,
3506 sim->ob,
3507 psys->hair_in_mesh,
3508 reinterpret_cast<float (*)[3]>(psys->hair_out_mesh->vert_positions_for_write().data()));
3509 psys->hair_out_mesh->tag_positions_changed();
3510
3511 /* restore cloth effector weights */
3512 psys->clmd->sim_parms->effector_weights = clmd_effweights;
3513}
3514static void hair_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
3515{
3516 ParticleSystem *psys = sim->psys;
3517 ParticleSettings *part = psys->part;
3518 PARTICLE_P;
3519 float disp = psys_get_current_display_percentage(psys, use_render_params);
3520
3522 {
3523 pa->size = part->size;
3524 if (part->randsize > 0.0f) {
3525 pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
3526 }
3527
3528 if (psys_frand(psys, p) > disp) {
3529 pa->flag |= PARS_NO_DISP;
3530 }
3531 else {
3532 pa->flag &= ~PARS_NO_DISP;
3533 }
3534 }
3535
3536 if (psys->recalc & ID_RECALC_PSYS_RESET) {
3537 /* need this for changing subsurf levels */
3538 psys_calc_dmcache(sim->ob, sim->psmd->mesh_final, sim->psmd->mesh_original, psys);
3539
3540 if (psys->clmd) {
3542 }
3543 }
3544
3545 /* dynamics with cloth simulation, psys->particles can be nullptr with 0 particles #25519. */
3546 if (psys->part->type == PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS && psys->particles) {
3547 do_hair_dynamics(sim);
3548 }
3549
3550 /* following lines were removed r29079 but cause bug #22811, see report for details */
3552 psys_update_path_cache(sim, cfra, use_render_params);
3553
3554 psys->flag |= PSYS_HAIR_UPDATED;
3555}
3556
3557static void save_hair(ParticleSimulationData *sim, float /*cfra*/)
3558{
3559 Object *ob = sim->ob;
3560 ParticleSystem *psys = sim->psys;
3561 HairKey *key, *root;
3562 PARTICLE_P;
3563
3564 invert_m4_m4(ob->runtime->world_to_object.ptr(), ob->object_to_world().ptr());
3565
3566 if (psys->totpart == 0) {
3567 return;
3568 }
3569
3570 psys_sim_data_init(sim);
3571
3572 /* save new keys for elements if needed */
3574 {
3575 /* first time alloc */
3576 if (pa->totkey == 0 || pa->hair == nullptr) {
3577 pa->hair = MEM_calloc_arrayN<HairKey>(size_t(psys->part->hair_step) + 1, "HairKeys");
3578 pa->totkey = 0;
3579 }
3580
3581 key = root = pa->hair;
3582 key += pa->totkey;
3583
3584 /* convert from global to geometry space */
3585 copy_v3_v3(key->co, pa->state.co);
3586 mul_m4_v3(ob->world_to_object().ptr(), key->co);
3587
3588 if (pa->totkey) {
3589 sub_v3_v3(key->co, root->co);
3590 psys_vec_rot_to_face(sim->psmd->mesh_final, pa, key->co);
3591 }
3592
3593 key->time = pa->state.time;
3594
3595 key->weight = 1.0f - key->time / 100.0f;
3596
3597 pa->totkey++;
3598
3599 /* Root is always in the origin of hair space
3600 * so we set it to be so after the last key is saved. */
3601 if (pa->totkey == psys->part->hair_step + 1) {
3602 zero_v3(root->co);
3603 }
3604 }
3605
3606 psys_sim_data_free(sim);
3607}
3608
3610static const float MIN_TIMESTEP = 1.0f / 101.0f;
3615static const float TIMESTEP_EXPANSION_FACTOR = 0.1f;
3616static const float TIMESTEP_EXPANSION_TOLERANCE = 1.5f;
3617
3625 ParticleSimulationData *sim, ParticleData *pa, float dtime, SPHData *sphdata, SpinLock *spin)
3626{
3627 float relative_vel[3];
3628
3629 sub_v3_v3v3(relative_vel, pa->prev_state.vel, sphdata->flow);
3630
3631 const float courant_num = len_v3(relative_vel) * dtime / sphdata->element_size;
3632 if (sim->courant_num < courant_num) {
3633 BLI_spin_lock(spin);
3634 sim->courant_num = std::max(sim->courant_num, courant_num);
3635 BLI_spin_unlock(spin);
3636 }
3637}
3639{
3640 return 1.0f / float(part->subframes + 1);
3641}
3642/* Update time step size to suit current conditions. */
3644{
3645 float dt_target;
3646 if (sim->courant_num == 0.0f) {
3647 dt_target = 1.0f;
3648 }
3649 else {
3650 dt_target = psys->dt_frac * (psys->part->courant_target / sim->courant_num);
3651 }
3652
3653 /* Make sure the time step is reasonable. For some reason, the CLAMP macro
3654 * doesn't work here. The time step becomes too large. - z0r */
3655 if (dt_target < MIN_TIMESTEP) {
3656 dt_target = MIN_TIMESTEP;
3657 }
3658 else if (dt_target > get_base_time_step(psys->part)) {
3659 dt_target = get_base_time_step(psys->part);
3660 }
3661
3662 /* Decrease time step instantly, but increase slowly. */
3663 if (dt_target > psys->dt_frac) {
3664 psys->dt_frac = interpf(dt_target, psys->dt_frac, TIMESTEP_EXPANSION_FACTOR);
3665 }
3666 else {
3667 psys->dt_frac = dt_target;
3668 }
3669}
3670
3671static float sync_timestep(ParticleSystem *psys, float t_frac)
3672{
3673 /* Sync with frame end if it's close. */
3674 if (t_frac == 1.0f) {
3675 return psys->dt_frac;
3676 }
3677 if (t_frac + (psys->dt_frac * TIMESTEP_EXPANSION_TOLERANCE) >= 1.0f) {
3678 return 1.0f - t_frac;
3679 }
3680
3681 return psys->dt_frac;
3682}
3683
3684/************************************************/
3685/* System Core */
3686/************************************************/
3687
3697
3698static SPHData dynamics_step_sphdata_reduce(const SPHData &sphdata_to, const SPHData &sphdata_from)
3699{
3700 SPHData result = sphdata_to;
3701 result.new_springs.extend(sphdata_from.new_springs);
3702 return result;
3703}
3704
3706 const int p,
3707 SPHData *sphdata)
3708{
3709 ParticleSimulationData *sim = data->sim;
3710 ParticleSystem *psys = sim->psys;
3711 ParticleSettings *part = psys->part;
3712
3713 ParticleData *pa;
3714
3715 if ((pa = psys->particles + p)->state.time <= 0.0f) {
3716 return;
3717 }
3718
3719 /* do global forces & effectors */
3720 basic_integrate(sim, p, pa->state.time, data->cfra);
3721
3722 /* actual fluids calculations */
3723 sph_integrate(sim, pa, pa->state.time, sphdata);
3724
3725 if (sim->colliders) {
3726 collision_check(sim, p, pa->state.time, data->cfra);
3727 }
3728
3729 /* SPH particles are not physical particles, just interpolation
3730 * particles, thus rotation has not a direct sense for them. */
3731 basic_rotate(part, pa, pa->state.time, data->timestep);
3732
3733 if (part->time_flag & PART_TIME_AUTOSF) {
3734 update_courant_num(sim, pa, data->dtime, sphdata, &data->spin);
3735 }
3736}
3737
3739 void *__restrict userdata, const int p, const TaskParallelTLS *__restrict /*tls*/)
3740{
3741 DynamicStepSolverTaskData *data = static_cast<DynamicStepSolverTaskData *>(userdata);
3742 ParticleSimulationData *sim = data->sim;
3743 ParticleSystem *psys = sim->psys;
3744
3745 ParticleData *pa;
3746
3747 if ((pa = psys->particles + p)->state.time <= 0.0f) {
3748 return;
3749 }
3750
3751 basic_integrate(sim, p, pa->state.time, data->cfra);
3752}
3753
3755 void *__restrict userdata, const int p, const TaskParallelTLS *__restrict tls)
3756{
3757 DynamicStepSolverTaskData *data = static_cast<DynamicStepSolverTaskData *>(userdata);
3758 ParticleSimulationData *sim = data->sim;
3759 ParticleSystem *psys = sim->psys;
3760
3761 SPHData *sphdata = static_cast<SPHData *>(tls->userdata_chunk);
3762
3763 ParticleData *pa;
3764
3765 if ((pa = psys->particles + p)->state.time <= 0.0f) {
3766 return;
3767 }
3768
3769 sphclassical_calc_dens(pa, pa->state.time, sphdata);
3770}
3771
3772static void dynamics_step_sph_classical_integrate_task_cb_ex(void *__restrict userdata,
3773 const int p,
3774 const TaskParallelTLS *__restrict tls)
3775{
3776 DynamicStepSolverTaskData *data = static_cast<DynamicStepSolverTaskData *>(userdata);
3777 ParticleSimulationData *sim = data->sim;
3778 ParticleSystem *psys = sim->psys;
3779 ParticleSettings *part = psys->part;
3780
3781 SPHData *sphdata = static_cast<SPHData *>(tls->userdata_chunk);
3782
3783 ParticleData *pa;
3784
3785 if ((pa = psys->particles + p)->state.time <= 0.0f) {
3786 return;
3787 }
3788
3789 /* actual fluids calculations */
3790 sph_integrate(sim, pa, pa->state.time, sphdata);
3791
3792 if (sim->colliders) {
3793 collision_check(sim, p, pa->state.time, data->cfra);
3794 }
3795
3796 /* SPH particles are not physical particles, just interpolation
3797 * particles, thus rotation has not a direct sense for them. */
3798 basic_rotate(part, pa, pa->state.time, data->timestep);
3799
3800 if (part->time_flag & PART_TIME_AUTOSF) {
3801 update_courant_num(sim, pa, data->dtime, sphdata, &data->spin);
3802 }
3803}
3804
3805/* unbaked particles are calculated dynamically */
3806static void dynamics_step(ParticleSimulationData *sim, float cfra)
3807{
3808 using namespace blender;
3809 ParticleSystem *psys = sim->psys;
3810 ParticleSettings *part = psys->part;
3811 BoidBrainData bbd;
3812 ParticleTexture ptex;
3813 PARTICLE_P;
3814 float timestep;
3815 /* frame & time changes */
3816 float dfra, dtime;
3817 float birthtime, dietime;
3818
3819 /* where have we gone in time since last time */
3820 dfra = cfra - psys->cfra;
3821
3822 timestep = psys_get_timestep(sim);
3823 dtime = dfra * timestep;
3824
3825 if (dfra < 0.0f) {
3827 {
3828 psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra);
3829 pa->size = part->size * ptex.size;
3830 if (part->randsize > 0.0f) {
3831 pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
3832 }
3833
3834 reset_particle(sim, pa, dtime, cfra);
3835 }
3836 return;
3837 }
3838
3839 /* for now do both, boids us 'rng' */
3840 sim->rng = BLI_rng_new_srandom(31415926 + int(cfra) + psys->seed);
3841
3843
3844 if (part->type != PART_HAIR) {
3846 }
3847
3848 /* initialize physics type specific stuff */
3849 switch (part->phystype) {
3850 case PART_PHYS_BOIDS: {
3851 ParticleTarget *pt = static_cast<ParticleTarget *>(psys->targets.first);
3852 bbd.sim = sim;
3853 bbd.part = part;
3854 bbd.cfra = cfra;
3855 bbd.dfra = dfra;
3856 bbd.timestep = timestep;
3857 bbd.rng = sim->rng;
3858
3859 psys_update_particle_tree(psys, cfra);
3860
3861 boids_precalc_rules(part, cfra);
3862
3863 for (; pt; pt = pt->next) {
3864 ParticleSystem *psys_target = psys_get_target_system(sim->ob, pt);
3865 if (psys_target && psys_target != psys) {
3866 psys_update_particle_tree(psys_target, cfra);
3867 }
3868 }
3869 break;
3870 }
3871 case PART_PHYS_FLUID: {
3872 ParticleTarget *pt = static_cast<ParticleTarget *>(psys->targets.first);
3873 psys_update_particle_bvhtree(psys, cfra);
3874
3875 /* Updating others systems particle tree for fluid-fluid interaction. */
3876 for (; pt; pt = pt->next) {
3877 if (pt->ob) {
3879 static_cast<ParticleSystem *>(BLI_findlink(&pt->ob->particlesystem, pt->psys - 1)),
3880 cfra);
3881 }
3882 }
3883 break;
3884 }
3885 }
3886 /* initialize all particles for dynamics */
3888 {
3889 copy_particle_key(&pa->prev_state, &pa->state, 1);
3890
3891 psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra);
3892
3893 pa->size = part->size * ptex.size;
3894 if (part->randsize > 0.0f) {
3895 pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
3896 }
3897
3898 birthtime = pa->time;
3899 dietime = pa->dietime;
3900
3901 /* store this, so we can do multiple loops over particles */
3902 pa->state.time = dfra;
3903
3904 if (dietime <= cfra && psys->cfra < dietime) {
3905 /* particle dies some time between this and last step */
3906 pa->state.time = dietime - ((birthtime > psys->cfra) ? birthtime : psys->cfra);
3907 pa->alive = PARS_DYING;
3908 }
3909 else if (birthtime <= cfra && birthtime >= psys->cfra) {
3910 /* Particle is born some time between this and last step. */
3911 reset_particle(sim, pa, dfra * timestep, cfra);
3912 pa->alive = PARS_ALIVE;
3913 pa->state.time = cfra - birthtime;
3914 }
3915 else if (dietime < cfra) {
3916 /* nothing to be done when particle is dead */
3917 }
3918
3919 /* Only reset unborn particles if they're shown or if the particle is born soon. */
3920 if (pa->alive == PARS_UNBORN &&
3921 (part->flag & PART_UNBORN || (cfra + psys->pointcache->step > pa->time)))
3922 {
3923 reset_particle(sim, pa, dtime, cfra);
3924 }
3925 else if (part->phystype == PART_PHYS_NO) {
3926 reset_particle(sim, pa, dtime, cfra);
3927 }
3928
3929 if (ELEM(pa->alive, PARS_ALIVE, PARS_DYING) == 0 || (pa->flag & (PARS_UNEXIST | PARS_NO_DISP)))
3930 {
3931 pa->state.time = -1.0f;
3932 }
3933 }
3934
3935 switch (part->phystype) {
3936 case PART_PHYS_NEWTON: {
3938 {
3939 /* do global forces & effectors */
3940 basic_integrate(sim, p, pa->state.time, cfra);
3941
3942 /* deflection */
3943 if (sim->colliders) {
3944 collision_check(sim, p, pa->state.time, cfra);
3945 }
3946
3947 /* rotations */
3948 basic_rotate(part, pa, pa->state.time, timestep);
3949 }
3950 break;
3951 }
3952 case PART_PHYS_BOIDS: {
3954 {
3955 bbd.goal_ob = nullptr;
3956
3957 boid_brain(&bbd, p, pa);
3958
3959 if (pa->alive != PARS_DYING) {
3960 boid_body(&bbd, pa);
3961
3962 /* deflection */
3963 if (sim->colliders) {
3964 collision_check(sim, p, pa->state.time, cfra);
3965 }
3966 }
3967 }
3968 break;
3969 }
3970 case PART_PHYS_FLUID: {
3972 SPHData sphdata;
3973 psys_sph_init(sim, &sphdata, eh);
3974
3975 DynamicStepSolverTaskData task_data{};
3976 task_data.sim = sim;
3977 task_data.cfra = cfra;
3978 task_data.timestep = timestep;
3979 task_data.dtime = dtime;
3980
3981 BLI_spin_init(&task_data.spin);
3982
3983 if (part->fluid->solver == SPH_SOLVER_DDR) {
3984 /* Apply SPH forces using double-density relaxation algorithm
3985 * (Clavat et al.) */
3987 IndexRange(psys->totpart),
3988 100,
3989 sphdata,
3990 [&](const IndexRange range, SPHData data) {
3991 for (const int i : range) {
3992 dynamics_step_sph_ddr_task_cb_ex(&task_data, i, &data);
3993 }
3994 return data;
3995 },
3997
3998 sph_springs_modify(psys, timestep);
3999 }
4000 else {
4001 /* SPH_SOLVER_CLASSICAL */
4002 /* Apply SPH forces using classical algorithm (due to Gingold
4003 * and Monaghan). Note that, unlike double-density relaxation,
4004 * this algorithm is separated into distinct loops. */
4005
4006 {
4007 TaskParallelSettings settings;
4009 settings.use_threading = (psys->totpart > 100);
4011 psys->totpart,
4012 &task_data,
4014 &settings);
4015 }
4016
4017 /* calculate summation density */
4018 /* Note that we could avoid copying sphdata for each thread here (it's only read here),
4019 * but doubt this would gain us anything except confusion... */
4020 {
4021 TaskParallelSettings settings;
4023 settings.use_threading = (psys->totpart > 100);
4024 settings.userdata_chunk = &sphdata;
4025 settings.userdata_chunk_size = sizeof(sphdata);
4027 psys->totpart,
4028 &task_data,
4030 &settings);
4031 }
4032
4033 /* do global forces & effectors */
4034 {
4035 TaskParallelSettings settings;
4037 settings.use_threading = (psys->totpart > 100);
4038 settings.userdata_chunk = &sphdata;
4039 settings.userdata_chunk_size = sizeof(sphdata);
4041 psys->totpart,
4042 &task_data,
4044 &settings);
4045 }
4046 }
4047
4048 BLI_spin_end(&task_data.spin);
4049
4050 psys_sph_finalize(&sphdata);
4051 break;
4052 }
4053 }
4054
4055 /* finalize particle state and time after dynamics */
4057 {
4058 if (pa->alive == PARS_DYING) {
4059 pa->alive = PARS_DEAD;
4060 pa->state.time = pa->dietime;
4061 }
4062 else {
4063 pa->state.time = cfra;
4064 }
4065 }
4066
4067 BKE_collider_cache_free(&sim->colliders);
4068 BLI_rng_free(sim->rng);
4069 sim->rng = nullptr;
4070}
4071
4072static void update_children(ParticleSimulationData *sim, const bool use_render_params)
4073{
4074 if ((sim->psys->part->type == PART_HAIR) && (sim->psys->flag & PSYS_HAIR_DONE) == 0) {
4075 /* don't generate children while growing hair - waste of time */
4077 }
4078 else if (sim->psys->part->childtype) {
4079 if (sim->psys->totchild != psys_get_tot_child(sim->scene, sim->psys, use_render_params)) {
4081 }
4082 else {
4083 /* Children are up to date, nothing to do. */
4084 }
4085 }
4086 else {
4088 }
4089}
4090/* Updates cached particles' alive & other flags etc. */
4091static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
4092{
4093 ParticleSystem *psys = sim->psys;
4094 ParticleSettings *part = psys->part;
4095 ParticleTexture ptex;
4096 PARTICLE_P;
4097 float disp, dietime;
4098
4100
4101 disp = psys_get_current_display_percentage(psys, use_render_params);
4102
4103 psys_sim_data_init(sim);
4104
4106 {
4107 psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra);
4108 pa->size = part->size * ptex.size;
4109 if (part->randsize > 0.0f) {
4110 pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
4111 }
4112
4113 dietime = pa->dietime;
4114
4115 /* update alive status and push events */
4116 if (pa->time > cfra) {
4117 pa->alive = PARS_UNBORN;
4118 if (part->flag & PART_UNBORN && (psys->pointcache->flag & PTCACHE_EXTERNAL) == 0) {
4119 reset_particle(sim, pa, 0.0f, cfra);
4120 }
4121 }
4122 else if (dietime <= cfra) {
4123 pa->alive = PARS_DEAD;
4124 }
4125 else {
4126 pa->alive = PARS_ALIVE;
4127 }
4128
4129 if (psys_frand(psys, p) > disp) {
4130 pa->flag |= PARS_NO_DISP;
4131 }
4132 else {
4133 pa->flag &= ~PARS_NO_DISP;
4134 }
4135 }
4136
4137 psys_sim_data_free(sim);
4138}
4139
4140static bool particles_has_flip(short parttype)
4141{
4142 return (parttype == PART_FLUID_FLIP);
4143}
4144
4145static bool particles_has_tracer(short parttype)
4146{
4147 return (parttype == PART_FLUID_TRACER);
4148}
4149
4150static bool particles_has_spray(short parttype)
4151{
4153}
4154
4155static bool particles_has_bubble(short parttype)
4156{
4158}
4159
4160static bool particles_has_foam(short parttype)
4161{
4163}
4164
4166 int cfra,
4167 const bool use_render_params)
4168{
4169 ParticleSystem *psys = sim->psys;
4170 if (psys->particles) {
4171 MEM_freeN(psys->particles);
4172 psys->particles = nullptr;
4173 psys->totpart = 0;
4174 }
4175
4176#ifndef WITH_FLUID
4177 UNUSED_VARS(use_render_params, cfra);
4178#else
4179 {
4180 Object *ob = sim->ob;
4183
4184 if (fmd && fmd->domain && fmd->domain->fluid) {
4185 FluidDomainSettings *fds = fmd->domain;
4186
4187 ParticleSettings *part = psys->part;
4188 ParticleData *pa = nullptr;
4189
4190 int p, totpart = 0, tottypepart = 0;
4191 int flagActivePart, activeParts = 0;
4192 float posX, posY, posZ, velX, velY, velZ;
4193 float resX, resY, resZ;
4194 int upres = 1;
4195 char debugStrBuffer[256];
4196 float tmp[3] = {0}, tmp2[3] = {0};
4197
4198 /* Helper variables for scaling. */
4199 float min[3], max[3], size[3], cell_size_scaled[3], max_size;
4200
4201 /* Sanity check: parts also enabled in fluid domain? */
4202 if ((particles_has_flip(part->type) &&
4204 (particles_has_spray(part->type) &&
4206 (particles_has_bubble(part->type) &&
4208 (particles_has_foam(part->type) &&
4210 (particles_has_tracer(part->type) &&
4212 {
4213 BLI_snprintf(debugStrBuffer,
4214 sizeof(debugStrBuffer),
4215 "particles_fluid_step::error - found particle system that is not enabled in "
4216 "fluid domain\n");
4217 return;
4218 }
4219
4220 /* Count particle amount. tottypepart is only important for snd particles. */
4221 if (part->type == PART_FLUID_FLIP) {
4222 tottypepart = totpart = manta_liquid_get_num_flip_particles(fds->fluid);
4223 }
4224 if (particles_has_spray(part->type) || particles_has_bubble(part->type) ||
4226 {
4228
4229 /* tottypepart is the amount of particles of a snd particle type. */
4230 for (p = 0; p < totpart; p++) {
4231 flagActivePart = manta_liquid_get_snd_particle_flag_at(fds->fluid, p);
4232 if (particles_has_spray(part->type) && (flagActivePart & PARTICLE_TYPE_SPRAY)) {
4233 tottypepart++;
4234 }
4235 if (particles_has_bubble(part->type) && (flagActivePart & PARTICLE_TYPE_BUBBLE)) {
4236 tottypepart++;
4237 }
4238 if (particles_has_foam(part->type) && (flagActivePart & PARTICLE_TYPE_FOAM)) {
4239 tottypepart++;
4240 }
4241 if (particles_has_tracer(part->type) && (flagActivePart & PARTICLE_TYPE_TRACER)) {
4242 tottypepart++;
4243 }
4244 }
4245 }
4246 /* Sanity check: no particles present. */
4247 if (!totpart || !tottypepart) {
4248 return;
4249 }
4250
4251 /* How many particles to display? */
4252 tottypepart = (use_render_params) ? tottypepart : (part->disp * tottypepart) / 100;
4253
4254 part->totpart = tottypepart;
4255 part->sta = part->end = 1.0f;
4256 part->lifetime = sim->scene->r.efra + 1;
4257
4258 /* Allocate particles. */
4259 realloc_particles(sim, part->totpart);
4260
4261 /* Set some randomness when choosing which particles to display. */
4262 sim->rng = BLI_rng_new_srandom(31415926 + cfra + psys->seed);
4263 double r, dispProb = double(part->disp) / 100.0;
4264
4265 /* Loop over *all* particles. Will break out of loop before tottypepart amount exceeded. */
4266 for (p = 0, pa = psys->particles; p < totpart; p++) {
4267
4268 /* Apply some randomness and determine which particles to skip. */
4269 r = BLI_rng_get_double(sim->rng);
4270 if (r > dispProb) {
4271 continue;
4272 }
4273
4274 /* flag, res, upres, pos, vel for FLIP and snd particles have different getters. */
4275 if (part->type == PART_FLUID_FLIP) {
4276 flagActivePart = manta_liquid_get_flip_particle_flag_at(fds->fluid, p);
4277
4278 resX = float(manta_get_res_x(fds->fluid));
4279 resY = float(manta_get_res_y(fds->fluid));
4280 resZ = float(manta_get_res_z(fds->fluid));
4281
4282 upres = 1;
4283
4287
4291 }
4292 else if (particles_has_spray(part->type) || particles_has_bubble(part->type) ||
4294 {
4295 flagActivePart = manta_liquid_get_snd_particle_flag_at(fds->fluid, p);
4296
4300
4302
4306
4310 }
4311 else {
4312 BLI_snprintf(debugStrBuffer,
4313 sizeof(debugStrBuffer),
4314 "particles_fluid_step::error - unknown particle system type\n");
4315 BLI_rng_free(sim->rng);
4316 return;
4317 }
4318# if 0
4319 /* Debugging: Print type of particle system and current particles. */
4320 printf("system type is %d and particle type is %d\n", part->type, flagActivePart);
4321# endif
4322
4323 /* Type of particle must match current particle system type
4324 * (only important for snd particles). */
4325 if ((flagActivePart & PARTICLE_TYPE_SPRAY) && !particles_has_spray(part->type)) {
4326 continue;
4327 }
4328 if ((flagActivePart & PARTICLE_TYPE_BUBBLE) && !particles_has_bubble(part->type)) {
4329 continue;
4330 }
4331 if ((flagActivePart & PARTICLE_TYPE_FOAM) && !particles_has_foam(part->type)) {
4332 continue;
4333 }
4334 if ((flagActivePart & PARTICLE_TYPE_TRACER) && !particles_has_tracer(part->type)) {
4335 continue;
4336 }
4337# if 0
4338 /* Debugging: Print type of particle system and current particles. */
4339 printf("system type is %d and particle type is %d\n", part->type, flagActivePart);
4340# endif
4341 /* Particle system has allocated 'tottypepart' particles - so break early before exceeded.
4342 */
4343 if (activeParts >= tottypepart) {
4344 break;
4345 }
4346
4347 /* Only show active particles, i.e. filter out dead particles that just Mantaflow needs.
4348 * Mantaflow convention: PARTICLE_TYPE_DELETE == inactive particle. */
4349 if ((flagActivePart & PARTICLE_TYPE_DELETE) == 0) {
4350 activeParts++;
4351
4352 /* Use particle system settings for particle size. */
4353 pa->size = part->size;
4354 if (part->randsize > 0.0f) {
4355 pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
4356 }
4357
4358 /* Get size (dimension) but considering scaling */
4359 copy_v3_v3(cell_size_scaled, fds->cell_size);
4360 mul_v3_v3(cell_size_scaled, ob->scale);
4361 madd_v3fl_v3fl_v3fl_v3i(min, fds->p0, cell_size_scaled, fds->res_min);
4362 madd_v3fl_v3fl_v3fl_v3i(max, fds->p0, cell_size_scaled, fds->res_max);
4364
4365 /* Biggest dimension will be used for up-scaling. */
4366 max_size = std::max(
4367 {size[0] / float(upres), size[1] / float(upres), size[2] / float(upres)});
4368
4369 /* Set particle position. */
4370 const float posParticle[3] = {posX, posY, posZ};
4371 copy_v3_v3(pa->state.co, posParticle);
4372
4373 /* Normalize to unit cube around 0. */
4374 float resDomain[3] = {resX, resY, resZ};
4375 mul_v3_fl(resDomain, 0.5f);
4376 sub_v3_v3(pa->state.co, resDomain);
4377 mul_v3_fl(pa->state.co, fds->dx);
4378
4379 /* Match domain dimension / size. */
4380 float scaleAbs[3] = {
4381 1.0f / fabsf(ob->scale[0]), 1.0f / fabsf(ob->scale[1]), 1.0f / fabsf(ob->scale[2])};
4382 mul_v3_fl(scaleAbs, max_size);
4383 mul_v3_v3(pa->state.co, scaleAbs);
4384
4385 /* Match domain scale. */
4386 mul_m4_v3(ob->object_to_world().ptr(), pa->state.co);
4387
4388 /* Add origin offset to particle position. */
4389 zero_v3(tmp);
4390 zero_v3(tmp2);
4391 sub_v3_v3v3(tmp2, fds->p1, fds->p0);
4392 mul_v3_fl(tmp2, 0.5f);
4393 add_v3_v3v3(tmp, tmp, fds->p1);
4394 sub_v3_v3(tmp, tmp2);
4395 mul_v3_v3(tmp, ob->scale);
4396 add_v3_v3(pa->state.co, tmp);
4397# if 0
4398 /* Debugging: Print particle coordinates. */
4399 printf("pa->state.co[0]: %f, pa->state.co[1]: %f, pa->state.co[2]: %f\n",
4400 pa->state.co[0],
4401 pa->state.co[1],
4402 pa->state.co[2]);
4403# endif
4404 /* Set particle velocity. */
4405 const float velParticle[3] = {velX, velY, velZ};
4406 copy_v3_v3(pa->state.vel, velParticle);
4407 mul_v3_fl(pa->state.vel, fds->dx);
4408# if 0
4409 /* Debugging: Print particle velocity. */
4410 printf("pa->state.vel[0]: %f, pa->state.vel[1]: %f, pa->state.vel[2]: %f\n",
4411 pa->state.vel[0],
4412 pa->state.vel[1],
4413 pa->state.vel[2]);
4414# endif
4415 /* Set default angular velocity and particle rotation. */
4416 zero_v3(pa->state.ave);
4417 unit_qt(pa->state.rot);
4418
4419 pa->time = 1.0f;
4420 pa->dietime = sim->scene->r.efra + 1;
4421 pa->lifetime = sim->scene->r.efra;
4422 pa->alive = PARS_ALIVE;
4423
4424 /* Increasing particle settings pointer only for active particles. */
4425 pa++;
4426 }
4427 }
4428# if 0
4429 /* Debugging: Print number of active particles. */
4430 printf("active parts: %d\n", activeParts);
4431# endif
4432 totpart = psys->totpart = part->totpart = activeParts;
4433
4434 BLI_rng_free(sim->rng);
4435 sim->rng = nullptr;
4436
4437 } /* Fluid sim particles done. */
4438 }
4439#endif /* WITH_FLUID */
4440}
4441
4442static int emit_particles(ParticleSimulationData *sim, PTCacheID *pid, float /*cfra*/)
4443{
4444 ParticleSystem *psys = sim->psys;
4445 int oldtotpart = psys->totpart;
4446 int totpart = tot_particles(psys, pid);
4447
4448 if (totpart != oldtotpart) {
4449 realloc_particles(sim, totpart);
4450 }
4451
4452 return totpart - oldtotpart;
4453}
4454
4465static void system_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
4466{
4467 ParticleSystem *psys = sim->psys;
4468 ParticleSettings *part = psys->part;
4469 PointCache *cache = psys->pointcache;
4470 PTCacheID ptcacheid, *pid = nullptr;
4471 PARTICLE_P;
4472 float disp, cache_cfra = cfra; /*, *vg_vel= 0, *vg_tan= 0, *vg_rot= 0, *vg_size= 0; */
4473 int startframe = 0, endframe = 100, oldtotpart = 0;
4474
4475 /* cache shouldn't be used for hair or "continue physics" */
4476 if (part->type != PART_HAIR) {
4478
4479 /* set suitable cache range automatically */
4480 if ((cache->flag & (PTCACHE_BAKING | PTCACHE_BAKED)) == 0) {
4481 psys_get_pointcache_start_end(sim->scene, psys, &cache->startframe, &cache->endframe);
4482 }
4483
4484 pid = &ptcacheid;
4485 BKE_ptcache_id_from_particles(pid, sim->ob, psys);
4486
4487 BKE_ptcache_id_time(pid, sim->scene, 0.0f, &startframe, &endframe, nullptr);
4488
4489 /* clear everything on start frame, or when psys needs full reset! */
4490 if ((cfra == startframe) || (psys->recalc & ID_RECALC_PSYS_RESET)) {
4492 BKE_ptcache_validate(cache, startframe);
4493 cache->flag &= ~PTCACHE_REDO_NEEDED;
4494 }
4495
4496 CLAMP(cache_cfra, startframe, endframe);
4497 }
4498
4499 /* 1. emit particles and redo particles if needed */
4500 oldtotpart = psys->totpart;
4501 if (emit_particles(sim, pid, cfra) || psys->recalc & ID_RECALC_PSYS_RESET) {
4502 distribute_particles(sim, part->from);
4504 /* reset only just created particles (on startframe all particles are recreated) */
4505 reset_all_particles(sim, 0.0, cfra, oldtotpart);
4507
4509
4510 psys->tot_fluidsprings = psys->alloc_fluidsprings = 0;
4511
4512 /* flag for possible explode modifiers after this system */
4514
4516 }
4517
4518 /* 2. try to read from the cache */
4519 if (pid) {
4520 int cache_result = BKE_ptcache_read(pid, cache_cfra, true);
4521
4523 cached_step(sim, cfra, use_render_params);
4524 update_children(sim, use_render_params);
4525 psys_update_path_cache(sim, cfra, use_render_params);
4526
4527 BKE_ptcache_validate(cache, int(cache_cfra));
4528
4529 if (cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED) {
4530 BKE_ptcache_write(pid, int(cache_cfra));
4531 }
4532
4533 return;
4534 }
4535 /* Cache is supposed to be baked, but no data was found so bail out */
4536 if (cache->flag & PTCACHE_BAKED) {
4538 return;
4539 }
4540 if (cache_result == PTCACHE_READ_OLD) {
4541 psys->cfra = float(cache->simframe);
4542 cached_step(sim, psys->cfra, use_render_params);
4543 }
4544
4545 /* if on second frame, write cache for first frame */
4546 if (psys->cfra == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) {
4547 BKE_ptcache_write(pid, startframe);
4548 }
4549 }
4550 else {
4552 }
4553
4554 /* 3. do dynamics */
4555 /* set particles to be not calculated TODO: can't work with pointcache */
4556 disp = psys_get_current_display_percentage(psys, use_render_params);
4557
4559 {
4560 if (psys_frand(psys, p) > disp) {
4561 pa->flag |= PARS_NO_DISP;
4562 }
4563 else {
4564 pa->flag &= ~PARS_NO_DISP;
4565 }
4566 }
4567
4568 if (psys->totpart) {
4569 int dframe, totframesback = 0;
4570 float t_frac, dt_frac;
4571
4572 /* handle negative frame start at the first frame by doing
4573 * all the steps before the first frame */
4574 if (int(cfra) == startframe && part->sta < startframe) {
4575 totframesback = startframe - int(part->sta);
4576 }
4577
4578 if (!(part->time_flag & PART_TIME_AUTOSF)) {
4579 /* Constant time step */
4580 psys->dt_frac = get_base_time_step(part);
4581 }
4582 else if (int(cfra) == startframe) {
4583 /* Variable time step; initialize to sub-frames. */
4584 psys->dt_frac = get_base_time_step(part);
4585 }
4586 else if (psys->dt_frac < MIN_TIMESTEP) {
4587 /* Variable time step; subsequent frames */
4588 psys->dt_frac = MIN_TIMESTEP;
4589 }
4590
4591 for (dframe = -totframesback; dframe <= 0; dframe++) {
4592 /* Simulate each sub-frame. */
4593 dt_frac = psys->dt_frac;
4594 for (t_frac = dt_frac; t_frac <= 1.0f; t_frac += dt_frac) {
4595 sim->courant_num = 0.0f;
4596 dynamics_step(sim, cfra + dframe + t_frac - 1.0f);
4597 psys->cfra = cfra + dframe + t_frac - 1.0f;
4598
4599 if (part->time_flag & PART_TIME_AUTOSF) {
4600 update_timestep(psys, sim);
4601 }
4602 /* Even without AUTOSF dt_frac may not add up to 1.0 due to float precision. */
4603 dt_frac = sync_timestep(psys, t_frac);
4604 }
4605 }
4606 }
4607
4608 /* 4. only write cache starting from second frame */
4609 if (pid) {
4610 BKE_ptcache_validate(cache, int(cache_cfra));
4611 if (int(cache_cfra) != startframe) {
4612 BKE_ptcache_write(pid, int(cache_cfra));
4613 }
4614 }
4615
4616 update_children(sim, use_render_params);
4617
4618 /* cleanup */
4619 psys_sim_data_free(sim);
4620}
4621
4623{
4624 ParticleSettings *part = psys->part;
4625 PTCacheID pid;
4626
4627 BKE_ptcache_id_from_particles(&pid, ob, psys);
4628
4629 if (part->phystype != PART_PHYS_KEYED) {
4630 psys->flag &= ~PSYS_KEYED;
4631 }
4632
4633 if (part->type == PART_HAIR) {
4635 part->ren_as = PART_DRAW_PATH;
4636 }
4637
4638 if (part->distr == PART_DISTR_GRID) {
4639 part->distr = PART_DISTR_JIT;
4640 }
4641
4643 part->draw_as = PART_DRAW_REND;
4644 }
4645
4646 CLAMP(part->path_start, 0.0f, 100.0f);
4647 CLAMP(part->path_end, 0.0f, 100.0f);
4648
4650 }
4651 else {
4652 free_hair(ob, psys, 1);
4653
4654 CLAMP(part->path_start, 0.0f, std::max(100.0f, part->end + part->lifetime));
4655 CLAMP(part->path_end, 0.0f, std::max(100.0f, part->end + part->lifetime));
4656 }
4657
4659}
4661{
4662 BoidParticle *bpa;
4663 PARTICLE_P;
4664
4665 pa = psys->particles;
4666
4667 if (!pa) {
4668 return;
4669 }
4670
4671 if (psys->part && psys->part->phystype == PART_PHYS_BOIDS) {
4672 if (!pa->boid) {
4673 bpa = MEM_calloc_arrayN<BoidParticle>(psys->totpart, "Boid Data");
4674
4676 {
4677 pa->boid = bpa++;
4678 }
4679 }
4680 }
4681 else if (pa->boid) {
4682 MEM_freeN(pa->boid);
4684 {
4685 pa->boid = nullptr;
4686 }
4687 }
4688}
4689
4691{
4692 SPHFluidSettings *fluid = part->fluid;
4693
4694 fluid->spring_k = 0.0f;
4695 fluid->plasticity_constant = 0.1f;
4696 fluid->yield_ratio = 0.1f;
4697 fluid->rest_length = 1.0f;
4698 fluid->viscosity_omega = 2.0f;
4699 fluid->viscosity_beta = 0.1f;
4700 fluid->stiffness_k = 1.0f;
4701 fluid->stiffness_knear = 1.0f;
4702 fluid->rest_density = 1.0f;
4703 fluid->buoyancy = 0.0f;
4704 fluid->radius = 1.0f;
4707}
4708
4710{
4711 ParticleSettings *part = sim->psys->part;
4712
4714 PTCacheID pid;
4715 BKE_ptcache_id_from_particles(&pid, sim->ob, sim->psys);
4717 }
4718 else {
4719 free_keyed_keys(sim->psys);
4720 sim->psys->flag &= ~PSYS_KEYED;
4721 }
4722
4723 /* RNA Update must ensure this is true. */
4724 if (part->phystype == PART_PHYS_BOIDS) {
4725 BLI_assert(part->boids != nullptr);
4726 }
4727 else if (part->phystype == PART_PHYS_FLUID) {
4728 BLI_assert(part->fluid != nullptr);
4729 }
4730
4732}
4734{
4735 if (!(psys->flag & PSYS_EDITED) && (!psys->edit || !psys->edit->edited) &&
4736 ((psys->flag & PSYS_HAIR_DONE) == 0 || psys->recalc & ID_RECALC_PSYS_RESET ||
4737 (psys->part->flag & PART_HAIR_REGROW && !psys->edit)))
4738 {
4739 return 1;
4740 }
4741
4742 return 0;
4743}
4744
4746{
4747 ParticleSettings *particle_settings_local = (ParticleSettings *)BKE_id_copy_ex(
4748 nullptr, (&particle_settings->id), nullptr, LIB_ID_COPY_LOCALIZE);
4749 return particle_settings_local;
4750}
4751
4752static void particle_settings_free_local(ParticleSettings *particle_settings)
4753{
4754 BKE_libblock_free_datablock(&particle_settings->id, 0);
4755 BKE_libblock_free_data(&particle_settings->id, false);
4756 BLI_assert(!particle_settings->id.py_instance); /* Or call #BKE_libblock_free_data_py. */
4757 MEM_freeN(particle_settings);
4758}
4759
4761 Scene *scene,
4762 Object *ob,
4763 ParticleSystem *psys,
4764 const bool use_render_params)
4765{
4766 ParticleSimulationData sim = {nullptr};
4767 ParticleSettings *part = psys->part;
4768 ParticleSystem *psys_orig = psys_orig_get(psys);
4769 float cfra;
4771
4772 /* Draw data is outdated after ANY change. */
4773 if (psys->pdd) {
4775 }
4776
4777 if (!psys_check_enabled(ob, psys, use_render_params)) {
4778 return;
4779 }
4780
4781 cfra = DEG_get_ctime(depsgraph);
4782
4783 sim.depsgraph = depsgraph;
4784 sim.scene = scene;
4785 sim.ob = ob;
4786 sim.psys = psys;
4787 sim.psmd = psmd;
4788
4789 /* system was already updated from modifier stack */
4792 /* make sure it really was updated to cfra */
4793 if (psys->cfra == cfra) {
4794 return;
4795 }
4796 }
4797
4798 if (!sim.psmd->mesh_final) {
4799 return;
4800 }
4801
4802 if (part->from != PART_FROM_VERT) {
4804 }
4805
4806 /* to verify if we need to restore object afterwards */
4807 psys->flag &= ~PSYS_OB_ANIM_RESTORE;
4808
4809 if (psys->recalc & ID_RECALC_PSYS_RESET) {
4810 psys->totunexist = 0;
4811 }
4812
4813 /* setup necessary physics type dependent additional data if it doesn't yet exist */
4815
4816 if (part->type == PART_HAIR) {
4817 /* nothing to do so bail out early */
4818 if (psys->totpart == 0 && part->totpart == 0) {
4819 psys_free_path_cache(psys, nullptr);
4820 free_hair(ob, psys, 0);
4821 psys->flag |= PSYS_HAIR_DONE;
4822 }
4823 /* (re-)create hair */
4824 else if (hair_needs_recalc(psys)) {
4825 float hcfra = 0.0f;
4826 int i, recalc = psys->recalc;
4827
4828 free_hair(ob, psys, 0);
4829
4830 if (psys_orig->edit && psys_orig->free_edit) {
4831 psys_orig->free_edit(psys_orig->edit);
4832 psys_orig->edit = nullptr;
4833 psys_orig->free_edit = nullptr;
4834 }
4835
4836 /* first step is negative so particles get killed and reset */
4837 psys->cfra = 1.0f;
4838
4839 ParticleSettings *part_local = part;
4840 if ((part->flag & PART_HAIR_REGROW) == 0) {
4841 part_local = particle_settings_localize(part);
4842 psys->part = part_local;
4843 }
4844
4845 for (i = 0; i <= part->hair_step; i++) {
4846 hcfra = 100.0f * float(i) / float(psys->part->hair_step);
4847 if ((part->flag & PART_HAIR_REGROW) == 0) {
4849 depsgraph, hcfra);
4851 &part_local->id, part_local->adt, &anim_eval_context, ADT_RECALC_ANIM, false);
4852 }
4853 system_step(&sim, hcfra, use_render_params);
4854 psys->cfra = hcfra;
4855 psys->recalc = 0;
4856 save_hair(&sim, hcfra);
4857 }
4858
4859 if (part_local != part) {
4860 particle_settings_free_local(part_local);
4861 psys->part = part;
4862 }
4863
4864 psys->flag |= PSYS_HAIR_DONE;
4865 psys->recalc = recalc;
4866 }
4867 else if (psys->flag & PSYS_EDITED) {
4868 psys->flag |= PSYS_HAIR_DONE;
4869 }
4870
4871 if (psys->flag & PSYS_HAIR_DONE) {
4872 hair_step(&sim, cfra, use_render_params);
4873 }
4874 }
4875 else if (particles_has_flip(part->type) || particles_has_spray(part->type) ||
4878 {
4879 particles_fluid_step(&sim, int(cfra), use_render_params);
4880 }
4881 else {
4882 switch (part->phystype) {
4883 case PART_PHYS_NO:
4884 case PART_PHYS_KEYED: {
4885 PARTICLE_P;
4886 float disp = psys_get_current_display_percentage(psys, use_render_params);
4887 bool free_unexisting = false;
4888
4889 /* Particles without dynamics haven't been reset yet because they don't use pointcache */
4890 if (psys->recalc & ID_RECALC_PSYS_RESET) {
4892 }
4893
4894 if (emit_particles(&sim, nullptr, cfra) || (psys->recalc & ID_RECALC_PSYS_RESET)) {
4895 free_keyed_keys(psys);
4896 distribute_particles(&sim, part->from);
4898 free_unexisting = true;
4899
4900 /* flag for possible explode modifiers after this system */
4902 }
4903
4904 ParticleTexture ptex;
4905
4907 {
4908 psys_get_texture(&sim, pa, &ptex, PAMAP_SIZE, cfra);
4909 pa->size = part->size * ptex.size;
4910 if (part->randsize > 0.0f) {
4911 pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
4912 }
4913
4914 reset_particle(&sim, pa, 0.0, cfra);
4915
4916 if (psys_frand(psys, p) > disp) {
4917 pa->flag |= PARS_NO_DISP;
4918 }
4919 else {
4920 pa->flag &= ~PARS_NO_DISP;
4921 }
4922 }
4923
4924 /* free unexisting after resetting particles */
4925 if (free_unexisting) {
4927 }
4928
4929 if (part->phystype == PART_PHYS_KEYED) {
4931 set_keyed_keys(&sim);
4932 psys_update_path_cache(&sim, int(cfra), use_render_params);
4933 }
4934 break;
4935 }
4936 default: {
4937 /* the main dynamic particle system step */
4938 system_step(&sim, cfra, use_render_params);
4939 break;
4940 }
4941 }
4942 }
4943
4944 /* make sure emitter is left at correct time (particle emission can change this) */
4945 if (psys->flag & PSYS_OB_ANIM_RESTORE) {
4946 evaluate_emitter_anim(depsgraph, scene, ob, cfra);
4947 psys->flag &= ~PSYS_OB_ANIM_RESTORE;
4948 }
4949
4950 if (psys_orig->edit) {
4952 }
4953
4954 psys->cfra = cfra;
4955 psys->recalc = 0;
4956
4957 if (DEG_is_active(depsgraph)) {
4958 if (psys_orig != psys) {
4959 if (psys_orig->edit != nullptr && psys_orig->edit->psys == psys_orig) {
4960 psys_orig->edit->psys_eval = psys;
4961 psys_orig->edit->psmd_eval = psmd;
4962 }
4963 psys_orig->flag = (psys->flag & ~PSYS_SHARED_CACHES);
4964 psys_orig->cfra = psys->cfra;
4965 psys_orig->recalc = psys->recalc;
4966 psys_orig->part->totpart = part->totpart;
4967 }
4968 }
4969
4970 /* Save matrix for duplicators,
4971 * at render-time the actual dupli-object's matrix is used so don't update! */
4972 invert_m4_m4(psys->imat, ob->object_to_world().ptr());
4973
4975}
4976
4977/* ID looper */
4978
4979/* unfortunately PSys and modifier ID loopers are not directly compatible, so we need this struct
4980 * and the callback below to map the former to the latter (thanks to psys embedding a Cloth
4981 * modifier data struct now, for Hair physics simulations). */
4987
4988static void particlesystem_modifiersForeachIDLink(void *user_data,
4989 Object * /*object*/,
4990 ID **id_pointer,
4991 const LibraryForeachIDCallbackFlag cb_flag)
4992{
4994 data->func(data->psys, id_pointer, data->userdata, cb_flag);
4995}
4996
4998{
4999 LibraryForeachIDData *foreachid_data = static_cast<LibraryForeachIDData *>(userdata);
5000 const int foreachid_data_flags = BKE_lib_query_foreachid_process_flags_get(foreachid_data);
5001
5002 func(psys, (ID **)&psys->part, userdata, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
5003 func(psys, (ID **)&psys->target_ob, userdata, IDWALK_CB_NOP);
5004 func(psys, (ID **)&psys->parent, userdata, IDWALK_CB_NOP);
5005
5006 if (psys->clmd != nullptr) {
5008
5009 if (mti->foreach_ID_link != nullptr) {
5011 data.psys = psys;
5012 data.func = func;
5013 data.userdata = userdata;
5014 mti->foreach_ID_link(
5016 }
5017 }
5018
5019 LISTBASE_FOREACH (ParticleTarget *, pt, &psys->targets) {
5020 func(psys, (ID **)&pt->ob, userdata, IDWALK_CB_NOP);
5021 }
5022
5023 /* In case `psys->part` is nullptr (See ID_REMAP_SKIP/FORCE/FLAG_NEVER_NULL_USAGE in
5024 * #BKE_library_remap), or accessing it is forbidden, always handle particles for potential boids
5025 * data. Unfortunate, but for now there is no other proper way to do this. */
5026 if (!(psys->part && (foreachid_data_flags & IDWALK_NO_ORIG_POINTERS_ACCESS) == 0) ||
5027 psys->part->phystype == PART_PHYS_BOIDS)
5028 {
5029 ParticleData *pa;
5030 int p;
5031
5032 for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) {
5033 if (pa->boid != nullptr) {
5034 func(psys, (ID **)&pa->boid->ground, userdata, IDWALK_CB_NOP);
5035 }
5036 }
5037 }
5038}
5039
5041{
5042 for (ModifierData *md = static_cast<ModifierData *>(object->modifiers.first); md != nullptr;
5043 md = md->next)
5044 {
5045 if (md->type != eModifierType_ParticleSystem) {
5046 continue;
5047 }
5049 ParticleSystem *psys = psmd->psys;
5051 }
5052}
5053
5054/* **** Depsgraph evaluation **** */
5055
5057{
5058 DEG_debug_print_eval(depsgraph, __func__, particle_settings->id.name, particle_settings);
5059 particle_settings->id.recalc |= ID_RECALC_PSYS_RESET;
5060}
5061
5063{
5064 DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
5065 for (ParticleSystem *psys = static_cast<ParticleSystem *>(object->particlesystem.first);
5066 psys != nullptr;
5067 psys = psys->next)
5068 {
5069 psys->recalc |= (psys->part->id.recalc & ID_RECALC_PSYS_ALL);
5070 }
5071}
AnimationEvalContext BKE_animsys_eval_context_construct(struct Depsgraph *depsgraph, float eval_time) ATTR_WARN_UNUSED_RESULT
Definition anim_sys.cc:738
@ ADT_RECALC_ANIM
void BKE_animsys_evaluate_animdata(struct ID *id, struct AnimData *adt, const struct AnimationEvalContext *anim_eval_context, eAnimData_Recalc recalc, bool flush_to_original)
void boid_brain(BoidBrainData *bbd, int p, struct ParticleData *pa)
Definition boids.cc:1054
void boid_body(BoidBrainData *bbd, struct ParticleData *pa)
Definition boids.cc:1211
void boids_precalc_rules(struct ParticleSettings *part, float cfra)
Definition boids.cc:957
void clothModifier_do(ClothModifierData *clmd, Depsgraph *depsgraph, Scene *scene, Object *ob, const Mesh *mesh, float(*vertexCos)[3])
Definition cloth.cc:320
void cloth_free_modifier(ClothModifierData *clmd)
Definition cloth.cc:432
void BKE_collider_cache_free(struct ListBase **colliders)
struct ListBase * BKE_collider_cache_create(struct Depsgraph *depsgraph, struct Object *self, struct Collection *collection)
void BKE_curvemapping_free(CurveMapping *cumap)
CustomData interface, see also DNA_customdata_types.h.
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
#define ORIGINDEX_NONE
void BKE_effectors_free(struct ListBase *lb)
Definition effect.cc:361
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:1106
struct ListBase * BKE_effectors_create(struct Depsgraph *depsgraph, struct Object *ob_src, struct ParticleSystem *psys_src, struct EffectorWeights *weights, bool use_rotation)
Definition effect.cc:306
void pd_point_from_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, struct EffectedPoint *point)
Definition effect.cc:378
void BKE_libblock_free_datablock(ID *id, int flag) ATTR_NONNULL()
void BKE_id_free(Main *bmain, void *idv)
void BKE_libblock_free_data(ID *id, bool do_id_user) ATTR_NONNULL()
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:777
@ LIB_ID_COPY_LOCALIZE
LibraryForeachIDCallbackFlag
@ IDWALK_CB_USER
@ IDWALK_CB_NEVER_NULL
@ IDWALK_CB_NOP
LibraryForeachIDFlag BKE_lib_query_foreachid_process_flags_get(const LibraryForeachIDData *data)
Definition lib_query.cc:129
@ IDWALK_NO_ORIG_POINTERS_ACCESS
General operations, lookup, etc. for materials.
Material * BKE_object_material_get(Object *ob, short act)
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
void BKE_mesh_tessface_ensure(Mesh *mesh)
ModifierData * BKE_modifiers_findby_type(const Object *ob, ModifierType type)
const ModifierTypeInfo * BKE_modifier_get_info(ModifierType type)
ModifierData * BKE_modifier_new(int type)
General operations, lookup, etc. for blender objects.
void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *ob, float ctime)
void distribute_particles(struct ParticleSimulationData *sim, int from)
bool do_guides(struct Depsgraph *depsgraph, struct ParticleSettings *part, struct ListBase *effectors, ParticleKey *state, int index, float time)
Definition particle.cc:2336
struct ParticleSystemModifierData * psys_get_modifier(struct Object *ob, struct ParticleSystem *psys)
Definition particle.cc:2155
#define PARTICLE_DRAW_DATA_UPDATED
void psys_vec_rot_to_face(struct Mesh *mesh, struct ParticleData *pa, float vec[3])
Definition particle.cc:3891
#define DMCACHE_NOTFOUND
void precalc_guides(struct ParticleSimulationData *sim, struct ListBase *effectors)
Definition particle.cc:2282
struct ParticleSystem * psys_orig_get(struct ParticleSystem *psys)
Definition particle.cc:660
#define LOOP_SHOWN_PARTICLES
void(* ParticleSystemIDFunc)(struct ParticleSystem *psys, struct ID **idpoin, void *userdata, LibraryForeachIDCallbackFlag cb_flag)
bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, bool use_render_params)
Definition particle.cc:710
void copy_particle_key(struct ParticleKey *to, struct ParticleKey *from, int time)
Definition particle.cc:3734
void psys_mat_hair_to_object(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4])
Definition particle.cc:3844
bool psys_in_edit_mode(struct Depsgraph *depsgraph, const struct ParticleSystem *psys)
int psys_get_tot_child(struct Scene *scene, struct ParticleSystem *psys, bool use_render_params)
float psys_get_timestep(struct ParticleSimulationData *sim)
Definition particle.cc:4467
void BKE_psys_collision_neartest_cb(void *userdata, int index, const struct BVHTreeRay *ray, struct BVHTreeRayHit *hit)
void psys_particle_on_emitter(struct ParticleSystemModifierData *psmd, int from, int index, int index_dmcache, float fuv[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3], float orco[3])
Definition particle.cc:2246
float psys_get_dietime_from_cache(struct PointCache *cache, int index)
Definition particle.cc:1274
void psys_free_particles(struct ParticleSystem *psys)
Definition particle.cc:932
void psys_free_children(struct ParticleSystem *psys)
Definition particle.cc:922
void free_keyed_keys(struct ParticleSystem *psys)
Definition particle.cc:881
void void psys_cache_paths(struct ParticleSimulationData *sim, float cfra, bool use_render_params)
Definition particle.cc:3249
#define PSYS_RESET_CACHE_MISS
int psys_uses_gravity(struct ParticleSimulationData *sim)
Definition particle.cc:829
float psys_particle_value_from_verts(struct Mesh *mesh, short from, struct ParticleData *pa, float *values)
Definition particle.cc:2141
#define LOOP_PARTICLES
void psys_sim_data_free(struct ParticleSimulationData *sim)
Definition particle.cc:633
#define PSYS_RESET_ALL
#define LOOP_DYNAMIC_PARTICLES
void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit)
Definition particle.cc:907
void psys_free_pdd(struct ParticleSystem *psys)
Definition particle.cc:962
#define DMCACHE_ISCHILD
#define PARTICLE_COLLISION_MAX_COLLISIONS
int psys_particle_dm_face_lookup(struct Mesh *mesh_final, struct Mesh *mesh_original, int findex_orig, const float fw[4], struct LinkNode **poly_nodes)
Definition particle.cc:1834
void psys_get_texture(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleTexture *ptex, int event, float cfra)
Definition particle.cc:4331
#define LOOP_EXISTING_PARTICLES
void free_hair(struct Object *ob, struct ParticleSystem *psys, int dynamics)
Definition particle.cc:846
void BKE_particle_batch_cache_dirty_tag(struct ParticleSystem *psys, int mode)
Definition particle.cc:5288
#define PSYS_RESET_DEPSGRAPH
@ BKE_PARTICLE_BATCH_DIRTY_ALL
void psys_find_parents(struct ParticleSimulationData *sim, bool use_render_params)
Definition particle.cc:2605
void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, bool editupdate, bool use_render_params)
Definition particle.cc:3150
void psys_sim_data_init(struct ParticleSimulationData *sim)
Definition particle.cc:592
#define PARTICLE_P
BLI_INLINE float psys_frand(ParticleSystem *psys, unsigned int seed)
bool psys_get_particle_state(struct ParticleSimulationData *sim, int p, struct ParticleKey *state, bool always)
Definition particle.cc:4879
void BKE_ptcache_free_mem(struct ListBase *mem_cache)
void BKE_ptcache_id_time(PTCacheID *pid, struct Scene *scene, float cfra, int *startframe, int *endframe, float *timescale)
#define PTCACHE_CLEAR_AFTER
void BKE_ptcache_id_from_particles(PTCacheID *pid, struct Object *ob, struct ParticleSystem *psys)
void BKE_ptcache_validate(struct PointCache *cache, int framenr)
void BKE_ptcache_disk_to_mem(struct PTCacheID *pid)
#define PTCACHE_CLEAR_ALL
#define PTCACHE_READ_INTERPOLATED
#define PTCACHE_READ_OLD
int BKE_ptcache_read(PTCacheID *pid, float cfra, bool no_extrapolate_old)
void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra)
@ PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL
#define PTCACHE_RESET_OUTDATED
int BKE_ptcache_id_reset(struct Scene *scene, PTCacheID *pid, int mode)
void BKE_ptcache_invalidate(struct PointCache *cache)
#define PTCACHE_READ_EXACT
int get_render_child_particle_number(const RenderData *r, int child_num, bool for_render)
Definition scene.cc:2766
#define BLI_assert(a)
Definition BLI_assert.h:46
BVHTree * BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
#define BVH_RAYCAST_DEFAULT
@ BVH_RAYCAST_WATERTIGHT
void BLI_bvhtree_balance(BVHTree *tree)
void BLI_bvhtree_free(BVHTree *tree)
void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints)
void(*)(void *userdata, int index, const float co[3], float dist_sq) BVHTree_RangeQuery
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)
int BLI_bvhtree_range_query(const BVHTree *tree, const float co[3], float radius, BVHTree_RangeQuery callback, void *userdata)
A KD-tree for nearest neighbor search.
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float pow2f(float x)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
MINLINE float pow3f(float x)
MINLINE float interpf(float target, float origin, float t)
MINLINE float pow4f(float x)
MINLINE float pow7f(float x)
MINLINE float safe_acosf(float a)
#define M_PI
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void copy_m3_m4(float m1[3][3], const float m2[4][4])
void mul_m4_v3(const float M[4][4], float r[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void mul_mat3_m4_v3(const float mat[4][4], float r[3])
void normalize_m4(float R[4][4]) ATTR_NONNULL()
void interp_qt_qtqt(float q[4], const float a[4], const float b[4], float t)
void axis_angle_to_quat(float r[4], const float axis[3], float angle)
void mat3_to_quat(float q[4], const float mat[3][3])
void vec_to_quat(float q[4], const float vec[3], short axis, short upflag)
float normalize_qt(float q[4])
void mul_qt_v3(const float q[4], float r[3])
void unit_qt(float q[4])
void mat3_to_quat_legacy(float q[4], const float wmat[3][3])
void invert_qt_qt_normalized(float q1[4], const float q2[4])
void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
void mat4_to_quat(float q[4], const float mat[4][4])
void copy_qt_qt(float q[4], const float a[4])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void madd_v3fl_v3fl_v3fl_v3i(float r[3], const float a[3], const float b[3], const int c[3])
MINLINE void mul_v3_v3(float r[3], const float a[3])
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_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)
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 madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
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.
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition rand.cc:53
struct RNG * BLI_rng_new_srandom(unsigned int seed)
Definition rand.cc:46
double BLI_rng_get_double(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition rand.cc:83
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition rand.cc:88
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
void BLI_uniquename(const struct ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_maxncpy) ATTR_NONNULL(1
void BLI_task_isolate(void(*func)(void *userdata), void *userdata)
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition task_range.cc:99
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:221
pthread_spinlock_t SpinLock
pthread_rwlock_t ThreadRWMutex
#define THREAD_LOCK_READ
#define THREAD_LOCK_WRITE
#define BLI_RWLOCK_INITIALIZER
int BLI_system_thread_count(void)
Definition threads.cc:253
void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode)
Definition threads.cc:467
void BLI_spin_init(SpinLock *spin)
Definition threads.cc:391
void BLI_spin_unlock(SpinLock *spin)
Definition threads.cc:430
void BLI_spin_lock(SpinLock *spin)
Definition threads.cc:405
void BLI_rw_mutex_unlock(ThreadRWMutex *mutex)
Definition threads.cc:477
void BLI_spin_end(SpinLock *spin)
Definition threads.cc:445
#define CLAMP(a, b, c)
#define UNUSED_VARS(...)
#define POINTER_FROM_INT(i)
#define POINTER_AS_INT(i)
#define ELEM(...)
@ DAG_EVAL_RENDER
bool DEG_is_active(const Depsgraph *depsgraph)
Definition depsgraph.cc:323
void DEG_debug_print_eval(Depsgraph *depsgraph, const char *function_name, const char *object_name, const void *object_address)
float DEG_get_ctime(const Depsgraph *graph)
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
@ ID_RECALC_PSYS_CHILD
Definition DNA_ID.h:1085
@ ID_RECALC_PSYS_ALL
Definition DNA_ID.h:1191
@ ID_RECALC_PSYS_RESET
Definition DNA_ID.h:1083
@ eBoidMode_OnLand
@ eBoidMode_InAir
@ BOID_ALLOW_LAND
@ CLOTH_COLLSETTINGS_FLAG_SELF
@ CLOTH_SIMSETTINGS_FLAG_RESIST_SPRING_COMPRESS
@ FLUID_DOMAIN_PARTICLE_SPRAY
@ FLUID_DOMAIN_PARTICLE_FOAM
@ FLUID_DOMAIN_PARTICLE_TRACER
@ FLUID_DOMAIN_PARTICLE_FLIP
@ FLUID_DOMAIN_PARTICLE_BUBBLE
These structs are the foundation for all linked lists in the library system.
@ eParticleSystemFlag_Pars
@ eParticleSystemFlag_psys_updated
@ eModifierType_ParticleSystem
@ eModifierType_Cloth
@ eModifierType_Fluid
@ OB_MODE_WEIGHT_PAINT
@ EFF_WEIGHT_DO_HAIR
Object is a sort of wrapper for general info.
@ OB_POSX
@ OB_POSZ
@ SPH_FAC_DENSITY
@ SPH_CURRENT_REST_LENGTH
@ SPH_FAC_REST_LENGTH
@ SPH_FAC_REPULSION
@ SPH_FAC_VISCOSITY
@ SPH_VISCOELASTIC_SPRINGS
@ SPH_FAC_RADIUS
@ PTARGET_VALID
@ SPH_SOLVER_DDR
@ PSYS_HAIR_DYNAMICS
@ PSYS_EDITED
@ PSYS_HAIR_DONE
@ PSYS_HAIR_UPDATED
@ PSYS_KEYED_TIMING
@ PSYS_OB_ANIM_RESTORE
@ PSYS_SHARED_CACHES
@ PSYS_KEYED
@ PART_DISTR_GRID
@ PART_DISTR_JIT
@ PART_UNBORN
@ PART_SIZEMASS
@ PART_HAIR_REGROW
@ PART_ROT_DYN
@ PART_DIE_ON_COL
@ PART_SIZE_DEFL
@ PART_ROTATIONS
@ PART_TIME_AUTOSF
@ PARS_ALIVE
@ PARS_DYING
@ PARS_DEAD
@ PARS_UNBORN
@ PART_AVE_GLOBAL_X
@ PART_AVE_GLOBAL_Z
@ PART_AVE_VERTICAL
@ PART_AVE_VELOCITY
@ PART_AVE_GLOBAL_Y
@ PART_AVE_HORIZONTAL
@ PART_AVE_RAND
@ PART_INT_VERLET
@ PART_INT_MIDPOINT
@ PART_INT_RK4
@ PART_INT_EULER
@ PART_FLUID_FLIP
@ PART_EMITTER
@ PART_FLUID_BUBBLE
@ PART_FLUID_TRACER
@ PART_FLUID_FOAM
@ PART_FLUID_SPRAYFOAMBUBBLE
@ PART_FLUID_SPRAYFOAM
@ PART_HAIR
@ PART_FLUID_SPRAY
@ PART_FLUID_FOAMBUBBLE
@ PAMAP_PHYSICS
@ PAMAP_SIZE
@ PAMAP_IVEL
@ PAMAP_INIT
@ PAMAP_LIFE
@ PART_ROT_VEL
@ PART_ROT_OB_Y
@ PART_ROT_NOR_TAN
@ PART_ROT_OB_Z
@ PART_ROT_GLOB_Y
@ PART_ROT_GLOB_X
@ PART_ROT_NOR
@ PART_ROT_OB_X
@ PART_ROT_GLOB_Z
@ PART_DRAW_PATH
@ PART_DRAW_NOT
@ PART_DRAW_GR
@ PART_DRAW_OB
@ PART_DRAW_REND
@ PARS_NO_DISP
@ PARS_UNEXIST
@ PART_PHYS_FLUID
@ PART_PHYS_NEWTON
@ PART_PHYS_KEYED
@ PART_PHYS_BOIDS
@ PART_PHYS_NO
@ PART_CHILD_FACES
@ PSYS_VG_DENSITY
@ PART_FROM_CHILD
@ PART_FROM_VERT
@ PARTICLE_TYPE_BUBBLE
@ PARTICLE_TYPE_DELETE
@ PARTICLE_TYPE_TRACER
@ PARTICLE_TYPE_FOAM
@ PARTICLE_TYPE_SPRAY
@ PTCACHE_EXTERNAL
@ PTCACHE_BAKED
@ PTCACHE_BAKING
@ PTCACHE_OUTDATED
@ PTCACHE_DISK_CACHE
@ PTCACHE_REDO_NEEDED
@ PE_DRAW_PART
@ PHYS_GLOBAL_GRAVITY
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static void mul(btAlignedObjectArray< T > &items, const Q &value)
int64_t size() const
void append(const T &value)
void clear_and_shrink()
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:570
void reserve(int64_t n)
Definition BLI_map.hh:1028
nullptr float
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
#define offsetof(t, d)
KDTree_3d * tree
#define rot(x, k)
uint nor
uint col
#define printf(...)
float length(VecOp< float, D >) RET
float distance(VecOp< float, D >, VecOp< float, D >) RET
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
int manta_liquid_get_flip_particle_flag_at(struct MANTA *liquid, int i)
int manta_liquid_get_snd_particle_flag_at(struct MANTA *liquid, int i)
float manta_liquid_get_flip_particle_velocity_z_at(struct MANTA *liquid, int i)
float manta_liquid_get_snd_particle_velocity_z_at(struct MANTA *liquid, int i)
float manta_liquid_get_flip_particle_velocity_y_at(struct MANTA *liquid, int i)
float manta_liquid_get_flip_particle_position_y_at(struct MANTA *liquid, int i)
int manta_liquid_get_particle_res_y(struct MANTA *liquid)
int manta_liquid_get_particle_upres(struct MANTA *liquid)
float manta_liquid_get_flip_particle_position_z_at(struct MANTA *liquid, int i)
int manta_get_res_x(struct MANTA *fluid)
int manta_get_res_z(struct MANTA *fluid)
int manta_get_res_y(struct MANTA *fluid)
float manta_liquid_get_snd_particle_position_z_at(struct MANTA *liquid, int i)
float manta_liquid_get_snd_particle_velocity_y_at(struct MANTA *liquid, int i)
int manta_liquid_get_num_flip_particles(struct MANTA *liquid)
int manta_liquid_get_particle_res_x(struct MANTA *liquid)
float manta_liquid_get_flip_particle_position_x_at(struct MANTA *liquid, int i)
float manta_liquid_get_snd_particle_position_x_at(struct MANTA *liquid, int i)
float manta_liquid_get_snd_particle_position_y_at(struct MANTA *liquid, int i)
float manta_liquid_get_snd_particle_velocity_x_at(struct MANTA *liquid, int i)
int manta_liquid_get_particle_res_z(struct MANTA *liquid)
int manta_liquid_get_num_snd_particles(struct MANTA *liquid)
float manta_liquid_get_flip_particle_velocity_x_at(struct MANTA *liquid, int i)
static ulong state[N]
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
Definition BLI_task.hh:151
VecBase< int32_t, 2 > int2
VecBase< int32_t, 3 > int3
void BKE_particlesettings_fluid_default_settings(ParticleSettings *part)
static void dynamics_step_sph_classical_calc_density_task_cb_ex(void *__restrict userdata, const int p, const TaskParallelTLS *__restrict tls)
static void get_angular_velocity_vector(short avemode, ParticleKey *state, float vec[3])
static void sphclassical_neighbor_accum_cb(void *userdata, int index, const float co[3], float)
static float collision_point_distance_with_normal(float p[3], ParticleCollisionElement *pce, float fac, ParticleCollision *col, float *nor)
static int emit_particles(ParticleSimulationData *sim, PTCacheID *pid, float)
static void psys_sph_init(ParticleSimulationData *sim, SPHData *sphdata, blender::Map< blender::OrderedEdge, int > &r_eh)
static void particlesystem_modifiersForeachIDLink(void *user_data, Object *, ID **id_pointer, const LibraryForeachIDCallbackFlag cb_flag)
#define COLLISION_ZERO
void psys_calc_dmcache(Object *ob, Mesh *mesh_final, Mesh *mesh_original, ParticleSystem *psys)
static float collision_newton_rhapson(ParticleCollision *col, float radius, ParticleCollisionElement *pce, NRDistanceFunc distance_func)
void BKE_particle_settings_eval_reset(Depsgraph *depsgraph, ParticleSettings *particle_settings)
static void dynamics_step(ParticleSimulationData *sim, float cfra)
static ParticleSpring * sph_spring_add(ParticleSystem *psys, ParticleSpring *spring)
static ThreadRWMutex psys_bvhtree_rwlock
ParticleSystem * psys_get_target_system(Object *ob, ParticleTarget *pt)
static void collision_point_on_surface(const float p[3], ParticleCollisionElement *pce, float fac, ParticleCollision *col, float *co)
static void sphclassical_density_accum_cb(void *userdata, int index, const float co[3], float)
static const float MIN_TIMESTEP
static void psys_prepare_physics(ParticleSimulationData *sim)
static bool particles_has_bubble(short parttype)
void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func, void *userdata)
static int collision_response(ParticleSimulationData *sim, ParticleData *pa, ParticleCollision *col, BVHTreeRayHit *hit, int kill, int dynamic_rotation)
static void sph_evaluate_func(BVHTree *tree, ParticleSystem **psys, const float co[3], SPHRangeData *pfr, float interaction_radius, BVHTree_RangeQuery callback)
static float nr_distance_to_edge(float *p, float radius, ParticleCollisionElement *pce, float *)
static void update_timestep(ParticleSystem *psys, ParticleSimulationData *sim)
static void basic_integrate(ParticleSimulationData *sim, int p, float dfra, float cfra)
static void init_particle_texture(ParticleSimulationData *sim, ParticleData *pa, int p)
static float sync_timestep(ParticleSystem *psys, float t_frac)
static void save_hair(ParticleSimulationData *sim, float)
static void sph_particle_courant(SPHData *sphdata, SPHRangeData *pfr)
static void psys_sph_flush_springs(SPHData *sphdata)
static void integrate_particle(ParticleSettings *part, ParticleData *pa, float dtime, float *external_acceleration, void(*force_func)(void *forcedata, ParticleKey *state, float *force, float *impulse), void *forcedata)
static int tot_particles(ParticleSystem *psys, PTCacheID *pid)
static const float TIMESTEP_EXPANSION_FACTOR
static void bvhtree_balance_isolated(void *userdata)
float psys_get_current_display_percentage(ParticleSystem *psys, const bool use_render_params)
#define SPH_NEIGHBORS
static bool particles_has_tracer(short parttype)
void psys_count_keyed_targets(ParticleSimulationData *sim)
void psys_unique_name(Object *object, ParticleSystem *psys, const char *defname)
static void collision_interpolate_element(ParticleCollisionElement *pce, float t, float fac, ParticleCollision *col)
static bool particles_has_foam(short parttype)
void particle_system_update(Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys, const bool use_render_params)
static void dynamics_step_sph_classical_basic_integrate_task_cb_ex(void *__restrict userdata, const int p, const TaskParallelTLS *__restrict)
void psys_thread_context_init(ParticleThreadContext *ctx, ParticleSimulationData *sim)
void psys_get_pointcache_start_end(Scene *scene, ParticleSystem *psys, int *sfra, int *efra)
static void sph_spring_delete(ParticleSystem *psys, int j)
static void basic_rotate(ParticleSettings *part, ParticleData *pa, float dfra, float timestep)
static void free_unexisting_particles(ParticleSimulationData *sim)
static void sph_density_accum_cb(void *userdata, int index, const float co[3], float squared_dist)
void psys_get_birth_coords(ParticleSimulationData *sim, ParticleData *pa, ParticleKey *state, float dtime, float cfra)
static float nr_signed_distance_to_plane(float *p, float radius, ParticleCollisionElement *pce, float *nor)
void BKE_particle_system_eval_init(Depsgraph *depsgraph, Object *object)
static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
int psys_get_tot_child(Scene *scene, ParticleSystem *psys, const bool use_render_params)
static bool particles_has_flip(short parttype)
static const float TIMESTEP_EXPANSION_TOLERANCE
static void evaluate_emitter_anim(Depsgraph *depsgraph, Scene *scene, Object *ob, float cfra)
static bool particles_has_spray(short parttype)
#define ZERO_F43
static void dynamics_step_sph_ddr_task_cb_ex(DynamicStepSolverTaskData *data, const int p, SPHData *sphdata)
void psys_reset(ParticleSystem *psys, int mode)
static MDeformVert * hair_set_pinning(MDeformVert *dvert, float weight)
static void system_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
static void hair_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
static ParticleSettings * particle_settings_localize(ParticleSettings *particle_settings)
static void collision_check(ParticleSimulationData *sim, int p, float dfra, float cfra)
#define PSYS_FLUID_SPRINGS_INITIAL_SIZE
void psys_changed_type(Object *ob, ParticleSystem *psys)
void psys_sph_finalize(SPHData *sphdata)
static void set_keyed_keys(ParticleSimulationData *sim)
static void sph_springs_modify(ParticleSystem *psys, float dtime)
static float get_base_time_step(ParticleSettings *part)
static void update_courant_num(ParticleSimulationData *sim, ParticleData *pa, float dtime, SPHData *sphdata, SpinLock *spin)
static void psys_update_effectors(ParticleSimulationData *sim)
static void collision_fail(ParticleData *pa, ParticleCollision *col)
static void reset_all_particles(ParticleSimulationData *sim, float dtime, float cfra, int from)
static void basic_force_cb(void *efdata_v, ParticleKey *state, float *force, float *impulse)
static void sph_integrate(ParticleSimulationData *sim, ParticleData *pa, float dfra, SPHData *sphdata)
int psys_get_child_number(Scene *scene, ParticleSystem *psys, const bool use_render_params)
void psys_update_particle_tree(ParticleSystem *psys, float cfra)
static void sphclassical_calc_dens(ParticleData *pa, float, SPHData *sphdata)
static void sph_force_cb(void *sphdata_v, ParticleKey *state, float *force, float *)
static void psys_update_particle_bvhtree(ParticleSystem *psys, float cfra)
static int particles_are_dynamic(ParticleSystem *psys)
static int collision_sphere_to_verts(ParticleCollision *col, float radius, ParticleCollisionElement *pce, float *t)
static void particle_settings_free_local(ParticleSettings *particle_settings)
void init_particle(ParticleSimulationData *sim, ParticleData *pa)
void psys_sph_density(BVHTree *tree, SPHData *sphdata, float co[3], float vars[2])
blender::Vector< ParticleTask > psys_tasks_create(ParticleThreadContext *ctx, int startpart, int endpart)
static void particles_fluid_step(ParticleSimulationData *sim, int cfra, const bool use_render_params)
static void do_hair_dynamics(ParticleSimulationData *sim)
static float nr_distance_to_vert(float *p, float radius, ParticleCollisionElement *pce, float *)
void psys_make_temp_pointcache(Object *ob, ParticleSystem *psys)
static void sphclassical_force_cb(void *sphdata_v, ParticleKey *state, float *force, float *)
static blender::Map< blender::OrderedEdge, int > sph_springhash_build(ParticleSystem *psys)
static SPHData dynamics_step_sphdata_reduce(const SPHData &sphdata_to, const SPHData &sphdata_from)
static void psys_clear_temp_pointcache(ParticleSystem *psys)
static int collision_sphere_to_edges(ParticleCollision *col, float radius, ParticleCollisionElement *pce, float *t)
#define COLLISION_MIN_RADIUS
void psys_tasks_free(blender::Vector< ParticleTask > &tasks)
static void initialize_all_particles(ParticleSimulationData *sim)
static int hair_needs_recalc(ParticleSystem *psys)
static void update_children(ParticleSimulationData *sim, const bool use_render_params)
static int collision_sphere_to_tri(ParticleCollision *col, float radius, ParticleCollisionElement *pce, float *t)
static void collision_point_velocity(ParticleCollisionElement *pce)
void BKE_psys_collision_neartest_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
static void dynamics_step_sph_classical_integrate_task_cb_ex(void *__restrict userdata, const int p, const TaskParallelTLS *__restrict tls)
void psys_check_boid_data(ParticleSystem *psys)
#define COLLISION_INIT_STEP
void psys_thread_context_free(ParticleThreadContext *ctx)
static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, const bool use_render_params)
static void realloc_particles(ParticleSimulationData *sim, int new_totpart)
static int collision_detect(ParticleData *pa, ParticleCollision *col, BVHTreeRayHit *hit, ListBase *colliders)
static bool psys_hair_use_simulation(ParticleData *pa, float max_length)
static void hair_create_input_mesh(ParticleSimulationData *sim, int totpoint, int totedge, Mesh **r_mesh)
void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, float cfra)
void BKE_particlesystem_reset_all(Object *object)
#define COLLISION_MIN_DISTANCE
float(*)(float *p, float radius, ParticleCollisionElement *pce, float *nor) NRDistanceFunc
const char * name
#define fabsf
#define sqrtf
#define sinf
#define cosf
#define min(a, b)
Definition sort.cc:36
#define FLT_MAX
Definition stdcycles.h:14
struct ParticleSettings * part
Definition BKE_boids.h:21
struct Object * goal_ob
Definition BKE_boids.h:26
struct RNG * rng
Definition BKE_boids.h:31
float timestep
Definition BKE_boids.h:22
struct ParticleSimulationData * sim
Definition BKE_boids.h:20
float acc[3]
struct Object * ground
struct BoidData data
struct ListBase states
float bending_stiffness
Definition BKE_cloth.hh:48
float rot[3][3]
Definition BKE_cloth.hh:45
float loc[3]
Definition BKE_cloth.hh:44
struct ClothHairData * hairdata
struct PointCache * point_cache
struct ClothSimSettings * sim_parms
struct ClothCollSettings * coll_parms
struct EffectorWeights * effector_weights
ParticleSimulationData * sim
ParticleTexture ptex
ParticleData * pa
ParticleSimulationData * sim
float * ave
Definition BKE_effect.h:27
struct FluidDomainSettings * domain
Definition DNA_ID.h:414
unsigned int recalc
Definition DNA_ID.h:445
void * py_instance
Definition DNA_ID.h:518
char name[258]
Definition DNA_ID.h:432
void * link
struct LinkNode * next
void * first
struct MDeformWeight * dw
int edges_num
MeshRuntimeHandle * runtime
CustomData face_data
CustomData vert_data
CustomData fdata_legacy
int totface_legacy
int verts_num
struct ModifierData * next
void(* foreach_ID_link)(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
ListBase particlesystem
ObjectRuntimeHandle * runtime
ListBase modifiers
float scale[3]
struct Object * parent
struct ParticleSystem * psys
struct ParticleSystemModifierData * psmd_eval
struct ParticleSystem * psys_eval
struct PointCache * cache
BoidParticle * boid
ParticleKey state
ParticleKey prev_state
ParticleKey * keys
struct Collection * collision_group
struct AnimData * adt
struct BoidSettings * boids
struct EffectorWeights * effector_weights
struct SPHFluidSettings * fluid
struct Depsgraph * depsgraph
struct ParticleSystemModifierData * psmd
struct Scene * scene
struct ParticleSystem * psys
struct Object * ob
struct ListBase * colliders
unsigned int delete_flag
unsigned int particle_index[2]
struct ParticleSystem * psys
ParticleSpring * fluid_springs
ChildParticle * child
struct PTCacheEdit * edit
ParticleData * particles
struct ListBase targets
ParticleSettings * part
struct ListBase * effectors
struct ParticleSystem * next
struct PointCache * pointcache
struct BVHTree * bvhtree
struct ClothModifierData * clmd
struct Object * target_ob
struct Mesh * hair_in_mesh
struct KDTree_3d * tree
struct Object * parent
struct Mesh * hair_out_mesh
struct ParticleDrawData * pdd
struct ParticleCacheKey ** pathcache
void(* free_edit)(struct PTCacheEdit *edit)
struct Object * ob
struct ParticleTarget * next
struct CurveMapping * roughcurve
struct Material * ma
struct CurveMapping * twistcurve
struct CurveMapping * clumpcurve
struct ParticleSeam * seams
struct ParticleSimulationData sim
struct KDTree_3d * tree
struct ListBase mem_cache
Definition rand.cc:33
blender::Vector< ParticleSpring > new_springs
void(* force_cb)(void *sphdata_v, ParticleKey *state, float *force, float *impulse)
ParticleData * pa
ParticleSystem * psys[10]
void(* density_cb)(void *rangedata_v, int index, const float co[3], float squared_dist)
const blender::Map< blender::OrderedEdge, int > * eh
float element_size
float flow[3]
float mass
float hfac
const float * gravity
ParticleSystem * psys
SPHNeighbor neighbors[SPH_NEIGHBORS]
ParticleSystem * npsys
ParticleData * pa
struct PhysicsSettings physics_settings
struct ToolSettings * toolsettings
struct RenderData r
size_t userdata_chunk_size
Definition BLI_task.h:164
struct ParticleEditSettings particle
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251