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