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
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/* -------------------------------------------------------------------- */
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. */
423 sub_v3_v3v3(size, max, min);
424 if (init_resolution) {
425 zero_v3_int(fds->base_res);
426 copy_v3_v3(fds->cell_size, size);
427 }
428 /* Apply object scale. */
429 for (i = 0; i < 3; i++) {
430 size[i] = fabsf(size[i] * ob->scale[i]);
431 }
432 copy_v3_v3(fds->global_size, size);
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{
475 if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
476 copy_v3_v3(fds->gravity_final, scene->physics_settings.gravity);
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
641/* -------------------------------------------------------------------- */
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
818/* -------------------------------------------------------------------- */
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;
955
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. */
986 update_velocities(data->fes,
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 }
1151 fes->flags &= ~FLUID_EFFECTOR_NEEDS_UPDATE;
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
1472/* -------------------------------------------------------------------- */
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)) {
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
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]>(
2091 CustomData_get_layer_named(&mesh->corner_data, CD_PROP_FLOAT2, ffs->uvlayer_name));
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
2188/* -------------------------------------------------------------------- */
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) {
2612 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",
3236 AttrDomain::Face);
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);
3276 sub_v3_v3v3(size, max, min);
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",
3300 AttrDomain::Point);
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 }
3625 fmd->flow->mesh = BKE_mesh_copy_for_eval(*mesh);
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 }
3652 fmd->effector->mesh = BKE_mesh_copy_for_eval(*mesh);
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
4074 fds->flags &= ~FLUID_DOMAIN_FILE_LOAD;
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). */
4156 fmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_DATA;
4157 fmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_NOISE;
4158 fmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_MESH;
4159 fmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_PARTICLES;
4160 fmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_GUIDE;
4161 }
4162
4163 if (!result) {
4164 result = BKE_mesh_copy_for_eval(*mesh);
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. */
4175 BKE_mesh_texspace_calc(result);
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. */
4475 part->draw_col = PART_DRAW_COL_VEL;
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
4513#endif /* WITH_FLUID */
4514
4515/* -------------------------------------------------------------------- */
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. */
4656 settings->coba_field = FLUID_DOMAIN_FIELD_DENSITY;
4657 }
4658
4659 /* Gas domains do not support VDB mini precision. */
4660 if (data_depth == VDB_PRECISION_MINI_FLOAT) {
4661 settings->openvdb_data_depth = VDB_PRECISION_HALF_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. */
4675 settings->coba_field = FLUID_DOMAIN_FIELD_PHI;
4676 }
4677 }
4678}
4679
4682/* -------------------------------------------------------------------- */
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;
4727 fmd->flow->flags &= ~FLUID_FLOW_NEEDS_UPDATE;
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;
4744 fmd->effector->flags &= ~FLUID_EFFECTOR_NEEDS_UPDATE;
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;
4781 fmd->flow->flags &= ~FLUID_FLOW_NEEDS_UPDATE;
4782 }
4783 else if (fmd->effector) {
4785 fmd->effector->numverts = 0;
4786 fmd->effector->flags &= ~FLUID_EFFECTOR_NEEDS_UPDATE;
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)
@ LIB_ID_COPY_SET_COPIED_ON_WRITE
void BKE_id_free(Main *bmain, void *idv)
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)
@ FLUID_DOMAIN_PARTICLE_SPRAY
@ FLUID_DOMAIN_PARTICLE_FOAM
@ FLUID_DOMAIN_PARTICLE_TRACER
@ FLUID_DOMAIN_PARTICLE_BUBBLE
@ VDB_COMPRESSION_ZIP
#define FLUID_DOMAIN_DIR_DATA
#define FLUID_DOMAIN_DIR_PARTICLES
@ 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_TYPE_GAS
@ FLUID_DOMAIN_TYPE_LIQUID
#define FLUID_DOMAIN_DIR_DEFAULT
#define FLUID_DOMAIN_DIR_MESH
@ FLUID_EFFECTOR_NEEDS_UPDATE
@ FLUID_EFFECTOR_USE_EFFEC
@ FLUID_EFFECTOR_USE_PLANE_INIT
#define FLUID_DOMAIN_DIR_GUIDE
#define FLUID_DOMAIN_DIR_SCRIPT
@ FLUID_DOMAIN_GUIDE_SRC_DOMAIN
@ 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_FILE_UNI
@ VDB_PRECISION_MINI_FLOAT
@ VDB_PRECISION_HALF_FLOAT
@ FLUID_EFFECTOR_GUIDE_MAX
@ FLUID_EFFECTOR_GUIDE_OVERRIDE
@ FLUID_EFFECTOR_GUIDE_AVERAGED
@ FLUID_EFFECTOR_GUIDE_MIN
@ 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_CACHE_ALL
@ FLUID_DOMAIN_CACHE_REPLAY
@ FLUID_DOMAIN_CACHE_MODULAR
#define FLUID_DOMAIN_DIR_CONFIG
@ 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
@ FLUID_FLOW_SOURCE_PARTICLES
@ FLUID_FLOW_SOURCE_MESH
@ 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_FLOW_TEXTURE_MAP_AUTO
@ FLUID_FLOW_TYPE_FIRE
@ FLUID_FLOW_TYPE_SMOKEFIRE
@ FLUID_FLOW_TYPE_LIQUID
@ FLUID_FLOW_TYPE_SMOKE
#define FLUID_DOMAIN_DIR_NOISE
@ FLUID_EFFECTOR_TYPE_GUIDE
@ FLUID_EFFECTOR_TYPE_COLLISION
@ 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_BEHAVIOR_GEOMETRY
@ FLUID_FLOW_BEHAVIOR_OUTFLOW
@ FLUID_FLOW_BEHAVIOR_INFLOW
@ LA_LOCAL
@ 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_DRAW_COL_VEL
@ PART_EMITTER
@ PART_FLUID
@ PART_HAIR
@ PARS_NO_DISP
@ PARS_UNEXIST
@ PART_PHYS_NO
@ PTCACHE_OUTDATED
@ PTCACHE_DISK_CACHE
Types and defines for representing Rigid Body entities.
@ RBO_TYPE_ACTIVE
@ PHYS_GLOBAL_GRAVITY
#define FPS
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
AttributeSet attributes
constexpr void fill(const T &value) const
Definition BLI_span.hh:518
constexpr bool is_empty() const
Definition BLI_span.hh:261
GAttributeReader lookup(const StringRef attribute_id) const
pow(value.r - subtrahend, 2.0)") .do_static_compilation(true)
#define printf
const Depsgraph * depsgraph
#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)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
bool is_adaptive(const CpuPatchTable *patch_table)
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
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
float tin
Definition RE_texture.h:87
float max
ccl_device_inline int abs(int x)
Definition util/math.h:120
uint8_t flag
Definition wm_window.cc:138