Blender  V2.93
fluid.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include "MEM_guardedalloc.h"
25 
26 #include "BLI_listbase.h"
27 
28 #include "BLI_fileops.h"
29 #include "BLI_hash.h"
30 #include "BLI_math.h"
31 #include "BLI_path_util.h"
32 #include "BLI_string.h"
33 #include "BLI_task.h"
34 #include "BLI_utildefines.h"
35 
36 #include "DNA_defaults.h"
37 #include "DNA_fluid_types.h"
38 #include "DNA_modifier_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_rigidbody_types.h"
41 
42 #include "BKE_effect.h"
43 #include "BKE_fluid.h"
44 #include "BKE_global.h"
45 #include "BKE_lib_id.h"
46 #include "BKE_modifier.h"
47 #include "BKE_pointcache.h"
48 
49 #ifdef WITH_FLUID
50 
51 # include <float.h>
52 # include <math.h>
53 # include <stdio.h>
54 # include <string.h> /* memset */
55 
56 # include "DNA_customdata_types.h"
57 # include "DNA_light_types.h"
58 # include "DNA_mesh_types.h"
59 # include "DNA_meshdata_types.h"
60 # include "DNA_particle_types.h"
61 # include "DNA_scene_types.h"
62 
63 # include "BLI_kdopbvh.h"
64 # include "BLI_kdtree.h"
65 # include "BLI_threads.h"
66 # include "BLI_voxel.h"
67 
68 # include "BKE_bvhutils.h"
69 # include "BKE_collision.h"
70 # include "BKE_colortools.h"
71 # include "BKE_customdata.h"
72 # include "BKE_deform.h"
73 # include "BKE_mesh.h"
74 # include "BKE_mesh_runtime.h"
75 # include "BKE_object.h"
76 # include "BKE_particle.h"
77 # include "BKE_scene.h"
78 # include "BKE_texture.h"
79 
80 # include "DEG_depsgraph.h"
81 # include "DEG_depsgraph_query.h"
82 
83 # include "RE_texture.h"
84 
85 # include "CLG_log.h"
86 
87 # include "manta_fluid_API.h"
88 
89 #endif /* WITH_FLUID */
90 
92 #define DT_DEFAULT 0.1f
93 
95 #define PHI_MAX 9999.0f
96 
97 static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *fmd, bool need_lock);
98 
99 #ifdef WITH_FLUID
100 // #define DEBUG_PRINT
101 
102 static CLG_LogRef LOG = {"bke.fluid"};
103 
104 /* -------------------------------------------------------------------- */
108 static ThreadMutex object_update_lock = BLI_MUTEX_INITIALIZER;
109 
110 struct FluidModifierData;
111 struct Mesh;
112 struct Object;
113 struct Scene;
114 
115 # define ADD_IF_LOWER_POS(a, b) (min_ff((a) + (b), max_ff((a), (b))))
116 # define ADD_IF_LOWER_NEG(a, b) (max_ff((a) + (b), min_ff((a), (b))))
117 # define ADD_IF_LOWER(a, b) (((b) > 0) ? ADD_IF_LOWER_POS((a), (b)) : ADD_IF_LOWER_NEG((a), (b)))
118 
119 bool BKE_fluid_reallocate_fluid(FluidDomainSettings *fds, int res[3], int free_old)
120 {
121  if (free_old && fds->fluid) {
122  manta_free(fds->fluid);
123  }
124  if (!min_iii(res[0], res[1], res[2])) {
125  fds->fluid = NULL;
126  }
127  else {
128  fds->fluid = manta_init(res, fds->fmd);
129 
130  fds->res_noise[0] = res[0] * fds->noise_scale;
131  fds->res_noise[1] = res[1] * fds->noise_scale;
132  fds->res_noise[2] = res[2] * fds->noise_scale;
133  }
134 
135  return (fds->fluid != NULL);
136 }
137 
139  int o_res[3],
140  int n_res[3],
141  const int o_min[3],
142  const int n_min[3],
143  const int o_max[3],
144  int o_shift[3],
145  int n_shift[3])
146 {
147  struct MANTA *fluid_old = fds->fluid;
148  const int block_size = fds->noise_scale;
149  int new_shift[3] = {0};
150  sub_v3_v3v3_int(new_shift, n_shift, o_shift);
151 
152  /* Allocate new fluid data. */
153  BKE_fluid_reallocate_fluid(fds, n_res, 0);
154 
155  int o_total_cells = o_res[0] * o_res[1] * o_res[2];
156  int n_total_cells = n_res[0] * n_res[1] * n_res[2];
157 
158  /* Copy values from old fluid to new fluid object. */
159  if (o_total_cells > 1 && n_total_cells > 1) {
160  float *o_dens = manta_smoke_get_density(fluid_old);
161  float *o_react = manta_smoke_get_react(fluid_old);
162  float *o_flame = manta_smoke_get_flame(fluid_old);
163  float *o_fuel = manta_smoke_get_fuel(fluid_old);
164  float *o_heat = manta_smoke_get_heat(fluid_old);
165  float *o_vx = manta_get_velocity_x(fluid_old);
166  float *o_vy = manta_get_velocity_y(fluid_old);
167  float *o_vz = manta_get_velocity_z(fluid_old);
168  float *o_r = manta_smoke_get_color_r(fluid_old);
169  float *o_g = manta_smoke_get_color_g(fluid_old);
170  float *o_b = manta_smoke_get_color_b(fluid_old);
171 
172  float *n_dens = manta_smoke_get_density(fds->fluid);
173  float *n_react = manta_smoke_get_react(fds->fluid);
174  float *n_flame = manta_smoke_get_flame(fds->fluid);
175  float *n_fuel = manta_smoke_get_fuel(fds->fluid);
176  float *n_heat = manta_smoke_get_heat(fds->fluid);
177  float *n_vx = manta_get_velocity_x(fds->fluid);
178  float *n_vy = manta_get_velocity_y(fds->fluid);
179  float *n_vz = manta_get_velocity_z(fds->fluid);
180  float *n_r = manta_smoke_get_color_r(fds->fluid);
181  float *n_g = manta_smoke_get_color_g(fds->fluid);
182  float *n_b = manta_smoke_get_color_b(fds->fluid);
183 
184  /* Noise smoke fields. */
185  float *o_wt_dens = manta_noise_get_density(fluid_old);
186  float *o_wt_react = manta_noise_get_react(fluid_old);
187  float *o_wt_flame = manta_noise_get_flame(fluid_old);
188  float *o_wt_fuel = manta_noise_get_fuel(fluid_old);
189  float *o_wt_r = manta_noise_get_color_r(fluid_old);
190  float *o_wt_g = manta_noise_get_color_g(fluid_old);
191  float *o_wt_b = manta_noise_get_color_b(fluid_old);
192  float *o_wt_tcu = manta_noise_get_texture_u(fluid_old);
193  float *o_wt_tcv = manta_noise_get_texture_v(fluid_old);
194  float *o_wt_tcw = manta_noise_get_texture_w(fluid_old);
195  float *o_wt_tcu2 = manta_noise_get_texture_u2(fluid_old);
196  float *o_wt_tcv2 = manta_noise_get_texture_v2(fluid_old);
197  float *o_wt_tcw2 = manta_noise_get_texture_w2(fluid_old);
198 
199  float *n_wt_dens = manta_noise_get_density(fds->fluid);
200  float *n_wt_react = manta_noise_get_react(fds->fluid);
201  float *n_wt_flame = manta_noise_get_flame(fds->fluid);
202  float *n_wt_fuel = manta_noise_get_fuel(fds->fluid);
203  float *n_wt_r = manta_noise_get_color_r(fds->fluid);
204  float *n_wt_g = manta_noise_get_color_g(fds->fluid);
205  float *n_wt_b = manta_noise_get_color_b(fds->fluid);
206  float *n_wt_tcu = manta_noise_get_texture_u(fds->fluid);
207  float *n_wt_tcv = manta_noise_get_texture_v(fds->fluid);
208  float *n_wt_tcw = manta_noise_get_texture_w(fds->fluid);
209  float *n_wt_tcu2 = manta_noise_get_texture_u2(fds->fluid);
210  float *n_wt_tcv2 = manta_noise_get_texture_v2(fds->fluid);
211  float *n_wt_tcw2 = manta_noise_get_texture_w2(fds->fluid);
212 
213  int wt_res_old[3];
214  manta_noise_get_res(fluid_old, wt_res_old);
215 
216  for (int z = o_min[2]; z < o_max[2]; z++) {
217  for (int y = o_min[1]; y < o_max[1]; y++) {
218  for (int x = o_min[0]; x < o_max[0]; x++) {
219  /* old grid index */
220  int xo = x - o_min[0];
221  int yo = y - o_min[1];
222  int zo = z - o_min[2];
223  int index_old = manta_get_index(xo, o_res[0], yo, o_res[1], zo);
224  /* new grid index */
225  int xn = x - n_min[0] - new_shift[0];
226  int yn = y - n_min[1] - new_shift[1];
227  int zn = z - n_min[2] - new_shift[2];
228  int index_new = manta_get_index(xn, n_res[0], yn, n_res[1], zn);
229 
230  /* Skip if outside new domain. */
231  if (xn < 0 || xn >= n_res[0] || yn < 0 || yn >= n_res[1] || zn < 0 || zn >= n_res[2]) {
232  continue;
233  }
234 # if 0
235  /* Note (sebbas):
236  * Disabling this "skip section" as not copying borders results in weird cut-off effects.
237  * It is possible that this cutting off is the reason for line effects as seen in T74559.
238  * Since domain borders will be handled on the simulation side anyways,
239  * copying border values should not be an issue. */
240 
241  /* boundary cells will be skipped when copying data */
242  int bwidth = fds->boundary_width;
243 
244  /* Skip if trying to copy from old boundary cell. */
245  if (xo < bwidth || yo < bwidth || zo < bwidth || xo >= o_res[0] - bwidth ||
246  yo >= o_res[1] - bwidth || zo >= o_res[2] - bwidth) {
247  continue;
248  }
249  /* Skip if trying to copy into new boundary cell. */
250  if (xn < bwidth || yn < bwidth || zn < bwidth || xn >= n_res[0] - bwidth ||
251  yn >= n_res[1] - bwidth || zn >= n_res[2] - bwidth) {
252  continue;
253  }
254 # endif
255 
256  /* copy data */
257  if (fds->flags & FLUID_DOMAIN_USE_NOISE) {
258  int i, j, k;
259  /* old grid index */
260  int xx_o = xo * block_size;
261  int yy_o = yo * block_size;
262  int zz_o = zo * block_size;
263  /* new grid index */
264  int xx_n = xn * block_size;
265  int yy_n = yn * block_size;
266  int zz_n = zn * block_size;
267 
268  /* insert old texture values into new texture grids */
269  n_wt_tcu[index_new] = o_wt_tcu[index_old];
270  n_wt_tcv[index_new] = o_wt_tcv[index_old];
271  n_wt_tcw[index_new] = o_wt_tcw[index_old];
272 
273  n_wt_tcu2[index_new] = o_wt_tcu2[index_old];
274  n_wt_tcv2[index_new] = o_wt_tcv2[index_old];
275  n_wt_tcw2[index_new] = o_wt_tcw2[index_old];
276 
277  for (i = 0; i < block_size; i++) {
278  for (j = 0; j < block_size; j++) {
279  for (k = 0; k < block_size; k++) {
280  int big_index_old = manta_get_index(
281  xx_o + i, wt_res_old[0], yy_o + j, wt_res_old[1], zz_o + k);
282  int big_index_new = manta_get_index(
283  xx_n + i, fds->res_noise[0], yy_n + j, fds->res_noise[1], zz_n + k);
284  /* copy data */
285  n_wt_dens[big_index_new] = o_wt_dens[big_index_old];
286  if (n_wt_flame && o_wt_flame) {
287  n_wt_flame[big_index_new] = o_wt_flame[big_index_old];
288  n_wt_fuel[big_index_new] = o_wt_fuel[big_index_old];
289  n_wt_react[big_index_new] = o_wt_react[big_index_old];
290  }
291  if (n_wt_r && o_wt_r) {
292  n_wt_r[big_index_new] = o_wt_r[big_index_old];
293  n_wt_g[big_index_new] = o_wt_g[big_index_old];
294  n_wt_b[big_index_new] = o_wt_b[big_index_old];
295  }
296  }
297  }
298  }
299  }
300 
301  n_dens[index_new] = o_dens[index_old];
302  /* heat */
303  if (n_heat && o_heat) {
304  n_heat[index_new] = o_heat[index_old];
305  }
306  /* fuel */
307  if (n_fuel && o_fuel) {
308  n_flame[index_new] = o_flame[index_old];
309  n_fuel[index_new] = o_fuel[index_old];
310  n_react[index_new] = o_react[index_old];
311  }
312  /* color */
313  if (o_r && n_r) {
314  n_r[index_new] = o_r[index_old];
315  n_g[index_new] = o_g[index_old];
316  n_b[index_new] = o_b[index_old];
317  }
318  n_vx[index_new] = o_vx[index_old];
319  n_vy[index_new] = o_vy[index_old];
320  n_vz[index_new] = o_vz[index_old];
321  }
322  }
323  }
324  }
325  manta_free(fluid_old);
326 }
327 
329 {
333  BKE_fluid_cache_free(fds, ob, cache_map);
334 }
335 
336 void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
337 {
338  char temp_dir[FILE_MAX];
339  int flags = fds->cache_flag;
340  const char *relbase = BKE_modifier_path_relbase_from_global(ob);
341 
342  if (cache_map & FLUID_DOMAIN_OUTDATED_DATA) {
344  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
345  BLI_path_abs(temp_dir, relbase);
346  if (BLI_exists(temp_dir)) {
347  BLI_delete(temp_dir, true, true);
348  }
349  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
350  BLI_path_abs(temp_dir, relbase);
351  if (BLI_exists(temp_dir)) {
352  BLI_delete(temp_dir, true, true);
353  }
354  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
355  BLI_path_abs(temp_dir, relbase);
356  if (BLI_exists(temp_dir)) {
357  BLI_delete(temp_dir, true, true);
358  }
359  fds->cache_frame_pause_data = 0;
360  }
361  if (cache_map & FLUID_DOMAIN_OUTDATED_NOISE) {
363  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
364  BLI_path_abs(temp_dir, relbase);
365  if (BLI_exists(temp_dir)) {
366  BLI_delete(temp_dir, true, true);
367  }
368  fds->cache_frame_pause_noise = 0;
369  }
370  if (cache_map & FLUID_DOMAIN_OUTDATED_MESH) {
372  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
373  BLI_path_abs(temp_dir, relbase);
374  if (BLI_exists(temp_dir)) {
375  BLI_delete(temp_dir, true, true);
376  }
377  fds->cache_frame_pause_mesh = 0;
378  }
379  if (cache_map & FLUID_DOMAIN_OUTDATED_PARTICLES) {
383  temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
384  BLI_path_abs(temp_dir, relbase);
385  if (BLI_exists(temp_dir)) {
386  BLI_delete(temp_dir, true, true);
387  }
389  }
390  if (cache_map & FLUID_DOMAIN_OUTDATED_GUIDE) {
392  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL);
393  BLI_path_abs(temp_dir, relbase);
394  if (BLI_exists(temp_dir)) {
395  BLI_delete(temp_dir, true, true);
396  }
397  fds->cache_frame_pause_guide = 0;
398  }
399  fds->cache_flag = flags;
400 }
401 
402 /* convert global position to domain cell space */
403 static void manta_pos_to_cell(FluidDomainSettings *fds, float pos[3])
404 {
405  mul_m4_v3(fds->imat, pos);
406  sub_v3_v3(pos, fds->p0);
407  pos[0] *= 1.0f / fds->cell_size[0];
408  pos[1] *= 1.0f / fds->cell_size[1];
409  pos[2] *= 1.0f / fds->cell_size[2];
410 }
411 
412 /* Set domain transformations and base resolution from object mesh. */
413 static void manta_set_domain_from_mesh(FluidDomainSettings *fds,
414  Object *ob,
415  Mesh *me,
416  bool init_resolution)
417 {
418  size_t i;
419  float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
420  float size[3];
421  MVert *verts = me->mvert;
422  float scale = 0.0;
423  int res;
424 
425  res = fds->maxres;
426 
427  /* Set minimum and maximum coordinates of BB. */
428  for (i = 0; i < me->totvert; i++) {
429  minmax_v3v3_v3(min, max, verts[i].co);
430  }
431 
432  /* Set domain bounds. */
433  copy_v3_v3(fds->p0, min);
434  copy_v3_v3(fds->p1, max);
435  fds->dx = 1.0f / res;
436 
437  /* Calculate domain dimensions. */
438  sub_v3_v3v3(size, max, min);
439  if (init_resolution) {
440  zero_v3_int(fds->base_res);
441  copy_v3_v3(fds->cell_size, size);
442  }
443  /* Apply object scale. */
444  for (i = 0; i < 3; i++) {
445  size[i] = fabsf(size[i] * ob->scale[i]);
446  }
447  copy_v3_v3(fds->global_size, size);
448  copy_v3_v3(fds->dp0, min);
449 
450  invert_m4_m4(fds->imat, ob->obmat);
451 
452  /* Prevent crash when initializing a plane as domain. */
453  if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) ||
454  (size[2] < FLT_EPSILON)) {
455  return;
456  }
457 
458  /* Define grid resolutions from longest domain side. */
459  if (size[0] >= MAX2(size[1], size[2])) {
460  scale = res / size[0];
461  fds->scale = size[0] / fabsf(ob->scale[0]);
462  fds->base_res[0] = res;
463  fds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
464  fds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
465  }
466  else if (size[1] >= MAX2(size[0], size[2])) {
467  scale = res / size[1];
468  fds->scale = size[1] / fabsf(ob->scale[1]);
469  fds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
470  fds->base_res[1] = res;
471  fds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
472  }
473  else {
474  scale = res / size[2];
475  fds->scale = size[2] / fabsf(ob->scale[2]);
476  fds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
477  fds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
478  fds->base_res[2] = res;
479  }
480 
481  /* Set cell size. */
482  fds->cell_size[0] /= (float)fds->base_res[0];
483  fds->cell_size[1] /= (float)fds->base_res[1];
484  fds->cell_size[2] /= (float)fds->base_res[2];
485 }
486 
487 static void update_final_gravity(FluidDomainSettings *fds, Scene *scene)
488 {
491  }
492  else {
493  copy_v3_v3(fds->gravity_final, fds->gravity);
494  }
496 }
497 
498 static bool BKE_fluid_modifier_init(
500 {
501  int scene_framenr = (int)DEG_get_ctime(depsgraph);
502 
503  if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain && !fmd->domain->fluid) {
504  FluidDomainSettings *fds = fmd->domain;
505  int res[3];
506  /* Set domain dimensions from mesh. */
507  manta_set_domain_from_mesh(fds, ob, me, true);
508  /* Set domain gravity, use global gravity if enabled. */
509  update_final_gravity(fds, scene);
510  /* Reset domain values. */
511  zero_v3_int(fds->shift);
512  zero_v3(fds->shift_f);
513  add_v3_fl(fds->shift_f, 0.5f);
514  zero_v3(fds->prev_loc);
515  mul_m4_v3(ob->obmat, fds->prev_loc);
516  copy_m4_m4(fds->obmat, ob->obmat);
517 
518  /* Set resolutions. */
519  if (fmd->domain->type == FLUID_DOMAIN_TYPE_GAS &&
521  res[0] = res[1] = res[2] = 1; /* Use minimum res for adaptive init. */
522  }
523  else {
524  copy_v3_v3_int(res, fds->base_res);
525  }
526  copy_v3_v3_int(fds->res, res);
527  fds->total_cells = fds->res[0] * fds->res[1] * fds->res[2];
528  fds->res_min[0] = fds->res_min[1] = fds->res_min[2] = 0;
529  copy_v3_v3_int(fds->res_max, res);
530 
531  /* Set time, frame length = 0.1 is at 25fps. */
532  float fps = scene->r.frs_sec / scene->r.frs_sec_base;
533  fds->frame_length = DT_DEFAULT * (25.0f / fps) * fds->time_scale;
534  /* Initially dt is equal to frame length (dt can change with adaptive-time stepping though). */
535  fds->dt = fds->frame_length;
536  fds->time_per_frame = 0;
537 
538  fmd->time = scene_framenr;
539 
540  /* Allocate fluid. */
541  return BKE_fluid_reallocate_fluid(fds, fds->res, 0);
542  }
543  if (fmd->type & MOD_FLUID_TYPE_FLOW) {
544  if (!fmd->flow) {
546  }
547  fmd->time = scene_framenr;
548  return true;
549  }
550  if (fmd->type & MOD_FLUID_TYPE_EFFEC) {
551  if (!fmd->effector) {
553  }
554  fmd->time = scene_framenr;
555  return true;
556  }
557  return false;
558 }
559 
560 // forward declaration
561 static void manta_smoke_calc_transparency(FluidDomainSettings *fds, ViewLayer *view_layer);
562 static float calc_voxel_transp(
563  float *result, const float *input, int res[3], int *pixel, float *t_ray, float correct);
564 static void update_distances(int index,
565  float *distance_map,
566  BVHTreeFromMesh *tree_data,
567  const float ray_start[3],
568  float surface_thickness,
569  bool use_plane_init);
570 
571 static int get_light(ViewLayer *view_layer, float *light)
572 {
573  Base *base_tmp = NULL;
574  int found_light = 0;
575 
576  /* Try to find a lamp, preferably local. */
577  for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) {
578  if (base_tmp->object->type == OB_LAMP) {
579  Light *la = base_tmp->object->data;
580 
581  if (la->type == LA_LOCAL) {
582  copy_v3_v3(light, base_tmp->object->obmat[3]);
583  return 1;
584  }
585  if (!found_light) {
586  copy_v3_v3(light, base_tmp->object->obmat[3]);
587  found_light = 1;
588  }
589  }
590  }
591 
592  return found_light;
593 }
594 
595 static void clamp_bounds_in_domain(FluidDomainSettings *fds,
596  int min[3],
597  int max[3],
598  const float *min_vel,
599  const float *max_vel,
600  int margin,
601  float dt)
602 {
603  for (int i = 0; i < 3; i++) {
604  int adapt = (fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) ? fds->adapt_res : 0;
605  /* Add some margin. */
606  min[i] -= margin;
607  max[i] += margin;
608 
609  /* Adapt to velocity. */
610  if (min_vel && min_vel[i] < 0.0f) {
611  min[i] += (int)floor(min_vel[i] * dt);
612  }
613  if (max_vel && max_vel[i] > 0.0f) {
614  max[i] += (int)ceil(max_vel[i] * dt);
615  }
616 
617  /* Clamp within domain max size. */
618  CLAMP(min[i], -adapt, fds->base_res[i] + adapt);
619  CLAMP(max[i], -adapt, fds->base_res[i] + adapt);
620  }
621 }
622 
623 static bool is_static_object(Object *ob)
624 {
625  /* Check if the object has modifiers that might make the object "dynamic". */
626  VirtualModifierData virtualModifierData;
627  ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
628  for (; md; md = md->next) {
629  if (ELEM(md->type,
637  return false;
638  }
639  }
640 
641  /* Active rigid body objects considered to be dynamic fluid objects. */
643  return false;
644  }
645 
646  /* Finally, check if the object has animation data. If so, it is considered dynamic. */
647  return !BKE_object_moves_in_time(ob, true);
648 }
649 
652 /* -------------------------------------------------------------------- */
656 typedef struct FluidObjectBB {
657  float *influence;
658  float *velocity;
659  float *distances;
660  float *numobjs;
661  int min[3], max[3], res[3];
662  int hmin[3], hmax[3], hres[3];
663  int total_cells, valid;
664 } FluidObjectBB;
665 
666 static void bb_boundInsert(FluidObjectBB *bb, const float point[3])
667 {
668  int i = 0;
669  if (!bb->valid) {
670  for (; i < 3; i++) {
671  bb->min[i] = (int)floor(point[i]);
672  bb->max[i] = (int)ceil(point[i]);
673  }
674  bb->valid = 1;
675  }
676  else {
677  for (; i < 3; i++) {
678  if (point[i] < bb->min[i]) {
679  bb->min[i] = (int)floor(point[i]);
680  }
681  if (point[i] > bb->max[i]) {
682  bb->max[i] = (int)ceil(point[i]);
683  }
684  }
685  }
686 }
687 
688 static void bb_allocateData(FluidObjectBB *bb, bool use_velocity, bool use_influence)
689 {
690  int i, res[3];
691 
692  for (i = 0; i < 3; i++) {
693  res[i] = bb->max[i] - bb->min[i];
694  if (res[i] <= 0) {
695  return;
696  }
697  }
698  bb->total_cells = res[0] * res[1] * res[2];
699  copy_v3_v3_int(bb->res, res);
700 
701  bb->numobjs = MEM_calloc_arrayN(bb->total_cells, sizeof(float), "fluid_bb_numobjs");
702  if (use_influence) {
703  bb->influence = MEM_calloc_arrayN(bb->total_cells, sizeof(float), "fluid_bb_influence");
704  }
705  if (use_velocity) {
706  bb->velocity = MEM_calloc_arrayN(bb->total_cells, sizeof(float[3]), "fluid_bb_velocity");
707  }
708 
709  bb->distances = MEM_malloc_arrayN(bb->total_cells, sizeof(float), "fluid_bb_distances");
710  copy_vn_fl(bb->distances, bb->total_cells, FLT_MAX);
711 
712  bb->valid = true;
713 }
714 
715 static void bb_freeData(FluidObjectBB *bb)
716 {
717  if (bb->numobjs) {
718  MEM_freeN(bb->numobjs);
719  }
720  if (bb->influence) {
721  MEM_freeN(bb->influence);
722  }
723  if (bb->velocity) {
724  MEM_freeN(bb->velocity);
725  }
726  if (bb->distances) {
727  MEM_freeN(bb->distances);
728  }
729 }
730 
731 static void bb_combineMaps(FluidObjectBB *output,
732  FluidObjectBB *bb2,
733  int additive,
734  float sample_size)
735 {
736  int i, x, y, z;
737 
738  /* Copyfill input 1 struct and clear output for new allocation. */
739  FluidObjectBB bb1;
740  memcpy(&bb1, output, sizeof(FluidObjectBB));
741  memset(output, 0, sizeof(FluidObjectBB));
742 
743  for (i = 0; i < 3; i++) {
744  if (bb1.valid) {
745  output->min[i] = MIN2(bb1.min[i], bb2->min[i]);
746  output->max[i] = MAX2(bb1.max[i], bb2->max[i]);
747  }
748  else {
749  output->min[i] = bb2->min[i];
750  output->max[i] = bb2->max[i];
751  }
752  }
753  /* Allocate output map. */
754  bb_allocateData(output, (bb1.velocity || bb2->velocity), (bb1.influence || bb2->influence));
755 
756  /* Low through bounding box */
757  for (x = output->min[0]; x < output->max[0]; x++) {
758  for (y = output->min[1]; y < output->max[1]; y++) {
759  for (z = output->min[2]; z < output->max[2]; z++) {
760  int index_out = manta_get_index(x - output->min[0],
761  output->res[0],
762  y - output->min[1],
763  output->res[1],
764  z - output->min[2]);
765 
766  /* Initialize with first input if in range. */
767  if (x >= bb1.min[0] && x < bb1.max[0] && y >= bb1.min[1] && y < bb1.max[1] &&
768  z >= bb1.min[2] && z < bb1.max[2]) {
769  int index_in = manta_get_index(
770  x - bb1.min[0], bb1.res[0], y - bb1.min[1], bb1.res[1], z - bb1.min[2]);
771 
772  /* Values. */
773  output->numobjs[index_out] = bb1.numobjs[index_in];
774  if (output->influence && bb1.influence) {
775  output->influence[index_out] = bb1.influence[index_in];
776  }
777  output->distances[index_out] = bb1.distances[index_in];
778  if (output->velocity && bb1.velocity) {
779  copy_v3_v3(&output->velocity[index_out * 3], &bb1.velocity[index_in * 3]);
780  }
781  }
782 
783  /* Apply second input if in range. */
784  if (x >= bb2->min[0] && x < bb2->max[0] && y >= bb2->min[1] && y < bb2->max[1] &&
785  z >= bb2->min[2] && z < bb2->max[2]) {
786  int index_in = manta_get_index(
787  x - bb2->min[0], bb2->res[0], y - bb2->min[1], bb2->res[1], z - bb2->min[2]);
788 
789  /* Values. */
790  output->numobjs[index_out] = MAX2(bb2->numobjs[index_in], output->numobjs[index_out]);
791  if (output->influence && bb2->influence) {
792  if (additive) {
793  output->influence[index_out] += bb2->influence[index_in] * sample_size;
794  }
795  else {
796  output->influence[index_out] = MAX2(bb2->influence[index_in],
797  output->influence[index_out]);
798  }
799  }
800  output->distances[index_out] = MIN2(bb2->distances[index_in],
801  output->distances[index_out]);
802  if (output->velocity && bb2->velocity) {
803  /* Last sample replaces the velocity. */
804  output->velocity[index_out * 3] = ADD_IF_LOWER(output->velocity[index_out * 3],
805  bb2->velocity[index_in * 3]);
806  output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1],
807  bb2->velocity[index_in * 3 + 1]);
808  output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2],
809  bb2->velocity[index_in * 3 + 2]);
810  }
811  }
812  } /* Low res loop. */
813  }
814  }
815 
816  /* Free original data. */
817  bb_freeData(&bb1);
818 }
819 
822 /* -------------------------------------------------------------------- */
826 BLI_INLINE void apply_effector_fields(FluidEffectorSettings *UNUSED(fes),
827  int index,
828  float src_distance_value,
829  float *dest_phi_in,
830  float src_numobjs_value,
831  float *dest_numobjs,
832  float const src_vel_value[3],
833  float *dest_vel_x,
834  float *dest_vel_y,
835  float *dest_vel_z)
836 {
837  /* Ensure that distance value is "joined" into the levelset. */
838  if (dest_phi_in) {
839  dest_phi_in[index] = MIN2(src_distance_value, dest_phi_in[index]);
840  }
841 
842  /* Accumulate effector object count (important once effector object overlap). */
843  if (dest_numobjs && src_numobjs_value > 0) {
844  dest_numobjs[index] += 1;
845  }
846 
847  /* Accumulate effector velocities for each cell. */
848  if (dest_vel_x && src_numobjs_value > 0) {
849  dest_vel_x[index] += src_vel_value[0];
850  dest_vel_y[index] += src_vel_value[1];
851  dest_vel_z[index] += src_vel_value[2];
852  }
853 }
854 
856  const MVert *mvert,
857  const MLoop *mloop,
858  const MLoopTri *mlooptri,
859  float *velocity_map,
860  int index,
861  BVHTreeFromMesh *tree_data,
862  const float ray_start[3],
863  const float *vert_vel,
864  bool has_velocity)
865 {
866  BVHTreeNearest nearest = {0};
867  nearest.index = -1;
868 
869  /* Distance between two opposing vertices in a unit cube.
870  * I.e. the unit cube diagonal or sqrt(3).
871  * This value is our nearest neighbor search distance. */
872  const float surface_distance = 1.732;
873  nearest.dist_sq = surface_distance * surface_distance; /* find_nearest uses squared distance */
874 
875  /* Find the nearest point on the mesh. */
876  if (has_velocity &&
878  tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) {
879  float weights[3];
880  int v1, v2, v3, f_index = nearest.index;
881 
882  /* Calculate barycentric weights for nearest point. */
883  v1 = mloop[mlooptri[f_index].tri[0]].v;
884  v2 = mloop[mlooptri[f_index].tri[1]].v;
885  v3 = mloop[mlooptri[f_index].tri[2]].v;
886  interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
887 
888  /* Apply object velocity. */
889  float hit_vel[3];
890  interp_v3_v3v3v3(hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights);
891 
892  /* Guiding has additional velocity multiplier */
893  if (fes->type == FLUID_EFFECTOR_TYPE_GUIDE) {
894  mul_v3_fl(hit_vel, fes->vel_multi);
895 
896  /* Absolute representation of new object velocity. */
897  float abs_hit_vel[3];
898  copy_v3_v3(abs_hit_vel, hit_vel);
899  abs_v3(abs_hit_vel);
900 
901  /* Absolute representation of current object velocity. */
902  float abs_vel[3];
903  copy_v3_v3(abs_vel, &velocity_map[index * 3]);
904  abs_v3(abs_vel);
905 
906  switch (fes->guide_mode) {
908  velocity_map[index * 3] = (velocity_map[index * 3] + hit_vel[0]) * 0.5f;
909  velocity_map[index * 3 + 1] = (velocity_map[index * 3 + 1] + hit_vel[1]) * 0.5f;
910  velocity_map[index * 3 + 2] = (velocity_map[index * 3 + 2] + hit_vel[2]) * 0.5f;
911  break;
913  velocity_map[index * 3] = hit_vel[0];
914  velocity_map[index * 3 + 1] = hit_vel[1];
915  velocity_map[index * 3 + 2] = hit_vel[2];
916  break;
918  velocity_map[index * 3] = MIN2(abs_hit_vel[0], abs_vel[0]);
919  velocity_map[index * 3 + 1] = MIN2(abs_hit_vel[1], abs_vel[1]);
920  velocity_map[index * 3 + 2] = MIN2(abs_hit_vel[2], abs_vel[2]);
921  break;
923  default:
924  velocity_map[index * 3] = MAX2(abs_hit_vel[0], abs_vel[0]);
925  velocity_map[index * 3 + 1] = MAX2(abs_hit_vel[1], abs_vel[1]);
926  velocity_map[index * 3 + 2] = MAX2(abs_hit_vel[2], abs_vel[2]);
927  break;
928  }
929  }
930  else if (fes->type == FLUID_EFFECTOR_TYPE_COLLISION) {
931  velocity_map[index * 3] = hit_vel[0];
932  velocity_map[index * 3 + 1] = hit_vel[1];
933  velocity_map[index * 3 + 2] = hit_vel[2];
934 # ifdef DEBUG_PRINT
935  /* Debugging: Print object velocities. */
936  printf("setting effector object vel: [%f, %f, %f]\n", hit_vel[0], hit_vel[1], hit_vel[2]);
937 # endif
938  }
939  else {
940  /* Should never reach this block. */
942  }
943  }
944  else {
945  /* Clear velocities at cells that are not moving. */
946  copy_v3_fl(velocity_map, 0.0);
947  }
948 }
949 
950 typedef struct ObstaclesFromDMData {
952 
953  const MVert *mvert;
954  const MLoop *mloop;
955  const MLoopTri *mlooptri;
956 
958  FluidObjectBB *bb;
959 
960  bool has_velocity;
961  float *vert_vel;
962  int *min, *max, *res;
963 } ObstaclesFromDMData;
964 
965 static void obstacles_from_mesh_task_cb(void *__restrict userdata,
966  const int z,
967  const TaskParallelTLS *__restrict UNUSED(tls))
968 {
969  ObstaclesFromDMData *data = userdata;
970  FluidObjectBB *bb = data->bb;
971 
972  for (int x = data->min[0]; x < data->max[0]; x++) {
973  for (int y = data->min[1]; y < data->max[1]; y++) {
974  const int index = manta_get_index(
975  x - bb->min[0], bb->res[0], y - bb->min[1], bb->res[1], z - bb->min[2]);
976  const float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f};
977 
978  /* Calculate levelset values from meshes. Result in bb->distances. */
979  update_distances(index,
980  bb->distances,
981  data->tree,
982  ray_start,
983  data->fes->surface_distance,
984  data->fes->flags & FLUID_EFFECTOR_USE_PLANE_INIT);
985 
986  /* Calculate object velocities. Result in bb->velocity. */
987  update_velocities(data->fes,
988  data->mvert,
989  data->mloop,
990  data->mlooptri,
991  bb->velocity,
992  index,
993  data->tree,
994  ray_start,
995  data->vert_vel,
996  data->has_velocity);
997 
998  /* Increase obstacle count inside of moving obstacles. */
999  if (bb->distances[index] < 0) {
1000  bb->numobjs[index]++;
1001  }
1002  }
1003  }
1004 }
1005 
1006 static void obstacles_from_mesh(Object *coll_ob,
1007  FluidDomainSettings *fds,
1008  FluidEffectorSettings *fes,
1009  FluidObjectBB *bb,
1010  float dt)
1011 {
1012  if (fes->mesh) {
1013  Mesh *me = NULL;
1014  MVert *mvert = NULL;
1015  const MLoopTri *looptri;
1016  const MLoop *mloop;
1017  BVHTreeFromMesh tree_data = {NULL};
1018  int numverts, i;
1019 
1020  float *vert_vel = NULL;
1021  bool has_velocity = false;
1022 
1023  me = BKE_mesh_copy_for_eval(fes->mesh, true);
1024 
1025  int min[3], max[3], res[3];
1026 
1027  /* Duplicate vertices to modify. */
1028  if (me->mvert) {
1029  me->mvert = MEM_dupallocN(me->mvert);
1030  CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
1031  }
1032 
1034  mvert = me->mvert;
1035  mloop = me->mloop;
1036  looptri = BKE_mesh_runtime_looptri_ensure(me);
1037  numverts = me->totvert;
1038 
1039  /* TODO(sebbas): Make initialization of vertex velocities optional? */
1040  {
1041  vert_vel = MEM_callocN(sizeof(float[3]) * numverts, "manta_obs_velocity");
1042 
1043  if (fes->numverts != numverts || !fes->verts_old) {
1044  if (fes->verts_old) {
1045  MEM_freeN(fes->verts_old);
1046  }
1047 
1048  fes->verts_old = MEM_callocN(sizeof(float[3]) * numverts, "manta_obs_verts_old");
1049  fes->numverts = numverts;
1050  }
1051  else {
1052  has_velocity = true;
1053  }
1054  }
1055 
1056  /* Transform mesh vertices to domain grid space for fast lookups */
1057  for (i = 0; i < numverts; i++) {
1058  float n[3];
1059  float co[3];
1060 
1061  /* Vertex position. */
1062  mul_m4_v3(coll_ob->obmat, mvert[i].co);
1063  manta_pos_to_cell(fds, mvert[i].co);
1064 
1065  /* Vertex normal. */
1066  normal_short_to_float_v3(n, mvert[i].no);
1067  mul_mat3_m4_v3(coll_ob->obmat, n);
1068  mul_mat3_m4_v3(fds->imat, n);
1069  normalize_v3(n);
1070  normal_float_to_short_v3(mvert[i].no, n);
1071 
1072  /* Vertex velocity. */
1073  add_v3fl_v3fl_v3i(co, mvert[i].co, fds->shift);
1074  if (has_velocity) {
1075  sub_v3_v3v3(&vert_vel[i * 3], co, &fes->verts_old[i * 3]);
1076  mul_v3_fl(&vert_vel[i * 3], 1.0f / dt);
1077  }
1078  copy_v3_v3(&fes->verts_old[i * 3], co);
1079 
1080  /* Calculate emission map bounds. */
1081  bb_boundInsert(bb, mvert[i].co);
1082  }
1083 
1084  /* Set emission map.
1085  * Use 3 cell diagonals as margin (3 * 1.732 = 5.196). */
1086  int bounds_margin = (int)ceil(5.196);
1087  clamp_bounds_in_domain(fds, bb->min, bb->max, NULL, NULL, bounds_margin, dt);
1088  bb_allocateData(bb, true, false);
1089 
1090  /* Setup loop bounds. */
1091  for (i = 0; i < 3; i++) {
1092  min[i] = bb->min[i];
1093  max[i] = bb->max[i];
1094  res[i] = bb->res[i];
1095  }
1096 
1097  /* Skip effector sampling loop if object has disabled effector. */
1098  bool use_effector = fes->flags & FLUID_EFFECTOR_USE_EFFEC;
1099  if (use_effector && BKE_bvhtree_from_mesh_get(&tree_data, me, BVHTREE_FROM_LOOPTRI, 4)) {
1100 
1101  ObstaclesFromDMData data = {
1102  .fes = fes,
1103  .mvert = mvert,
1104  .mloop = mloop,
1105  .mlooptri = looptri,
1106  .tree = &tree_data,
1107  .bb = bb,
1108  .has_velocity = has_velocity,
1109  .vert_vel = vert_vel,
1110  .min = min,
1111  .max = max,
1112  .res = res,
1113  };
1114 
1115  TaskParallelSettings settings;
1117  settings.min_iter_per_thread = 2;
1118  BLI_task_parallel_range(min[2], max[2], &data, obstacles_from_mesh_task_cb, &settings);
1119  }
1120  /* Free bvh tree. */
1121  free_bvhtree_from_mesh(&tree_data);
1122 
1123  if (vert_vel) {
1124  MEM_freeN(vert_vel);
1125  }
1126  if (me->mvert) {
1127  MEM_freeN(me->mvert);
1128  }
1129  BKE_id_free(NULL, me);
1130  }
1131 }
1132 
1133 static void ensure_obstaclefields(FluidDomainSettings *fds)
1134 {
1136  manta_ensure_obstacle(fds->fluid, fds->fmd);
1137  }
1139  manta_ensure_guiding(fds->fluid, fds->fmd);
1140  }
1141  manta_update_pointers(fds->fluid, fds->fmd, false);
1142 }
1143 
1144 static void update_obstacleflags(FluidDomainSettings *fds,
1145  Object **coll_ob_array,
1146  int coll_ob_array_len)
1147 {
1148  int active_fields = fds->active_fields;
1149  uint coll_index;
1150 
1151  /* First, remove all flags that we want to update. */
1153  active_fields &= ~prev_flags;
1154 
1155  /* Monitor active fields based on flow settings */
1156  for (coll_index = 0; coll_index < coll_ob_array_len; coll_index++) {
1157  Object *coll_ob = coll_ob_array[coll_index];
1160 
1161  /* Sanity check. */
1162  if (!fmd2) {
1163  continue;
1164  }
1165 
1166  if ((fmd2->type & MOD_FLUID_TYPE_EFFEC) && fmd2->effector) {
1167  FluidEffectorSettings *fes = fmd2->effector;
1168  if (!fes) {
1169  break;
1170  }
1171  if (fes->flags & FLUID_EFFECTOR_NEEDS_UPDATE) {
1174  }
1175  if (fes->type == FLUID_EFFECTOR_TYPE_COLLISION) {
1176  active_fields |= FLUID_DOMAIN_ACTIVE_OBSTACLE;
1177  }
1178  if (fes->type == FLUID_EFFECTOR_TYPE_GUIDE) {
1179  active_fields |= FLUID_DOMAIN_ACTIVE_GUIDE;
1180  }
1181  }
1182  }
1183  fds->active_fields = active_fields;
1184 }
1185 
1186 static bool escape_effectorobject(Object *flowobj,
1187  FluidDomainSettings *fds,
1189  int frame)
1190 {
1191  bool is_static = is_static_object(flowobj);
1192 
1193  bool is_resume = (fds->cache_frame_pause_data == frame);
1194  bool is_adaptive = (fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN);
1195  bool is_first_frame = (frame == fds->cache_frame_start);
1196 
1197  /* Cannot use static mode with adaptive domain.
1198  * The adaptive domain might expand and only later discover the static object. */
1199  if (is_adaptive) {
1200  is_static = false;
1201  }
1202  /* Skip static effector objects after initial frame. */
1203  if (is_static && !is_first_frame && !is_resume) {
1204  return true;
1205  }
1206  return false;
1207 }
1208 
1209 static void compute_obstaclesemission(Scene *scene,
1210  FluidObjectBB *bb_maps,
1211  struct Depsgraph *depsgraph,
1212  float dt,
1213  Object **effecobjs,
1214  int frame,
1215  float frame_length,
1216  FluidDomainSettings *fds,
1217  uint numeffecobjs,
1218  float time_per_frame)
1219 {
1220  bool is_first_frame = (frame == fds->cache_frame_start);
1221 
1222  /* Prepare effector maps. */
1223  for (int effec_index = 0; effec_index < numeffecobjs; effec_index++) {
1224  Object *effecobj = effecobjs[effec_index];
1227 
1228  /* Sanity check. */
1229  if (!fmd2) {
1230  continue;
1231  }
1232 
1233  /* Check for initialized effector object. */
1234  if ((fmd2->type & MOD_FLUID_TYPE_EFFEC) && fmd2->effector) {
1235  FluidEffectorSettings *fes = fmd2->effector;
1236  int subframes = fes->subframes;
1237  FluidObjectBB *bb = &bb_maps[effec_index];
1238 
1239  /* Optimization: Skip this object under certain conditions. */
1240  if (escape_effectorobject(effecobj, fds, fes, frame)) {
1241  continue;
1242  }
1243 
1244  /* First frame cannot have any subframes because there is (obviously) no previous frame from
1245  * where subframes could come from. */
1246  if (is_first_frame) {
1247  subframes = 0;
1248  }
1249 
1250  /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */
1251  float sample_size = 1.0f / (float)(subframes + 1);
1252  float subframe_dt = dt * sample_size;
1253 
1254  /* Emission loop. When not using subframes this will loop only once. */
1255  for (int subframe = 0; subframe <= subframes; subframe++) {
1256 
1257  /* Temporary emission map used when subframes are enabled, i.e. at least one subframe. */
1258  FluidObjectBB bb_temp = {NULL};
1259 
1260  /* Set scene time */
1261  /* Handle emission subframe */
1262  if ((subframe < subframes || time_per_frame + dt + FLT_EPSILON < frame_length) &&
1263  !is_first_frame) {
1264  scene->r.subframe = (time_per_frame + (subframe + 1.0f) * subframe_dt) / frame_length;
1265  scene->r.cfra = frame - 1;
1266  }
1267  else {
1268  scene->r.subframe = 0.0f;
1269  scene->r.cfra = frame;
1270  }
1271  /* Sanity check: subframe portion must be between 0 and 1. */
1272  CLAMP(scene->r.subframe, 0.0f, 1.0f);
1273 # ifdef DEBUG_PRINT
1274  /* Debugging: Print subframe information. */
1275  printf(
1276  "effector: frame (is first: %d): %d // scene current frame: %d // scene current "
1277  "subframe: "
1278  "%f\n",
1279  is_first_frame,
1280  frame,
1281  scene->r.cfra,
1282  scene->r.subframe);
1283 # endif
1284  /* Update frame time, this is considering current subframe fraction
1285  * BLI_mutex_lock() called in manta_step(), so safe to update subframe here
1286  * TODO(sebbas): Using BKE_scene_frame_get(scene) instead of new DEG_get_ctime(depsgraph)
1287  * as subframes don't work with the latter yet. */
1290 
1291  if (subframes) {
1292  obstacles_from_mesh(effecobj, fds, fes, &bb_temp, subframe_dt);
1293  }
1294  else {
1295  obstacles_from_mesh(effecobj, fds, fes, bb, subframe_dt);
1296  }
1297 
1298  /* If this we emitted with temp emission map in this loop (subframe emission), we combine
1299  * the temp map with the original emission map. */
1300  if (subframes) {
1301  /* Combine emission maps. */
1302  bb_combineMaps(bb, &bb_temp, 0, 0.0f);
1303  bb_freeData(&bb_temp);
1304  }
1305  }
1306  }
1307  }
1308 }
1309 
1310 static void update_obstacles(Depsgraph *depsgraph,
1311  Scene *scene,
1312  Object *ob,
1313  FluidDomainSettings *fds,
1314  float time_per_frame,
1315  float frame_length,
1316  int frame,
1317  float dt)
1318 {
1319  FluidObjectBB *bb_maps = NULL;
1320  Object **effecobjs = NULL;
1321  uint numeffecobjs = 0;
1322  bool is_resume = (fds->cache_frame_pause_data == frame);
1323  bool is_first_frame = (frame == fds->cache_frame_start);
1324 
1325  effecobjs = BKE_collision_objects_create(
1326  depsgraph, ob, fds->effector_group, &numeffecobjs, eModifierType_Fluid);
1327 
1328  /* Update all effector related flags and ensure that corresponding grids get initialized. */
1329  update_obstacleflags(fds, effecobjs, numeffecobjs);
1330  ensure_obstaclefields(fds);
1331 
1332  /* Allocate effector map for each effector object. */
1333  bb_maps = MEM_callocN(sizeof(struct FluidObjectBB) * numeffecobjs, "fluid_effector_bb_maps");
1334 
1335  /* Initialize effector map for each effector object. */
1336  compute_obstaclesemission(scene,
1337  bb_maps,
1338  depsgraph,
1339  dt,
1340  effecobjs,
1341  frame,
1342  frame_length,
1343  fds,
1344  numeffecobjs,
1345  time_per_frame);
1346 
1347  float *vel_x = manta_get_ob_velocity_x(fds->fluid);
1348  float *vel_y = manta_get_ob_velocity_y(fds->fluid);
1349  float *vel_z = manta_get_ob_velocity_z(fds->fluid);
1350  float *vel_x_guide = manta_get_guide_velocity_x(fds->fluid);
1351  float *vel_y_guide = manta_get_guide_velocity_y(fds->fluid);
1352  float *vel_z_guide = manta_get_guide_velocity_z(fds->fluid);
1353  float *phi_obs_in = manta_get_phiobs_in(fds->fluid);
1354  float *phi_obsstatic_in = manta_get_phiobsstatic_in(fds->fluid);
1355  float *phi_guide_in = manta_get_phiguide_in(fds->fluid);
1356  float *num_obstacles = manta_get_num_obstacle(fds->fluid);
1357  float *num_guides = manta_get_num_guide(fds->fluid);
1358  uint z;
1359 
1360  bool use_adaptivedomain = (fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN);
1361 
1362  /* Grid reset before writing again. */
1363  for (z = 0; z < fds->res[0] * fds->res[1] * fds->res[2]; z++) {
1364 
1365  /* Use big value that's not inf to initialize levelset grids. */
1366  if (phi_obs_in) {
1367  phi_obs_in[z] = PHI_MAX;
1368  }
1369  /* Only reset static effectors on first frame. Only use static effectors without adaptive
1370  * domains. */
1371  if (phi_obsstatic_in && (is_first_frame || use_adaptivedomain)) {
1372  phi_obsstatic_in[z] = PHI_MAX;
1373  }
1374  if (phi_guide_in) {
1375  phi_guide_in[z] = PHI_MAX;
1376  }
1377  if (num_obstacles) {
1378  num_obstacles[z] = 0;
1379  }
1380  if (num_guides) {
1381  num_guides[z] = 0;
1382  }
1383  if (vel_x && vel_y && vel_z) {
1384  vel_x[z] = 0.0f;
1385  vel_y[z] = 0.0f;
1386  vel_z[z] = 0.0f;
1387  }
1388  if (vel_x_guide && vel_y_guide && vel_z_guide) {
1389  vel_x_guide[z] = 0.0f;
1390  vel_y_guide[z] = 0.0f;
1391  vel_z_guide[z] = 0.0f;
1392  }
1393  }
1394 
1395  /* Prepare grids from effector objects. */
1396  for (int effec_index = 0; effec_index < numeffecobjs; effec_index++) {
1397  Object *effecobj = effecobjs[effec_index];
1400 
1401  /* Sanity check. */
1402  if (!fmd2) {
1403  continue;
1404  }
1405 
1406  /* Cannot use static mode with adaptive domain.
1407  * The adaptive domain might expand and only later in the simulations discover the static
1408  * object. */
1409  bool is_static = is_static_object(effecobj) && !use_adaptivedomain;
1410 
1411  /* Check for initialized effector object. */
1412  if ((fmd2->type & MOD_FLUID_TYPE_EFFEC) && fmd2->effector) {
1413  FluidEffectorSettings *fes = fmd2->effector;
1414 
1415  /* Optimization: Skip effector objects with disabled effec flag. */
1416  if ((fes->flags & FLUID_EFFECTOR_USE_EFFEC) == 0) {
1417  continue;
1418  }
1419 
1420  FluidObjectBB *bb = &bb_maps[effec_index];
1421  float *velocity_map = bb->velocity;
1422  float *numobjs_map = bb->numobjs;
1423  float *distance_map = bb->distances;
1424 
1425  int gx, gy, gz, ex, ey, ez, dx, dy, dz;
1426  size_t e_index, d_index;
1427 
1428  /* Loop through every emission map cell. */
1429  for (gx = bb->min[0]; gx < bb->max[0]; gx++) {
1430  for (gy = bb->min[1]; gy < bb->max[1]; gy++) {
1431  for (gz = bb->min[2]; gz < bb->max[2]; gz++) {
1432  /* Compute emission map index. */
1433  ex = gx - bb->min[0];
1434  ey = gy - bb->min[1];
1435  ez = gz - bb->min[2];
1436  e_index = manta_get_index(ex, bb->res[0], ey, bb->res[1], ez);
1437 
1438  /* Get domain index. */
1439  dx = gx - fds->res_min[0];
1440  dy = gy - fds->res_min[1];
1441  dz = gz - fds->res_min[2];
1442  d_index = manta_get_index(dx, fds->res[0], dy, fds->res[1], dz);
1443  /* Make sure emission cell is inside the new domain boundary. */
1444  if (dx < 0 || dy < 0 || dz < 0 || dx >= fds->res[0] || dy >= fds->res[1] ||
1445  dz >= fds->res[2]) {
1446  continue;
1447  }
1448 
1449  if (fes->type == FLUID_EFFECTOR_TYPE_COLLISION) {
1450  float *levelset = ((is_first_frame || is_resume) && is_static) ? phi_obsstatic_in :
1451  phi_obs_in;
1452  apply_effector_fields(fes,
1453  d_index,
1454  distance_map[e_index],
1455  levelset,
1456  numobjs_map[e_index],
1457  num_obstacles,
1458  &velocity_map[e_index * 3],
1459  vel_x,
1460  vel_y,
1461  vel_z);
1462  }
1463  if (fes->type == FLUID_EFFECTOR_TYPE_GUIDE) {
1464  apply_effector_fields(fes,
1465  d_index,
1466  distance_map[e_index],
1467  phi_guide_in,
1468  numobjs_map[e_index],
1469  num_guides,
1470  &velocity_map[e_index * 3],
1471  vel_x_guide,
1472  vel_y_guide,
1473  vel_z_guide);
1474  }
1475  }
1476  }
1477  } /* End of effector map loop. */
1478  bb_freeData(bb);
1479  } /* End of effector object loop. */
1480  }
1481 
1482  BKE_collision_objects_free(effecobjs);
1483  if (bb_maps) {
1484  MEM_freeN(bb_maps);
1485  }
1486 }
1487 
1490 /* -------------------------------------------------------------------- */
1494 typedef struct EmitFromParticlesData {
1495  FluidFlowSettings *ffs;
1496  KDTree_3d *tree;
1497 
1498  FluidObjectBB *bb;
1499  float *particle_vel;
1500  int *min, *max, *res;
1501 
1502  float solid;
1503  float smooth;
1504 } EmitFromParticlesData;
1505 
1506 static void emit_from_particles_task_cb(void *__restrict userdata,
1507  const int z,
1508  const TaskParallelTLS *__restrict UNUSED(tls))
1509 {
1510  EmitFromParticlesData *data = userdata;
1511  FluidFlowSettings *ffs = data->ffs;
1512  FluidObjectBB *bb = data->bb;
1513 
1514  for (int x = data->min[0]; x < data->max[0]; x++) {
1515  for (int y = data->min[1]; y < data->max[1]; y++) {
1516  const int index = manta_get_index(
1517  x - bb->min[0], bb->res[0], y - bb->min[1], bb->res[1], z - bb->min[2]);
1518  const float ray_start[3] = {((float)x) + 0.5f, ((float)y) + 0.5f, ((float)z) + 0.5f};
1519 
1520  /* Find particle distance from the kdtree. */
1521  KDTreeNearest_3d nearest;
1522  const float range = data->solid + data->smooth;
1523  BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
1524 
1525  if (nearest.dist < range) {
1526  bb->influence[index] = (nearest.dist < data->solid) ?
1527  1.0f :
1528  (1.0f - (nearest.dist - data->solid) / data->smooth);
1529  /* Uses particle velocity as initial velocity for smoke. */
1530  if (ffs->flags & FLUID_FLOW_INITVELOCITY && (ffs->psys->part->phystype != PART_PHYS_NO)) {
1531  madd_v3_v3fl(
1532  &bb->velocity[index * 3], &data->particle_vel[nearest.index * 3], ffs->vel_multi);
1533  }
1534  }
1535  }
1536  }
1537 }
1538 
1539 static void emit_from_particles(Object *flow_ob,
1540  FluidDomainSettings *fds,
1541  FluidFlowSettings *ffs,
1542  FluidObjectBB *bb,
1544  Scene *scene,
1545  float dt)
1546 {
1547  if (ffs && ffs->psys && ffs->psys->part &&
1548  ELEM(ffs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected
1549  {
1551  ParticleSystem *psys = ffs->psys;
1552  float *particle_pos;
1553  float *particle_vel;
1554  int totpart = psys->totpart, totchild;
1555  int p = 0;
1556  int valid_particles = 0;
1557  int bounds_margin = 1;
1558 
1559  /* radius based flow */
1560  const float solid = ffs->particle_size * 0.5f;
1561  const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */
1562  KDTree_3d *tree = NULL;
1563 
1564  sim.depsgraph = depsgraph;
1565  sim.scene = scene;
1566  sim.ob = flow_ob;
1567  sim.psys = psys;
1569 
1570  /* prepare curvemapping tables */
1571  if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve) {
1573  }
1574  if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve) {
1576  }
1577  if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve) {
1579  }
1580 
1581  /* initialize particle cache */
1582  if (psys->part->type == PART_HAIR) {
1583  // TODO: PART_HAIR not supported whatsoever
1584  totchild = 0;
1585  }
1586  else {
1587  totchild = psys->totchild * psys->part->disp / 100;
1588  }
1589 
1590  particle_pos = MEM_callocN(sizeof(float[3]) * (totpart + totchild),
1591  "manta_flow_particles_pos");
1592  particle_vel = MEM_callocN(sizeof(float[3]) * (totpart + totchild),
1593  "manta_flow_particles_vel");
1594 
1595  /* setup particle radius emission if enabled */
1596  if (ffs->flags & FLUID_FLOW_USE_PART_SIZE) {
1597  tree = BLI_kdtree_3d_new(psys->totpart + psys->totchild);
1598  bounds_margin = (int)ceil(solid + smooth);
1599  }
1600 
1601  /* calculate local position for each particle */
1602  for (p = 0; p < totpart + totchild; p++) {
1604  float *pos, *vel;
1605  if (p < totpart) {
1606  if (psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
1607  continue;
1608  }
1609  }
1610  else {
1611  /* handle child particle */
1612  ChildParticle *cpa = &psys->child[p - totpart];
1613  if (psys->particles[cpa->parent].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
1614  continue;
1615  }
1616  }
1617 
1618  state.time = BKE_scene_frame_get(
1619  scene); /* DEG_get_ctime(depsgraph) does not give subframe time */
1620  if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
1621  continue;
1622  }
1623 
1624  /* location */
1625  pos = &particle_pos[valid_particles * 3];
1626  copy_v3_v3(pos, state.co);
1627  manta_pos_to_cell(fds, pos);
1628 
1629  /* velocity */
1630  vel = &particle_vel[valid_particles * 3];
1631  copy_v3_v3(vel, state.vel);
1632  mul_mat3_m4_v3(fds->imat, &particle_vel[valid_particles * 3]);
1633 
1634  if (ffs->flags & FLUID_FLOW_USE_PART_SIZE) {
1635  BLI_kdtree_3d_insert(tree, valid_particles, pos);
1636  }
1637 
1638  /* calculate emission map bounds */
1639  bb_boundInsert(bb, pos);
1640  valid_particles++;
1641  }
1642 
1643  /* set emission map */
1644  clamp_bounds_in_domain(fds, bb->min, bb->max, NULL, NULL, bounds_margin, dt);
1645  bb_allocateData(bb, ffs->flags & FLUID_FLOW_INITVELOCITY, true);
1646 
1647  if (!(ffs->flags & FLUID_FLOW_USE_PART_SIZE)) {
1648  for (p = 0; p < valid_particles; p++) {
1649  int cell[3];
1650  size_t i = 0;
1651  size_t index = 0;
1652  int badcell = 0;
1653 
1654  /* 1. get corresponding cell */
1655  cell[0] = floor(particle_pos[p * 3]) - bb->min[0];
1656  cell[1] = floor(particle_pos[p * 3 + 1]) - bb->min[1];
1657  cell[2] = floor(particle_pos[p * 3 + 2]) - bb->min[2];
1658  /* check if cell is valid (in the domain boundary) */
1659  for (i = 0; i < 3; i++) {
1660  if ((cell[i] > bb->res[i] - 1) || (cell[i] < 0)) {
1661  badcell = 1;
1662  break;
1663  }
1664  }
1665  if (badcell) {
1666  continue;
1667  }
1668  /* get cell index */
1669  index = manta_get_index(cell[0], bb->res[0], cell[1], bb->res[1], cell[2]);
1670  /* Add influence to emission map */
1671  bb->influence[index] = 1.0f;
1672  /* Uses particle velocity as initial velocity for smoke */
1673  if (ffs->flags & FLUID_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO)) {
1674  madd_v3_v3fl(&bb->velocity[index * 3], &particle_vel[p * 3], ffs->vel_multi);
1675  }
1676  } // particles loop
1677  }
1678  else if (valid_particles > 0) { // FLUID_FLOW_USE_PART_SIZE
1679  int min[3], max[3], res[3];
1680 
1681  /* setup loop bounds */
1682  for (int i = 0; i < 3; i++) {
1683  min[i] = bb->min[i];
1684  max[i] = bb->max[i];
1685  res[i] = bb->res[i];
1686  }
1687 
1688  BLI_kdtree_3d_balance(tree);
1689 
1690  EmitFromParticlesData data = {
1691  .ffs = ffs,
1692  .tree = tree,
1693  .bb = bb,
1694  .particle_vel = particle_vel,
1695  .min = min,
1696  .max = max,
1697  .res = res,
1698  .solid = solid,
1699  .smooth = smooth,
1700  };
1701 
1702  TaskParallelSettings settings;
1704  settings.min_iter_per_thread = 2;
1705  BLI_task_parallel_range(min[2], max[2], &data, emit_from_particles_task_cb, &settings);
1706  }
1707 
1708  if (ffs->flags & FLUID_FLOW_USE_PART_SIZE) {
1709  BLI_kdtree_3d_free(tree);
1710  }
1711 
1712  /* free data */
1713  if (particle_pos) {
1714  MEM_freeN(particle_pos);
1715  }
1716  if (particle_vel) {
1717  MEM_freeN(particle_vel);
1718  }
1719  }
1720 }
1721 
1722 /* Calculate map of (minimum) distances to flow/obstacle surface. Distances outside mesh are
1723  * positive, inside negative. */
1724 static void update_distances(int index,
1725  float *distance_map,
1726  BVHTreeFromMesh *tree_data,
1727  const float ray_start[3],
1728  float surface_thickness,
1729  bool use_plane_init)
1730 {
1731  float min_dist = PHI_MAX;
1732 
1733  /* Planar initialization: Find nearest cells around mesh. */
1734  if (use_plane_init) {
1735  BVHTreeNearest nearest = {0};
1736  nearest.index = -1;
1737  /* Distance between two opposing vertices in a unit cube.
1738  * I.e. the unit cube diagonal or sqrt(3).
1739  * This value is our nearest neighbor search distance. */
1740  const float surface_distance = 1.732;
1741  nearest.dist_sq = surface_distance *
1742  surface_distance; /* find_nearest uses squared distance. */
1743 
1744  /* Subtract optional surface thickness value and virtually increase the object size. */
1745  if (surface_thickness) {
1746  nearest.dist_sq += surface_thickness;
1747  }
1748 
1750  tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) {
1751  float ray[3] = {0};
1752  sub_v3_v3v3(ray, ray_start, nearest.co);
1753  min_dist = len_v3(ray);
1754  min_dist = (-1.0f) * fabsf(min_dist);
1755  }
1756  }
1757  /* Volumetric initialization: Ray-casts around mesh object. */
1758  else {
1759  /* Ray-casts in 26 directions.
1760  * (6 main axis + 12 quadrant diagonals (2D) + 8 octant diagonals (3D)). */
1761  float ray_dirs[26][3] = {
1762  {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f},
1763  {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 1.0f, 0.0f}, {1.0f, -1.0f, 0.0f},
1764  {-1.0f, 1.0f, 0.0f}, {-1.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 1.0f}, {1.0f, 0.0f, -1.0f},
1765  {-1.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, -1.0f}, {0.0f, 1.0f, 1.0f}, {0.0f, 1.0f, -1.0f},
1766  {0.0f, -1.0f, 1.0f}, {0.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, -1.0f, 1.0f},
1767  {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, 1.0f, -1.0f}, {1.0f, -1.0f, -1.0f},
1768  {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}};
1769 
1770  /* Count ray mesh misses (i.e. no face hit) and cases where the ray direction matches the face
1771  * normal direction. From this information it can be derived whether a cell is inside or
1772  * outside the mesh. */
1773  int miss_cnt = 0, dir_cnt = 0;
1774 
1775  for (int i = 0; i < ARRAY_SIZE(ray_dirs); i++) {
1776  BVHTreeRayHit hit_tree = {0};
1777  hit_tree.index = -1;
1778  hit_tree.dist = PHI_MAX;
1779 
1780  normalize_v3(ray_dirs[i]);
1781  BLI_bvhtree_ray_cast(tree_data->tree,
1782  ray_start,
1783  ray_dirs[i],
1784  0.0f,
1785  &hit_tree,
1786  tree_data->raycast_callback,
1787  tree_data);
1788 
1789  /* Ray did not hit mesh.
1790  * Current point definitely not inside mesh. Inside mesh as all rays have to hit. */
1791  if (hit_tree.index == -1) {
1792  miss_cnt++;
1793  /* Skip this ray since nothing was hit. */
1794  continue;
1795  }
1796 
1797  /* Ray and normal are pointing in opposite directions. */
1798  if (dot_v3v3(ray_dirs[i], hit_tree.no) <= 0) {
1799  dir_cnt++;
1800  }
1801 
1802  if (hit_tree.dist < min_dist) {
1803  min_dist = hit_tree.dist;
1804  }
1805  }
1806 
1807  /* Point lies inside mesh. Use negative sign for distance value.
1808  * This "if statement" has 2 conditions that can be true for points outside mesh. */
1809  if (!(miss_cnt > 0 || dir_cnt == ARRAY_SIZE(ray_dirs))) {
1810  min_dist = (-1.0f) * fabsf(min_dist);
1811  }
1812 
1813  /* Subtract optional surface thickness value and virtually increase the object size. */
1814  if (surface_thickness) {
1815  min_dist -= surface_thickness;
1816  }
1817  }
1818 
1819  /* Update global distance array but ensure that older entries are not overridden. */
1820  distance_map[index] = MIN2(distance_map[index], min_dist);
1821 
1822  /* Sanity check: Ensure that distances don't explode. */
1823  CLAMP(distance_map[index], -PHI_MAX, PHI_MAX);
1824 }
1825 
1826 static void sample_mesh(FluidFlowSettings *ffs,
1827  const MVert *mvert,
1828  const MLoop *mloop,
1829  const MLoopTri *mlooptri,
1830  const MLoopUV *mloopuv,
1831  float *influence_map,
1832  float *velocity_map,
1833  int index,
1834  const int base_res[3],
1835  const float global_size[3],
1836  const float flow_center[3],
1837  BVHTreeFromMesh *tree_data,
1838  const float ray_start[3],
1839  const float *vert_vel,
1840  bool has_velocity,
1841  int defgrp_index,
1842  MDeformVert *dvert,
1843  float x,
1844  float y,
1845  float z)
1846 {
1847  float ray_dir[3] = {1.0f, 0.0f, 0.0f};
1848  BVHTreeRayHit hit = {0};
1849  BVHTreeNearest nearest = {0};
1850 
1851  float volume_factor = 0.0f;
1852 
1853  hit.index = -1;
1854  hit.dist = PHI_MAX;
1855  nearest.index = -1;
1856 
1857  /* Distance between two opposing vertices in a unit cube.
1858  * I.e. the unit cube diagonal or sqrt(3).
1859  * This value is our nearest neighbor search distance. */
1860  const float surface_distance = 1.732;
1861  nearest.dist_sq = surface_distance * surface_distance; /* find_nearest uses squared distance. */
1862 
1863  bool is_gas_flow = (ffs->type == FLUID_FLOW_TYPE_SMOKE || ffs->type == FLUID_FLOW_TYPE_FIRE ||
1865 
1866  /* Emission strength for gases will be computed below.
1867  * For liquids it's not needed. Just set to non zero value
1868  * to allow initial velocity computation. */
1869  float emission_strength = (is_gas_flow) ? 0.0f : 1.0f;
1870 
1871  /* Emission inside the flow object. */
1872  if (is_gas_flow && ffs->volume_density) {
1873  if (BLI_bvhtree_ray_cast(tree_data->tree,
1874  ray_start,
1875  ray_dir,
1876  0.0f,
1877  &hit,
1878  tree_data->raycast_callback,
1879  tree_data) != -1) {
1880  float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2];
1881  /* If ray and hit face normal are facing same direction hit point is inside a closed mesh. */
1882  if (dot >= 0) {
1883  /* Also cast a ray in opposite direction to make sure point is at least surrounded by two
1884  * faces. */
1885  negate_v3(ray_dir);
1886  hit.index = -1;
1887  hit.dist = PHI_MAX;
1888 
1889  BLI_bvhtree_ray_cast(tree_data->tree,
1890  ray_start,
1891  ray_dir,
1892  0.0f,
1893  &hit,
1894  tree_data->raycast_callback,
1895  tree_data);
1896  if (hit.index != -1) {
1897  volume_factor = ffs->volume_density;
1898  }
1899  }
1900  }
1901  }
1902 
1903  /* Find the nearest point on the mesh. */
1905  tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) {
1906  float weights[3];
1907  int v1, v2, v3, f_index = nearest.index;
1908  float n1[3], n2[3], n3[3], hit_normal[3];
1909 
1910  /* Calculate barycentric weights for nearest point. */
1911  v1 = mloop[mlooptri[f_index].tri[0]].v;
1912  v2 = mloop[mlooptri[f_index].tri[1]].v;
1913  v3 = mloop[mlooptri[f_index].tri[2]].v;
1914  interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
1915 
1916  /* Compute emission strength for smoke flow. */
1917  if (is_gas_flow) {
1918  /* Emission from surface is based on UI configurable distance value. */
1919  if (ffs->surface_distance) {
1920  emission_strength = sqrtf(nearest.dist_sq) / ffs->surface_distance;
1921  CLAMP(emission_strength, 0.0f, 1.0f);
1922  emission_strength = pow(1.0f - emission_strength, 0.5f);
1923  }
1924  else {
1925  emission_strength = 0.0f;
1926  }
1927 
1928  /* Apply vertex group influence if it is being used. */
1929  if (defgrp_index != -1 && dvert) {
1930  float weight_mask = BKE_defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] +
1931  BKE_defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] +
1932  BKE_defvert_find_weight(&dvert[v3], defgrp_index) * weights[2];
1933  emission_strength *= weight_mask;
1934  }
1935 
1936  /* Apply emission texture. */
1937  if ((ffs->flags & FLUID_FLOW_TEXTUREEMIT) && ffs->noise_texture) {
1938  float tex_co[3] = {0};
1939  TexResult texres;
1940 
1942  tex_co[0] = ((x - flow_center[0]) / base_res[0]) / ffs->texture_size;
1943  tex_co[1] = ((y - flow_center[1]) / base_res[1]) / ffs->texture_size;
1944  tex_co[2] = ((z - flow_center[2]) / base_res[2] - ffs->texture_offset) /
1945  ffs->texture_size;
1946  }
1947  else if (mloopuv) {
1948  const float *uv[3];
1949  uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv;
1950  uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv;
1951  uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv;
1952 
1953  interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights);
1954 
1955  /* Map texure coord between -1.0f and 1.0f. */
1956  tex_co[0] = tex_co[0] * 2.0f - 1.0f;
1957  tex_co[1] = tex_co[1] * 2.0f - 1.0f;
1958  tex_co[2] = ffs->texture_offset;
1959  }
1960  texres.nor = NULL;
1961  BKE_texture_get_value(NULL, ffs->noise_texture, tex_co, &texres, false);
1962  emission_strength *= texres.tin;
1963  }
1964  }
1965 
1966  /* Initial velocity of flow object. Only compute velocity if emission is present. */
1967  if (ffs->flags & FLUID_FLOW_INITVELOCITY && velocity_map && emission_strength != 0.0) {
1968  /* Apply normal directional velocity. */
1969  if (ffs->vel_normal) {
1970  /* Interpolate vertex normal vectors to get nearest point normal. */
1971  normal_short_to_float_v3(n1, mvert[v1].no);
1972  normal_short_to_float_v3(n2, mvert[v2].no);
1973  normal_short_to_float_v3(n3, mvert[v3].no);
1974  interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights);
1975  normalize_v3(hit_normal);
1976 
1977  /* Apply normal directional velocity. */
1978  velocity_map[index * 3] += hit_normal[0] * ffs->vel_normal;
1979  velocity_map[index * 3 + 1] += hit_normal[1] * ffs->vel_normal;
1980  velocity_map[index * 3 + 2] += hit_normal[2] * ffs->vel_normal;
1981  }
1982  /* Apply object velocity. */
1983  if (has_velocity && ffs->vel_multi) {
1984  float hit_vel[3];
1986  hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights);
1987  velocity_map[index * 3] += hit_vel[0] * ffs->vel_multi;
1988  velocity_map[index * 3 + 1] += hit_vel[1] * ffs->vel_multi;
1989  velocity_map[index * 3 + 2] += hit_vel[2] * ffs->vel_multi;
1990 # ifdef DEBUG_PRINT
1991  /* Debugging: Print flow object velocities. */
1992  printf("adding flow object vel: [%f, %f, %f]\n", hit_vel[0], hit_vel[1], hit_vel[2]);
1993 # endif
1994  }
1995  /* Convert xyz velocities flow settings from world to grid space. */
1996  float convert_vel[3];
1997  copy_v3_v3(convert_vel, ffs->vel_coord);
1998  float time_mult = 1.0 / (25.0f * DT_DEFAULT);
1999  float size_mult = MAX3(base_res[0], base_res[1], base_res[2]) /
2000  MAX3(global_size[0], global_size[1], global_size[2]);
2001  mul_v3_v3fl(convert_vel, ffs->vel_coord, size_mult * time_mult);
2002 
2003  velocity_map[index * 3] += convert_vel[0];
2004  velocity_map[index * 3 + 1] += convert_vel[1];
2005  velocity_map[index * 3 + 2] += convert_vel[2];
2006 # ifdef DEBUG_PRINT
2007  printf("initial vel: [%f, %f, %f]\n",
2008  velocity_map[index * 3],
2009  velocity_map[index * 3 + 1],
2010  velocity_map[index * 3 + 2]);
2011 # endif
2012  }
2013  }
2014 
2015  /* Apply final influence value but also consider volume initialization factor. */
2016  influence_map[index] = MAX2(volume_factor, emission_strength);
2017 }
2018 
2019 typedef struct EmitFromDMData {
2020  FluidDomainSettings *fds;
2021  FluidFlowSettings *ffs;
2022 
2023  const MVert *mvert;
2024  const MLoop *mloop;
2025  const MLoopTri *mlooptri;
2026  const MLoopUV *mloopuv;
2027  MDeformVert *dvert;
2028  int defgrp_index;
2029 
2031  FluidObjectBB *bb;
2032 
2033  bool has_velocity;
2034  float *vert_vel;
2035  float *flow_center;
2036  int *min, *max, *res;
2037 } EmitFromDMData;
2038 
2039 static void emit_from_mesh_task_cb(void *__restrict userdata,
2040  const int z,
2041  const TaskParallelTLS *__restrict UNUSED(tls))
2042 {
2043  EmitFromDMData *data = userdata;
2044  FluidObjectBB *bb = data->bb;
2045 
2046  for (int x = data->min[0]; x < data->max[0]; x++) {
2047  for (int y = data->min[1]; y < data->max[1]; y++) {
2048  const int index = manta_get_index(
2049  x - bb->min[0], bb->res[0], y - bb->min[1], bb->res[1], z - bb->min[2]);
2050  const float ray_start[3] = {((float)x) + 0.5f, ((float)y) + 0.5f, ((float)z) + 0.5f};
2051 
2052  /* Compute emission only for flow objects that produce fluid (i.e. skip outflow objects).
2053  * Result in bb->influence. Also computes initial velocities. Result in bb->velocity. */
2054  if ((data->ffs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY) ||
2055  (data->ffs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW)) {
2056  sample_mesh(data->ffs,
2057  data->mvert,
2058  data->mloop,
2059  data->mlooptri,
2060  data->mloopuv,
2061  bb->influence,
2062  bb->velocity,
2063  index,
2064  data->fds->base_res,
2065  data->fds->global_size,
2066  data->flow_center,
2067  data->tree,
2068  ray_start,
2069  data->vert_vel,
2070  data->has_velocity,
2071  data->defgrp_index,
2072  data->dvert,
2073  (float)x,
2074  (float)y,
2075  (float)z);
2076  }
2077 
2078  /* Calculate levelset values from meshes. Result in bb->distances. */
2079  update_distances(index,
2080  bb->distances,
2081  data->tree,
2082  ray_start,
2083  data->ffs->surface_distance,
2084  data->ffs->flags & FLUID_FLOW_USE_PLANE_INIT);
2085  }
2086  }
2087 }
2088 
2089 static void emit_from_mesh(
2090  Object *flow_ob, FluidDomainSettings *fds, FluidFlowSettings *ffs, FluidObjectBB *bb, float dt)
2091 {
2092  if (ffs->mesh) {
2093  Mesh *me = NULL;
2094  MVert *mvert = NULL;
2095  const MLoopTri *mlooptri = NULL;
2096  const MLoop *mloop = NULL;
2097  const MLoopUV *mloopuv = NULL;
2098  MDeformVert *dvert = NULL;
2099  BVHTreeFromMesh tree_data = {NULL};
2100  int numverts, i;
2101 
2102  float *vert_vel = NULL;
2103  bool has_velocity = false;
2104 
2105  int defgrp_index = ffs->vgroup_density - 1;
2106  float flow_center[3] = {0};
2107  int min[3], max[3], res[3];
2108 
2109  /* Copy mesh for thread safety as we modify it.
2110  * Main issue is its VertArray being modified, then replaced and freed. */
2111  me = BKE_mesh_copy_for_eval(ffs->mesh, true);
2112 
2113  /* Duplicate vertices to modify. */
2114  if (me->mvert) {
2115  me->mvert = MEM_dupallocN(me->mvert);
2116  CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
2117  }
2118 
2120  mvert = me->mvert;
2121  mloop = me->mloop;
2122  mlooptri = BKE_mesh_runtime_looptri_ensure(me);
2123  numverts = me->totvert;
2124  dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
2126 
2127  if (ffs->flags & FLUID_FLOW_INITVELOCITY) {
2128  vert_vel = MEM_callocN(sizeof(float[3]) * numverts, "manta_flow_velocity");
2129 
2130  if (ffs->numverts != numverts || !ffs->verts_old) {
2131  if (ffs->verts_old) {
2132  MEM_freeN(ffs->verts_old);
2133  }
2134  ffs->verts_old = MEM_callocN(sizeof(float[3]) * numverts, "manta_flow_verts_old");
2135  ffs->numverts = numverts;
2136  }
2137  else {
2138  has_velocity = true;
2139  }
2140  }
2141 
2142  /* Transform mesh vertices to domain grid space for fast lookups */
2143  for (i = 0; i < numverts; i++) {
2144  float n[3];
2145 
2146  /* Vertex position. */
2147  mul_m4_v3(flow_ob->obmat, mvert[i].co);
2148  manta_pos_to_cell(fds, mvert[i].co);
2149 
2150  /* Vertex normal. */
2151  normal_short_to_float_v3(n, mvert[i].no);
2152  mul_mat3_m4_v3(flow_ob->obmat, n);
2153  mul_mat3_m4_v3(fds->imat, n);
2154  normalize_v3(n);
2155  normal_float_to_short_v3(mvert[i].no, n);
2156 
2157  /* Vertex velocity. */
2158  if (ffs->flags & FLUID_FLOW_INITVELOCITY) {
2159  float co[3];
2160  add_v3fl_v3fl_v3i(co, mvert[i].co, fds->shift);
2161  if (has_velocity) {
2162  sub_v3_v3v3(&vert_vel[i * 3], co, &ffs->verts_old[i * 3]);
2163  mul_v3_fl(&vert_vel[i * 3], 1.0 / dt);
2164  }
2165  copy_v3_v3(&ffs->verts_old[i * 3], co);
2166  }
2167 
2168  /* Calculate emission map bounds. */
2169  bb_boundInsert(bb, mvert[i].co);
2170  }
2171  mul_m4_v3(flow_ob->obmat, flow_center);
2172  manta_pos_to_cell(fds, flow_center);
2173 
2174  /* Set emission map.
2175  * Use 3 cell diagonals as margin (3 * 1.732 = 5.196). */
2176  int bounds_margin = (int)ceil(5.196);
2177  clamp_bounds_in_domain(fds, bb->min, bb->max, NULL, NULL, bounds_margin, dt);
2178  bb_allocateData(bb, ffs->flags & FLUID_FLOW_INITVELOCITY, true);
2179 
2180  /* Setup loop bounds. */
2181  for (i = 0; i < 3; i++) {
2182  min[i] = bb->min[i];
2183  max[i] = bb->max[i];
2184  res[i] = bb->res[i];
2185  }
2186 
2187  /* Skip flow sampling loop if object has disabled flow. */
2188  bool use_flow = ffs->flags & FLUID_FLOW_USE_INFLOW;
2189  if (use_flow && BKE_bvhtree_from_mesh_get(&tree_data, me, BVHTREE_FROM_LOOPTRI, 4)) {
2190 
2191  EmitFromDMData data = {
2192  .fds = fds,
2193  .ffs = ffs,
2194  .mvert = mvert,
2195  .mloop = mloop,
2196  .mlooptri = mlooptri,
2197  .mloopuv = mloopuv,
2198  .dvert = dvert,
2199  .defgrp_index = defgrp_index,
2200  .tree = &tree_data,
2201  .bb = bb,
2202  .has_velocity = has_velocity,
2203  .vert_vel = vert_vel,
2204  .flow_center = flow_center,
2205  .min = min,
2206  .max = max,
2207  .res = res,
2208  };
2209 
2210  TaskParallelSettings settings;
2212  settings.min_iter_per_thread = 2;
2213  BLI_task_parallel_range(min[2], max[2], &data, emit_from_mesh_task_cb, &settings);
2214  }
2215  /* Free bvh tree. */
2216  free_bvhtree_from_mesh(&tree_data);
2217 
2218  if (vert_vel) {
2219  MEM_freeN(vert_vel);
2220  }
2221  if (me->mvert) {
2222  MEM_freeN(me->mvert);
2223  }
2224  BKE_id_free(NULL, me);
2225  }
2226 }
2227 
2230 /* -------------------------------------------------------------------- */
2234 static void adaptive_domain_adjust(
2235  FluidDomainSettings *fds, Object *ob, FluidObjectBB *bb_maps, uint numflowobj, float dt)
2236 {
2237  /* calculate domain shift for current frame */
2238  int new_shift[3] = {0};
2239  int total_shift[3];
2240  float frame_shift_f[3];
2241  float ob_loc[3] = {0};
2242 
2243  mul_m4_v3(ob->obmat, ob_loc);
2244 
2245  sub_v3_v3v3(frame_shift_f, ob_loc, fds->prev_loc);
2246  copy_v3_v3(fds->prev_loc, ob_loc);
2247  /* convert global space shift to local "cell" space */
2248  mul_mat3_m4_v3(fds->imat, frame_shift_f);
2249  frame_shift_f[0] = frame_shift_f[0] / fds->cell_size[0];
2250  frame_shift_f[1] = frame_shift_f[1] / fds->cell_size[1];
2251  frame_shift_f[2] = frame_shift_f[2] / fds->cell_size[2];
2252  /* add to total shift */
2253  add_v3_v3(fds->shift_f, frame_shift_f);
2254  /* convert to integer */
2255  total_shift[0] = (int)(floorf(fds->shift_f[0]));
2256  total_shift[1] = (int)(floorf(fds->shift_f[1]));
2257  total_shift[2] = (int)(floorf(fds->shift_f[2]));
2258  int temp_shift[3];
2259  copy_v3_v3_int(temp_shift, fds->shift);
2260  sub_v3_v3v3_int(new_shift, total_shift, fds->shift);
2261  copy_v3_v3_int(fds->shift, total_shift);
2262 
2263  /* calculate new domain boundary points so that smoke doesn't slide on sub-cell movement */
2264  fds->p0[0] = fds->dp0[0] - fds->cell_size[0] * (fds->shift_f[0] - total_shift[0] - 0.5f);
2265  fds->p0[1] = fds->dp0[1] - fds->cell_size[1] * (fds->shift_f[1] - total_shift[1] - 0.5f);
2266  fds->p0[2] = fds->dp0[2] - fds->cell_size[2] * (fds->shift_f[2] - total_shift[2] - 0.5f);
2267  fds->p1[0] = fds->p0[0] + fds->cell_size[0] * fds->base_res[0];
2268  fds->p1[1] = fds->p0[1] + fds->cell_size[1] * fds->base_res[1];
2269  fds->p1[2] = fds->p0[2] + fds->cell_size[2] * fds->base_res[2];
2270 
2271  /* adjust domain resolution */
2272  const int block_size = fds->noise_scale;
2273  int min[3] = {32767, 32767, 32767}, max[3] = {-32767, -32767, -32767}, res[3];
2274  int total_cells = 1, res_changed = 0, shift_changed = 0;
2275  float min_vel[3], max_vel[3];
2276  int x, y, z;
2277  float *density = manta_smoke_get_density(fds->fluid);
2278  float *fuel = manta_smoke_get_fuel(fds->fluid);
2279  float *bigdensity = manta_noise_get_density(fds->fluid);
2280  float *bigfuel = manta_noise_get_fuel(fds->fluid);
2281  float *vx = manta_get_velocity_x(fds->fluid);
2282  float *vy = manta_get_velocity_y(fds->fluid);
2283  float *vz = manta_get_velocity_z(fds->fluid);
2284  int wt_res[3];
2285 
2286  if (fds->flags & FLUID_DOMAIN_USE_NOISE && fds->fluid) {
2287  manta_noise_get_res(fds->fluid, wt_res);
2288  }
2289 
2290  INIT_MINMAX(min_vel, max_vel);
2291 
2292  /* Calculate bounds for current domain content */
2293  for (x = fds->res_min[0]; x < fds->res_max[0]; x++) {
2294  for (y = fds->res_min[1]; y < fds->res_max[1]; y++) {
2295  for (z = fds->res_min[2]; z < fds->res_max[2]; z++) {
2296  int xn = x - new_shift[0];
2297  int yn = y - new_shift[1];
2298  int zn = z - new_shift[2];
2299  int index;
2300  float max_den;
2301 
2302  /* skip if cell already belongs to new area */
2303  if (xn >= min[0] && xn <= max[0] && yn >= min[1] && yn <= max[1] && zn >= min[2] &&
2304  zn <= max[2]) {
2305  continue;
2306  }
2307 
2308  index = manta_get_index(x - fds->res_min[0],
2309  fds->res[0],
2310  y - fds->res_min[1],
2311  fds->res[1],
2312  z - fds->res_min[2]);
2313  max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index];
2314 
2315  /* Check high resolution bounds if max density isn't already high enough. */
2316  if (max_den < fds->adapt_threshold && fds->flags & FLUID_DOMAIN_USE_NOISE && fds->fluid) {
2317  int i, j, k;
2318  /* high res grid index */
2319  int xx = (x - fds->res_min[0]) * block_size;
2320  int yy = (y - fds->res_min[1]) * block_size;
2321  int zz = (z - fds->res_min[2]) * block_size;
2322 
2323  for (i = 0; i < block_size; i++) {
2324  for (j = 0; j < block_size; j++) {
2325  for (k = 0; k < block_size; k++) {
2326  int big_index = manta_get_index(xx + i, wt_res[0], yy + j, wt_res[1], zz + k);
2327  float den = (bigfuel) ? MAX2(bigdensity[big_index], bigfuel[big_index]) :
2328  bigdensity[big_index];
2329  if (den > max_den) {
2330  max_den = den;
2331  }
2332  }
2333  }
2334  }
2335  }
2336 
2337  /* content bounds (use shifted coordinates) */
2338  if (max_den >= fds->adapt_threshold) {
2339  if (min[0] > xn) {
2340  min[0] = xn;
2341  }
2342  if (min[1] > yn) {
2343  min[1] = yn;
2344  }
2345  if (min[2] > zn) {
2346  min[2] = zn;
2347  }
2348  if (max[0] < xn) {
2349  max[0] = xn;
2350  }
2351  if (max[1] < yn) {
2352  max[1] = yn;
2353  }
2354  if (max[2] < zn) {
2355  max[2] = zn;
2356  }
2357  }
2358 
2359  /* velocity bounds */
2360  if (min_vel[0] > vx[index]) {
2361  min_vel[0] = vx[index];
2362  }
2363  if (min_vel[1] > vy[index]) {
2364  min_vel[1] = vy[index];
2365  }
2366  if (min_vel[2] > vz[index]) {
2367  min_vel[2] = vz[index];
2368  }
2369  if (max_vel[0] < vx[index]) {
2370  max_vel[0] = vx[index];
2371  }
2372  if (max_vel[1] < vy[index]) {
2373  max_vel[1] = vy[index];
2374  }
2375  if (max_vel[2] < vz[index]) {
2376  max_vel[2] = vz[index];
2377  }
2378  }
2379  }
2380  }
2381 
2382  /* also apply emission maps */
2383  for (int i = 0; i < numflowobj; i++) {
2384  FluidObjectBB *bb = &bb_maps[i];
2385 
2386  for (x = bb->min[0]; x < bb->max[0]; x++) {
2387  for (y = bb->min[1]; y < bb->max[1]; y++) {
2388  for (z = bb->min[2]; z < bb->max[2]; z++) {
2389  int index = manta_get_index(
2390  x - bb->min[0], bb->res[0], y - bb->min[1], bb->res[1], z - bb->min[2]);
2391  float max_den = bb->influence[index];
2392 
2393  /* density bounds */
2394  if (max_den >= fds->adapt_threshold) {
2395  if (min[0] > x) {
2396  min[0] = x;
2397  }
2398  if (min[1] > y) {
2399  min[1] = y;
2400  }
2401  if (min[2] > z) {
2402  min[2] = z;
2403  }
2404  if (max[0] < x) {
2405  max[0] = x;
2406  }
2407  if (max[1] < y) {
2408  max[1] = y;
2409  }
2410  if (max[2] < z) {
2411  max[2] = z;
2412  }
2413  }
2414  }
2415  }
2416  }
2417  }
2418 
2419  /* calculate new bounds based on these values */
2420  clamp_bounds_in_domain(fds, min, max, min_vel, max_vel, fds->adapt_margin + 1, dt);
2421 
2422  for (int i = 0; i < 3; i++) {
2423  /* calculate new resolution */
2424  res[i] = max[i] - min[i];
2425  total_cells *= res[i];
2426 
2427  if (new_shift[i]) {
2428  shift_changed = 1;
2429  }
2430 
2431  /* if no content set minimum dimensions */
2432  if (res[i] <= 0) {
2433  int j;
2434  for (j = 0; j < 3; j++) {
2435  min[j] = 0;
2436  max[j] = 1;
2437  res[j] = 1;
2438  }
2439  res_changed = 1;
2440  total_cells = 1;
2441  break;
2442  }
2443  if (min[i] != fds->res_min[i] || max[i] != fds->res_max[i]) {
2444  res_changed = 1;
2445  }
2446  }
2447 
2448  if (res_changed || shift_changed) {
2450  fds, fds->res, res, fds->res_min, min, fds->res_max, temp_shift, total_shift);
2451 
2452  /* set new domain dimensions */
2453  copy_v3_v3_int(fds->res_min, min);
2454  copy_v3_v3_int(fds->res_max, max);
2455  copy_v3_v3_int(fds->res, res);
2456  fds->total_cells = total_cells;
2457 
2458  /* Redo adapt time step in manta to refresh solver state (ie time variables) */
2460  }
2461 }
2462 
2463 BLI_INLINE void apply_outflow_fields(int index,
2464  float distance_value,
2465  float *density,
2466  float *heat,
2467  float *fuel,
2468  float *react,
2469  float *color_r,
2470  float *color_g,
2471  float *color_b,
2472  float *phiout)
2473 {
2474  /* Set levelset value for liquid inflow.
2475  * Ensure that distance value is "joined" into the levelset. */
2476  if (phiout) {
2477  phiout[index] = MIN2(distance_value, phiout[index]);
2478  }
2479 
2480  /* Set smoke outflow, i.e. reset cell to zero. */
2481  if (density) {
2482  density[index] = 0.0f;
2483  }
2484  if (heat) {
2485  heat[index] = 0.0f;
2486  }
2487  if (fuel) {
2488  fuel[index] = 0.0f;
2489  react[index] = 0.0f;
2490  }
2491  if (color_r) {
2492  color_r[index] = 0.0f;
2493  color_g[index] = 0.0f;
2494  color_b[index] = 0.0f;
2495  }
2496 }
2497 
2498 BLI_INLINE void apply_inflow_fields(FluidFlowSettings *ffs,
2499  float emission_value,
2500  float distance_value,
2501  int index,
2502  float *density_in,
2503  const float *density,
2504  float *heat_in,
2505  const float *heat,
2506  float *fuel_in,
2507  const float *fuel,
2508  float *react_in,
2509  const float *react,
2510  float *color_r_in,
2511  const float *color_r,
2512  float *color_g_in,
2513  const float *color_g,
2514  float *color_b_in,
2515  const float *color_b,
2516  float *phi_in,
2517  float *emission_in)
2518 {
2519  /* Set levelset value for liquid inflow.
2520  * Ensure that distance value is "joined" into the levelset. */
2521  if (phi_in) {
2522  phi_in[index] = MIN2(distance_value, phi_in[index]);
2523  }
2524 
2525  /* Set emission value for smoke inflow.
2526  * Ensure that emission value is "maximized". */
2527  if (emission_in) {
2528  emission_in[index] = MAX2(emission_value, emission_in[index]);
2529  }
2530 
2531  /* Set inflow for smoke from here on. */
2532  int absolute_flow = (ffs->flags & FLUID_FLOW_ABSOLUTE);
2533  float dens_old = (density) ? density[index] : 0.0;
2534  // float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */
2535  float dens_flow = (ffs->type == FLUID_FLOW_TYPE_FIRE) ? 0.0f : emission_value * ffs->density;
2536  float fuel_flow = (fuel) ? emission_value * ffs->fuel_amount : 0.0f;
2537  /* Set heat inflow. */
2538  if (heat && heat_in) {
2539  if (emission_value > 0.0f) {
2540  heat_in[index] = ADD_IF_LOWER(heat[index], ffs->temperature);
2541  }
2542  }
2543 
2544  /* Set density and fuel - absolute mode. */
2545  if (absolute_flow) {
2546  if (density && density_in) {
2547  if (ffs->type != FLUID_FLOW_TYPE_FIRE && dens_flow > density[index]) {
2548  /* Use MAX2 to preserve values from other emitters at this cell. */
2549  density_in[index] = MAX2(dens_flow, density_in[index]);
2550  }
2551  }
2552  if (fuel && fuel_in) {
2553  if (ffs->type != FLUID_FLOW_TYPE_SMOKE && fuel_flow && fuel_flow > fuel[index]) {
2554  /* Use MAX2 to preserve values from other emitters at this cell. */
2555  fuel_in[index] = MAX2(fuel_flow, fuel_in[index]);
2556  }
2557  }
2558  }
2559  /* Set density and fuel - additive mode. */
2560  else {
2561  if (density && density_in) {
2562  if (ffs->type != FLUID_FLOW_TYPE_FIRE) {
2563  density_in[index] += dens_flow;
2564  CLAMP(density_in[index], 0.0f, 1.0f);
2565  }
2566  }
2567  if (fuel && fuel_in) {
2568  if (ffs->type != FLUID_FLOW_TYPE_SMOKE && ffs->fuel_amount) {
2569  fuel_in[index] += fuel_flow;
2570  CLAMP(fuel_in[index], 0.0f, 10.0f);
2571  }
2572  }
2573  }
2574 
2575  /* Set color. */
2576  if (color_r && color_r_in) {
2577  if (dens_flow) {
2578  float total_dens = density[index] / (dens_old + dens_flow);
2579  color_r_in[index] = (color_r[index] + ffs->color[0] * dens_flow) * total_dens;
2580  color_g_in[index] = (color_g[index] + ffs->color[1] * dens_flow) * total_dens;
2581  color_b_in[index] = (color_b[index] + ffs->color[2] * dens_flow) * total_dens;
2582  }
2583  }
2584 
2585  /* Set fire reaction coordinate. */
2586  if (fuel && fuel_in) {
2587  /* Instead of using 1.0 for all new fuel add slight falloff to reduce flow blocky-ness. */
2588  float value = 1.0f - pow2f(1.0f - emission_value);
2589 
2590  if (fuel_in[index] > FLT_EPSILON && value > react[index]) {
2591  float f = fuel_flow / fuel_in[index];
2592  react_in[index] = value * f + (1.0f - f) * react[index];
2593  CLAMP(react_in[index], 0.0f, value);
2594  }
2595  }
2596 }
2597 
2598 static void ensure_flowsfields(FluidDomainSettings *fds)
2599 {
2601  manta_ensure_invelocity(fds->fluid, fds->fmd);
2602  }
2604  manta_ensure_outflow(fds->fluid, fds->fmd);
2605  }
2607  manta_smoke_ensure_heat(fds->fluid, fds->fmd);
2608  }
2610  manta_smoke_ensure_fire(fds->fluid, fds->fmd);
2611  }
2613  /* Initialize all smoke with "active_color". */
2614  manta_smoke_ensure_colors(fds->fluid, fds->fmd);
2615  }
2616  if (fds->type == FLUID_DOMAIN_TYPE_LIQUID &&
2621  }
2622  manta_update_pointers(fds->fluid, fds->fmd, false);
2623 }
2624 
2625 static void update_flowsflags(FluidDomainSettings *fds, Object **flowobjs, int numflowobj)
2626 {
2627  int active_fields = fds->active_fields;
2628  uint flow_index;
2629 
2630  /* First, remove all flags that we want to update. */
2633  active_fields &= ~prev_flags;
2634 
2635  /* Monitor active fields based on flow settings. */
2636  for (flow_index = 0; flow_index < numflowobj; flow_index++) {
2637  Object *flow_ob = flowobjs[flow_index];
2640 
2641  /* Sanity check. */
2642  if (!fmd2) {
2643  continue;
2644  }
2645 
2646  /* Activate specific grids if at least one flow object requires this grid. */
2647  if ((fmd2->type & MOD_FLUID_TYPE_FLOW) && fmd2->flow) {
2648  FluidFlowSettings *ffs = fmd2->flow;
2649  if (!ffs) {
2650  break;
2651  }
2652  if (ffs->flags & FLUID_FLOW_NEEDS_UPDATE) {
2653  ffs->flags &= ~FLUID_FLOW_NEEDS_UPDATE;
2655  }
2656  if (ffs->flags & FLUID_FLOW_INITVELOCITY) {
2657  active_fields |= FLUID_DOMAIN_ACTIVE_INVEL;
2658  }
2659  if (ffs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW) {
2660  active_fields |= FLUID_DOMAIN_ACTIVE_OUTFLOW;
2661  }
2662  /* liquids done from here */
2663  if (fds->type == FLUID_DOMAIN_TYPE_LIQUID) {
2664  continue;
2665  }
2666 
2667  /* Activate heat field if a flow object produces any heat. */
2668  if (ffs->temperature != 0.0) {
2669  active_fields |= FLUID_DOMAIN_ACTIVE_HEAT;
2670  }
2671  /* Activate fuel field if a flow object is of fire type. */
2672  if (ffs->fuel_amount != 0.0 || ffs->type == FLUID_FLOW_TYPE_FIRE ||
2673  ffs->type == FLUID_FLOW_TYPE_SMOKEFIRE) {
2674  active_fields |= FLUID_DOMAIN_ACTIVE_FIRE;
2675  }
2676  /* Activate color field if flows add smoke with varying colors. */
2677  if (ffs->density != 0.0 &&
2679  if (!(active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET)) {
2680  copy_v3_v3(fds->active_color, ffs->color);
2681  active_fields |= FLUID_DOMAIN_ACTIVE_COLOR_SET;
2682  }
2683  else if (!equals_v3v3(fds->active_color, ffs->color)) {
2684  copy_v3_v3(fds->active_color, ffs->color);
2685  active_fields |= FLUID_DOMAIN_ACTIVE_COLORS;
2686  }
2687  }
2688  }
2689  }
2690  /* Monitor active fields based on domain settings. */
2691  if (fds->type == FLUID_DOMAIN_TYPE_GAS && active_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
2692  /* Heat is always needed for fire. */
2693  active_fields |= FLUID_DOMAIN_ACTIVE_HEAT;
2694  /* Also activate colors if domain smoke color differs from active color. */
2695  if (!(active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET)) {
2697  active_fields |= FLUID_DOMAIN_ACTIVE_COLOR_SET;
2698  }
2699  else if (!equals_v3v3(fds->active_color, fds->flame_smoke_color)) {
2701  active_fields |= FLUID_DOMAIN_ACTIVE_COLORS;
2702  }
2703  }
2704  fds->active_fields = active_fields;
2705 }
2706 
2707 static bool escape_flowsobject(Object *flowobj,
2708  FluidDomainSettings *fds,
2709  FluidFlowSettings *ffs,
2710  int frame)
2711 {
2712  bool use_velocity = (ffs->flags & FLUID_FLOW_INITVELOCITY);
2713  bool is_static = is_static_object(flowobj);
2714 
2715  bool liquid_flow = ffs->type == FLUID_FLOW_TYPE_LIQUID;
2716  bool gas_flow = (ffs->type == FLUID_FLOW_TYPE_SMOKE || ffs->type == FLUID_FLOW_TYPE_FIRE ||
2718  bool is_geometry = (ffs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY);
2719 
2720  bool liquid_domain = fds->type == FLUID_DOMAIN_TYPE_LIQUID;
2721  bool gas_domain = fds->type == FLUID_DOMAIN_TYPE_GAS;
2722  bool is_adaptive = (fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN);
2723  bool is_resume = (fds->cache_frame_pause_data == frame);
2724  bool is_first_frame = (fds->cache_frame_start == frame);
2725 
2726  /* Cannot use static mode with adaptive domain.
2727  * The adaptive domain might expand and only later discover the static object. */
2728  if (is_adaptive) {
2729  is_static = false;
2730  }
2731  /* No need to compute emission value if it won't be applied. */
2732  if (liquid_flow && is_geometry && !is_first_frame) {
2733  return true;
2734  }
2735  /* Skip flow object if it does not "belong" to this domain type. */
2736  if ((liquid_flow && gas_domain) || (gas_flow && liquid_domain)) {
2737  return true;
2738  }
2739  /* Optimization: Static liquid flow objects don't need emission after first frame.
2740  * TODO(sebbas): Also do not use static mode if initial velocities are enabled. */
2741  if (liquid_flow && is_static && !is_first_frame && !is_resume && !use_velocity) {
2742  return true;
2743  }
2744  return false;
2745 }
2746 
2747 static void compute_flowsemission(Scene *scene,
2748  FluidObjectBB *bb_maps,
2749  struct Depsgraph *depsgraph,
2750  float dt,
2751  Object **flowobjs,
2752  int frame,
2753  float frame_length,
2754  FluidDomainSettings *fds,
2755  uint numflowobjs,
2756  float time_per_frame)
2757 {
2758  bool is_first_frame = (frame == fds->cache_frame_start);
2759 
2760  /* Prepare flow emission maps. */
2761  for (int flow_index = 0; flow_index < numflowobjs; flow_index++) {
2762  Object *flowobj = flowobjs[flow_index];
2765 
2766  /* Sanity check. */
2767  if (!fmd2) {
2768  continue;
2769  }
2770 
2771  /* Check for initialized flow object. */
2772  if ((fmd2->type & MOD_FLUID_TYPE_FLOW) && fmd2->flow) {
2773  FluidFlowSettings *ffs = fmd2->flow;
2774  int subframes = ffs->subframes;
2775  FluidObjectBB *bb = &bb_maps[flow_index];
2776 
2777  /* Optimization: Skip this object under certain conditions. */
2778  if (escape_flowsobject(flowobj, fds, ffs, frame)) {
2779  continue;
2780  }
2781 
2782  /* First frame cannot have any subframes because there is (obviously) no previous frame from
2783  * where subframes could come from. */
2784  if (is_first_frame) {
2785  subframes = 0;
2786  }
2787 
2788  /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */
2789  float sample_size = 1.0f / (float)(subframes + 1);
2790  float subframe_dt = dt * sample_size;
2791 
2792  /* Emission loop. When not using subframes this will loop only once. */
2793  for (int subframe = 0; subframe <= subframes; subframe++) {
2794  /* Temporary emission map used when subframes are enabled, i.e. at least one subframe. */
2795  FluidObjectBB bb_temp = {NULL};
2796 
2797  /* Set scene time */
2798  if ((subframe < subframes || time_per_frame + dt + FLT_EPSILON < frame_length) &&
2799  !is_first_frame) {
2800  scene->r.subframe = (time_per_frame + (subframe + 1.0f) * subframe_dt) / frame_length;
2801  scene->r.cfra = frame - 1;
2802  }
2803  else {
2804  scene->r.subframe = 0.0f;
2805  scene->r.cfra = frame;
2806  }
2807 
2808  /* Sanity check: subframe portion must be between 0 and 1. */
2809  CLAMP(scene->r.subframe, 0.0f, 1.0f);
2810 # ifdef DEBUG_PRINT
2811  /* Debugging: Print subframe information. */
2812  printf(
2813  "flow: frame (is first: %d): %d // scene current frame: %d // scene current subframe: "
2814  "%f\n",
2815  is_first_frame,
2816  frame,
2817  scene->r.cfra,
2818  scene->r.subframe);
2819 # endif
2820  /* Update frame time, this is considering current subframe fraction
2821  * BLI_mutex_lock() called in manta_step(), so safe to update subframe here
2822  * TODO(sebbas): Using BKE_scene_frame_get(scene) instead of new DEG_get_ctime(depsgraph)
2823  * as subframes don't work with the latter yet. */
2826 
2827  /* Emission from particles. */
2828  if (ffs->source == FLUID_FLOW_SOURCE_PARTICLES) {
2829  if (subframes) {
2830  emit_from_particles(flowobj, fds, ffs, &bb_temp, depsgraph, scene, subframe_dt);
2831  }
2832  else {
2833  emit_from_particles(flowobj, fds, ffs, bb, depsgraph, scene, subframe_dt);
2834  }
2835  }
2836  /* Emission from mesh. */
2837  else if (ffs->source == FLUID_FLOW_SOURCE_MESH) {
2838  if (subframes) {
2839  emit_from_mesh(flowobj, fds, ffs, &bb_temp, subframe_dt);
2840  }
2841  else {
2842  emit_from_mesh(flowobj, fds, ffs, bb, subframe_dt);
2843  }
2844  }
2845  else {
2846  printf("Error: unknown flow emission source\n");
2847  }
2848 
2849  /* If this we emitted with temp emission map in this loop (subframe emission), we combine
2850  * the temp map with the original emission map. */
2851  if (subframes) {
2852  /* Combine emission maps. */
2853  bb_combineMaps(bb, &bb_temp, !(ffs->flags & FLUID_FLOW_ABSOLUTE), sample_size);
2854  bb_freeData(&bb_temp);
2855  }
2856  }
2857  }
2858  }
2859 # ifdef DEBUG_PRINT
2860  /* Debugging: Print time information. */
2861  printf("flow: frame: %d // time per frame: %f // frame length: %f // dt: %f\n",
2862  frame,
2863  time_per_frame,
2864  frame_length,
2865  dt);
2866 # endif
2867 }
2868 
2869 static void update_flowsfluids(struct Depsgraph *depsgraph,
2870  Scene *scene,
2871  Object *ob,
2872  FluidDomainSettings *fds,
2873  float time_per_frame,
2874  float frame_length,
2875  int frame,
2876  float dt)
2877 {
2878  FluidObjectBB *bb_maps = NULL;
2879  Object **flowobjs = NULL;
2880  uint numflowobjs = 0;
2881  bool is_resume = (fds->cache_frame_pause_data == frame);
2882  bool is_first_frame = (fds->cache_frame_start == frame);
2883 
2884  flowobjs = BKE_collision_objects_create(
2885  depsgraph, ob, fds->fluid_group, &numflowobjs, eModifierType_Fluid);
2886 
2887  /* Update all flow related flags and ensure that corresponding grids get initialized. */
2888  update_flowsflags(fds, flowobjs, numflowobjs);
2889  ensure_flowsfields(fds);
2890 
2891  /* Allocate emission map for each flow object. */
2892  bb_maps = MEM_callocN(sizeof(struct FluidObjectBB) * numflowobjs, "fluid_flow_bb_maps");
2893 
2894  /* Initialize emission map for each flow object. */
2895  compute_flowsemission(scene,
2896  bb_maps,
2897  depsgraph,
2898  dt,
2899  flowobjs,
2900  frame,
2901  frame_length,
2902  fds,
2903  numflowobjs,
2904  time_per_frame);
2905 
2906  /* Adjust domain size if needed. Only do this once for every frame. */
2908  adaptive_domain_adjust(fds, ob, bb_maps, numflowobjs, dt);
2909  }
2910 
2911  float *phi_in = manta_get_phi_in(fds->fluid);
2912  float *phistatic_in = manta_get_phistatic_in(fds->fluid);
2913  float *phiout_in = manta_get_phiout_in(fds->fluid);
2914  float *phioutstatic_in = manta_get_phioutstatic_in(fds->fluid);
2915 
2916  float *density = manta_smoke_get_density(fds->fluid);
2917  float *color_r = manta_smoke_get_color_r(fds->fluid);
2918  float *color_g = manta_smoke_get_color_g(fds->fluid);
2919  float *color_b = manta_smoke_get_color_b(fds->fluid);
2920  float *fuel = manta_smoke_get_fuel(fds->fluid);
2921  float *heat = manta_smoke_get_heat(fds->fluid);
2922  float *react = manta_smoke_get_react(fds->fluid);
2923 
2924  float *density_in = manta_smoke_get_density_in(fds->fluid);
2925  float *heat_in = manta_smoke_get_heat_in(fds->fluid);
2926  float *color_r_in = manta_smoke_get_color_r_in(fds->fluid);
2927  float *color_g_in = manta_smoke_get_color_g_in(fds->fluid);
2928  float *color_b_in = manta_smoke_get_color_b_in(fds->fluid);
2929  float *fuel_in = manta_smoke_get_fuel_in(fds->fluid);
2930  float *react_in = manta_smoke_get_react_in(fds->fluid);
2931  float *emission_in = manta_smoke_get_emission_in(fds->fluid);
2932 
2933  float *velx_initial = manta_get_in_velocity_x(fds->fluid);
2934  float *vely_initial = manta_get_in_velocity_y(fds->fluid);
2935  float *velz_initial = manta_get_in_velocity_z(fds->fluid);
2936 
2937  float *forcex = manta_get_force_x(fds->fluid);
2938  float *forcey = manta_get_force_y(fds->fluid);
2939  float *forcez = manta_get_force_z(fds->fluid);
2940 
2941  BLI_assert(forcex && forcey && forcez);
2942 
2943  /* Either all or no components have to exist. */
2944  BLI_assert((color_r && color_g && color_b) || (!color_r && !color_g && !color_b));
2945  BLI_assert((color_r_in && color_g_in && color_b_in) ||
2946  (!color_r_in && !color_g_in && !color_b_in));
2947  BLI_assert((velx_initial && vely_initial && velz_initial) ||
2948  (!velx_initial && !vely_initial && !velz_initial));
2949 
2950  uint z;
2951  /* Grid reset before writing again. */
2952  for (z = 0; z < fds->res[0] * fds->res[1] * fds->res[2]; z++) {
2953  /* Only reset static phi on first frame, dynamic phi gets reset every time. */
2954  if (phistatic_in && is_first_frame) {
2955  phistatic_in[z] = PHI_MAX;
2956  }
2957  if (phi_in) {
2958  phi_in[z] = PHI_MAX;
2959  }
2960  /* Only reset static phi on first frame, dynamic phi gets reset every time. */
2961  if (phioutstatic_in && is_first_frame) {
2962  phioutstatic_in[z] = PHI_MAX;
2963  }
2964  if (phiout_in) {
2965  phiout_in[z] = PHI_MAX;
2966  }
2967  /* Sync smoke inflow grids with their counterparts (simulation grids). */
2968  if (density_in) {
2969  density_in[z] = density[z];
2970  }
2971  if (heat_in) {
2972  heat_in[z] = heat[z];
2973  }
2974  if (color_r_in && color_g_in && color_b_in) {
2975  color_r_in[z] = color_r[z];
2976  color_g_in[z] = color_b[z];
2977  color_b_in[z] = color_g[z];
2978  }
2979  if (fuel_in) {
2980  fuel_in[z] = fuel[z];
2981  react_in[z] = react[z];
2982  }
2983  if (emission_in) {
2984  emission_in[z] = 0.0f;
2985  }
2986  if (velx_initial && vely_initial && velz_initial) {
2987  velx_initial[z] = 0.0f;
2988  vely_initial[z] = 0.0f;
2989  velz_initial[z] = 0.0f;
2990  }
2991  /* Reset forces here as update_effectors() is skipped when no external forces are present. */
2992  forcex[z] = 0.0f;
2993  forcey[z] = 0.0f;
2994  forcez[z] = 0.0f;
2995  }
2996 
2997  /* Apply emission data for every flow object. */
2998  for (int flow_index = 0; flow_index < numflowobjs; flow_index++) {
2999  Object *flowobj = flowobjs[flow_index];
3002 
3003  /* Sanity check. */
3004  if (!fmd2) {
3005  continue;
3006  }
3007 
3008  /* Check for initialized flow object. */
3009  if ((fmd2->type & MOD_FLUID_TYPE_FLOW) && fmd2->flow) {
3010  FluidFlowSettings *ffs = fmd2->flow;
3011 
3012  bool is_inflow = (ffs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW);
3013  bool is_geometry = (ffs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY);
3014  bool is_outflow = (ffs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW);
3015  bool is_static = is_static_object(flowobj) &&
3016  ((fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) == 0);
3017 
3018  FluidObjectBB *bb = &bb_maps[flow_index];
3019  float *velocity_map = bb->velocity;
3020  float *emission_map = bb->influence;
3021  float *distance_map = bb->distances;
3022 
3023  int gx, gy, gz, ex, ey, ez, dx, dy, dz;
3024  size_t e_index, d_index;
3025 
3026  /* Loop through every emission map cell. */
3027  for (gx = bb->min[0]; gx < bb->max[0]; gx++) {
3028  for (gy = bb->min[1]; gy < bb->max[1]; gy++) {
3029  for (gz = bb->min[2]; gz < bb->max[2]; gz++) {
3030  /* Compute emission map index. */
3031  ex = gx - bb->min[0];
3032  ey = gy - bb->min[1];
3033  ez = gz - bb->min[2];
3034  e_index = manta_get_index(ex, bb->res[0], ey, bb->res[1], ez);
3035 
3036  /* Get domain index. */
3037  dx = gx - fds->res_min[0];
3038  dy = gy - fds->res_min[1];
3039  dz = gz - fds->res_min[2];
3040  d_index = manta_get_index(dx, fds->res[0], dy, fds->res[1], dz);
3041  /* Make sure emission cell is inside the new domain boundary. */
3042  if (dx < 0 || dy < 0 || dz < 0 || dx >= fds->res[0] || dy >= fds->res[1] ||
3043  dz >= fds->res[2]) {
3044  continue;
3045  }
3046 
3047  /* Delete fluid in outflow regions. */
3048  if (is_outflow) {
3049  float *levelset = ((is_first_frame || is_resume) && is_static) ? phioutstatic_in :
3050  phiout_in;
3051  apply_outflow_fields(d_index,
3052  distance_map[e_index],
3053  density_in,
3054  heat_in,
3055  fuel_in,
3056  react_in,
3057  color_r_in,
3058  color_g_in,
3059  color_b_in,
3060  levelset);
3061  }
3062  /* Do not apply inflow after the first frame when in geometry mode. */
3063  else if (is_geometry && !is_first_frame) {
3064  apply_inflow_fields(ffs,
3065  0.0f,
3066  PHI_MAX,
3067  d_index,
3068  density_in,
3069  density,
3070  heat_in,
3071  heat,
3072  fuel_in,
3073  fuel,
3074  react_in,
3075  react,
3076  color_r_in,
3077  color_r,
3078  color_g_in,
3079  color_g,
3080  color_b_in,
3081  color_b,
3082  phi_in,
3083  emission_in);
3084  }
3085  /* Main inflow application. */
3086  else if (is_geometry || is_inflow) {
3087  float *levelset = ((is_first_frame || is_resume) && is_static && !is_geometry) ?
3088  phistatic_in :
3089  phi_in;
3090  apply_inflow_fields(ffs,
3091  emission_map[e_index],
3092  distance_map[e_index],
3093  d_index,
3094  density_in,
3095  density,
3096  heat_in,
3097  heat,
3098  fuel_in,
3099  fuel,
3100  react_in,
3101  react,
3102  color_r_in,
3103  color_r,
3104  color_g_in,
3105  color_g,
3106  color_b_in,
3107  color_b,
3108  levelset,
3109  emission_in);
3110  if (ffs->flags & FLUID_FLOW_INITVELOCITY) {
3111  /* Use the initial velocity from the inflow object with the highest velocity for
3112  * now. */
3113  float vel_initial[3];
3114  vel_initial[0] = velx_initial[d_index];
3115  vel_initial[1] = vely_initial[d_index];
3116  vel_initial[2] = velz_initial[d_index];
3117  float vel_initial_strength = len_squared_v3(vel_initial);
3118  float vel_map_strength = len_squared_v3(velocity_map + 3 * e_index);
3119  if (vel_map_strength > vel_initial_strength) {
3120  velx_initial[d_index] = velocity_map[e_index * 3];
3121  vely_initial[d_index] = velocity_map[e_index * 3 + 1];
3122  velz_initial[d_index] = velocity_map[e_index * 3 + 2];
3123  }
3124  }
3125  }
3126  }
3127  }
3128  } /* End of flow emission map loop. */
3129  bb_freeData(bb);
3130  } /* End of flow object loop. */
3131  }
3132 
3133  BKE_collision_objects_free(flowobjs);
3134  if (bb_maps) {
3135  MEM_freeN(bb_maps);
3136  }
3137 }
3138 
3139 typedef struct UpdateEffectorsData {
3140  Scene *scene;
3141  FluidDomainSettings *fds;
3142  ListBase *effectors;
3143 
3144  float *density;
3145  float *fuel;
3146  float *force_x;
3147  float *force_y;
3148  float *force_z;
3149  float *velocity_x;
3150  float *velocity_y;
3151  float *velocity_z;
3152  int *flags;
3153  float *phi_obs_in;
3154 } UpdateEffectorsData;
3155 
3156 static void update_effectors_task_cb(void *__restrict userdata,
3157  const int x,
3158  const TaskParallelTLS *__restrict UNUSED(tls))
3159 {
3160  UpdateEffectorsData *data = userdata;
3161  FluidDomainSettings *fds = data->fds;
3162 
3163  for (int y = 0; y < fds->res[1]; y++) {
3164  for (int z = 0; z < fds->res[2]; z++) {
3165  EffectedPoint epoint;
3166  float mag;
3167  float voxel_center[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0};
3168  const uint index = manta_get_index(x, fds->res[0], y, fds->res[1], z);
3169 
3170  if ((data->fuel && MAX2(data->density[index], data->fuel[index]) < FLT_EPSILON) ||
3171  (data->density && data->density[index] < FLT_EPSILON) ||
3172  (data->phi_obs_in && data->phi_obs_in[index] < 0.0f) ||
3173  data->flags[index] & 2) // mantaflow convention: 2 == FlagObstacle
3174  {
3175  continue;
3176  }
3177 
3178  /* Get velocities from manta grid space and convert to blender units. */
3179  vel[0] = data->velocity_x[index];
3180  vel[1] = data->velocity_y[index];
3181  vel[2] = data->velocity_z[index];
3182  mul_v3_fl(vel, fds->dx);
3183 
3184  /* Convert vel to global space. */
3185  mag = len_v3(vel);
3186  mul_mat3_m4_v3(fds->obmat, vel);
3187  normalize_v3(vel);
3188  mul_v3_fl(vel, mag);
3189 
3190  voxel_center[0] = fds->p0[0] + fds->cell_size[0] * ((float)(x + fds->res_min[0]) + 0.5f);
3191  voxel_center[1] = fds->p0[1] + fds->cell_size[1] * ((float)(y + fds->res_min[1]) + 0.5f);
3192  voxel_center[2] = fds->p0[2] + fds->cell_size[2] * ((float)(z + fds->res_min[2]) + 0.5f);
3193  mul_m4_v3(fds->obmat, voxel_center);
3194 
3195  /* Do effectors. */
3196  pd_point_from_loc(data->scene, voxel_center, vel, index, &epoint);
3198  data->effectors, NULL, fds->effector_weights, &epoint, retvel, NULL, NULL);
3199 
3200  /* Convert retvel to local space. */
3201  mag = len_v3(retvel);
3202  mul_mat3_m4_v3(fds->imat, retvel);
3203  normalize_v3(retvel);
3204  mul_v3_fl(retvel, mag);
3205 
3206  /* Copy computed force to fluid solver forces. */
3207  mul_v3_fl(retvel, 0.2f); /* Factor from 0e6820cc5d62. */
3208  CLAMP3(retvel, -1.0f, 1.0f); /* Restrict forces to +-1 interval. */
3209  data->force_x[index] = retvel[0];
3210  data->force_y[index] = retvel[1];
3211  data->force_z[index] = retvel[2];
3212 
3213 # ifdef DEBUG_PRINT
3214  /* Debugging: Print forces. */
3215  printf("setting force: [%f, %f, %f]\n",
3216  data->force_x[index],
3217  data->force_y[index],
3218  data->force_z[index]);
3219 # endif
3220  }
3221  }
3222 }
3223 
3224 static void update_effectors(
3225  Depsgraph *depsgraph, Scene *scene, Object *ob, FluidDomainSettings *fds, float UNUSED(dt))
3226 {
3227  ListBase *effectors;
3228  /* make sure smoke flow influence is 0.0f */
3230  effectors = BKE_effectors_create(depsgraph, ob, NULL, fds->effector_weights, false);
3231 
3232  if (effectors) {
3233  /* Precalculate wind forces. */
3234  UpdateEffectorsData data;
3235  data.scene = scene;
3236  data.fds = fds;
3237  data.effectors = effectors;
3238  data.density = manta_smoke_get_density(fds->fluid);
3239  data.fuel = manta_smoke_get_fuel(fds->fluid);
3240  data.force_x = manta_get_force_x(fds->fluid);
3241  data.force_y = manta_get_force_y(fds->fluid);
3242  data.force_z = manta_get_force_z(fds->fluid);
3243  data.velocity_x = manta_get_velocity_x(fds->fluid);
3244  data.velocity_y = manta_get_velocity_y(fds->fluid);
3245  data.velocity_z = manta_get_velocity_z(fds->fluid);
3246  data.flags = manta_smoke_get_flags(fds->fluid);
3247  data.phi_obs_in = manta_get_phiobs_in(fds->fluid);
3248 
3249  TaskParallelSettings settings;
3251  settings.min_iter_per_thread = 2;
3252  BLI_task_parallel_range(0, fds->res[0], &data, update_effectors_task_cb, &settings);
3253  }
3254 
3255  BKE_effectors_free(effectors);
3256 }
3257 
3258 static Mesh *create_liquid_geometry(FluidDomainSettings *fds, Mesh *orgmesh, Object *ob)
3259 {
3260  Mesh *me;
3261  MVert *mverts;
3262  MPoly *mpolys;
3263  MLoop *mloops;
3264  short *normals, *no_s;
3265  float no[3];
3266  float min[3];
3267  float max[3];
3268  float size[3];
3269  float cell_size_scaled[3];
3270 
3271  /* Assign material + flags to new mesh.
3272  * If there are no faces in original mesh, keep materials and flags unchanged. */
3273  MPoly *mpoly;
3274  MPoly mp_example = {0};
3275  mpoly = orgmesh->mpoly;
3276  if (mpoly) {
3277  mp_example = *mpoly;
3278  }
3279 
3280  const short mp_mat_nr = mp_example.mat_nr;
3281  const char mp_flag = mp_example.flag;
3282 
3283  int i;
3284  int num_verts, num_normals, num_faces;
3285 
3286  if (!fds->fluid) {
3287  return NULL;
3288  }
3289 
3290  num_verts = manta_liquid_get_num_verts(fds->fluid);
3291  num_normals = manta_liquid_get_num_normals(fds->fluid);
3292  num_faces = manta_liquid_get_num_triangles(fds->fluid);
3293 
3294 # ifdef DEBUG_PRINT
3295  /* Debugging: Print number of vertices, normals, and faces. */
3296  printf("num_verts: %d, num_normals: %d, num_faces: %d\n", num_verts, num_normals, num_faces);
3297 # endif
3298 
3299  if (!num_verts || !num_faces) {
3300  return NULL;
3301  }
3302  /* Normals are per vertex, so these must match. */
3303  BLI_assert(num_verts == num_normals);
3304 
3305  /* If needed, vertex velocities will be read too. */
3306  bool use_speedvectors = fds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS;
3307  FluidDomainVertexVelocity *velarray = NULL;
3308  float time_mult = 25.0f * DT_DEFAULT;
3309 
3310  if (use_speedvectors) {
3311  if (fds->mesh_velocities) {
3312  MEM_freeN(fds->mesh_velocities);
3313  }
3314 
3316  num_verts, sizeof(FluidDomainVertexVelocity), "fluid_mesh_vertvelocities");
3317  fds->totvert = num_verts;
3318  velarray = fds->mesh_velocities;
3319  }
3320 
3321  me = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 3, num_faces);
3322  if (!me) {
3323  return NULL;
3324  }
3325  mverts = me->mvert;
3326  mpolys = me->mpoly;
3327  mloops = me->mloop;
3328 
3329  /* Get size (dimension) but considering scaling scaling. */
3330  copy_v3_v3(cell_size_scaled, fds->cell_size);
3331  mul_v3_v3(cell_size_scaled, ob->scale);
3332  madd_v3fl_v3fl_v3fl_v3i(min, fds->p0, cell_size_scaled, fds->res_min);
3333  madd_v3fl_v3fl_v3fl_v3i(max, fds->p0, cell_size_scaled, fds->res_max);
3334  sub_v3_v3v3(size, max, min);
3335 
3336  /* Biggest dimension will be used for upscaling. */
3337  float max_size = MAX3(size[0], size[1], size[2]);
3338 
3339  float co_scale[3];
3340  co_scale[0] = max_size / ob->scale[0];
3341  co_scale[1] = max_size / ob->scale[1];
3342  co_scale[2] = max_size / ob->scale[2];
3343 
3344  float co_offset[3];
3345  co_offset[0] = (fds->p0[0] + fds->p1[0]) / 2.0f;
3346  co_offset[1] = (fds->p0[1] + fds->p1[1]) / 2.0f;
3347  co_offset[2] = (fds->p0[2] + fds->p1[2]) / 2.0f;
3348 
3349  /* Normals. */
3350  normals = MEM_callocN(sizeof(short[3]) * num_normals, "Fluidmesh_tmp_normals");
3351 
3352  /* Loop for vertices and normals. */
3353  for (i = 0, no_s = normals; i < num_verts && i < num_normals; i++, mverts++, no_s += 3) {
3354 
3355  /* Vertices (data is normalized cube around domain origin). */
3356  mverts->co[0] = manta_liquid_get_vertex_x_at(fds->fluid, i);
3357  mverts->co[1] = manta_liquid_get_vertex_y_at(fds->fluid, i);
3358  mverts->co[2] = manta_liquid_get_vertex_z_at(fds->fluid, i);
3359 
3360  /* Adjust coordinates from Mantaflow to match viewport scaling. */
3361  float tmp[3] = {(float)fds->res[0], (float)fds->res[1], (float)fds->res[2]};
3362  /* Scale to unit cube around 0. */
3363  mul_v3_fl(tmp, fds->mesh_scale * 0.5f);
3364  sub_v3_v3(mverts->co, tmp);
3365  /* Apply scaling of domain object. */
3366  mul_v3_fl(mverts->co, fds->dx / fds->mesh_scale);
3367 
3368  mul_v3_v3(mverts->co, co_scale);
3369  add_v3_v3(mverts->co, co_offset);
3370 
3371 # ifdef DEBUG_PRINT
3372  /* Debugging: Print coordinates of vertices. */
3373  printf("mverts->co[0]: %f, mverts->co[1]: %f, mverts->co[2]: %f\n",
3374  mverts->co[0],
3375  mverts->co[1],
3376  mverts->co[2]);
3377 # endif
3378 
3379  /* Normals (data is normalized cube around domain origin). */
3380  no[0] = manta_liquid_get_normal_x_at(fds->fluid, i);
3381  no[1] = manta_liquid_get_normal_y_at(fds->fluid, i);
3382  no[2] = manta_liquid_get_normal_z_at(fds->fluid, i);
3383 
3384  normal_float_to_short_v3(no_s, no);
3385 # ifdef DEBUG_PRINT
3386  /* Debugging: Print coordinates of normals. */
3387  printf("no_s[0]: %d, no_s[1]: %d, no_s[2]: %d\n", no_s[0], no_s[1], no_s[2]);
3388 # endif
3389 
3390  if (use_speedvectors) {
3391  velarray[i].vel[0] = manta_liquid_get_vertvel_x_at(fds->fluid, i) * (fds->dx / time_mult);
3392  velarray[i].vel[1] = manta_liquid_get_vertvel_y_at(fds->fluid, i) * (fds->dx / time_mult);
3393  velarray[i].vel[2] = manta_liquid_get_vertvel_z_at(fds->fluid, i) * (fds->dx / time_mult);
3394 # ifdef DEBUG_PRINT
3395  /* Debugging: Print velocities of vertices. */
3396  printf("velarray[%d].vel[0]: %f, velarray[%d].vel[1]: %f, velarray[%d].vel[2]: %f\n",
3397  i,
3398  velarray[i].vel[0],
3399  i,
3400  velarray[i].vel[1],
3401  i,
3402  velarray[i].vel[2]);
3403 # endif
3404  }
3405  }
3406 
3407  /* Loop for triangles. */
3408  for (i = 0; i < num_faces; i++, mpolys++, mloops += 3) {
3409  /* Initialize from existing face. */
3410  mpolys->mat_nr = mp_mat_nr;
3411  mpolys->flag = mp_flag;
3412 
3413  mpolys->loopstart = i * 3;
3414  mpolys->totloop = 3;
3415 
3416  mloops[0].v = manta_liquid_get_triangle_x_at(fds->fluid, i);
3417  mloops[1].v = manta_liquid_get_triangle_y_at(fds->fluid, i);
3418  mloops[2].v = manta_liquid_get_triangle_z_at(fds->fluid, i);
3419 # ifdef DEBUG_PRINT
3420  /* Debugging: Print mesh faces. */
3421  printf("mloops[0].v: %d, mloops[1].v: %d, mloops[2].v: %d\n",
3422  mloops[0].v,
3423  mloops[1].v,
3424  mloops[2].v);
3425 # endif
3426  }
3427 
3429  BKE_mesh_calc_edges(me, false, false);
3430  BKE_mesh_vert_normals_apply(me, (short(*)[3])normals);
3431 
3432  MEM_freeN(normals);
3433 
3434  return me;
3435 }
3436 
3437 static Mesh *create_smoke_geometry(FluidDomainSettings *fds, Mesh *orgmesh, Object *ob)
3438 {
3439  Mesh *result;
3440  MVert *mverts;
3441  MPoly *mpolys;
3442  MLoop *mloops;
3443  float min[3];
3444  float max[3];
3445  float *co;
3446  MPoly *mp;
3447  MLoop *ml;
3448 
3449  int num_verts = 8;
3450  int num_faces = 6;
3451  float ob_loc[3] = {0};
3452  float ob_cache_loc[3] = {0};
3453 
3454  /* Just copy existing mesh if there is no content or if the adaptive domain is not being used. */
3455  if (fds->total_cells <= 1 || (fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) == 0) {
3456  return BKE_mesh_copy_for_eval(orgmesh, false);
3457  }
3458 
3459  result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces);
3460  mverts = result->mvert;
3461  mpolys = result->mpoly;
3462  mloops = result->mloop;
3463 
3464  if (num_verts) {
3465  /* Volume bounds. */
3466  madd_v3fl_v3fl_v3fl_v3i(min, fds->p0, fds->cell_size, fds->res_min);
3467  madd_v3fl_v3fl_v3fl_v3i(max, fds->p0, fds->cell_size, fds->res_max);
3468 
3469  /* Set vertices of smoke BB. Especially important, when BB changes (adaptive domain). */
3470  /* Top slab */
3471  co = mverts[0].co;
3472  co[0] = min[0];
3473  co[1] = min[1];
3474  co[2] = max[2];
3475  co = mverts[1].co;
3476  co[0] = max[0];
3477  co[1] = min[1];
3478  co[2] = max[2];
3479  co = mverts[2].co;
3480  co[0] = max[0];
3481  co[1] = max[1];
3482  co[2] = max[2];
3483  co = mverts[3].co;
3484  co[0] = min[0];
3485  co[1] = max[1];
3486  co[2] = max[2];
3487  /* Bottom slab. */
3488  co = mverts[4].co;
3489  co[0] = min[0];
3490  co[1] = min[1];
3491  co[2] = min[2];
3492  co = mverts[5].co;
3493  co[0] = max[0];
3494  co[1] = min[1];
3495  co[2] = min[2];
3496  co = mverts[6].co;
3497  co[0] = max[0];
3498  co[1] = max[1];
3499  co[2] = min[2];
3500  co = mverts[7].co;
3501  co[0] = min[0];
3502  co[1] = max[1];
3503  co[2] = min[2];
3504 
3505  /* Create faces. */
3506  /* Top side. */
3507  mp = &mpolys[0];
3508  ml = &mloops[0 * 4];
3509  mp->loopstart = 0 * 4;
3510  mp->totloop = 4;
3511  ml[0].v = 0;
3512  ml[1].v = 1;
3513  ml[2].v = 2;
3514  ml[3].v = 3;
3515  /* Right side. */
3516  mp = &mpolys[1];
3517  ml = &mloops[1 * 4];
3518  mp->loopstart = 1 * 4;
3519  mp->totloop = 4;
3520  ml[0].v = 2;
3521  ml[1].v = 1;
3522  ml[2].v = 5;
3523  ml[3].v = 6;
3524  /* Bottom side. */
3525  mp = &mpolys[2];
3526  ml = &mloops[2 * 4];
3527  mp->loopstart = 2 * 4;
3528  mp->totloop = 4;
3529  ml[0].v = 7;
3530  ml[1].v = 6;
3531  ml[2].v = 5;
3532  ml[3].v = 4;
3533  /* Left side. */
3534  mp = &mpolys[3];
3535  ml = &mloops[3 * 4];
3536  mp->loopstart = 3 * 4;
3537  mp->totloop = 4;
3538  ml[0].v = 0;
3539  ml[1].v = 3;
3540  ml[2].v = 7;
3541  ml[3].v = 4;
3542  /* Front side. */
3543  mp = &mpolys[4];
3544  ml = &mloops[4 * 4];
3545  mp->loopstart = 4 * 4;
3546  mp->totloop = 4;
3547  ml[0].v = 3;
3548  ml[1].v = 2;
3549  ml[2].v = 6;
3550  ml[3].v = 7;
3551  /* Back side. */
3552  mp = &mpolys[5];
3553  ml = &mloops[5 * 4];
3554  mp->loopstart = 5 * 4;
3555  mp->totloop = 4;
3556  ml[0].v = 1;
3557  ml[1].v = 0;
3558  ml[2].v = 4;
3559  ml[3].v = 5;
3560 
3561  /* Calculate required shift to match domain's global position
3562  * it was originally simulated at (if object moves without manta step). */
3563  invert_m4_m4(ob->imat, ob->obmat);
3564  mul_m4_v3(ob->obmat, ob_loc);
3565  mul_m4_v3(fds->obmat, ob_cache_loc);
3566  sub_v3_v3v3(fds->obj_shift_f, ob_cache_loc, ob_loc);
3567  /* Convert shift to local space and apply to vertices. */
3568  mul_mat3_m4_v3(ob->imat, fds->obj_shift_f);
3569  /* Apply shift to vertices. */
3570  for (int i = 0; i < num_verts; i++) {
3571  add_v3_v3(mverts[i].co, fds->obj_shift_f);
3572  }
3573  }
3574 
3575  BKE_mesh_calc_edges(result, false, false);
3576  result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
3577  return result;
3578 }
3579 
3580 static int manta_step(
3581  Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me, FluidModifierData *fmd, int frame)
3582 {
3583  FluidDomainSettings *fds = fmd->domain;
3584  float dt, frame_length, time_total, time_total_old;
3585  float time_per_frame;
3586  bool init_resolution = true;
3587 
3588  /* Store baking success - bake might be aborted anytime by user. */
3589  int result = 1;
3590  int mode = fds->cache_type;
3591  bool mode_replay = (mode == FLUID_DOMAIN_CACHE_REPLAY);
3592 
3593  /* Update object state. */
3594  invert_m4_m4(fds->imat, ob->obmat);
3595  copy_m4_m4(fds->obmat, ob->obmat);
3596 
3597  /* Gas domain might use adaptive domain. */
3598  if (fds->type == FLUID_DOMAIN_TYPE_GAS) {
3599  init_resolution = (fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) != 0;
3600  }
3601  manta_set_domain_from_mesh(fds, ob, me, init_resolution);
3602 
3603  /* Use local variables for adaptive loop, dt can change. */
3604  frame_length = fds->frame_length;
3605  dt = fds->dt;
3606  time_per_frame = 0;
3607  time_total = fds->time_total;
3608  /* Keep track of original total time to correct small errors at end of step. */
3609  time_total_old = fds->time_total;
3610 
3611  BLI_mutex_lock(&object_update_lock);
3612 
3613  /* Loop as long as time_per_frame (sum of sub dt's) does not exceed actual framelength. */
3614  while (time_per_frame + FLT_EPSILON < frame_length) {
3616  dt = manta_get_timestep(fds->fluid);
3617 
3618  /* Save adapted dt so that MANTA object can access it (important when adaptive domain creates
3619  * new MANTA object). */
3620  fds->dt = dt;
3621 
3622  /* Calculate inflow geometry. */
3623  update_flowsfluids(depsgraph, scene, ob, fds, time_per_frame, frame_length, frame, dt);
3624 
3625  /* If user requested stop, quit baking */
3626  if (G.is_break && !mode_replay) {
3627  result = 0;
3628  break;
3629  }
3630 
3631  manta_update_variables(fds->fluid, fmd);
3632 
3633  /* Calculate obstacle geometry. */
3634  update_obstacles(depsgraph, scene, ob, fds, time_per_frame, frame_length, frame, dt);
3635 
3636  /* If user requested stop, quit baking */
3637  if (G.is_break && !mode_replay) {
3638  result = 0;
3639  break;
3640  }
3641 
3642  /* Only bake if the domain is bigger than one cell (important for adaptive domain). */
3643  if (fds->total_cells > 1) {
3644  update_effectors(depsgraph, scene, ob, fds, dt);
3645  manta_bake_data(fds->fluid, fmd, frame);
3646  }
3647 
3648  /* Count for how long this while loop is running. */
3649  time_per_frame += dt;
3650  time_total += dt;
3651 
3652  fds->time_per_frame = time_per_frame;
3653  fds->time_total = time_total;
3654  }
3655 
3656  /* Total time must not exceed framecount times framelength. Correct tiny errors here. */
3657  CLAMP_MAX(fds->time_total, time_total_old + fds->frame_length);
3658 
3659  /* Compute shadow grid for gas simulations. Make sure to skip if bake job was canceled early. */
3660  if (fds->type == FLUID_DOMAIN_TYPE_GAS && result) {
3661  manta_smoke_calc_transparency(fds, DEG_get_evaluated_view_layer(depsgraph));
3662  }
3663 
3664  BLI_mutex_unlock(&object_update_lock);
3665  return result;
3666 }
3667 
3668 static void manta_guiding(
3669  Depsgraph *depsgraph, Scene *scene, Object *ob, FluidModifierData *fmd, int frame)
3670 {
3671  FluidDomainSettings *fds = fmd->domain;
3672  float fps = scene->r.frs_sec / scene->r.frs_sec_base;
3673  float dt = DT_DEFAULT * (25.0f / fps) * fds->time_scale;
3674 
3675  BLI_mutex_lock(&object_update_lock);
3676 
3677  update_obstacles(depsgraph, scene, ob, fds, dt, dt, frame, dt);
3678  manta_bake_guiding(fds->fluid, fmd, frame);
3679 
3680  BLI_mutex_unlock(&object_update_lock);
3681 }
3682 
3683 static void BKE_fluid_modifier_processFlow(FluidModifierData *fmd,
3685  Scene *scene,
3686  Object *ob,
3687  Mesh *me,
3688  const int scene_framenr)
3689 {
3690  if (scene_framenr >= fmd->time) {
3691  BKE_fluid_modifier_init(fmd, depsgraph, ob, scene, me);
3692  }
3693 
3694  if (fmd->flow) {
3695  if (fmd->flow->mesh) {
3696  BKE_id_free(NULL, fmd->flow->mesh);
3697  }
3698  fmd->flow->mesh = BKE_mesh_copy_for_eval(me, false);
3699  }
3700 
3701  if (scene_framenr > fmd->time) {
3702  fmd->time = scene_framenr;
3703  }
3704  else if (scene_framenr < fmd->time) {
3705  fmd->time = scene_framenr;
3706  BKE_fluid_modifier_reset_ex(fmd, false);
3707  }
3708 }
3709 
3710 static void BKE_fluid_modifier_processEffector(FluidModifierData *fmd,
3712  Scene *scene,
3713  Object *ob,
3714  Mesh *me,
3715  const int scene_framenr)
3716 {
3717  if (scene_framenr >= fmd->time) {
3718  BKE_fluid_modifier_init(fmd, depsgraph, ob, scene, me);
3719  }
3720 
3721  if (fmd->effector) {
3722  if (fmd->effector->mesh) {
3723  BKE_id_free(NULL, fmd->effector->mesh);
3724  }
3725  fmd->effector->mesh = BKE_mesh_copy_for_eval(me, false);
3726  }
3727 
3728  if (scene_framenr > fmd->time) {
3729  fmd->time = scene_framenr;
3730  }
3731  else if (scene_framenr < fmd->time) {
3732  fmd->time = scene_framenr;
3733  BKE_fluid_modifier_reset_ex(fmd, false);
3734  }
3735 }
3736 
3737 static void BKE_fluid_modifier_processDomain(FluidModifierData *fmd,
3739  Scene *scene,
3740  Object *ob,
3741  Mesh *me,
3742  const int scene_framenr)
3743 {
3744  FluidDomainSettings *fds = fmd->domain;
3745  Object *guide_parent = NULL;
3746  Object **objs = NULL;
3747  uint numobj = 0;
3748  FluidModifierData *fmd_parent = NULL;
3749 
3750  bool is_startframe, has_advanced;
3751  is_startframe = (scene_framenr == fds->cache_frame_start);
3752  has_advanced = (scene_framenr == fmd->time + 1);
3753  int mode = fds->cache_type;
3754 
3755  /* Do not process modifier if current frame is out of cache range. */
3756  bool escape = false;
3757  switch (mode) {
3760  if (fds->cache_frame_offset > 0) {
3761  if (scene_framenr < fds->cache_frame_start ||
3762  scene_framenr > fds->cache_frame_end + fds->cache_frame_offset) {
3763  escape = true;
3764  }
3765  }
3766  else {
3767  if (scene_framenr < fds->cache_frame_start + fds->cache_frame_offset ||
3768  scene_framenr > fds->cache_frame_end) {
3769  escape = true;
3770  }
3771  }
3772  break;
3774  default:
3775  if (scene_framenr < fds->cache_frame_start || scene_framenr > fds->cache_frame_end) {
3776  escape = true;
3777  }
3778  break;
3779  }
3780  /* If modifier will not be processed, update/flush pointers from (old) fluid object once more. */
3781  if (escape && fds->fluid) {
3782  manta_update_pointers(fds->fluid, fmd, true);
3783  return;
3784  }
3785 
3786  /* Reset fluid if no fluid present. Also resets active fields. */
3787  if (!fds->fluid) {
3788  BKE_fluid_modifier_reset_ex(fmd, false);
3789  }
3790 
3791  /* Ensure cache directory is not relative. */
3792  const char *relbase = BKE_modifier_path_relbase_from_global(ob);
3793  BLI_path_abs(fds->cache_directory, relbase);
3794 
3795  /* Ensure that all flags are up to date before doing any baking and/or cache reading. */
3797  depsgraph, ob, fds->fluid_group, &numobj, eModifierType_Fluid);
3798  update_flowsflags(fds, objs, numobj);
3799  if (objs) {
3800  MEM_freeN(objs);
3801  }
3803  depsgraph, ob, fds->effector_group, &numobj, eModifierType_Fluid);
3804  update_obstacleflags(fds, objs, numobj);
3805  if (objs) {
3806  MEM_freeN(objs);
3807  }
3808 
3809  /* TODO(sebbas): Cache reset for when flow / effector object need update flag is set. */
3810 # if 0
3811  /* If the just updated flags now carry the 'outdated' flag, reset the cache here!
3812  * Plus sanity check: Do not clear cache on file load. */
3814  ((fds->flags & FLUID_DOMAIN_FILE_LOAD) == 0)) {
3815  BKE_fluid_cache_free_all(fds, ob);
3816  BKE_fluid_modifier_reset_ex(fmd, false);
3817  }
3818 # endif
3819 
3820  /* Fluid domain init must not fail in order to continue modifier evaluation. */
3821  if (!fds->fluid && !BKE_fluid_modifier_init(fmd, depsgraph, ob, scene, me)) {
3822  CLOG_ERROR(&LOG, "Fluid initialization failed. Should not happen!");
3823  return;
3824  }
3825  BLI_assert(fds->fluid);
3826 
3827  /* Guiding parent res pointer needs initialization. */
3828  guide_parent = fds->guide_parent;
3829  if (guide_parent) {
3830  fmd_parent = (FluidModifierData *)BKE_modifiers_findby_type(guide_parent, eModifierType_Fluid);
3831  if (fmd_parent && fmd_parent->domain) {
3832  copy_v3_v3_int(fds->guide_res, fmd_parent->domain->res);
3833  }
3834  }
3835 
3836  /* Adaptive domain needs to know about current state, so save it here. */
3837  int o_res[3], o_min[3], o_max[3], o_shift[3];
3838  copy_v3_v3_int(o_res, fds->res);
3839  copy_v3_v3_int(o_min, fds->res_min);
3840  copy_v3_v3_int(o_max, fds->res_max);
3841  copy_v3_v3_int(o_shift, fds->shift);
3842 
3843  /* Ensure that time parameters are initialized correctly before every step. */
3844  float fps = scene->r.frs_sec / scene->r.frs_sec_base;
3845  fds->frame_length = DT_DEFAULT * (25.0f / fps) * fds->time_scale;
3846  fds->dt = fds->frame_length;
3847  fds->time_per_frame = 0;
3848 
3849  /* Ensure that gravity is copied over every frame (could be keyframed). */
3850  update_final_gravity(fds, scene);
3851 
3852  int next_frame = scene_framenr + 1;
3853  int prev_frame = scene_framenr - 1;
3854  /* Ensure positive of previous frame. */
3855  CLAMP_MIN(prev_frame, fds->cache_frame_start);
3856 
3857  int data_frame = scene_framenr, noise_frame = scene_framenr;
3858  int mesh_frame = scene_framenr, particles_frame = scene_framenr, guide_frame = scene_framenr;
3859 
3860  bool with_smoke, with_liquid;
3861  with_smoke = fds->type == FLUID_DOMAIN_TYPE_GAS;
3862  with_liquid = fds->type == FLUID_DOMAIN_TYPE_LIQUID;
3863 
3864  bool drops, bubble, floater;
3867  floater = fds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM;
3868 
3869  bool with_resumable_cache = fds->flags & FLUID_DOMAIN_USE_RESUMABLE_CACHE;
3870  bool with_script, with_noise, with_mesh, with_particles, with_guide;
3871  with_script = fds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT;
3872  with_noise = fds->flags & FLUID_DOMAIN_USE_NOISE;
3873  with_mesh = fds->flags & FLUID_DOMAIN_USE_MESH;
3874  with_guide = fds->flags & FLUID_DOMAIN_USE_GUIDE;
3875  with_particles = drops || bubble || floater;
3876 
3877  bool has_data, has_noise, has_mesh, has_particles, has_guide, has_config;
3878  has_data = manta_has_data(fds->fluid, fmd, scene_framenr);
3879  has_noise = manta_has_noise(fds->fluid, fmd, scene_framenr);
3880  has_mesh = manta_has_mesh(fds->fluid, fmd, scene_framenr);
3881  has_particles = manta_has_particles(fds->fluid, fmd, scene_framenr);
3882  has_guide = manta_has_guiding(fds->fluid, fmd, scene_framenr, guide_parent);
3883  has_config = manta_read_config(fds->fluid, fmd, scene_framenr);
3884 
3885  /* When reading data from cache (has_config == true) ensure that active fields are allocated.
3886  * update_flowsflags() and update_obstacleflags() will not find flow sources hidden from renders.
3887  * See also: T72192. */
3888  if (has_config) {
3889  ensure_flowsfields(fds);
3890  ensure_obstaclefields(fds);
3891  }
3892 
3893  bool baking_data, baking_noise, baking_mesh, baking_particles, baking_guide;
3894  baking_data = fds->cache_flag & FLUID_DOMAIN_BAKING_DATA;
3895  baking_noise = fds->cache_flag & FLUID_DOMAIN_BAKING_NOISE;
3896  baking_mesh = fds->cache_flag & FLUID_DOMAIN_BAKING_MESH;
3897  baking_particles = fds->cache_flag & FLUID_DOMAIN_BAKING_PARTICLES;
3898  baking_guide = fds->cache_flag & FLUID_DOMAIN_BAKING_GUIDE;
3899 
3900  bool resume_data, resume_noise, resume_mesh, resume_particles, resume_guide;
3901  resume_data = (!is_startframe) && (fds->cache_frame_pause_data == scene_framenr);
3902  resume_noise = (!is_startframe) && (fds->cache_frame_pause_noise == scene_framenr);
3903  resume_mesh = (!is_startframe) && (fds->cache_frame_pause_mesh == scene_framenr);
3904  resume_particles = (!is_startframe) && (fds->cache_frame_pause_particles == scene_framenr);
3905  resume_guide = (!is_startframe) && (fds->cache_frame_pause_guide == scene_framenr);
3906 
3907  bool read_cache, bake_cache;
3908  read_cache = false;
3909  bake_cache = baking_data || baking_noise || baking_mesh || baking_particles || baking_guide;
3910 
3911  bool next_data, next_noise, next_mesh, next_particles, next_guide;
3912  next_data = manta_has_data(fds->fluid, fmd, next_frame);
3913  next_noise = manta_has_noise(fds->fluid, fmd, next_frame);
3914  next_mesh = manta_has_mesh(fds->fluid, fmd, next_frame);
3915  next_particles = manta_has_particles(fds->fluid, fmd, next_frame);
3916  next_guide = manta_has_guiding(fds->fluid, fmd, next_frame, guide_parent);
3917 
3918  bool prev_data, prev_noise, prev_mesh, prev_particles, prev_guide;
3919  prev_data = manta_has_data(fds->fluid, fmd, prev_frame);
3920  prev_noise = manta_has_noise(fds->fluid, fmd, prev_frame);
3921  prev_mesh = manta_has_mesh(fds->fluid, fmd, prev_frame);
3922  prev_particles = manta_has_particles(fds->fluid, fmd, prev_frame);
3923  prev_guide = manta_has_guiding(fds->fluid, fmd, prev_frame, guide_parent);
3924 
3925  /* Unused for now. */
3926  UNUSED_VARS(next_mesh, next_guide);
3927 
3928  bool with_gdomain;
3929  with_gdomain = (fds->guide_source == FLUID_DOMAIN_GUIDE_SRC_DOMAIN);
3930 
3931  /* Cache mode specific settings. */
3932  switch (mode) {
3935  /* Just load the data that has already been baked */
3936  if (!baking_data && !baking_noise && !baking_mesh && !baking_particles && !baking_guide) {
3937  read_cache = true;
3938  bake_cache = false;
3939 
3940  /* Apply frame offset. */
3941  data_frame -= fmd->domain->cache_frame_offset;
3942  noise_frame -= fmd->domain->cache_frame_offset;
3943  mesh_frame -= fmd->domain->cache_frame_offset;
3944  particles_frame -= fmd->domain->cache_frame_offset;
3945  break;
3946  }
3947 
3948  /* Set to previous frame if the bake was resumed
3949  * ie don't read all of the already baked frames, just the one before bake resumes */
3950  if (baking_data && resume_data) {
3951  data_frame = prev_frame;
3952  }
3953  if (baking_noise && resume_noise) {
3954  noise_frame = prev_frame;
3955  }
3956  if (baking_mesh && resume_mesh) {
3957  mesh_frame = prev_frame;
3958  }
3959  if (baking_particles && resume_particles) {
3960  particles_frame = prev_frame;
3961  }
3962  if (baking_guide && resume_guide) {
3963  guide_frame = prev_frame;
3964  }
3965 
3966  /* Noise, mesh and particles can never be baked more than data. */
3967  CLAMP_MAX(noise_frame, data_frame);
3968  CLAMP_MAX(mesh_frame, data_frame);
3969  CLAMP_MAX(particles_frame, data_frame);
3970  CLAMP_MAX(guide_frame, fds->cache_frame_end);
3971 
3972  /* Force to read cache as we're resuming the bake */
3973  read_cache = true;
3974  break;
3976  default:
3977  baking_data = !has_data && (is_startframe || prev_data);
3978  if (with_smoke && with_noise) {
3979  baking_noise = !has_noise && (is_startframe || prev_noise);
3980  }
3981  if (with_liquid && with_mesh) {
3982  baking_mesh = !has_mesh && (is_startframe || prev_mesh);
3983  }
3984  if (with_liquid && with_particles) {
3985  baking_particles = !has_particles && (is_startframe || prev_particles);
3986  }
3987 
3988  /* Always trying to read the cache in replay mode. */
3989  read_cache = true;
3990  bake_cache = false;
3991  break;
3992  }
3993 
3994  bool read_partial = false, read_all = false;
3995  bool grid_display = fds->use_coba;
3996 
3997  /* Try to read from cache and keep track of read success. */
3998  if (read_cache) {
3999 
4000  /* Read mesh cache. */
4001  if (with_liquid && with_mesh) {
4002  if (mesh_frame != scene_framenr) {
4003  has_config = manta_read_config(fds->fluid, fmd, mesh_frame);
4004  }
4005 
4006  /* Only load the mesh at the resolution it ways originally simulated at.
4007  * The mesh files don't have a header, i.e. the don't store the grid resolution. */
4008  if (!manta_needs_realloc(fds->fluid, fmd)) {
4009  has_mesh = manta_read_mesh(fds->fluid, fmd, mesh_frame);
4010  }
4011  }
4012 
4013  /* Read particles cache. */
4014  if (with_liquid && with_particles) {
4015  if (particles_frame != scene_framenr) {
4016  has_config = manta_read_config(fds->fluid, fmd, particles_frame);
4017  }
4018 
4019  read_partial = !baking_data && !baking_particles && next_particles;
4020  read_all = !read_partial && with_resumable_cache;
4021  has_particles = manta_read_particles(fds->fluid, fmd, particles_frame, read_all);
4022  }
4023 
4024  /* Read guide cache. */
4025  if (with_guide) {
4026  FluidModifierData *fmd2 = (with_gdomain) ? fmd_parent : fmd;
4027  has_guide = manta_read_guiding(fds->fluid, fmd2, scene_framenr, with_gdomain);
4028  }
4029 
4030  /* Read noise and data cache */
4031  if (with_smoke && with_noise) {
4032  if (noise_frame != scene_framenr) {
4033  has_config = manta_read_config(fds->fluid, fmd, noise_frame);
4034  }
4035 
4036  /* Only reallocate when just reading cache or when resuming during bake. */
4037  if (has_data && has_config && manta_needs_realloc(fds->fluid, fmd)) {
4039  fds, o_res, fds->res, o_min, fds->res_min, o_max, o_shift, fds->shift);
4040  }
4041 
4042  read_partial = !baking_data && !baking_noise && next_noise;
4043  read_all = !read_partial && with_resumable_cache;
4044  has_noise = manta_read_noise(fds->fluid, fmd, noise_frame, read_all);
4045 
4046  read_partial = !baking_data && !baking_noise && next_data && next_noise;
4047  read_all = !read_partial && with_resumable_cache;
4048  has_data = manta_read_data(fds->fluid, fmd, data_frame, read_all);
4049  }
4050  /* Read data cache only */
4051  else {
4052  if (data_frame != scene_framenr) {
4053  has_config = manta_read_config(fds->fluid, fmd, data_frame);
4054  }
4055 
4056  if (with_smoke) {
4057  /* Read config and realloc fluid object if needed. */
4058  if (has_config && manta_needs_realloc(fds->fluid, fmd)) {
4059  BKE_fluid_reallocate_fluid(fds, fds->res, 1);
4060  }
4061  }
4062 
4063  read_partial = !baking_data && !baking_particles && !baking_mesh && next_data &&
4064  !grid_display;
4065  read_all = !read_partial && with_resumable_cache;
4066  has_data = manta_read_data(fds->fluid, fmd, data_frame, read_all);
4067  }
4068  }
4069 
4070  /* Cache mode specific settings */
4071  switch (mode) {
4074  if (!baking_data && !baking_noise && !baking_mesh && !baking_particles && !baking_guide) {
4075  bake_cache = false;
4076  }
4077  break;
4079  default:
4080  if (with_guide) {
4081  baking_guide = !has_guide && (is_startframe || prev_guide);
4082  }
4083  baking_data = !has_data && (is_startframe || prev_data);
4084  if (with_smoke && with_noise) {
4085  baking_noise = !has_noise && (is_startframe || prev_noise);
4086  }
4087  if (with_liquid && with_mesh) {
4088  baking_mesh = !has_mesh && (is_startframe || prev_mesh);
4089  }
4090  if (with_liquid && with_particles) {
4091  baking_particles = !has_particles && (is_startframe || prev_particles);
4092  }
4093 
4094  /* Only bake if time advanced by one frame. */
4095  if (is_startframe || has_advanced) {
4096  bake_cache = baking_data || baking_noise || baking_mesh || baking_particles;
4097  }
4098  break;
4099  }
4100 
4101  /* Trigger bake calls individually */
4102  if (bake_cache) {
4103  /* Ensure fresh variables at every animation step */
4104  manta_update_variables(fds->fluid, fmd);
4105 
4106  /* Export mantaflow python script on first frame (once only) and for any bake type */
4107  if (with_script && is_startframe) {
4108  if (with_smoke) {
4110  }
4111  if (with_liquid) {
4113  }
4114  }
4115 
4116  if (baking_guide && with_guide) {
4117  manta_guiding(depsgraph, scene, ob, fmd, scene_framenr);
4118  }
4119  if (baking_data) {
4120  /* Only save baked data if all of it completed successfully. */
4121  if (manta_step(depsgraph, scene, ob, me, fmd, scene_framenr)) {
4122  manta_write_config(fds->fluid, fmd, scene_framenr);
4123  manta_write_data(fds->fluid, fmd, scene_framenr);
4124  }
4125  }
4126  if (has_data || baking_data) {
4127  if (baking_noise && with_smoke && with_noise) {
4128  /* Ensure that no bake occurs if domain was minimized by adaptive domain. */
4129  if (fds->total_cells > 1) {
4130  manta_bake_noise(fds->fluid, fmd, scene_framenr);
4131  }
4132  manta_write_noise(fds->fluid, fmd, scene_framenr);
4133  }
4134  if (baking_mesh && with_liquid && with_mesh) {
4135  manta_bake_mesh(fds->fluid, fmd, scene_framenr);
4136  }
4137  if (baking_particles && with_liquid && with_particles) {
4138  manta_bake_particles(fds->fluid, fmd, scene_framenr);
4139  }
4140  }
4141  }
4142 
4143  /* Ensure that fluid pointers are always up to date at the end of modifier processing. */
4144  manta_update_pointers(fds->fluid, fmd, false);
4145 
4146  fds->flags &= ~FLUID_DOMAIN_FILE_LOAD;
4147  fmd->time = scene_framenr;
4148 }
4149 
4150 static void BKE_fluid_modifier_process(
4152 {
4153  const int scene_framenr = (int)DEG_get_ctime(depsgraph);
4154 
4155  if ((fmd->type & MOD_FLUID_TYPE_FLOW)) {
4156  BKE_fluid_modifier_processFlow(fmd, depsgraph, scene, ob, me, scene_framenr);
4157  }
4158  else if (fmd->type & MOD_FLUID_TYPE_EFFEC) {
4159  BKE_fluid_modifier_processEffector(fmd, depsgraph, scene, ob, me, scene_framenr);
4160  }
4161  else if (fmd->type & MOD_FLUID_TYPE_DOMAIN) {
4162  BKE_fluid_modifier_processDomain(fmd, depsgraph, scene, ob, me, scene_framenr);
4163  }
4164 }
4165 
4166 struct Mesh *BKE_fluid_modifier_do(
4168 {
4169  /* Optimization: Do not update viewport during bakes (except in replay mode)
4170  * Reason: UI is locked and updated liquid / smoke geometry is not visible anyways. */
4171  bool needs_viewport_update = false;
4172 
4173  /* Optimization: Only process modifier if object is not being altered. */
4174  if (!G.moving) {
4175  /* Lock so preview render does not read smoke data while it gets modified. */
4176  if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain) {
4178  }
4179 
4180  BKE_fluid_modifier_process(fmd, depsgraph, scene, ob, me);
4181 
4182  if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain) {
4184  }
4185 
4186  if (fmd->domain) {
4187  FluidDomainSettings *fds = fmd->domain;
4188 
4189  /* Always update viewport in cache replay mode. */
4190  if (fds->cache_type == FLUID_DOMAIN_CACHE_REPLAY ||
4192  needs_viewport_update = true;
4193  }
4194  /* In other cache modes, only update the viewport when no bake is going on. */
4195  else {
4196  bool with_mesh;
4197  with_mesh = fds->flags & FLUID_DOMAIN_USE_MESH;
4198  bool baking_data, baking_noise, baking_mesh, baking_particles, baking_guide;
4199  baking_data = fds->cache_flag & FLUID_DOMAIN_BAKING_DATA;
4200  baking_noise = fds->cache_flag & FLUID_DOMAIN_BAKING_NOISE;
4201  baking_mesh = fds->cache_flag & FLUID_DOMAIN_BAKING_MESH;
4202  baking_particles = fds->cache_flag & FLUID_DOMAIN_BAKING_PARTICLES;
4203  baking_guide = fds->cache_flag & FLUID_DOMAIN_BAKING_GUIDE;
4204 
4205  if (with_mesh && !baking_data && !baking_noise && !baking_mesh && !baking_particles &&
4206  !baking_guide) {
4207  needs_viewport_update = true;
4208  }
4209  }
4210  }
4211  }
4212 
4213  Mesh *result = NULL;
4214  if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
4215  if (needs_viewport_update) {
4216  /* Return generated geometry depending on domain type. */
4217  if (fmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) {
4218  result = create_liquid_geometry(fmd->domain, me, ob);
4219  }
4220  if (fmd->domain->type == FLUID_DOMAIN_TYPE_GAS) {
4221  result = create_smoke_geometry(fmd->domain, me, ob);
4222  }
4223  }
4224 
4225  /* Clear flag outside of locked block (above). */
4231  }
4232 
4233  if (!result) {
4234  result = BKE_mesh_copy_for_eval(me, false);
4235  }
4236  else {
4238  }
4239 
4240  /* Liquid simulation has a texture space that based on the bounds of the fluid mesh.
4241  * This does not seem particularly useful, but it's backwards compatible.
4242  *
4243  * Smoke simulation needs a texture space relative to the adaptive domain bounds, not the
4244  * original mesh. So recompute it at this point in the modifier stack. See T58492. */
4246 
4247  return result;
4248 }
4249 
4250 static float calc_voxel_transp(
4251  float *result, const float *input, int res[3], int *pixel, float *t_ray, float correct)
4252 {
4253  const size_t index = manta_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]);
4254 
4255  // T_ray *= T_vox
4256  *t_ray *= expf(input[index] * correct);
4257 
4258  if (result[index] < 0.0f) {
4259  result[index] = *t_ray;
4260  }
4261 
4262  return *t_ray;
4263 }
4264 
4265 static void bresenham_linie_3D(int x1,
4266  int y1,
4267  int z1,
4268  int x2,
4269  int y2,
4270  int z2,
4271  float *t_ray,
4273  float *result,
4274  float *input,
4275  int res[3],
4276  float correct)
4277 {
4278  int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
4279  int pixel[3];
4280 
4281  pixel[0] = x1;
4282  pixel[1] = y1;
4283  pixel[2] = z1;
4284 
4285  dx = x2 - x1;
4286  dy = y2 - y1;
4287  dz = z2 - z1;
4288 
4289  x_inc = (dx < 0) ? -1 : 1;
4290  l = abs(dx);
4291  y_inc = (dy < 0) ? -1 : 1;
4292  m = abs(dy);
4293  z_inc = (dz < 0) ? -1 : 1;
4294  n = abs(dz);
4295  dx2 = l << 1;
4296  dy2 = m << 1;
4297  dz2 = n << 1;
4298 
4299  if ((l >= m) && (l >= n)) {
4300  err_1 = dy2 - l;
4301  err_2 = dz2 - l;
4302  for (i = 0; i < l; i++) {
4303  if (cb(result, input, res, pixel, t_ray, correct) <= FLT_EPSILON) {
4304  break;
4305  }
4306  if (err_1 > 0) {
4307  pixel[1] += y_inc;
4308  err_1 -= dx2;
4309  }
4310  if (err_2 > 0) {
4311  pixel[2] += z_inc;
4312  err_2 -= dx2;
4313  }
4314  err_1 += dy2;
4315  err_2 += dz2;
4316  pixel[0] += x_inc;
4317  }
4318  }
4319  else if ((m >= l) && (m >= n)) {
4320  err_1 = dx2 - m;
4321  err_2 = dz2 - m;
4322  for (i = 0; i < m; i++) {
4323  if (cb(result, input, res, pixel, t_ray, correct) <= FLT_EPSILON) {
4324  break;
4325  }
4326  if (err_1 > 0) {
4327  pixel[0] += x_inc;
4328  err_1 -= dy2;
4329  }
4330  if (err_2 > 0) {
4331  pixel[2] += z_inc;
4332  err_2 -= dy2;
4333  }
4334  err_1 += dx2;
4335  err_2 += dz2;
4336  pixel[1] += y_inc;
4337  }
4338  }
4339  else {
4340  err_1 = dy2 - n;
4341  err_2 = dx2 - n;
4342  for (i = 0; i < n; i++) {
4343  if (cb(result, input, res, pixel, t_ray, correct) <= FLT_EPSILON) {
4344  break;
4345  }
4346  if (err_1 > 0) {
4347  pixel[1] += y_inc;
4348  err_1 -= dz2;
4349  }
4350  if (err_2 > 0) {
4351  pixel[0] += x_inc;
4352  err_2 -= dz2;
4353  }
4354  err_1 += dy2;
4355  err_2 += dx2;
4356  pixel[2] += z_inc;
4357  }
4358  }
4359  cb(result, input, res, pixel, t_ray, correct);
4360 }
4361 
4362 static void manta_smoke_calc_transparency(FluidDomainSettings *fds, ViewLayer *view_layer)
4363 {
4364  float bv[6] = {0};
4365  float light[3];
4366  int slabsize = fds->res[0] * fds->res[1];
4367  float *density = manta_smoke_get_density(fds->fluid);
4368  float *shadow = manta_smoke_get_shadow(fds->fluid);
4369  float correct = -7.0f * fds->dx;
4370 
4371  if (!get_light(view_layer, light)) {
4372  return;
4373  }
4374 
4375  /* Convert light pos to sim cell space. */
4376  mul_m4_v3(fds->imat, light);
4377  light[0] = (light[0] - fds->p0[0]) / fds->cell_size[0] - 0.5f - (float)fds->res_min[0];
4378  light[1] = (light[1] - fds->p0[1]) / fds->cell_size[1] - 0.5f - (float)fds->res_min[1];
4379  light[2] = (light[2] - fds->p0[2]) / fds->cell_size[2] - 0.5f - (float)fds->res_min[2];
4380 
4381  /* Calculate domain bounds in sim cell space. */
4382  // 0,2,4 = 0.0f
4383  bv[1] = (float)fds->res[0]; // x
4384  bv[3] = (float)fds->res[1]; // y
4385  bv[5] = (float)fds->res[2]; // z
4386 
4387  for (int z = 0; z < fds->res[2]; z++) {
4388  size_t index = z * slabsize;
4389 
4390  for (int y = 0; y < fds->res[1]; y++) {
4391  for (int x = 0; x < fds->res[0]; x++, index++) {
4392  float voxel_center[3];
4393  float pos[3];
4394  int cell[3];
4395  float t_ray = 1.0;
4396 
4397  /* Reset shadow value.*/
4398  shadow[index] = -1.0f;
4399 
4400  voxel_center[0] = (float)x;
4401  voxel_center[1] = (float)y;
4402  voxel_center[2] = (float)z;
4403 
4404  /* Get starting cell (light pos). */
4405  if (BLI_bvhtree_bb_raycast(bv, light, voxel_center, pos) > FLT_EPSILON) {
4406  /* We're outside -> use point on side of domain. */
4407  cell[0] = (int)floor(pos[0]);
4408  cell[1] = (int)floor(pos[1]);
4409  cell[2] = (int)floor(pos[2]);
4410  }
4411  else {
4412  /* We're inside -> use light itself. */
4413  cell[0] = (int)floor(light[0]);
4414  cell[1] = (int)floor(light[1]);
4415  cell[2] = (int)floor(light[2]);
4416  }
4417  /* Clamp within grid bounds */
4418  CLAMP(cell[0], 0, fds->res[0] - 1);
4419  CLAMP(cell[1], 0, fds->res[1] - 1);
4420  CLAMP(cell[2], 0, fds->res[2] - 1);
4421 
4422  bresenham_linie_3D(cell[0],
4423  cell[1],
4424  cell[2],
4425  x,
4426  y,
4427  z,
4428  &t_ray,
4429  calc_voxel_transp,
4430  shadow,
4431  density,
4432  fds->res,
4433  correct);
4434 
4435  /* Convention -> from a RGBA float array, use G value for t_ray. */
4436  shadow[index] = t_ray;
4437  }
4438  }
4439  }
4440 }
4441 
4442 /* Get fluid velocity and density at given coordinates
4443  * Returns fluid density or -1.0f if outside domain. */
4444 float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3])
4445 {
4447  zero_v3(velocity);
4448 
4449  if (fmd && (fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain && fmd->domain->fluid) {
4450  FluidDomainSettings *fds = fmd->domain;
4451  float time_mult = 25.0f * DT_DEFAULT;
4452  float size_mult = MAX3(fds->global_size[0], fds->global_size[1], fds->global_size[2]) /
4453  MAX3(fds->base_res[0], fds->base_res[1], fds->base_res[2]);
4454  float vel_mag;
4455  float density = 0.0f, fuel = 0.0f;
4456  float pos[3];
4457  copy_v3_v3(pos, position);
4458  manta_pos_to_cell(fds, pos);
4459 
4460  /* Check if position is outside domain max bounds. */
4461  if (pos[0] < fds->res_min[0] || pos[1] < fds->res_min[1] || pos[2] < fds->res_min[2]) {
4462  return -1.0f;
4463  }
4464  if (pos[0] > fds->res_max[0] || pos[1] > fds->res_max[1] || pos[2] > fds->res_max[2]) {
4465  return -1.0f;
4466  }
4467 
4468  /* map pos between 0.0 - 1.0 */
4469  pos[0] = (pos[0] - fds->res_min[0]) / ((float)fds->res[0]);
4470  pos[1] = (pos[1] - fds->res_min[1]) / ((float)fds->res[1]);
4471  pos[2] = (pos[2] - fds->res_min[2]) / ((float)fds->res[2]);
4472 
4473  /* Check if position is outside active area. */
4475  if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) {
4476  return 0.0f;
4477  }
4478  if (pos[0] > 1.0f || pos[1] > 1.0f || pos[2] > 1.0f) {
4479  return 0.0f;
4480  }
4481  }
4482 
4483  /* Get interpolated velocity at given position. */
4484  velocity[0] = BLI_voxel_sample_trilinear(manta_get_velocity_x(fds->fluid), fds->res, pos);
4485  velocity[1] = BLI_voxel_sample_trilinear(manta_get_velocity_y(fds->fluid), fds->res, pos);
4486  velocity[2] = BLI_voxel_sample_trilinear(manta_get_velocity_z(fds->fluid), fds->res, pos);
4487 
4488  /* Convert simulation units to Blender units. */
4489  mul_v3_fl(velocity, size_mult);
4490  mul_v3_fl(velocity, time_mult);
4491 
4492  /* Convert velocity direction to global space. */
4493  vel_mag = len_v3(velocity);
4494  mul_mat3_m4_v3(fds->obmat, velocity);
4495  normalize_v3(velocity);
4496  mul_v3_fl(velocity, vel_mag);
4497 
4498  /* Use max value of fuel or smoke density. */
4500  if (manta_smoke_has_fuel(fds->fluid)) {
4502  }
4503  return MAX2(density, fuel);
4504  }
4505  return -1.0f;
4506 }
4507 
4509 {
4510  int flags = 0;
4511 
4512  if (fds->fluid) {
4513  if (manta_smoke_has_heat(fds->fluid)) {
4514  flags |= FLUID_DOMAIN_ACTIVE_HEAT;
4515  }
4516  if (manta_smoke_has_fuel(fds->fluid)) {
4517  flags |= FLUID_DOMAIN_ACTIVE_FIRE;
4518  }
4519  if (manta_smoke_has_colors(fds->fluid)) {
4520  flags |= FLUID_DOMAIN_ACTIVE_COLORS;
4521  }
4522  }
4523 
4524  return flags;
4525 }
4526 
4527 void BKE_fluid_particle_system_create(struct Main *bmain,
4528  struct Object *ob,
4529  const char *pset_name,
4530  const char *parts_name,
4531  const char *psys_name,
4532  const int psys_type)
4533 {
4534  ParticleSystem *psys;
4535  ParticleSettings *part;
4537 
4538  /* add particle system */
4539  part = BKE_particlesettings_add(bmain, pset_name);
4540  psys = MEM_callocN(sizeof(ParticleSystem), "particle_system");
4541 
4542  part->type = psys_type;
4543  part->totpart = 0;
4544  part->draw_size = 0.01f; /* Make fluid particles more subtle in viewport. */
4545  part->draw_col = PART_DRAW_COL_VEL;
4546  part->phystype = PART_PHYS_NO; /* No physics needed, part system only used to display data. */
4547  psys->part = part;
4548  psys->pointcache = BKE_ptcache_add(&psys->ptcaches);
4549  BLI_strncpy(psys->name, parts_name, sizeof(psys->name));
4550  BLI_addtail(&ob->particlesystem, psys);
4551 
4552  /* add modifier */
4554  BLI_strncpy(pfmd->modifier.name, psys_name, sizeof(pfmd->modifier.name));
4555  pfmd->psys = psys;
4556  BLI_addtail(&ob->modifiers, pfmd);
4558 }
4559 
4560 void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_type)
4561 {
4563  ParticleSystem *psys, *next_psys;
4564 
4565  for (psys = ob->particlesystem.first; psys; psys = next_psys) {
4566  next_psys = psys->next;
4567  if (psys->part->type == particle_type) {
4568  /* clear modifier */
4569  pfmd = psys_get_modifier(ob, psys);
4572 
4573  /* clear particle system */
4574  BLI_remlink(&ob->particlesystem, psys);
4575  psys_free(ob, psys);
4576  }
4577  }
4578 }
4579 
4580 #endif /* WITH_FLUID */
4581 
4584 /* -------------------------------------------------------------------- */
4591 {
4592  settings->cache_frame_start = (value > settings->cache_frame_end) ? settings->cache_frame_end :
4593  value;
4594 }
4595 
4597 {
4598  settings->cache_frame_end = (value < settings->cache_frame_start) ? settings->cache_frame_start :
4599  value;
4600 }
4601 
4602 void BKE_fluid_cachetype_mesh_set(FluidDomainSettings *settings, int cache_mesh_format)
4603 {
4604  if (cache_mesh_format == settings->cache_mesh_format) {
4605  return;
4606  }
4607  /* TODO(sebbas): Clear old caches. */
4608  settings->cache_mesh_format = cache_mesh_format;
4609 }
4610 
4611 void BKE_fluid_cachetype_data_set(FluidDomainSettings *settings, int cache_data_format)
4612 {
4613  if (cache_data_format == settings->cache_data_format) {
4614  return;
4615  }
4616  /* TODO(sebbas): Clear old caches. */
4617  settings->cache_data_format = cache_data_format;
4618 }
4619 
4620 void BKE_fluid_cachetype_particle_set(FluidDomainSettings *settings, int cache_particle_format)
4621 {
4622  if (cache_particle_format == settings->cache_particle_format) {
4623  return;
4624  }
4625  /* TODO(sebbas): Clear old caches. */
4626  settings->cache_particle_format = cache_particle_format;
4627 }
4628 
4629 void BKE_fluid_cachetype_noise_set(FluidDomainSettings *settings, int cache_noise_format)
4630 {
4631  if (cache_noise_format == settings->cache_noise_format) {
4632  return;
4633  }
4634  /* TODO(sebbas): Clear old caches. */
4635  settings->cache_noise_format = cache_noise_format;
4636 }
4637 
4639 {
4640  if (clear) {
4641  settings->border_collisions &= value;
4642  }
4643  else {
4644  settings->border_collisions |= value;
4645  }
4646 }
4647 
4648 void BKE_fluid_particles_set(FluidDomainSettings *settings, int value, bool clear)
4649 {
4650  if (clear) {
4651  settings->particle_type &= ~value;
4652  }
4653  else {
4654  settings->particle_type |= value;
4655  }
4656 }
4657 
4659 {
4660  /* Set values for border collision:
4661  * Liquids should have a closed domain, smoke domains should be open. */
4662  if (type == FLUID_DOMAIN_TYPE_GAS) {
4669  object->dt = OB_WIRE;
4670  }
4671  else if (type == FLUID_DOMAIN_TYPE_LIQUID) {
4678  object->dt = OB_SOLID;
4679  }
4680 
4681  /* Set actual domain type. */
4682  settings->type = type;
4683 }
4684 
4685 void BKE_fluid_flow_behavior_set(Object *UNUSED(object), FluidFlowSettings *settings, int behavior)
4686 {
4687  settings->behavior = behavior;
4688 }
4689 
4691 {
4692  /* By default, liquid flow objects should behave like their geometry (geometry behavior),
4693  * gas flow objects should continuously produce smoke (inflow behavior). */
4694  if (type == FLUID_FLOW_TYPE_LIQUID) {
4696  }
4697  else {
4699  }
4700 
4701  /* Set actual flow type. */
4702  settings->type = type;
4703 }
4704 
4706 {
4707  settings->type = type;
4708 }
4709 
4711 {
4712  /* Based on the domain type, certain fields are defaulted accordingly if the selected field
4713  * is unsupported. */
4714  const char coba_field = settings->coba_field;
4715  const char data_depth = settings->openvdb_data_depth;
4716 
4717  if (settings->type == FLUID_DOMAIN_TYPE_GAS) {
4718  if (ELEM(coba_field,
4723  /* Defaulted to density for gas domain. */
4725  }
4726 
4727  /* Gas domains do not support vdb mini precision. */
4728  if (data_depth == VDB_PRECISION_MINI_FLOAT) {
4730  }
4731  }
4732  else if (settings->type == FLUID_DOMAIN_TYPE_LIQUID) {
4733  if (ELEM(coba_field,
4741  /* Defaulted to phi for liquid domain. */
4742  settings->coba_field = FLUID_DOMAIN_FIELD_PHI;
4743  }
4744  }
4745 }
4746 
4749 /* -------------------------------------------------------------------- */
4756 {
4757  if (fmd->domain) {
4758  if (fmd->domain->fluid) {
4759 #ifdef WITH_FLUID
4760  manta_free(fmd->domain->fluid);
4761 #endif
4762  }
4763 
4764  if (fmd->domain->fluid_mutex) {
4766  }
4767 
4768  if (fmd->domain->effector_weights) {
4770  }
4771  fmd->domain->effector_weights = NULL;
4772 
4773  if (!(fmd->modifier.flag & eModifierFlag_SharedCaches)) {
4774  BKE_ptcache_free_list(&(fmd->domain->ptcaches[0]));
4775  fmd->domain->point_cache[0] = NULL;
4776  }
4777 
4778  if (fmd->domain->mesh_velocities) {
4780  }
4781  fmd->domain->mesh_velocities = NULL;
4782 
4783  if (fmd->domain->coba) {
4784  MEM_freeN(fmd->domain->coba);
4785  }
4786 
4787  MEM_freeN(fmd->domain);
4788  fmd->domain = NULL;
4789  }
4790 }
4791 
4793 {
4794  if (fmd->flow) {
4795  if (fmd->flow->mesh) {
4796  BKE_id_free(NULL, fmd->flow->mesh);
4797  }
4798  fmd->flow->mesh = NULL;
4799 
4800  if (fmd->flow->verts_old) {
4801  MEM_freeN(fmd->flow->verts_old);
4802  }
4803  fmd->flow->verts_old = NULL;
4804  fmd->flow->numverts = 0;
4806 
4807  MEM_freeN(fmd->flow);
4808  fmd->flow = NULL;
4809  }
4810 }
4811 
4813 {
4814  if (fmd->effector) {
4815  if (fmd->effector->mesh) {
4816  BKE_id_free(NULL, fmd->effector->mesh);
4817  }
4818  fmd->effector->mesh = NULL;
4819 
4820  if (fmd->effector->verts_old) {
4821  MEM_freeN(fmd->effector->verts_old);
4822  }
4823  fmd->effector->verts_old = NULL;
4824  fmd->effector->numverts = 0;
4826 
4827  MEM_freeN(fmd->effector);
4828  fmd->effector = NULL;
4829  }
4830 }
4831 
4832 static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *fmd, bool need_lock)
4833 {
4834  if (!fmd) {
4835  return;
4836  }
4837 
4838  if (fmd->domain) {
4839  if (fmd->domain->fluid) {
4840  if (need_lock) {
4842  }
4843 
4844 #ifdef WITH_FLUID
4845  manta_free(fmd->domain->fluid);
4846 #endif
4847  fmd->domain->fluid = NULL;
4848 
4849  if (need_lock) {
4851  }
4852  }
4853 
4854  fmd->time = -1;
4855  fmd->domain->total_cells = 0;
4856  fmd->domain->active_fields = 0;
4857  }
4858  else if (fmd->flow) {
4859  if (fmd->flow->verts_old) {
4860  MEM_freeN(fmd->flow->verts_old);
4861  }
4862  fmd->flow->verts_old = NULL;
4863  fmd->flow->numverts = 0;
4865  }
4866  else if (fmd->effector) {
4867  if (fmd->effector->verts_old) {
4868  MEM_freeN(fmd->effector->verts_old);
4869  }
4870  fmd->effector->verts_old = NULL;
4871  fmd->effector->numverts = 0;
4873  }
4874 }
4875 
4877 {
4878  BKE_fluid_modifier_reset_ex(fmd, true);
4879 }
4880 
4882 {
4883  if (!fmd) {
4884  return;
4885  }
4886 
4890 }
4891 
4893 {
4894  if (!fmd) {
4895  return;
4896  }
4897 
4898  if (fmd->type & MOD_FLUID_TYPE_DOMAIN) {
4899  if (fmd->domain) {
4901  }
4902 
4904  fmd->domain->fmd = fmd;
4905 
4906  /* Turn off incompatible options. */
4907 #ifndef WITH_OPENVDB
4911 #endif
4912 #ifndef WITH_OPENVDB_BLOSC
4914 #endif
4915 
4918 
4919  char cache_name[64];
4920  BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name);
4922  fmd->domain->cache_directory, sizeof(fmd->domain->cache_directory), cache_name);
4923 
4924  /* pointcache options */
4925  fmd->domain->point_cache[0] = BKE_ptcache_add(&(fmd->domain->ptcaches[0]));
4927  fmd->domain->point_cache[0]->step = 1;
4928  fmd->domain->point_cache[1] = NULL; /* Deprecated */
4929  }
4930  else if (fmd->type & MOD_FLUID_TYPE_FLOW) {
4931  if (fmd->flow) {
4933  }
4934 
4936  fmd->flow->fmd = fmd;
4937  }
4938  else if (fmd->type & MOD_FLUID_TYPE_EFFEC) {
4939  if (fmd->effector) {
4941  }
4942 
4944  fmd->effector->fmd = fmd;
4945  }
4946 }
4947 
4949  struct FluidModifierData *tfmd,
4950  const int flag)
4951 {
4952  tfmd->type = fmd->type;
4953  tfmd->time = fmd->time;
4954 
4956 
4957  if (tfmd->domain) {
4958  FluidDomainSettings *tfds = tfmd->domain;
4959  FluidDomainSettings *fds = fmd->domain;
4960 
4961  /* domain object data */
4962  tfds->fluid_group = fds->fluid_group;
4963  tfds->force_group = fds->force_group;
4964  tfds->effector_group = fds->effector_group;
4965  if (tfds->effector_weights) {
4966  MEM_freeN(tfds->effector_weights);
4967  }
4969 
4970  /* adaptive domain options */
4971  tfds->adapt_margin = fds->adapt_margin;
4972  tfds->adapt_res = fds->adapt_res;
4973  tfds->adapt_threshold = fds->adapt_threshold;
4974 
4975  /* fluid domain options */
4976  tfds->maxres = fds->maxres;
4977  tfds->solver_res = fds->solver_res;
4978  tfds->border_collisions = fds->border_collisions;
4979  tfds->flags = fds->flags;
4980  tfds->gravity[0] = fds->gravity[0];
4981  tfds->gravity[1] = fds->gravity[1];
4982  tfds->gravity[2] = fds->gravity[2];
4983  tfds->active_fields = fds->active_fields;
4984  tfds->type = fds->type;
4985  tfds->boundary_width = fds->boundary_width;
4986 
4987  /* smoke domain options */
4988  tfds->alpha = fds->alpha;
4989  tfds->beta = fds->beta;
4990  tfds->diss_speed = fds->diss_speed;
4991  tfds->vorticity = fds->vorticity;
4992  tfds->highres_sampling = fds->highres_sampling;
4993 
4994  /* flame options */
4995  tfds->burning_rate = fds->burning_rate;
4996  tfds->flame_smoke = fds->flame_smoke;
4997  tfds->flame_vorticity = fds->flame_vorticity;
4998  tfds->flame_ignition = fds->flame_ignition;
4999  tfds->flame_max_temp = fds->flame_max_temp;
5001 
5002  /* noise options */
5003  tfds->noise_strength = fds->noise_strength;
5004  tfds->noise_pos_scale = fds->noise_pos_scale;
5005  tfds->noise_time_anim = fds->noise_time_anim;
5006  tfds->noise_scale = fds->noise_scale;
5007  tfds->noise_type = fds->noise_type;
5008 
5009  /* liquid domain options */
5010  tfds->flip_ratio = fds->flip_ratio;
5012  tfds->particle_number = fds->particle_number;
5013  tfds->particle_minimum = fds->particle_minimum;
5014  tfds->particle_maximum = fds->particle_maximum;
5015  tfds->particle_radius = fds->particle_radius;
5020  tfds->simulation_method = fds->simulation_method;
5021 
5022  /* viscosity options */
5023  tfds->viscosity_value = fds->viscosity_value;
5024 
5025  /* diffusion options*/
5026  tfds->surface_tension = fds->surface_tension;
5027  tfds->viscosity_base = fds->viscosity_base;
5029 
5030  /* mesh options */
5031  if (fds->mesh_velocities) {
5033  }
5037  tfds->mesh_smoothen_pos = fds->mesh_smoothen_pos;
5038  tfds->mesh_smoothen_neg = fds->mesh_smoothen_neg;
5039  tfds->mesh_scale = fds->mesh_scale;
5040  tfds->totvert = fds->totvert;
5041  tfds->mesh_generator = fds->mesh_generator;
5042 
5043  /* secondary particle options */
5044  tfds->sndparticle_k_b = fds->sndparticle_k_b;
5045  tfds->sndparticle_k_d = fds->sndparticle_k_d;
5046  tfds->sndparticle_k_ta = fds->sndparticle_k_ta;
5047  tfds->sndparticle_k_wc = fds->sndparticle_k_wc;
5048  tfds->sndparticle_l_max = fds->sndparticle_l_max;
5049  tfds->sndparticle_l_min = fds->sndparticle_l_min;
5060  tfds->particle_type = fds->particle_type;
5061  tfds->particle_scale = fds->particle_scale;
5062 
5063  /* fluid guide options */
5064  tfds->guide_parent = fds->guide_parent;
5065  tfds->guide_alpha = fds->guide_alpha;
5066  tfds->guide_beta = fds->guide_beta;
5067  tfds->guide_vel_factor = fds->guide_vel_factor;
5068  copy_v3_v3_int(tfds->guide_res, fds->guide_res);
5069  tfds->guide_source = fds->guide_source;
5070 
5071  /* cache options */
5072  tfds->cache_frame_start = fds->cache_frame_start;
5073  tfds->cache_frame_end = fds->cache_frame_end;
5080  tfds->cache_flag = fds->cache_flag;
5081  tfds->cache_type = fds->cache_type;
5082  tfds->cache_mesh_format = fds->cache_mesh_format;
5083  tfds->cache_data_format = fds->cache_data_format;
5086  BLI_strncpy(tfds->cache_directory, fds->cache_directory, sizeof(tfds->cache_directory));
5087 
5088  /* time options */
5089  tfds->time_scale = fds->time_scale;
5090  tfds->cfl_condition = fds->cfl_condition;
5091  tfds->timesteps_minimum = fds->timesteps_minimum;
5092  tfds->timesteps_maximum = fds->timesteps_maximum;
5093 
5094  /* display options */
5095  tfds->axis_slice_method = fds->axis_slice_method;
5096  tfds->slice_axis = fds->slice_axis;
5097  tfds->interp_method = fds->interp_method;
5098  tfds->draw_velocity = fds->draw_velocity;
5099  tfds->slice_per_voxel = fds->slice_per_voxel;
5100  tfds->slice_depth = fds->slice_depth;
5101  tfds->display_thickness = fds->display_thickness;
5102  tfds->show_gridlines = fds->show_gridlines;
5103  if (fds->coba) {
5104  tfds->coba = MEM_dupallocN(fds->coba);
5105  }
5106  tfds->vector_scale = fds->vector_scale;
5107  tfds->vector_draw_type = fds->vector_draw_type;
5108  tfds->vector_field = fds->vector_field;
5111  tfds->use_coba = fds->use_coba;
5112  tfds->coba_field = fds->coba_field;
5113  tfds->grid_scale = fds->grid_scale;
5119 
5120  /* -- Deprecated / unsed options (below)-- */
5121 
5122  /* pointcache options */
5123  BKE_ptcache_free_list(&(tfds->ptcaches[0]));
5124  if (flag & LIB_ID_CREATE_NO_MAIN) {
5125  /* Share the cache with the original object's modifier. */
5127  tfds->point_cache[0] = fds->point_cache[0];
5128  tfds->ptcaches[0] = fds->ptcaches[0];
5129  }
5130  else {
5132  &(tfds->ptcaches[0]), &(fds->ptcaches[0]), flag);
5133  }
5134 
5135  /* OpenVDB cache options */
5137  tfds->clipping = fds->clipping;
5139  }
5140  else if (tfmd->flow) {
5141  FluidFlowSettings *tffs = tfmd->flow;
5142  FluidFlowSettings *ffs = fmd->flow;
5143 
5144  /* NOTE: This is dangerous, as it will generate invalid data in case we are copying between
5145  * different objects. Extra external code has to be called then to ensure proper remapping of
5146  * that pointer. See e.g. `BKE_object_copy_particlesystems` or `BKE_object_copy_modifier`. */
5147  tffs->psys = ffs->psys;
5148  tffs->noise_texture = ffs->noise_texture;
5149 
5150  /* initial velocity */
5151  tffs->vel_multi = ffs->vel_multi;
5152  tffs->vel_normal = ffs->vel_normal;
5153  tffs->vel_random = ffs->vel_random;
5154  tffs->vel_coord[0] = ffs->vel_coord[0];
5155  tffs->vel_coord[1] = ffs->vel_coord[1];
5156  tffs->vel_coord[2] = ffs->vel_coord[2];
5157 
5158  /* emission */
5159  tffs->density = ffs->density;
5160  copy_v3_v3(tffs->color, ffs->color);
5161  tffs->fuel_amount = ffs->fuel_amount;
5162  tffs->temperature = ffs->temperature;
5163  tffs->volume_density = ffs->volume_density;
5164  tffs->surface_distance = ffs->surface_distance;
5165  tffs->particle_size = ffs->particle_size;
5166  tffs->subframes = ffs->subframes;
5167 
5168  /* texture control */
5169  tffs->texture_size = ffs->texture_size;
5170  tffs->texture_offset = ffs->texture_offset;
5171  BLI_strncpy(tffs->uvlayer_name, ffs->uvlayer_name, sizeof(tffs->uvlayer_name));
5172  tffs->vgroup_density = ffs->vgroup_density;
5173 
5174  tffs->type = ffs->type;
5175  tffs->behavior = ffs->behavior;
5176  tffs->source = ffs->source;
5177  tffs->texture_type = ffs->texture_type;
5178  tffs->flags = ffs->flags;
5179  }
5180  else if (tfmd->effector) {
5181  FluidEffectorSettings *tfes = tfmd->effector;
5182  FluidEffectorSettings *fes = fmd->effector;
5183 
5184  tfes->surface_distance = fes->surface_distance;
5185  tfes->type = fes->type;
5186  tfes->flags = fes->flags;
5187  tfes->subframes = fes->subframes;
5188 
5189  /* guide options */
5190  tfes->guide_mode = fes->guide_mode;
5191  tfes->vel_multi = fes->vel_multi;
5192  }
5193 }
5194 
5195 void BKE_fluid_cache_new_name_for_current_session(int maxlen, char *r_name)
5196 {
5197  static int counter = 1;
5198  BLI_snprintf(r_name, maxlen, FLUID_DOMAIN_DIR_DEFAULT "_%x", BLI_hash_int(counter));
5199  counter++;
5200 }
5201 
typedef float(TangentPoint)[2]
BVHTree * BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, struct Mesh *mesh, const BVHCacheType bvh_cache_type, const int tree_type)
Definition: bvhutils.c:1413
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
Definition: bvhutils.c:1701
@ BVHTREE_FROM_LOOPTRI
Definition: BKE_bvhutils.h:93
struct Object ** BKE_collision_objects_create(struct Depsgraph *depsgraph, struct Object *self, struct Collection *collection, unsigned int *numcollobj, unsigned int modifier_type)
Definition: collision.c:1297
void BKE_collision_objects_free(struct Object **objects)
Definition: collision.c:1337
void BKE_curvemapping_changed_all(struct CurveMapping *cumap)
Definition: colortools.c:954
CustomData interface, see also DNA_customdata_types.h.
void * CustomData_set_layer(const struct CustomData *data, int type, void *ptr)
void * CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
Definition: customdata.c:3217
void * CustomData_get_layer(const struct CustomData *data, int type)
support for deformation groups and hooks.
float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
Definition: deform.c:632
void BKE_effectors_free(struct ListBase *lb)
Definition: effect.c:388
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.c:1145
struct EffectorWeights * BKE_effector_add_weights(struct Collection *collection)
Definition: effect.c:73
void pd_point_from_loc(struct Scene *scene, float *loc, float *vel, int index, struct EffectedPoint *point)
Definition: effect.c:438
struct ListBase * BKE_effectors_create(struct Depsgraph *depsgraph, struct Object *ob_src, struct ParticleSystem *psys_src, struct EffectorWeights *weights, bool use_rotation)
Definition: effect.c:333
void BKE_fluid_cache_free_all(struct FluidDomainSettings *fds, struct Object *ob)
int BKE_fluid_get_data_flags(struct FluidDomainSettings *fds)
bool BKE_fluid_reallocate_fluid(struct FluidDomainSettings *fds, int res[3], int free_old)
void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_type)
void BKE_fluid_particle_system_create(struct Main *bmain, struct Object *ob, const char *pset_name, const char *parts_name, const char *psys_name, const int psys_type)
struct Mesh * BKE_fluid_modifier_do(struct FluidModifierData *fmd, struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct Mesh *me)
float(* BKE_Fluid_BresenhamFn)(float *result, const float *input, int res[3], int *pixel, float *tRay, float correct)
Definition: BKE_fluid.h:38
void BKE_fluid_reallocate_copy_fluid(struct FluidDomainSettings *fds, int o_res[3], int n_res[3], const int o_min[3], const int n_min[3], const int o_max[3], int o_shift[3], int n_shift[3])
float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3])
void BKE_fluid_cache_free(struct FluidDomainSettings *fds, struct Object *ob, int cache_map)
@ LIB_ID_CREATE_NO_MAIN
Definition: BKE_lib_id.h:88
void BKE_id_free(struct Main *bmain, void *idv)
void BKE_mesh_ensure_normals(struct Mesh *me)
struct Mesh * BKE_mesh_copy_for_eval(struct Mesh *source, bool reference)
Definition: mesh.c:995
struct Mesh * BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
Definition: mesh.c:877
void BKE_mesh_vert_normals_apply(struct Mesh *mesh, const short(*vert_normals)[3])
Definition: mesh.c:1779
void BKE_mesh_texspace_calc(struct Mesh *me)
Definition: mesh.c:1079
void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, const bool select_new_edges)
void BKE_mesh_copy_settings(struct Mesh *me_dst, const struct Mesh *me_src)
const struct MLoopTri * BKE_mesh_runtime_looptri_ensure(struct Mesh *mesh)
Definition: mesh_runtime.c:155
void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
void BKE_modifier_free(struct ModifierData *md)
struct ModifierData * BKE_modifiers_get_virtual_modifierlist(const struct Object *ob, struct VirtualModifierData *data)
const char * BKE_modifier_path_relbase_from_global(struct Object *ob)
struct ModifierData * BKE_modifiers_findby_type(const struct Object *ob, ModifierType type)
void BKE_modifier_remove_from_list(struct Object *ob, struct ModifierData *md)
struct ModifierData * BKE_modifier_new(int type)
bool BKE_modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md)
General operations, lookup, etc. for blender objects.
bool BKE_object_modifier_update_subframe(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, bool update_mesh, int parent_recursion, float frame, int type)
Definition: object.c:5546
bool BKE_object_moves_in_time(const struct Object *object, bool recurse_parent)
struct LatticeDeformData * psys_create_lattice_deform_data(struct ParticleSimulationData *sim)
Definition: particle.c:696
struct ParticleSettings * BKE_particlesettings_add(struct Main *bmain, const char *name)
Definition: particle.c:4086
int psys_get_particle_state(struct ParticleSimulationData *sim, int p, struct ParticleKey *state, int always)
Definition: particle.c:4854
struct ParticleSystemModifierData * psys_get_modifier(struct Object *ob, struct ParticleSystem *psys)
Definition: particle.c:2201
void psys_free(struct Object *ob, struct ParticleSystem *psys)
Definition: particle.c:1070
struct PointCache * BKE_ptcache_copy_list(struct ListBase *ptcaches_new, const struct ListBase *ptcaches_old, const int flag)
struct PointCache * BKE_ptcache_add(struct ListBase *ptcaches)
Definition: pointcache.c:3072
void BKE_ptcache_free_list(struct ListBase *ptcaches)
Definition: pointcache.c:3110
float BKE_scene_frame_get(const struct Scene *scene)
void BKE_texture_get_value(const struct Scene *scene, struct Tex *texture, const float *tex_co, struct TexResult *texres, bool use_color_management)
#define BLI_assert_unreachable()
Definition: BLI_assert.h:96
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:349
int BLI_delete(const char *file, bool dir, bool recursive) ATTR_NONNULL()
Definition: fileops.c:1037
BLI_INLINE unsigned int BLI_hash_int(unsigned int k)
Definition: BLI_hash.h:103
float BLI_bvhtree_bb_raycast(const float bv[6], const float light_start[3], const float light_end[3], float pos[3])
Definition: BLI_kdopbvh.c:1996
int BLI_bvhtree_ray_cast(BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:1984
int BLI_bvhtree_find_nearest(BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:1654
A kd-tree for nearest neighbor search.
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
MINLINE float pow2f(float x)
MINLINE int max_ii(int a, int b)
MINLINE int min_iii(int a, int b, int c)
void interp_weights_tri_v3(float w[3], const float v1[3], const float v2[3], const float v3[3], const float co[3])
Definition: math_geom.c:3831
void mul_mat3_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:794
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:95
void copy_vn_fl(float *array_tar, const int size, const float val)
Definition: math_vector.c:1410
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
Definition: math_vector.c:1020
MINLINE void add_v3fl_v3fl_v3i(float r[3], const float a[3], const int b[3])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_fl(float r[3], float f)
MINLINE void normal_float_to_short_v3(short r[3], const float n[3])
MINLINE void madd_v3fl_v3fl_v3fl_v3i(float r[3], const float a[3], const float b[3], const int c[3])
MINLINE float normalize_v3(float r[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])
void interp_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3])
Definition: math_vector.c:191
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void normal_short_to_float_v3(float r[3], const short n[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v2_v2v2v2(float r[2], const float a[2], const float b[2], const float c[2], const float t[3])
Definition: math_vector.c:42
MINLINE void copy_v3_v3_int(int r[3], const int a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3_int(int r[3])
MINLINE void abs_v3(float r[3])
MINLINE void negate_v3(float r[3])
MINLINE void sub_v3_v3v3_int(int r[3], const int a[3], const int b[3])
MINLINE bool equals_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_fl(float r[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 len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
#define FILE_MAX
size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path_first,...) ATTR_NONNULL(1
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL()
Definition: path_util.c:1016
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
unsigned int uint
Definition: BLI_sys_types.h:83
void BLI_task_parallel_range(const int start, const int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:110
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:231
#define THREAD_LOCK_WRITE
Definition: BLI_threads.h:122
#define BLI_MUTEX_INITIALIZER
Definition: BLI_threads.h:84
void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode)
Definition: threads.cc:516
void BLI_mutex_lock(ThreadMutex *mutex)
Definition: threads.cc:401
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition: threads.cc:406
ThreadRWMutex * BLI_rw_mutex_alloc(void)
Definition: threads.cc:536
void BLI_rw_mutex_free(ThreadRWMutex *mutex)
Definition: threads.cc:544
void BLI_rw_mutex_unlock(ThreadRWMutex *mutex)
Definition: threads.cc:526
pthread_mutex_t ThreadMutex
Definition: BLI_threads.h:83
#define CLAMP_MAX(a, c)
#define INIT_MINMAX(min, max)
#define MAX3(a, b, c)
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define UNUSED(x)
#define UNPACK3(a)
#define MAX2(a, b)
#define ELEM(...)
#define MIN2(a, b)
#define CLAMP3(vec, b, c)
#define CLAMP_MIN(a, b)
float BLI_voxel_sample_trilinear(const float *data, const int res[3], const float co[3])
Definition: voxel.c:70
#define CLOG_ERROR(clg_ref,...)
Definition: CLG_log.h:204
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
float DEG_get_ctime(const Depsgraph *graph)
struct ViewLayer * DEG_get_evaluated_view_layer(const struct Depsgraph *graph)
#define CD_MASK_NORMAL
@ CD_MDEFORMVERT
@ CD_MVERT
@ CD_MLOOPUV
#define DNA_struct_default_alloc(struct_name)
Definition: DNA_defaults.h:47
@ FLUID_DOMAIN_BAKED_DATA
@ FLUID_DOMAIN_OUTDATED_GUIDE
@ FLUID_DOMAIN_OUTDATED_PARTICLES
@ FLUID_DOMAIN_BAKING_MESH
@ FLUID_DOMAIN_BAKING_NOISE
@ FLUID_DOMAIN_BAKING_GUIDE
@ FLUID_DOMAIN_OUTDATED_NOISE
@ FLUID_DOMAIN_BAKED_NOISE
@ FLUID_DOMAIN_BAKED_MESH
@ FLUID_DOMAIN_OUTDATED_MESH
@ FLUID_DOMAIN_BAKING_DATA
@ FLUID_DOMAIN_BAKED_GUIDE
@ FLUID_DOMAIN_BAKED_PARTICLES
@ FLUID_DOMAIN_OUTDATED_DATA
@ FLUID_DOMAIN_BAKING_PARTICLES
@ FLUID_FLOW_ABSOLUTE
@ FLUID_FLOW_TEXTUREEMIT
@ FLUID_FLOW_USE_PART_SIZE
@ FLUID_FLOW_NEEDS_UPDATE
@ FLUID_FLOW_USE_PLANE_INIT
@ FLUID_FLOW_INITVELOCITY
@ FLUID_FLOW_USE_INFLOW
@ VDB_COMPRESSION_ZIP
#define FLUID_DOMAIN_DIR_DATA
#define FLUID_DOMAIN_DIR_PARTICLES
@ FLUID_FLOW_SOURCE_PARTICLES
@ FLUID_FLOW_SOURCE_MESH
@ FLUID_EFFECTOR_TYPE_GUIDE
@ FLUID_EFFECTOR_TYPE_COLLISION
#define FLUID_DOMAIN_DIR_DEFAULT
#define FLUID_DOMAIN_DIR_MESH
#define FLUID_DOMAIN_DIR_GUIDE
#define FLUID_DOMAIN_DIR_SCRIPT
@ FLUID_EFFECTOR_NEEDS_UPDATE
@ FLUID_EFFECTOR_USE_EFFEC
@ FLUID_EFFECTOR_USE_PLANE_INIT
@ FLUID_FLOW_BEHAVIOR_GEOMETRY
@ FLUID_FLOW_BEHAVIOR_OUTFLOW
@ FLUID_FLOW_BEHAVIOR_INFLOW
@ FLUID_DOMAIN_PARTICLE_SPRAY
@ FLUID_DOMAIN_PARTICLE_FOAM
@ FLUID_DOMAIN_PARTICLE_TRACER
@ FLUID_DOMAIN_PARTICLE_BUBBLE
@ FLUID_DOMAIN_FIELD_COLOR_B
@ FLUID_DOMAIN_FIELD_FLAME
@ FLUID_DOMAIN_FIELD_PHI_OUT
@ FLUID_DOMAIN_FIELD_PHI_OBSTACLE
@ FLUID_DOMAIN_FIELD_PHI
@ FLUID_DOMAIN_FIELD_DENSITY
@ FLUID_DOMAIN_FIELD_PHI_IN
@ FLUID_DOMAIN_FIELD_HEAT
@ FLUID_DOMAIN_FIELD_COLOR_G
@ FLUID_DOMAIN_FIELD_FUEL
@ FLUID_DOMAIN_FIELD_COLOR_R
@ FLUID_DOMAIN_CACHE_ALL
@ FLUID_DOMAIN_CACHE_REPLAY
@ FLUID_DOMAIN_CACHE_MODULAR
@ FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN
@ FLUID_DOMAIN_USE_MESH
@ FLUID_DOMAIN_USE_RESUMABLE_CACHE
@ FLUID_DOMAIN_USE_GUIDE
@ FLUID_DOMAIN_EXPORT_MANTA_SCRIPT
@ FLUID_DOMAIN_USE_SPEED_VECTORS
@ FLUID_DOMAIN_USE_NOISE
@ FLUID_DOMAIN_FILE_LOAD
@ FLUID_DOMAIN_ACTIVE_COLORS
@ FLUID_DOMAIN_ACTIVE_FIRE
@ FLUID_DOMAIN_ACTIVE_INVEL
@ FLUID_DOMAIN_ACTIVE_GUIDE
@ FLUID_DOMAIN_ACTIVE_OUTFLOW
@ FLUID_DOMAIN_ACTIVE_COLOR_SET
@ FLUID_DOMAIN_ACTIVE_HEAT
@ FLUID_DOMAIN_ACTIVE_OBSTACLE
@ FLUID_DOMAIN_FILE_UNI
#define FLUID_DOMAIN_DIR_CONFIG
@ VDB_PRECISION_MINI_FLOAT
@ VDB_PRECISION_HALF_FLOAT
@ FLUID_FLOW_TYPE_FIRE
@ FLUID_FLOW_TYPE_SMOKEFIRE
@ FLUID_FLOW_TYPE_LIQUID
@ FLUID_FLOW_TYPE_SMOKE
@ FLUID_DOMAIN_BORDER_BOTTOM
@ FLUID_DOMAIN_BORDER_LEFT
@ FLUID_DOMAIN_BORDER_RIGHT
@ FLUID_DOMAIN_BORDER_FRONT
@ FLUID_DOMAIN_BORDER_TOP
@ FLUID_DOMAIN_BORDER_BACK
@ FLUID_DOMAIN_GUIDE_SRC_DOMAIN
@ FLUID_FLOW_TEXTURE_MAP_AUTO
#define FLUID_DOMAIN_DIR_NOISE
@ FLUID_EFFECTOR_GUIDE_MAX
@ FLUID_EFFECTOR_GUIDE_OVERRIDE
@ FLUID_EFFECTOR_GUIDE_AVERAGED
@ FLUID_EFFECTOR_GUIDE_MIN
@ FLUID_DOMAIN_TYPE_GAS
@ FLUID_DOMAIN_TYPE_LIQUID
#define LA_LOCAL
@ eModifierFlag_SharedCaches
@ eModifierType_ParticleSystem
@ eModifierType_Explode
@ eModifierType_Cloth
@ eModifierType_Fluid
@ eModifierType_ShapeKey
@ eModifierType_Ocean
@ eModifierType_Nodes
@ eModifierType_DynamicPaint
@ eModifierType_Softbody
@ MOD_FLUID_TYPE_EFFEC
@ MOD_FLUID_TYPE_DOMAIN
@ MOD_FLUID_TYPE_FLOW
@ OB_WIRE
@ OB_SOLID
@ PFIELD_FLUIDFLOW
Object is a sort of wrapper for general info.
@ OB_LAMP
#define PARS_UNEXIST
#define PARS_NO_DISP
#define PART_PHYS_NO
#define PART_DRAW_COL_VEL
@ PART_CHILD_USE_TWIST_CURVE
@ PART_CHILD_USE_CLUMP_CURVE
@ PART_CHILD_USE_ROUGH_CURVE
@ PART_EMITTER
@ PART_FLUID
@ PART_HAIR
#define PTCACHE_DISK_CACHE
Types and defines for representing Rigid Body entities.
@ RBO_TYPE_ACTIVE
#define FIRSTBASE(_view_layer)
#define PHYS_GLOBAL_GRAVITY
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble z
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble y1
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble x2
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
Group RGB to Bright Vector Camera CLAMP
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
#define output
size_t index
Definition: geometry.h:114
double time
Scene scene
const Depsgraph * depsgraph
void * tree
#define PHI_MAX
Definition: fluid.c:95
void BKE_fluid_modifier_reset(struct FluidModifierData *fmd)
Definition: fluid.c:4876
#define DT_DEFAULT
Definition: fluid.c:92
void BKE_fluid_cachetype_noise_set(FluidDomainSettings *settings, int cache_noise_format)
Definition: fluid.c:4629
static void BKE_fluid_modifier_freeDomain(FluidModifierData *fmd)
Definition: fluid.c:4755
void BKE_fluid_modifier_copy(const struct FluidModifierData *fmd, struct FluidModifierData *tfmd, const int flag)
Definition: fluid.c:4948
void BKE_fluid_cachetype_particle_set(FluidDomainSettings *settings, int cache_particle_format)
Definition: fluid.c:4620
void BKE_fluid_flow_behavior_set(Object *UNUSED(object), FluidFlowSettings *settings, int behavior)
Definition: fluid.c:4685
void BKE_fluid_domain_type_set(Object *object, FluidDomainSettings *settings, int type)
Definition: fluid.c:4658
void BKE_fluid_particles_set(FluidDomainSettings *settings, int value, bool clear)
Definition: fluid.c:4648
static void BKE_fluid_modifier_freeFlow(FluidModifierData *fmd)
Definition: fluid.c:4792
void BKE_fluid_cachetype_data_set(FluidDomainSettings *settings, int cache_data_format)
Definition: fluid.c:4611
static void BKE_fluid_modifier_freeEffector(FluidModifierData *fmd)
Definition: fluid.c:4812
static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *fmd, bool need_lock)
Definition: fluid.c:4832
void BKE_fluid_modifier_create_type_data(struct FluidModifierData *fmd)
Definition: fluid.c:4892
void BKE_fluid_collisionextents_set(FluidDomainSettings *settings, int value, bool clear)
Definition: fluid.c:4638
void BKE_fluid_cache_new_name_for_current_session(int maxlen, char *r_name)
Definition: fluid.c:5195
void BKE_fluid_cache_endframe_set(FluidDomainSettings *settings, int value)
Definition: fluid.c:4596
void BKE_fluid_fields_sanitize(FluidDomainSettings *settings)
Definition: fluid.c:4710
void BKE_fluid_cache_startframe_set(FluidDomainSettings *settings, int value)
Definition: fluid.c:4590
void BKE_fluid_flow_type_set(Object *object, FluidFlowSettings *settings, int type)
Definition: fluid.c:4690
void BKE_fluid_effector_type_set(Object *UNUSED(object), FluidEffectorSettings *settings, int type)
Definition: fluid.c:4705
void BKE_fluid_cachetype_mesh_set(FluidDomainSettings *settings, int cache_mesh_format)
Definition: fluid.c:4602
void BKE_fluid_modifier_free(FluidModifierData *fmd)
Definition: fluid.c:4881
static float verts[][3]
static float normals[][3]
uint pos
#define expf(x)
#define floorf(x)
#define fabsf(x)
#define sqrtf(x)
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:48
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:46
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
float * manta_smoke_get_heat_in(struct MANTA *smoke)
bool manta_has_particles(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float manta_liquid_get_normal_x_at(struct MANTA *liquid, int i)
float * manta_smoke_get_shadow(struct MANTA *fluid)
float * manta_smoke_get_color_g(struct MANTA *smoke)
float * manta_get_force_y(struct MANTA *fluid)
bool manta_has_mesh(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float * manta_get_phiobs_in(struct MANTA *fluid)
float manta_liquid_get_vertex_y_at(struct MANTA *liquid, int i)
float * manta_smoke_get_color_b(struct MANTA *smoke)
float * manta_smoke_get_emission_in(struct MANTA *smoke)
float * manta_noise_get_texture_w2(struct MANTA *smoke)
bool manta_ensure_invelocity(struct MANTA *fluid, struct FluidModifierData *fmd)
bool manta_read_guiding(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr, bool sourceDomain)
bool manta_has_data(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
bool manta_bake_particles(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float * manta_get_phioutstatic_in(struct MANTA *fluid)
float * manta_smoke_get_fuel(struct MANTA *smoke)
float * manta_smoke_get_heat(struct MANTA *smoke)
bool manta_smoke_ensure_colors(struct MANTA *smoke, struct FluidModifierData *fmd)
void manta_free(struct MANTA *fluid)
bool manta_smoke_has_heat(struct MANTA *smoke)
int manta_liquid_get_num_triangles(struct MANTA *liquid)
bool manta_bake_mesh(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float manta_get_timestep(struct MANTA *fluid)
float * manta_get_in_velocity_x(struct MANTA *fluid)
bool manta_bake_noise(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float * manta_smoke_get_color_g_in(struct MANTA *smoke)
float * manta_smoke_get_color_b_in(struct MANTA *smoke)
float * manta_noise_get_texture_u2(struct MANTA *smoke)
float * manta_smoke_get_color_r_in(struct MANTA *smoke)
float * manta_get_phistatic_in(struct MANTA *fluid)
float * manta_get_guide_velocity_z(struct MANTA *fluid)
float * manta_smoke_get_density(struct MANTA *smoke)
float * manta_smoke_get_color_r(struct MANTA *smoke)
bool manta_read_mesh(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
bool manta_liquid_ensure_sndparts(struct MANTA *fluid, struct FluidModifierData *fmd)
float * manta_get_force_x(struct MANTA *fluid)
float * manta_get_velocity_x(struct MANTA *fluid)
float * manta_smoke_get_flame(struct MANTA *smoke)
float * manta_noise_get_texture_v2(struct MANTA *smoke)
bool manta_write_data(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
int * manta_smoke_get_flags(struct MANTA *smoke)
float * manta_get_phi_in(struct MANTA *fluid)
bool manta_smoke_ensure_fire(struct MANTA *smoke, struct FluidModifierData *fmd)
float * manta_get_velocity_y(struct MANTA *fluid)
void manta_noise_get_res(struct MANTA *smoke, int *res)
float * manta_noise_get_fuel(struct MANTA *smoke)
float manta_liquid_get_vertvel_y_at(struct MANTA *liquid, int i)
int manta_liquid_get_num_verts(struct MANTA *liquid)
bool manta_ensure_obstacle(struct MANTA *fluid, struct FluidModifierData *fmd)
bool manta_write_config(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float * manta_get_in_velocity_z(struct MANTA *fluid)
float * manta_noise_get_texture_v(struct MANTA *smoke)
bool manta_needs_realloc(struct MANTA *fluid, struct FluidModifierData *fmd)
bool manta_has_noise(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float manta_liquid_get_vertvel_z_at(struct MANTA *liquid, int i)
bool manta_read_noise(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr, bool resumable)
float * manta_get_num_guide(struct MANTA *fluid)
size_t manta_get_index(int x, int max_x, int y, int max_y, int z)
bool manta_read_particles(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr, bool resumable)
bool manta_write_noise(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float * manta_get_force_z(struct MANTA *fluid)
float manta_liquid_get_vertvel_x_at(struct MANTA *liquid, int i)
float * manta_get_ob_velocity_x(struct MANTA *fluid)
float * manta_smoke_get_fuel_in(struct MANTA *smoke)
bool manta_smoke_ensure_heat(struct MANTA *smoke, struct FluidModifierData *fmd)
void manta_update_pointers(struct MANTA *fluid, struct FluidModifierData *fmd, bool flush)
bool manta_ensure_guiding(struct MANTA *fluid, struct FluidModifierData *fmd)
float * manta_noise_get_density(struct MANTA *smoke)
bool manta_read_data(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr, bool resumable)
float * manta_noise_get_color_b(struct MANTA *smoke)
float * manta_get_ob_velocity_z(struct MANTA *fluid)
float * manta_get_guide_velocity_x(struct MANTA *fluid)
float * manta_get_phiout_in(struct MANTA *fluid)
bool manta_has_guiding(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr, bool domain)
float * manta_noise_get_react(struct MANTA *smoke)
float * manta_noise_get_flame(struct MANTA *smoke)
bool manta_smoke_has_colors(struct MANTA *smoke)
bool manta_read_config(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float manta_liquid_get_vertex_z_at(struct MANTA *liquid, int i)
int manta_liquid_get_num_normals(struct MANTA *liquid)
float * manta_smoke_get_react_in(struct MANTA *smoke)
float * manta_get_in_velocity_y(struct MANTA *fluid)
float * manta_get_velocity_z(struct MANTA *fluid)
float * manta_noise_get_texture_w(struct MANTA *smoke)
int manta_liquid_get_triangle_z_at(struct MANTA *liquid, int i)
bool manta_smoke_has_fuel(struct MANTA *smoke)
float manta_liquid_get_vertex_x_at(struct MANTA *liquid, int i)
float * manta_smoke_get_react(struct MANTA *smoke)
bool manta_liquid_export_script(struct MANTA *smoke, struct FluidModifierData *fmd)
bool manta_ensure_outflow(struct MANTA *fluid, struct FluidModifierData *fmd)
float manta_liquid_get_normal_y_at(struct MANTA *liquid, int i)
void manta_update_variables(struct MANTA *fluid, struct FluidModifierData *fmd)
int manta_liquid_get_triangle_x_at(struct MANTA *liquid, int i)
float * manta_get_num_obstacle(struct MANTA *fluid)
float * manta_get_phiguide_in(struct MANTA *fluid)
struct MANTA * manta_init(int *res, struct FluidModifierData *fmd)
float * manta_get_guide_velocity_y(struct MANTA *fluid)
float * manta_get_ob_velocity_y(struct MANTA *fluid)
void manta_adapt_timestep(struct MANTA *fluid)
int manta_liquid_get_triangle_y_at(struct MANTA *liquid, int i)
float manta_liquid_get_normal_z_at(struct MANTA *liquid, int i)
float * manta_noise_get_texture_u(struct MANTA *smoke)
bool manta_bake_data(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
bool manta_smoke_export_script(struct MANTA *smoke, struct FluidModifierData *fmd)
float * manta_noise_get_color_r(struct MANTA *smoke)
bool manta_bake_guiding(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float * manta_get_phiobsstatic_in(struct MANTA *fluid)
float * manta_noise_get_color_g(struct MANTA *smoke)
float * manta_smoke_get_density_in(struct MANTA *smoke)
static ulong state[N]
static void clear(Message *msg)
Definition: msgfmt.c:294
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
Definition: rall1d.h:359
static void update_velocities(PTCacheEdit *edit)
#define min(a, b)
Definition: sort.c:51
BVHTree_RayCastCallback raycast_callback
Definition: BKE_bvhutils.h:70
struct BVHTree * tree
Definition: BKE_bvhutils.h:66
BVHTree_NearestPointCallback nearest_callback
Definition: BKE_bvhutils.h:69
float co[3]
Definition: BLI_kdopbvh.h:59
float no[3]
Definition: BLI_kdopbvh.h:86
struct Base * next
struct Object * object
struct ListBase ptcaches[2]
struct FluidModifierData * fmd
struct Collection * force_group
struct FluidDomainVertexVelocity * mesh_velocities
struct Collection * effector_group
struct MANTA * fluid
struct PointCache * point_cache[2]
char cache_directory[1024]
struct ColorBand * coba
float gridlines_range_color[4]
struct Object * guide_parent
struct Collection * fluid_group
struct EffectorWeights * effector_weights
struct FluidModifierData * fmd
struct FluidModifierData * fmd
struct ParticleSystem * psys
struct Mesh * mesh
struct Tex * noise_texture
struct FluidDomainSettings * domain
struct FluidEffectorSettings * effector
struct FluidFlowSettings * flow
short type
void * first
Definition: DNA_listBase.h:47
unsigned int tri[3]
unsigned int v
short mat_nr
float co[3]
Definition: BKE_main.h:116
struct CustomData pdata ldata
struct MVert * mvert
int totvert
short flag
struct MLoop * mloop
struct MPoly * mpoly
struct ModifierData * next
ListBase particlesystem
ListBase modifiers
struct RigidBodyOb * rigidbody_object
float scale[3]
float imat[4][4]
float obmat[4][4]
void * data
struct CurveMapping * clumpcurve
struct CurveMapping * roughcurve
struct CurveMapping * twistcurve
struct Depsgraph * depsgraph
Definition: BKE_particle.h:87
struct Scene * scene
Definition: BKE_particle.h:88
struct ParticleSystem * psys
Definition: BKE_particle.h:90
struct Object * ob
Definition: BKE_particle.h:89
struct ParticleSystem * psys
ChildParticle * child
struct ListBase ptcaches
ParticleData * particles
ParticleSettings * part
struct ParticleSystem * next
struct PointCache * pointcache
struct LatticeDeformData * lattice_deform_data
float frs_sec_base
struct PhysicsSettings physics_settings
struct RenderData r
float * nor
Definition: RE_texture.h:86
float tin
Definition: RE_texture.h:84
float max
__forceinline const avxi abs(const avxi &a)
Definition: util_avxi.h:186
#define LOG(severity)
Definition: util_logging.h:49
ccl_device_inline float2 floor(const float2 &a)
ccl_device_inline float3 ceil(const float3 &a)
#define G(x, y, z)