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