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