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