Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/smoke.c')
-rw-r--r--source/blender/blenkernel/intern/smoke.c6053
1 files changed, 3219 insertions, 2834 deletions
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 122bb5a19c5..23cdf802c81 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
/* Part of the code copied from elbeem fluid library, copyright by Nils Thuerey */
#include "MEM_guardedalloc.h"
@@ -89,11 +88,11 @@
#ifdef WITH_SMOKE
-#include "smoke_API.h"
+# include "smoke_API.h"
-#include "BLI_task.h"
-#include "BLI_kdtree.h"
-#include "BLI_voxel.h"
+# include "BLI_task.h"
+# include "BLI_kdtree.h"
+# include "BLI_voxel.h"
static ThreadMutex object_update_lock = BLI_MUTEX_INITIALIZER;
@@ -103,26 +102,66 @@ struct Scene;
struct SmokeModifierData;
// timestep default value for nice appearance 0.1f
-#define DT_DEFAULT 0.1f
+# define DT_DEFAULT 0.1f
-#define ADD_IF_LOWER_POS(a, b) (min_ff((a) + (b), max_ff((a), (b))))
-#define ADD_IF_LOWER_NEG(a, b) (max_ff((a) + (b), min_ff((a), (b))))
-#define ADD_IF_LOWER(a, b) (((b) > 0) ? ADD_IF_LOWER_POS((a), (b)) : ADD_IF_LOWER_NEG((a), (b)))
+# define ADD_IF_LOWER_POS(a, b) (min_ff((a) + (b), max_ff((a), (b))))
+# define ADD_IF_LOWER_NEG(a, b) (max_ff((a) + (b), min_ff((a), (b))))
+# define ADD_IF_LOWER(a, b) (((b) > 0) ? ADD_IF_LOWER_POS((a), (b)) : ADD_IF_LOWER_NEG((a), (b)))
#else /* WITH_SMOKE */
/* Stubs to use when smoke is disabled */
-struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), int UNUSED(amplify), int UNUSED(noisetype), const char *UNUSED(noisefile_path), int UNUSED(use_fire), int UNUSED(use_colors)) { return NULL; }
+struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res),
+ int UNUSED(amplify),
+ int UNUSED(noisetype),
+ const char *UNUSED(noisefile_path),
+ int UNUSED(use_fire),
+ int UNUSED(use_colors))
+{
+ return NULL;
+}
//struct FLUID_3D *smoke_init(int *UNUSED(res), float *UNUSED(dx), float *UNUSED(dtdef), int UNUSED(use_heat), int UNUSED(use_fire), int UNUSED(use_colors)) { return NULL; }
-void smoke_free(struct FLUID_3D *UNUSED(fluid)) {}
-float *smoke_get_density(struct FLUID_3D *UNUSED(fluid)) { return NULL; }
-void smoke_turbulence_free(struct WTURBULENCE *UNUSED(wt)) {}
-void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(strength)) {}
-void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), float *UNUSED(alpha), float *UNUSED(beta), float *UNUSED(dt_factor), float *UNUSED(vorticity),
- int *UNUSED(border_colli), float *UNUSED(burning_rate), float *UNUSED(flame_smoke), float *UNUSED(flame_smoke_color),
- float *UNUSED(flame_vorticity), float *UNUSED(flame_ignition_temp), float *UNUSED(flame_max_temp)) {}
-struct Mesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Depsgraph *UNUSED(depsgraph), Scene *UNUSED(scene), Object *UNUSED(ob), Mesh *UNUSED(me)) { return NULL; }
-float BKE_smoke_get_velocity_at(struct Object *UNUSED(ob), float UNUSED(position[3]), float UNUSED(velocity[3])) { return 0.0f; }
+void smoke_free(struct FLUID_3D *UNUSED(fluid))
+{
+}
+float *smoke_get_density(struct FLUID_3D *UNUSED(fluid))
+{
+ return NULL;
+}
+void smoke_turbulence_free(struct WTURBULENCE *UNUSED(wt))
+{
+}
+void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(strength))
+{
+}
+void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid),
+ float *UNUSED(alpha),
+ float *UNUSED(beta),
+ float *UNUSED(dt_factor),
+ float *UNUSED(vorticity),
+ int *UNUSED(border_colli),
+ float *UNUSED(burning_rate),
+ float *UNUSED(flame_smoke),
+ float *UNUSED(flame_smoke_color),
+ float *UNUSED(flame_vorticity),
+ float *UNUSED(flame_ignition_temp),
+ float *UNUSED(flame_max_temp))
+{
+}
+struct Mesh *smokeModifier_do(SmokeModifierData *UNUSED(smd),
+ Depsgraph *UNUSED(depsgraph),
+ Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ Mesh *UNUSED(me))
+{
+ return NULL;
+}
+float BKE_smoke_get_velocity_at(struct Object *UNUSED(ob),
+ float UNUSED(position[3]),
+ float UNUSED(velocity[3]))
+{
+ return 0.0f;
+}
#endif /* WITH_SMOKE */
@@ -130,613 +169,616 @@ float BKE_smoke_get_velocity_at(struct Object *UNUSED(ob), float UNUSED(position
void BKE_smoke_reallocate_fluid(SmokeDomainSettings *sds, float dx, int res[3], int free_old)
{
- int use_heat = (sds->active_fields & SM_ACTIVE_HEAT);
- int use_fire = (sds->active_fields & SM_ACTIVE_FIRE);
- int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
-
- if (free_old && sds->fluid)
- smoke_free(sds->fluid);
- if (!min_iii(res[0], res[1], res[2])) {
- sds->fluid = NULL;
- return;
- }
- sds->fluid = smoke_init(res, dx, DT_DEFAULT, use_heat, use_fire, use_colors);
- smoke_initBlenderRNA(sds->fluid, &(sds->alpha), &(sds->beta), &(sds->time_scale), &(sds->vorticity), &(sds->border_collisions),
- &(sds->burning_rate), &(sds->flame_smoke), sds->flame_smoke_color, &(sds->flame_vorticity), &(sds->flame_ignition), &(sds->flame_max_temp));
-
- /* reallocate shadow buffer */
- if (sds->shadow)
- MEM_freeN(sds->shadow);
- sds->shadow = MEM_callocN(sizeof(float) * res[0] * res[1] * res[2], "SmokeDomainShadow");
+ int use_heat = (sds->active_fields & SM_ACTIVE_HEAT);
+ int use_fire = (sds->active_fields & SM_ACTIVE_FIRE);
+ int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
+
+ if (free_old && sds->fluid)
+ smoke_free(sds->fluid);
+ if (!min_iii(res[0], res[1], res[2])) {
+ sds->fluid = NULL;
+ return;
+ }
+ sds->fluid = smoke_init(res, dx, DT_DEFAULT, use_heat, use_fire, use_colors);
+ smoke_initBlenderRNA(sds->fluid,
+ &(sds->alpha),
+ &(sds->beta),
+ &(sds->time_scale),
+ &(sds->vorticity),
+ &(sds->border_collisions),
+ &(sds->burning_rate),
+ &(sds->flame_smoke),
+ sds->flame_smoke_color,
+ &(sds->flame_vorticity),
+ &(sds->flame_ignition),
+ &(sds->flame_max_temp));
+
+ /* reallocate shadow buffer */
+ if (sds->shadow)
+ MEM_freeN(sds->shadow);
+ sds->shadow = MEM_callocN(sizeof(float) * res[0] * res[1] * res[2], "SmokeDomainShadow");
}
-void BKE_smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, float dx, int res[3], int free_old)
+void BKE_smoke_reallocate_highres_fluid(SmokeDomainSettings *sds,
+ float dx,
+ int res[3],
+ int free_old)
{
- int use_fire = (sds->active_fields & (SM_ACTIVE_HEAT | SM_ACTIVE_FIRE));
- int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
+ int use_fire = (sds->active_fields & (SM_ACTIVE_HEAT | SM_ACTIVE_FIRE));
+ int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
- if (free_old && sds->wt)
- smoke_turbulence_free(sds->wt);
- if (!min_iii(res[0], res[1], res[2])) {
- sds->wt = NULL;
- return;
- }
+ if (free_old && sds->wt)
+ smoke_turbulence_free(sds->wt);
+ if (!min_iii(res[0], res[1], res[2])) {
+ sds->wt = NULL;
+ return;
+ }
- /* smoke_turbulence_init uses non-threadsafe functions from fftw3 lib (like fftw_plan & co). */
- BLI_thread_lock(LOCK_FFTW);
+ /* smoke_turbulence_init uses non-threadsafe functions from fftw3 lib (like fftw_plan & co). */
+ BLI_thread_lock(LOCK_FFTW);
- sds->wt = smoke_turbulence_init(res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors);
+ sds->wt = smoke_turbulence_init(
+ res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors);
- BLI_thread_unlock(LOCK_FFTW);
+ BLI_thread_unlock(LOCK_FFTW);
- sds->res_wt[0] = res[0] * (sds->amplify + 1);
- sds->res_wt[1] = res[1] * (sds->amplify + 1);
- sds->res_wt[2] = res[2] * (sds->amplify + 1);
- sds->dx_wt = dx / (sds->amplify + 1);
- smoke_initWaveletBlenderRNA(sds->wt, &(sds->strength));
+ sds->res_wt[0] = res[0] * (sds->amplify + 1);
+ sds->res_wt[1] = res[1] * (sds->amplify + 1);
+ sds->res_wt[2] = res[2] * (sds->amplify + 1);
+ sds->dx_wt = dx / (sds->amplify + 1);
+ smoke_initWaveletBlenderRNA(sds->wt, &(sds->strength));
}
/* convert global position to domain cell space */
static void smoke_pos_to_cell(SmokeDomainSettings *sds, float pos[3])
{
- mul_m4_v3(sds->imat, pos);
- sub_v3_v3(pos, sds->p0);
- pos[0] *= 1.0f / sds->cell_size[0];
- pos[1] *= 1.0f / sds->cell_size[1];
- pos[2] *= 1.0f / sds->cell_size[2];
+ mul_m4_v3(sds->imat, pos);
+ sub_v3_v3(pos, sds->p0);
+ pos[0] *= 1.0f / sds->cell_size[0];
+ pos[1] *= 1.0f / sds->cell_size[1];
+ pos[2] *= 1.0f / sds->cell_size[2];
}
/* set domain transformations and base resolution from object mesh */
-static void smoke_set_domain_from_mesh(SmokeDomainSettings *sds, Object *ob, Mesh *me, bool init_resolution)
+static void smoke_set_domain_from_mesh(SmokeDomainSettings *sds,
+ Object *ob,
+ Mesh *me,
+ bool init_resolution)
{
- size_t i;
- float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
- float size[3];
- MVert *verts = me->mvert;
- float scale = 0.0;
- int res;
-
- res = sds->maxres;
-
- // get BB of domain
- for (i = 0; i < me->totvert; i++)
- {
- // min BB
- min[0] = MIN2(min[0], verts[i].co[0]);
- min[1] = MIN2(min[1], verts[i].co[1]);
- min[2] = MIN2(min[2], verts[i].co[2]);
-
- // max BB
- max[0] = MAX2(max[0], verts[i].co[0]);
- max[1] = MAX2(max[1], verts[i].co[1]);
- max[2] = MAX2(max[2], verts[i].co[2]);
- }
-
- /* set domain bounds */
- copy_v3_v3(sds->p0, min);
- copy_v3_v3(sds->p1, max);
- sds->dx = 1.0f / res;
-
- /* calculate domain dimensions */
- sub_v3_v3v3(size, max, min);
- if (init_resolution) {
- zero_v3_int(sds->base_res);
- copy_v3_v3(sds->cell_size, size);
- }
- /* apply object scale */
- for (i = 0; i < 3; i++) {
- size[i] = fabsf(size[i] * ob->scale[i]);
- }
- copy_v3_v3(sds->global_size, size);
- copy_v3_v3(sds->dp0, min);
-
- invert_m4_m4(sds->imat, ob->obmat);
-
- // prevent crash when initializing a plane as domain
- if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || (size[2] < FLT_EPSILON))
- return;
-
- /* define grid resolutions from longest domain side */
- if (size[0] >= MAX2(size[1], size[2])) {
- scale = res / size[0];
- sds->scale = size[0] / fabsf(ob->scale[0]);
- sds->base_res[0] = res;
- sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
- sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
- }
- else if (size[1] >= MAX2(size[0], size[2])) {
- scale = res / size[1];
- sds->scale = size[1] / fabsf(ob->scale[1]);
- sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
- sds->base_res[1] = res;
- sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
- }
- else {
- scale = res / size[2];
- sds->scale = size[2] / fabsf(ob->scale[2]);
- sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
- sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
- sds->base_res[2] = res;
- }
-
- /* set cell size */
- sds->cell_size[0] /= (float)sds->base_res[0];
- sds->cell_size[1] /= (float)sds->base_res[1];
- sds->cell_size[2] /= (float)sds->base_res[2];
+ size_t i;
+ float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
+ float size[3];
+ MVert *verts = me->mvert;
+ float scale = 0.0;
+ int res;
+
+ res = sds->maxres;
+
+ // get BB of domain
+ for (i = 0; i < me->totvert; i++) {
+ // min BB
+ min[0] = MIN2(min[0], verts[i].co[0]);
+ min[1] = MIN2(min[1], verts[i].co[1]);
+ min[2] = MIN2(min[2], verts[i].co[2]);
+
+ // max BB
+ max[0] = MAX2(max[0], verts[i].co[0]);
+ max[1] = MAX2(max[1], verts[i].co[1]);
+ max[2] = MAX2(max[2], verts[i].co[2]);
+ }
+
+ /* set domain bounds */
+ copy_v3_v3(sds->p0, min);
+ copy_v3_v3(sds->p1, max);
+ sds->dx = 1.0f / res;
+
+ /* calculate domain dimensions */
+ sub_v3_v3v3(size, max, min);
+ if (init_resolution) {
+ zero_v3_int(sds->base_res);
+ copy_v3_v3(sds->cell_size, size);
+ }
+ /* apply object scale */
+ for (i = 0; i < 3; i++) {
+ size[i] = fabsf(size[i] * ob->scale[i]);
+ }
+ copy_v3_v3(sds->global_size, size);
+ copy_v3_v3(sds->dp0, min);
+
+ invert_m4_m4(sds->imat, ob->obmat);
+
+ // prevent crash when initializing a plane as domain
+ if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) ||
+ (size[2] < FLT_EPSILON))
+ return;
+
+ /* define grid resolutions from longest domain side */
+ if (size[0] >= MAX2(size[1], size[2])) {
+ scale = res / size[0];
+ sds->scale = size[0] / fabsf(ob->scale[0]);
+ sds->base_res[0] = res;
+ sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
+ sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
+ }
+ else if (size[1] >= MAX2(size[0], size[2])) {
+ scale = res / size[1];
+ sds->scale = size[1] / fabsf(ob->scale[1]);
+ sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
+ sds->base_res[1] = res;
+ sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
+ }
+ else {
+ scale = res / size[2];
+ sds->scale = size[2] / fabsf(ob->scale[2]);
+ sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
+ sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
+ sds->base_res[2] = res;
+ }
+
+ /* set cell size */
+ sds->cell_size[0] /= (float)sds->base_res[0];
+ sds->cell_size[1] /= (float)sds->base_res[1];
+ sds->cell_size[2] /= (float)sds->base_res[2];
}
static int smokeModifier_init(SmokeModifierData *smd, Object *ob, int scene_framenr, Mesh *me)
{
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid)
- {
- SmokeDomainSettings *sds = smd->domain;
- int res[3];
- /* set domain dimensions from mesh */
- smoke_set_domain_from_mesh(sds, ob, me, true);
- /* reset domain values */
- zero_v3_int(sds->shift);
- zero_v3(sds->shift_f);
- add_v3_fl(sds->shift_f, 0.5f);
- zero_v3(sds->prev_loc);
- mul_m4_v3(ob->obmat, sds->prev_loc);
- copy_m4_m4(sds->obmat, ob->obmat);
-
- /* set resolutions */
- if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- res[0] = res[1] = res[2] = 1; /* use minimum res for adaptive init */
- }
- else {
- copy_v3_v3_int(res, sds->base_res);
- }
- copy_v3_v3_int(sds->res, res);
- sds->total_cells = sds->res[0] * sds->res[1] * sds->res[2];
- sds->res_min[0] = sds->res_min[1] = sds->res_min[2] = 0;
- copy_v3_v3_int(sds->res_max, res);
-
- /* allocate fluid */
- BKE_smoke_reallocate_fluid(sds, sds->dx, sds->res, 0);
-
- smd->time = scene_framenr;
-
- /* allocate highres fluid */
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- BKE_smoke_reallocate_highres_fluid(sds, sds->dx, sds->res, 0);
- }
- /* allocate shadow buffer */
- if (!sds->shadow)
- sds->shadow = MEM_callocN(sizeof(float) * sds->res[0] * sds->res[1] * sds->res[2], "SmokeDomainShadow");
-
- return 1;
- }
- else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow)
- {
- smd->time = scene_framenr;
-
- return 1;
- }
- else if ((smd->type & MOD_SMOKE_TYPE_COLL))
- {
- if (!smd->coll)
- {
- smokeModifier_createType(smd);
- }
-
- smd->time = scene_framenr;
-
- return 1;
- }
-
- return 2;
+ if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid) {
+ SmokeDomainSettings *sds = smd->domain;
+ int res[3];
+ /* set domain dimensions from mesh */
+ smoke_set_domain_from_mesh(sds, ob, me, true);
+ /* reset domain values */
+ zero_v3_int(sds->shift);
+ zero_v3(sds->shift_f);
+ add_v3_fl(sds->shift_f, 0.5f);
+ zero_v3(sds->prev_loc);
+ mul_m4_v3(ob->obmat, sds->prev_loc);
+ copy_m4_m4(sds->obmat, ob->obmat);
+
+ /* set resolutions */
+ if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ res[0] = res[1] = res[2] = 1; /* use minimum res for adaptive init */
+ }
+ else {
+ copy_v3_v3_int(res, sds->base_res);
+ }
+ copy_v3_v3_int(sds->res, res);
+ sds->total_cells = sds->res[0] * sds->res[1] * sds->res[2];
+ sds->res_min[0] = sds->res_min[1] = sds->res_min[2] = 0;
+ copy_v3_v3_int(sds->res_max, res);
+
+ /* allocate fluid */
+ BKE_smoke_reallocate_fluid(sds, sds->dx, sds->res, 0);
+
+ smd->time = scene_framenr;
+
+ /* allocate highres fluid */
+ if (sds->flags & MOD_SMOKE_HIGHRES) {
+ BKE_smoke_reallocate_highres_fluid(sds, sds->dx, sds->res, 0);
+ }
+ /* allocate shadow buffer */
+ if (!sds->shadow)
+ sds->shadow = MEM_callocN(sizeof(float) * sds->res[0] * sds->res[1] * sds->res[2],
+ "SmokeDomainShadow");
+
+ return 1;
+ }
+ else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) {
+ smd->time = scene_framenr;
+
+ return 1;
+ }
+ else if ((smd->type & MOD_SMOKE_TYPE_COLL)) {
+ if (!smd->coll) {
+ smokeModifier_createType(smd);
+ }
+
+ smd->time = scene_framenr;
+
+ return 1;
+ }
+
+ return 2;
}
#endif /* WITH_SMOKE */
static void smokeModifier_freeDomain(SmokeModifierData *smd)
{
- if (smd->domain)
- {
- if (smd->domain->shadow)
- MEM_freeN(smd->domain->shadow);
- smd->domain->shadow = NULL;
+ if (smd->domain) {
+ if (smd->domain->shadow)
+ MEM_freeN(smd->domain->shadow);
+ smd->domain->shadow = NULL;
- if (smd->domain->fluid)
- smoke_free(smd->domain->fluid);
+ if (smd->domain->fluid)
+ smoke_free(smd->domain->fluid);
- if (smd->domain->fluid_mutex)
- BLI_rw_mutex_free(smd->domain->fluid_mutex);
+ if (smd->domain->fluid_mutex)
+ BLI_rw_mutex_free(smd->domain->fluid_mutex);
- if (smd->domain->wt)
- smoke_turbulence_free(smd->domain->wt);
+ if (smd->domain->wt)
+ smoke_turbulence_free(smd->domain->wt);
- if (smd->domain->effector_weights)
- MEM_freeN(smd->domain->effector_weights);
- smd->domain->effector_weights = NULL;
+ if (smd->domain->effector_weights)
+ MEM_freeN(smd->domain->effector_weights);
+ smd->domain->effector_weights = NULL;
- if (!(smd->modifier.flag & eModifierFlag_SharedCaches)) {
- BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
- smd->domain->point_cache[0] = NULL;
- }
+ if (!(smd->modifier.flag & eModifierFlag_SharedCaches)) {
+ BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
+ smd->domain->point_cache[0] = NULL;
+ }
- if (smd->domain->coba) {
- MEM_freeN(smd->domain->coba);
- }
+ if (smd->domain->coba) {
+ MEM_freeN(smd->domain->coba);
+ }
- MEM_freeN(smd->domain);
- smd->domain = NULL;
- }
+ MEM_freeN(smd->domain);
+ smd->domain = NULL;
+ }
}
static void smokeModifier_freeFlow(SmokeModifierData *smd)
{
- if (smd->flow)
- {
- if (smd->flow->mesh) BKE_id_free(NULL, smd->flow->mesh);
- if (smd->flow->verts_old) MEM_freeN(smd->flow->verts_old);
- MEM_freeN(smd->flow);
- smd->flow = NULL;
- }
+ if (smd->flow) {
+ if (smd->flow->mesh)
+ BKE_id_free(NULL, smd->flow->mesh);
+ if (smd->flow->verts_old)
+ MEM_freeN(smd->flow->verts_old);
+ MEM_freeN(smd->flow);
+ smd->flow = NULL;
+ }
}
static void smokeModifier_freeCollision(SmokeModifierData *smd)
{
- if (smd->coll)
- {
- SmokeCollSettings *scs = smd->coll;
-
- if (scs->numverts)
- {
- if (scs->verts_old)
- {
- MEM_freeN(scs->verts_old);
- scs->verts_old = NULL;
- }
- }
-
- if (smd->coll->mesh)
- BKE_id_free(NULL, smd->coll->mesh);
- smd->coll->mesh = NULL;
-
- MEM_freeN(smd->coll);
- smd->coll = NULL;
- }
+ if (smd->coll) {
+ SmokeCollSettings *scs = smd->coll;
+
+ if (scs->numverts) {
+ if (scs->verts_old) {
+ MEM_freeN(scs->verts_old);
+ scs->verts_old = NULL;
+ }
+ }
+
+ if (smd->coll->mesh)
+ BKE_id_free(NULL, smd->coll->mesh);
+ smd->coll->mesh = NULL;
+
+ MEM_freeN(smd->coll);
+ smd->coll = NULL;
+ }
}
void smokeModifier_reset_turbulence(struct SmokeModifierData *smd)
{
- if (smd && smd->domain && smd->domain->wt)
- {
- smoke_turbulence_free(smd->domain->wt);
- smd->domain->wt = NULL;
- }
+ if (smd && smd->domain && smd->domain->wt) {
+ smoke_turbulence_free(smd->domain->wt);
+ smd->domain->wt = NULL;
+ }
}
static void smokeModifier_reset_ex(struct SmokeModifierData *smd, bool need_lock)
{
- if (smd)
- {
- if (smd->domain)
- {
- if (smd->domain->shadow)
- MEM_freeN(smd->domain->shadow);
- smd->domain->shadow = NULL;
-
- if (smd->domain->fluid)
- {
- if (need_lock)
- BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
-
- smoke_free(smd->domain->fluid);
- smd->domain->fluid = NULL;
-
- if (need_lock)
- BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
- }
-
- smokeModifier_reset_turbulence(smd);
-
- smd->time = -1;
- smd->domain->total_cells = 0;
- smd->domain->active_fields = 0;
- }
- else if (smd->flow)
- {
- if (smd->flow->verts_old) MEM_freeN(smd->flow->verts_old);
- smd->flow->verts_old = NULL;
- smd->flow->numverts = 0;
- }
- else if (smd->coll)
- {
- SmokeCollSettings *scs = smd->coll;
-
- if (scs->numverts && scs->verts_old)
- {
- MEM_freeN(scs->verts_old);
- scs->verts_old = NULL;
- }
- }
- }
+ if (smd) {
+ if (smd->domain) {
+ if (smd->domain->shadow)
+ MEM_freeN(smd->domain->shadow);
+ smd->domain->shadow = NULL;
+
+ if (smd->domain->fluid) {
+ if (need_lock)
+ BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
+
+ smoke_free(smd->domain->fluid);
+ smd->domain->fluid = NULL;
+
+ if (need_lock)
+ BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
+ }
+
+ smokeModifier_reset_turbulence(smd);
+
+ smd->time = -1;
+ smd->domain->total_cells = 0;
+ smd->domain->active_fields = 0;
+ }
+ else if (smd->flow) {
+ if (smd->flow->verts_old)
+ MEM_freeN(smd->flow->verts_old);
+ smd->flow->verts_old = NULL;
+ smd->flow->numverts = 0;
+ }
+ else if (smd->coll) {
+ SmokeCollSettings *scs = smd->coll;
+
+ if (scs->numverts && scs->verts_old) {
+ MEM_freeN(scs->verts_old);
+ scs->verts_old = NULL;
+ }
+ }
+ }
}
void smokeModifier_reset(struct SmokeModifierData *smd)
{
- smokeModifier_reset_ex(smd, true);
+ smokeModifier_reset_ex(smd, true);
}
void smokeModifier_free(SmokeModifierData *smd)
{
- if (smd)
- {
- smokeModifier_freeDomain(smd);
- smokeModifier_freeFlow(smd);
- smokeModifier_freeCollision(smd);
- }
+ if (smd) {
+ smokeModifier_freeDomain(smd);
+ smokeModifier_freeFlow(smd);
+ smokeModifier_freeCollision(smd);
+ }
}
void smokeModifier_createType(struct SmokeModifierData *smd)
{
- if (smd)
- {
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN)
- {
- if (smd->domain)
- smokeModifier_freeDomain(smd);
-
- smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain");
-
- smd->domain->smd = smd;
-
- smd->domain->point_cache[0] = BKE_ptcache_add(&(smd->domain->ptcaches[0]));
- smd->domain->point_cache[0]->flag |= PTCACHE_DISK_CACHE;
- smd->domain->point_cache[0]->step = 1;
-
- /* Deprecated */
- smd->domain->point_cache[1] = NULL;
- BLI_listbase_clear(&smd->domain->ptcaches[1]);
- /* set some standard values */
- smd->domain->fluid = NULL;
- smd->domain->fluid_mutex = BLI_rw_mutex_alloc();
- smd->domain->wt = NULL;
- smd->domain->eff_group = NULL;
- smd->domain->fluid_group = NULL;
- smd->domain->coll_group = NULL;
- smd->domain->maxres = 32;
- smd->domain->amplify = 1;
- smd->domain->alpha = -0.001;
- smd->domain->beta = 0.1;
- smd->domain->time_scale = 1.0;
- smd->domain->vorticity = 2.0;
- smd->domain->border_collisions = SM_BORDER_OPEN; // open domain
- smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG;
- smd->domain->highres_sampling = SM_HRES_FULLSAMPLE;
- smd->domain->strength = 2.0;
- smd->domain->noise = MOD_SMOKE_NOISEWAVE;
- smd->domain->diss_speed = 5;
- smd->domain->active_fields = 0;
-
- smd->domain->adapt_margin = 4;
- smd->domain->adapt_res = 0;
- smd->domain->adapt_threshold = 0.02f;
-
- smd->domain->burning_rate = 0.75f;
- smd->domain->flame_smoke = 1.0f;
- smd->domain->flame_vorticity = 0.5f;
- smd->domain->flame_ignition = 1.5f;
- smd->domain->flame_max_temp = 3.0f;
- /* color */
- smd->domain->flame_smoke_color[0] = 0.7f;
- smd->domain->flame_smoke_color[1] = 0.7f;
- smd->domain->flame_smoke_color[2] = 0.7f;
-
- smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOW_HIGHRES;
- smd->domain->effector_weights = BKE_effector_add_weights(NULL);
+ if (smd) {
+ if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
+ if (smd->domain)
+ smokeModifier_freeDomain(smd);
+
+ smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain");
+
+ smd->domain->smd = smd;
+
+ smd->domain->point_cache[0] = BKE_ptcache_add(&(smd->domain->ptcaches[0]));
+ smd->domain->point_cache[0]->flag |= PTCACHE_DISK_CACHE;
+ smd->domain->point_cache[0]->step = 1;
+
+ /* Deprecated */
+ smd->domain->point_cache[1] = NULL;
+ BLI_listbase_clear(&smd->domain->ptcaches[1]);
+ /* set some standard values */
+ smd->domain->fluid = NULL;
+ smd->domain->fluid_mutex = BLI_rw_mutex_alloc();
+ smd->domain->wt = NULL;
+ smd->domain->eff_group = NULL;
+ smd->domain->fluid_group = NULL;
+ smd->domain->coll_group = NULL;
+ smd->domain->maxres = 32;
+ smd->domain->amplify = 1;
+ smd->domain->alpha = -0.001;
+ smd->domain->beta = 0.1;
+ smd->domain->time_scale = 1.0;
+ smd->domain->vorticity = 2.0;
+ smd->domain->border_collisions = SM_BORDER_OPEN; // open domain
+ smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG;
+ smd->domain->highres_sampling = SM_HRES_FULLSAMPLE;
+ smd->domain->strength = 2.0;
+ smd->domain->noise = MOD_SMOKE_NOISEWAVE;
+ smd->domain->diss_speed = 5;
+ smd->domain->active_fields = 0;
+
+ smd->domain->adapt_margin = 4;
+ smd->domain->adapt_res = 0;
+ smd->domain->adapt_threshold = 0.02f;
+
+ smd->domain->burning_rate = 0.75f;
+ smd->domain->flame_smoke = 1.0f;
+ smd->domain->flame_vorticity = 0.5f;
+ smd->domain->flame_ignition = 1.5f;
+ smd->domain->flame_max_temp = 3.0f;
+ /* color */
+ smd->domain->flame_smoke_color[0] = 0.7f;
+ smd->domain->flame_smoke_color[1] = 0.7f;
+ smd->domain->flame_smoke_color[2] = 0.7f;
+
+ smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOW_HIGHRES;
+ smd->domain->effector_weights = BKE_effector_add_weights(NULL);
#ifdef WITH_OPENVDB_BLOSC
- smd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC;
+ smd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC;
#else
- smd->domain->openvdb_comp = VDB_COMPRESSION_ZIP;
+ smd->domain->openvdb_comp = VDB_COMPRESSION_ZIP;
#endif
- smd->domain->data_depth = 0;
- smd->domain->cache_file_format = PTCACHE_FILE_PTCACHE;
-
- smd->domain->display_thickness = 1.0f;
- smd->domain->slice_method = MOD_SMOKE_SLICE_VIEW_ALIGNED;
- smd->domain->axis_slice_method = AXIS_SLICE_FULL;
- smd->domain->slice_per_voxel = 5.0f;
- smd->domain->slice_depth = 0.5f;
- smd->domain->slice_axis = 0;
- smd->domain->vector_scale = 1.0f;
-
- smd->domain->coba = NULL;
- smd->domain->coba_field = FLUID_FIELD_DENSITY;
-
- smd->domain->clipping = 1e-3f;
- }
- else if (smd->type & MOD_SMOKE_TYPE_FLOW)
- {
- if (smd->flow)
- smokeModifier_freeFlow(smd);
-
- smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow");
-
- smd->flow->smd = smd;
-
- /* set some standard values */
- smd->flow->density = 1.0f;
- smd->flow->fuel_amount = 1.0f;
- smd->flow->temp = 1.0f;
- smd->flow->flags = MOD_SMOKE_FLOW_ABSOLUTE | MOD_SMOKE_FLOW_USE_PART_SIZE;
- smd->flow->vel_multi = 1.0f;
- smd->flow->volume_density = 0.0f;
- smd->flow->surface_distance = 1.5f;
- smd->flow->source = MOD_SMOKE_FLOW_SOURCE_MESH;
- smd->flow->texture_size = 1.0f;
- smd->flow->particle_size = 1.0f;
- smd->flow->subframes = 0;
-
- smd->flow->color[0] = 0.7f;
- smd->flow->color[1] = 0.7f;
- smd->flow->color[2] = 0.7f;
-
- smd->flow->mesh = NULL;
- smd->flow->psys = NULL;
-
- }
- else if (smd->type & MOD_SMOKE_TYPE_COLL)
- {
- if (smd->coll)
- smokeModifier_freeCollision(smd);
-
- smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl");
-
- smd->coll->smd = smd;
- smd->coll->verts_old = NULL;
- smd->coll->numverts = 0;
- smd->coll->type = 0; // static obstacle
- smd->coll->mesh = NULL;
- }
- }
+ smd->domain->data_depth = 0;
+ smd->domain->cache_file_format = PTCACHE_FILE_PTCACHE;
+
+ smd->domain->display_thickness = 1.0f;
+ smd->domain->slice_method = MOD_SMOKE_SLICE_VIEW_ALIGNED;
+ smd->domain->axis_slice_method = AXIS_SLICE_FULL;
+ smd->domain->slice_per_voxel = 5.0f;
+ smd->domain->slice_depth = 0.5f;
+ smd->domain->slice_axis = 0;
+ smd->domain->vector_scale = 1.0f;
+
+ smd->domain->coba = NULL;
+ smd->domain->coba_field = FLUID_FIELD_DENSITY;
+
+ smd->domain->clipping = 1e-3f;
+ }
+ else if (smd->type & MOD_SMOKE_TYPE_FLOW) {
+ if (smd->flow)
+ smokeModifier_freeFlow(smd);
+
+ smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow");
+
+ smd->flow->smd = smd;
+
+ /* set some standard values */
+ smd->flow->density = 1.0f;
+ smd->flow->fuel_amount = 1.0f;
+ smd->flow->temp = 1.0f;
+ smd->flow->flags = MOD_SMOKE_FLOW_ABSOLUTE | MOD_SMOKE_FLOW_USE_PART_SIZE;
+ smd->flow->vel_multi = 1.0f;
+ smd->flow->volume_density = 0.0f;
+ smd->flow->surface_distance = 1.5f;
+ smd->flow->source = MOD_SMOKE_FLOW_SOURCE_MESH;
+ smd->flow->texture_size = 1.0f;
+ smd->flow->particle_size = 1.0f;
+ smd->flow->subframes = 0;
+
+ smd->flow->color[0] = 0.7f;
+ smd->flow->color[1] = 0.7f;
+ smd->flow->color[2] = 0.7f;
+
+ smd->flow->mesh = NULL;
+ smd->flow->psys = NULL;
+ }
+ else if (smd->type & MOD_SMOKE_TYPE_COLL) {
+ if (smd->coll)
+ smokeModifier_freeCollision(smd);
+
+ smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl");
+
+ smd->coll->smd = smd;
+ smd->coll->verts_old = NULL;
+ smd->coll->numverts = 0;
+ smd->coll->type = 0; // static obstacle
+ smd->coll->mesh = NULL;
+ }
+ }
}
-void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifierData *tsmd, const int flag)
+void smokeModifier_copy(const struct SmokeModifierData *smd,
+ struct SmokeModifierData *tsmd,
+ const int flag)
{
- tsmd->type = smd->type;
- tsmd->time = smd->time;
-
- smokeModifier_createType(tsmd);
-
- if (tsmd->domain) {
- SmokeDomainSettings *tsds = tsmd->domain;
- SmokeDomainSettings *sds = smd->domain;
-
- BKE_ptcache_free_list(&(tsds->ptcaches[0]));
-
- if (flag & LIB_ID_CREATE_NO_MAIN) {
- /* Share the cache with the original object's modifier. */
- tsmd->modifier.flag |= eModifierFlag_SharedCaches;
- tsds->point_cache[0] = sds->point_cache[0];
- tsds->ptcaches[0] = sds->ptcaches[0];
- }
- else {
- tsds->point_cache[0] = BKE_ptcache_copy_list(&(tsds->ptcaches[0]), &(sds->ptcaches[0]), flag);
- }
-
- tsds->fluid_group = sds->fluid_group;
- tsds->coll_group = sds->coll_group;
-
- tsds->adapt_margin = sds->adapt_margin;
- tsds->adapt_res = sds->adapt_res;
- tsds->adapt_threshold = sds->adapt_threshold;
-
- tsds->alpha = sds->alpha;
- tsds->beta = sds->beta;
- tsds->amplify = sds->amplify;
- tsds->maxres = sds->maxres;
- tsds->flags = sds->flags;
- tsds->highres_sampling = sds->highres_sampling;
- tsds->viewsettings = sds->viewsettings;
- tsds->noise = sds->noise;
- tsds->diss_speed = sds->diss_speed;
- tsds->strength = sds->strength;
-
- tsds->border_collisions = sds->border_collisions;
- tsds->vorticity = sds->vorticity;
- tsds->time_scale = sds->time_scale;
-
- tsds->burning_rate = sds->burning_rate;
- tsds->flame_smoke = sds->flame_smoke;
- tsds->flame_vorticity = sds->flame_vorticity;
- tsds->flame_ignition = sds->flame_ignition;
- tsds->flame_max_temp = sds->flame_max_temp;
- copy_v3_v3(tsds->flame_smoke_color, sds->flame_smoke_color);
-
- MEM_freeN(tsds->effector_weights);
- tsds->effector_weights = MEM_dupallocN(sds->effector_weights);
- tsds->openvdb_comp = sds->openvdb_comp;
- tsds->data_depth = sds->data_depth;
- tsds->cache_file_format = sds->cache_file_format;
-
- tsds->display_thickness = sds->display_thickness;
- tsds->slice_method = sds->slice_method;
- tsds->axis_slice_method = sds->axis_slice_method;
- tsds->slice_per_voxel = sds->slice_per_voxel;
- tsds->slice_depth = sds->slice_depth;
- tsds->slice_axis = sds->slice_axis;
- tsds->interp_method = sds->interp_method;
- tsds->draw_velocity = sds->draw_velocity;
- tsds->vector_draw_type = sds->vector_draw_type;
- tsds->vector_scale = sds->vector_scale;
-
- tsds->use_coba = sds->use_coba;
- tsds->coba_field = sds->coba_field;
- if (sds->coba) {
- tsds->coba = MEM_dupallocN(sds->coba);
- }
-
- tsds->clipping = sds->clipping;
- }
- else if (tsmd->flow) {
- SmokeFlowSettings *tsfs = tsmd->flow;
- SmokeFlowSettings *sfs = smd->flow;
-
- tsfs->psys = sfs->psys;
- tsfs->noise_texture = sfs->noise_texture;
-
- tsfs->vel_multi = sfs->vel_multi;
- tsfs->vel_normal = sfs->vel_normal;
- tsfs->vel_random = sfs->vel_random;
-
- tsfs->density = sfs->density;
- copy_v3_v3(tsfs->color, sfs->color);
- tsfs->fuel_amount = sfs->fuel_amount;
- tsfs->temp = sfs->temp;
- tsfs->volume_density = sfs->volume_density;
- tsfs->surface_distance = sfs->surface_distance;
- tsfs->particle_size = sfs->particle_size;
- tsfs->subframes = sfs->subframes;
-
- tsfs->texture_size = sfs->texture_size;
- tsfs->texture_offset = sfs->texture_offset;
- BLI_strncpy(tsfs->uvlayer_name, sfs->uvlayer_name, sizeof(tsfs->uvlayer_name));
- tsfs->vgroup_density = sfs->vgroup_density;
-
- tsfs->type = sfs->type;
- tsfs->source = sfs->source;
- tsfs->texture_type = sfs->texture_type;
- tsfs->flags = sfs->flags;
- }
- else if (tsmd->coll) {
- /* leave it as initialized, collision settings is mostly caches */
- }
+ tsmd->type = smd->type;
+ tsmd->time = smd->time;
+
+ smokeModifier_createType(tsmd);
+
+ if (tsmd->domain) {
+ SmokeDomainSettings *tsds = tsmd->domain;
+ SmokeDomainSettings *sds = smd->domain;
+
+ BKE_ptcache_free_list(&(tsds->ptcaches[0]));
+
+ if (flag & LIB_ID_CREATE_NO_MAIN) {
+ /* Share the cache with the original object's modifier. */
+ tsmd->modifier.flag |= eModifierFlag_SharedCaches;
+ tsds->point_cache[0] = sds->point_cache[0];
+ tsds->ptcaches[0] = sds->ptcaches[0];
+ }
+ else {
+ tsds->point_cache[0] = BKE_ptcache_copy_list(
+ &(tsds->ptcaches[0]), &(sds->ptcaches[0]), flag);
+ }
+
+ tsds->fluid_group = sds->fluid_group;
+ tsds->coll_group = sds->coll_group;
+
+ tsds->adapt_margin = sds->adapt_margin;
+ tsds->adapt_res = sds->adapt_res;
+ tsds->adapt_threshold = sds->adapt_threshold;
+
+ tsds->alpha = sds->alpha;
+ tsds->beta = sds->beta;
+ tsds->amplify = sds->amplify;
+ tsds->maxres = sds->maxres;
+ tsds->flags = sds->flags;
+ tsds->highres_sampling = sds->highres_sampling;
+ tsds->viewsettings = sds->viewsettings;
+ tsds->noise = sds->noise;
+ tsds->diss_speed = sds->diss_speed;
+ tsds->strength = sds->strength;
+
+ tsds->border_collisions = sds->border_collisions;
+ tsds->vorticity = sds->vorticity;
+ tsds->time_scale = sds->time_scale;
+
+ tsds->burning_rate = sds->burning_rate;
+ tsds->flame_smoke = sds->flame_smoke;
+ tsds->flame_vorticity = sds->flame_vorticity;
+ tsds->flame_ignition = sds->flame_ignition;
+ tsds->flame_max_temp = sds->flame_max_temp;
+ copy_v3_v3(tsds->flame_smoke_color, sds->flame_smoke_color);
+
+ MEM_freeN(tsds->effector_weights);
+ tsds->effector_weights = MEM_dupallocN(sds->effector_weights);
+ tsds->openvdb_comp = sds->openvdb_comp;
+ tsds->data_depth = sds->data_depth;
+ tsds->cache_file_format = sds->cache_file_format;
+
+ tsds->display_thickness = sds->display_thickness;
+ tsds->slice_method = sds->slice_method;
+ tsds->axis_slice_method = sds->axis_slice_method;
+ tsds->slice_per_voxel = sds->slice_per_voxel;
+ tsds->slice_depth = sds->slice_depth;
+ tsds->slice_axis = sds->slice_axis;
+ tsds->interp_method = sds->interp_method;
+ tsds->draw_velocity = sds->draw_velocity;
+ tsds->vector_draw_type = sds->vector_draw_type;
+ tsds->vector_scale = sds->vector_scale;
+
+ tsds->use_coba = sds->use_coba;
+ tsds->coba_field = sds->coba_field;
+ if (sds->coba) {
+ tsds->coba = MEM_dupallocN(sds->coba);
+ }
+
+ tsds->clipping = sds->clipping;
+ }
+ else if (tsmd->flow) {
+ SmokeFlowSettings *tsfs = tsmd->flow;
+ SmokeFlowSettings *sfs = smd->flow;
+
+ tsfs->psys = sfs->psys;
+ tsfs->noise_texture = sfs->noise_texture;
+
+ tsfs->vel_multi = sfs->vel_multi;
+ tsfs->vel_normal = sfs->vel_normal;
+ tsfs->vel_random = sfs->vel_random;
+
+ tsfs->density = sfs->density;
+ copy_v3_v3(tsfs->color, sfs->color);
+ tsfs->fuel_amount = sfs->fuel_amount;
+ tsfs->temp = sfs->temp;
+ tsfs->volume_density = sfs->volume_density;
+ tsfs->surface_distance = sfs->surface_distance;
+ tsfs->particle_size = sfs->particle_size;
+ tsfs->subframes = sfs->subframes;
+
+ tsfs->texture_size = sfs->texture_size;
+ tsfs->texture_offset = sfs->texture_offset;
+ BLI_strncpy(tsfs->uvlayer_name, sfs->uvlayer_name, sizeof(tsfs->uvlayer_name));
+ tsfs->vgroup_density = sfs->vgroup_density;
+
+ tsfs->type = sfs->type;
+ tsfs->source = sfs->source;
+ tsfs->texture_type = sfs->texture_type;
+ tsfs->flags = sfs->flags;
+ }
+ else if (tsmd->coll) {
+ /* leave it as initialized, collision settings is mostly caches */
+ }
}
#ifdef WITH_SMOKE
// forward declaration
static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer);
-static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
+static float calc_voxel_transp(
+ float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
static int get_light(ViewLayer *view_layer, float *light)
{
- Base *base_tmp = NULL;
- int found_light = 0;
-
- // try to find a lamp, preferably local
- for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) {
- if (base_tmp->object->type == OB_LAMP) {
- Light *la = base_tmp->object->data;
-
- if (la->type == LA_LOCAL) {
- copy_v3_v3(light, base_tmp->object->obmat[3]);
- return 1;
- }
- else if (!found_light) {
- copy_v3_v3(light, base_tmp->object->obmat[3]);
- found_light = 1;
- }
- }
- }
-
- return found_light;
+ Base *base_tmp = NULL;
+ int found_light = 0;
+
+ // try to find a lamp, preferably local
+ for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) {
+ if (base_tmp->object->type == OB_LAMP) {
+ Light *la = base_tmp->object->data;
+
+ if (la->type == LA_LOCAL) {
+ copy_v3_v3(light, base_tmp->object->obmat[3]);
+ return 1;
+ }
+ else if (!found_light) {
+ copy_v3_v3(light, base_tmp->object->obmat[3]);
+ found_light = 1;
+ }
+ }
+ }
+
+ return found_light;
}
/**********************************************************
@@ -744,256 +786,277 @@ static int get_light(ViewLayer *view_layer, float *light)
**********************************************************/
typedef struct ObstaclesFromDMData {
- SmokeDomainSettings *sds;
- const MVert *mvert;
- const MLoop *mloop;
- const MLoopTri *looptri;
- BVHTreeFromMesh *tree;
- unsigned char *obstacle_map;
-
- bool has_velocity;
- float *vert_vel;
- float *velocityX, *velocityY, *velocityZ;
- int *num_obstacles;
+ SmokeDomainSettings *sds;
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MLoopTri *looptri;
+ BVHTreeFromMesh *tree;
+ unsigned char *obstacle_map;
+
+ bool has_velocity;
+ float *vert_vel;
+ float *velocityX, *velocityY, *velocityZ;
+ int *num_obstacles;
} ObstaclesFromDMData;
-static void obstacles_from_mesh_task_cb(
- void *__restrict userdata,
- const int z,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void obstacles_from_mesh_task_cb(void *__restrict userdata,
+ const int z,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- ObstaclesFromDMData *data = userdata;
- SmokeDomainSettings *sds = data->sds;
-
- /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */
- const float surface_distance = 0.867f;
-
- for (int x = sds->res_min[0]; x < sds->res_max[0]; x++) {
- for (int y = sds->res_min[1]; y < sds->res_max[1]; y++) {
- const int index = smoke_get_index(x - sds->res_min[0], sds->res[0], y - sds->res_min[1], sds->res[1], z - sds->res_min[2]);
-
- float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f};
- BVHTreeNearest nearest = {0};
- nearest.index = -1;
- nearest.dist_sq = surface_distance * surface_distance; /* find_nearest uses squared distance */
-
- /* find the nearest point on the mesh */
- if (BLI_bvhtree_find_nearest(data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) != -1) {
- const MLoopTri *lt = &data->looptri[nearest.index];
- float weights[3];
- int v1, v2, v3;
-
- /* calculate barycentric weights for nearest point */
- v1 = data->mloop[lt->tri[0]].v;
- v2 = data->mloop[lt->tri[1]].v;
- v3 = data->mloop[lt->tri[2]].v;
- interp_weights_tri_v3(weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co);
-
- // DG TODO
- if (data->has_velocity)
- {
- /* apply object velocity */
- {
- float hit_vel[3];
- interp_v3_v3v3v3(hit_vel, &data->vert_vel[v1 * 3], &data->vert_vel[v2 * 3], &data->vert_vel[v3 * 3], weights);
- data->velocityX[index] += hit_vel[0];
- data->velocityY[index] += hit_vel[1];
- data->velocityZ[index] += hit_vel[2];
- }
- }
-
- /* tag obstacle cells */
- data->obstacle_map[index] = 1;
-
- if (data->has_velocity) {
- data->obstacle_map[index] |= 8;
- data->num_obstacles[index]++;
- }
- }
- }
- }
+ ObstaclesFromDMData *data = userdata;
+ SmokeDomainSettings *sds = data->sds;
+
+ /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */
+ const float surface_distance = 0.867f;
+
+ for (int x = sds->res_min[0]; x < sds->res_max[0]; x++) {
+ for (int y = sds->res_min[1]; y < sds->res_max[1]; y++) {
+ const int index = smoke_get_index(
+ x - sds->res_min[0], sds->res[0], y - sds->res_min[1], sds->res[1], z - sds->res_min[2]);
+
+ float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f};
+ BVHTreeNearest nearest = {0};
+ nearest.index = -1;
+ nearest.dist_sq = surface_distance *
+ surface_distance; /* find_nearest uses squared distance */
+
+ /* find the nearest point on the mesh */
+ if (BLI_bvhtree_find_nearest(
+ data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) !=
+ -1) {
+ const MLoopTri *lt = &data->looptri[nearest.index];
+ float weights[3];
+ int v1, v2, v3;
+
+ /* calculate barycentric weights for nearest point */
+ v1 = data->mloop[lt->tri[0]].v;
+ v2 = data->mloop[lt->tri[1]].v;
+ v3 = data->mloop[lt->tri[2]].v;
+ interp_weights_tri_v3(
+ weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co);
+
+ // DG TODO
+ if (data->has_velocity) {
+ /* apply object velocity */
+ {
+ float hit_vel[3];
+ interp_v3_v3v3v3(hit_vel,
+ &data->vert_vel[v1 * 3],
+ &data->vert_vel[v2 * 3],
+ &data->vert_vel[v3 * 3],
+ weights);
+ data->velocityX[index] += hit_vel[0];
+ data->velocityY[index] += hit_vel[1];
+ data->velocityZ[index] += hit_vel[2];
+ }
+ }
+
+ /* tag obstacle cells */
+ data->obstacle_map[index] = 1;
+
+ if (data->has_velocity) {
+ data->obstacle_map[index] |= 8;
+ data->num_obstacles[index]++;
+ }
+ }
+ }
+ }
}
-static void obstacles_from_mesh(
- Object *coll_ob, SmokeDomainSettings *sds, SmokeCollSettings *scs,
- unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, int *num_obstacles, float dt)
+static void obstacles_from_mesh(Object *coll_ob,
+ SmokeDomainSettings *sds,
+ SmokeCollSettings *scs,
+ unsigned char *obstacle_map,
+ float *velocityX,
+ float *velocityY,
+ float *velocityZ,
+ int *num_obstacles,
+ float dt)
{
- if (!scs->mesh) return;
- {
- Mesh *me = NULL;
- MVert *mvert = NULL;
- const MLoopTri *looptri;
- const MLoop *mloop;
- BVHTreeFromMesh treeData = {NULL};
- int numverts, i;
-
- float *vert_vel = NULL;
- bool has_velocity = false;
-
- me = BKE_mesh_copy_for_eval(scs->mesh, true);
- BKE_mesh_ensure_normals(me);
- mvert = me->mvert;
- mloop = me->mloop;
- looptri = BKE_mesh_runtime_looptri_ensure(me);
- numverts = me->totvert;
-
- // DG TODO
- // if (scs->type > SM_COLL_STATIC)
- // if line above is used, the code is in trouble if the object moves but is declared as "does not move"
-
- {
- vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_velocity");
-
- if (scs->numverts != numverts || !scs->verts_old) {
- if (scs->verts_old) MEM_freeN(scs->verts_old);
-
- scs->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_verts_old");
- scs->numverts = numverts;
- }
- else {
- has_velocity = true;
- }
- }
-
- /* Transform collider vertices to
- * domain grid space for fast lookups */
- for (i = 0; i < numverts; i++) {
- float n[3];
- float co[3];
-
- /* vert pos */
- mul_m4_v3(coll_ob->obmat, mvert[i].co);
- smoke_pos_to_cell(sds, mvert[i].co);
-
- /* vert normal */
- normal_short_to_float_v3(n, mvert[i].no);
- mul_mat3_m4_v3(coll_ob->obmat, n);
- mul_mat3_m4_v3(sds->imat, n);
- normalize_v3(n);
- normal_float_to_short_v3(mvert[i].no, n);
-
- /* vert velocity */
- add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift);
- if (has_velocity)
- {
- sub_v3_v3v3(&vert_vel[i * 3], co, &scs->verts_old[i * 3]);
- mul_v3_fl(&vert_vel[i * 3], sds->dx / dt);
- }
- copy_v3_v3(&scs->verts_old[i * 3], co);
- }
-
- if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
- ObstaclesFromDMData data = {
- .sds = sds, .mvert = mvert, .mloop = mloop, .looptri = looptri,
- .tree = &treeData, .obstacle_map = obstacle_map,
- .has_velocity = has_velocity, .vert_vel = vert_vel,
- .velocityX = velocityX, .velocityY = velocityY, .velocityZ = velocityZ,
- .num_obstacles = num_obstacles,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(sds->res_min[2], sds->res_max[2],
- &data,
- obstacles_from_mesh_task_cb,
- &settings);
- }
- /* free bvh tree */
- free_bvhtree_from_mesh(&treeData);
- BKE_id_free(NULL, me);
-
- if (vert_vel) MEM_freeN(vert_vel);
- }
+ if (!scs->mesh)
+ return;
+ {
+ Mesh *me = NULL;
+ MVert *mvert = NULL;
+ const MLoopTri *looptri;
+ const MLoop *mloop;
+ BVHTreeFromMesh treeData = {NULL};
+ int numverts, i;
+
+ float *vert_vel = NULL;
+ bool has_velocity = false;
+
+ me = BKE_mesh_copy_for_eval(scs->mesh, true);
+ BKE_mesh_ensure_normals(me);
+ mvert = me->mvert;
+ mloop = me->mloop;
+ looptri = BKE_mesh_runtime_looptri_ensure(me);
+ numverts = me->totvert;
+
+ // DG TODO
+ // if (scs->type > SM_COLL_STATIC)
+ // if line above is used, the code is in trouble if the object moves but is declared as "does not move"
+
+ {
+ vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_velocity");
+
+ if (scs->numverts != numverts || !scs->verts_old) {
+ if (scs->verts_old)
+ MEM_freeN(scs->verts_old);
+
+ scs->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_verts_old");
+ scs->numverts = numverts;
+ }
+ else {
+ has_velocity = true;
+ }
+ }
+
+ /* Transform collider vertices to
+ * domain grid space for fast lookups */
+ for (i = 0; i < numverts; i++) {
+ float n[3];
+ float co[3];
+
+ /* vert pos */
+ mul_m4_v3(coll_ob->obmat, mvert[i].co);
+ smoke_pos_to_cell(sds, mvert[i].co);
+
+ /* vert normal */
+ normal_short_to_float_v3(n, mvert[i].no);
+ mul_mat3_m4_v3(coll_ob->obmat, n);
+ mul_mat3_m4_v3(sds->imat, n);
+ normalize_v3(n);
+ normal_float_to_short_v3(mvert[i].no, n);
+
+ /* vert velocity */
+ add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift);
+ if (has_velocity) {
+ sub_v3_v3v3(&vert_vel[i * 3], co, &scs->verts_old[i * 3]);
+ mul_v3_fl(&vert_vel[i * 3], sds->dx / dt);
+ }
+ copy_v3_v3(&scs->verts_old[i * 3], co);
+ }
+
+ if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
+ ObstaclesFromDMData data = {
+ .sds = sds,
+ .mvert = mvert,
+ .mloop = mloop,
+ .looptri = looptri,
+ .tree = &treeData,
+ .obstacle_map = obstacle_map,
+ .has_velocity = has_velocity,
+ .vert_vel = vert_vel,
+ .velocityX = velocityX,
+ .velocityY = velocityY,
+ .velocityZ = velocityZ,
+ .num_obstacles = num_obstacles,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(
+ sds->res_min[2], sds->res_max[2], &data, obstacles_from_mesh_task_cb, &settings);
+ }
+ /* free bvh tree */
+ free_bvhtree_from_mesh(&treeData);
+ BKE_id_free(NULL, me);
+
+ if (vert_vel)
+ MEM_freeN(vert_vel);
+ }
}
/* Animated obstacles: dx_step = ((x_new - x_old) / totalsteps) * substep */
-static void update_obstacles(Depsgraph *depsgraph, Object *ob, SmokeDomainSettings *sds, float dt,
- int UNUSED(substep), int UNUSED(totalsteps))
+static void update_obstacles(Depsgraph *depsgraph,
+ Object *ob,
+ SmokeDomainSettings *sds,
+ float dt,
+ int UNUSED(substep),
+ int UNUSED(totalsteps))
{
- Object **collobjs = NULL;
- unsigned int numcollobj = 0;
-
- unsigned int collIndex;
- unsigned char *obstacles = smoke_get_obstacle(sds->fluid);
- float *velx = NULL;
- float *vely = NULL;
- float *velz = NULL;
- float *velxOrig = smoke_get_velocity_x(sds->fluid);
- float *velyOrig = smoke_get_velocity_y(sds->fluid);
- float *velzOrig = smoke_get_velocity_z(sds->fluid);
- float *density = smoke_get_density(sds->fluid);
- float *fuel = smoke_get_fuel(sds->fluid);
- float *flame = smoke_get_flame(sds->fluid);
- float *r = smoke_get_color_r(sds->fluid);
- float *g = smoke_get_color_g(sds->fluid);
- float *b = smoke_get_color_b(sds->fluid);
- unsigned int z;
-
- int *num_obstacles = MEM_callocN(sizeof(int) * sds->res[0] * sds->res[1] * sds->res[2], "smoke_num_obstacles");
-
- smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz);
-
- // TODO: delete old obstacle flags
- for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++)
- {
- if (obstacles[z] & 8) // Do not delete static obstacles
- {
- obstacles[z] = 0;
- }
-
- velx[z] = 0;
- vely[z] = 0;
- velz[z] = 0;
- }
-
-
- collobjs = BKE_collision_objects_create(depsgraph, ob, sds->coll_group, &numcollobj, eModifierType_Smoke);
-
- // update obstacle tags in cells
- for (collIndex = 0; collIndex < numcollobj; collIndex++)
- {
- Object *collob = collobjs[collIndex];
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob, eModifierType_Smoke);
-
- // DG TODO: check if modifier is active?
-
- if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll)
- {
- SmokeCollSettings *scs = smd2->coll;
- obstacles_from_mesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt);
- }
- }
-
- BKE_collision_objects_free(collobjs);
-
- /* obstacle cells should not contain any velocity from the smoke simulation */
- for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++)
- {
- if (obstacles[z])
- {
- velxOrig[z] = 0;
- velyOrig[z] = 0;
- velzOrig[z] = 0;
- density[z] = 0;
- if (fuel) {
- fuel[z] = 0;
- flame[z] = 0;
- }
- if (r) {
- r[z] = 0;
- g[z] = 0;
- b[z] = 0;
- }
- }
- /* average velocities from multiple obstacles in one cell */
- if (num_obstacles[z]) {
- velx[z] /= num_obstacles[z];
- vely[z] /= num_obstacles[z];
- velz[z] /= num_obstacles[z];
- }
- }
-
- MEM_freeN(num_obstacles);
+ Object **collobjs = NULL;
+ unsigned int numcollobj = 0;
+
+ unsigned int collIndex;
+ unsigned char *obstacles = smoke_get_obstacle(sds->fluid);
+ float *velx = NULL;
+ float *vely = NULL;
+ float *velz = NULL;
+ float *velxOrig = smoke_get_velocity_x(sds->fluid);
+ float *velyOrig = smoke_get_velocity_y(sds->fluid);
+ float *velzOrig = smoke_get_velocity_z(sds->fluid);
+ float *density = smoke_get_density(sds->fluid);
+ float *fuel = smoke_get_fuel(sds->fluid);
+ float *flame = smoke_get_flame(sds->fluid);
+ float *r = smoke_get_color_r(sds->fluid);
+ float *g = smoke_get_color_g(sds->fluid);
+ float *b = smoke_get_color_b(sds->fluid);
+ unsigned int z;
+
+ int *num_obstacles = MEM_callocN(sizeof(int) * sds->res[0] * sds->res[1] * sds->res[2],
+ "smoke_num_obstacles");
+
+ smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz);
+
+ // TODO: delete old obstacle flags
+ for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++) {
+ if (obstacles[z] & 8) // Do not delete static obstacles
+ {
+ obstacles[z] = 0;
+ }
+
+ velx[z] = 0;
+ vely[z] = 0;
+ velz[z] = 0;
+ }
+
+ collobjs = BKE_collision_objects_create(
+ depsgraph, ob, sds->coll_group, &numcollobj, eModifierType_Smoke);
+
+ // update obstacle tags in cells
+ for (collIndex = 0; collIndex < numcollobj; collIndex++) {
+ Object *collob = collobjs[collIndex];
+ SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob,
+ eModifierType_Smoke);
+
+ // DG TODO: check if modifier is active?
+
+ if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) {
+ SmokeCollSettings *scs = smd2->coll;
+ obstacles_from_mesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt);
+ }
+ }
+
+ BKE_collision_objects_free(collobjs);
+
+ /* obstacle cells should not contain any velocity from the smoke simulation */
+ for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++) {
+ if (obstacles[z]) {
+ velxOrig[z] = 0;
+ velyOrig[z] = 0;
+ velzOrig[z] = 0;
+ density[z] = 0;
+ if (fuel) {
+ fuel[z] = 0;
+ flame[z] = 0;
+ }
+ if (r) {
+ r[z] = 0;
+ g[z] = 0;
+ b[z] = 0;
+ }
+ }
+ /* average velocities from multiple obstacles in one cell */
+ if (num_obstacles[z]) {
+ velx[z] /= num_obstacles[z];
+ vely[z] /= num_obstacles[z];
+ velz[z] /= num_obstacles[z];
+ }
+ }
+
+ MEM_freeN(num_obstacles);
}
/**********************************************************
@@ -1001,2162 +1064,2484 @@ static void update_obstacles(Depsgraph *depsgraph, Object *ob, SmokeDomainSettin
**********************************************************/
typedef struct EmissionMap {
- float *influence;
- float *influence_high;
- float *velocity;
- int min[3], max[3], res[3];
- int hmin[3], hmax[3], hres[3];
- int total_cells, valid;
+ float *influence;
+ float *influence_high;
+ float *velocity;
+ int min[3], max[3], res[3];
+ int hmin[3], hmax[3], hres[3];
+ int total_cells, valid;
} EmissionMap;
static void em_boundInsert(EmissionMap *em, float point[3])
{
- int i = 0;
- if (!em->valid) {
- for (; i < 3; i++) {
- em->min[i] = (int)floor(point[i]);
- em->max[i] = (int)ceil(point[i]);
- }
- em->valid = 1;
- }
- else {
- for (; i < 3; i++) {
- if (point[i] < em->min[i]) em->min[i] = (int)floor(point[i]);
- if (point[i] > em->max[i]) em->max[i] = (int)ceil(point[i]);
- }
- }
+ int i = 0;
+ if (!em->valid) {
+ for (; i < 3; i++) {
+ em->min[i] = (int)floor(point[i]);
+ em->max[i] = (int)ceil(point[i]);
+ }
+ em->valid = 1;
+ }
+ else {
+ for (; i < 3; i++) {
+ if (point[i] < em->min[i])
+ em->min[i] = (int)floor(point[i]);
+ if (point[i] > em->max[i])
+ em->max[i] = (int)ceil(point[i]);
+ }
+ }
}
-static void clampBoundsInDomain(SmokeDomainSettings *sds, int min[3], int max[3], float *min_vel, float *max_vel, int margin, float dt)
+static void clampBoundsInDomain(SmokeDomainSettings *sds,
+ int min[3],
+ int max[3],
+ float *min_vel,
+ float *max_vel,
+ int margin,
+ float dt)
{
- int i;
- for (i = 0; i < 3; i++) {
- int adapt = (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) ? sds->adapt_res : 0;
- /* add margin */
- min[i] -= margin;
- max[i] += margin;
-
- /* adapt to velocity */
- if (min_vel && min_vel[i] < 0.0f) {
- min[i] += (int)floor(min_vel[i] * dt);
- }
- if (max_vel && max_vel[i] > 0.0f) {
- max[i] += (int)ceil(max_vel[i] * dt);
- }
-
- /* clamp within domain max size */
- CLAMP(min[i], -adapt, sds->base_res[i] + adapt);
- CLAMP(max[i], -adapt, sds->base_res[i] + adapt);
- }
+ int i;
+ for (i = 0; i < 3; i++) {
+ int adapt = (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) ? sds->adapt_res : 0;
+ /* add margin */
+ min[i] -= margin;
+ max[i] += margin;
+
+ /* adapt to velocity */
+ if (min_vel && min_vel[i] < 0.0f) {
+ min[i] += (int)floor(min_vel[i] * dt);
+ }
+ if (max_vel && max_vel[i] > 0.0f) {
+ max[i] += (int)ceil(max_vel[i] * dt);
+ }
+
+ /* clamp within domain max size */
+ CLAMP(min[i], -adapt, sds->base_res[i] + adapt);
+ CLAMP(max[i], -adapt, sds->base_res[i] + adapt);
+ }
}
static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul)
{
- int i, res[3];
-
- for (i = 0; i < 3; i++) {
- res[i] = em->max[i] - em->min[i];
- if (res[i] <= 0)
- return;
- }
- em->total_cells = res[0] * res[1] * res[2];
- copy_v3_v3_int(em->res, res);
-
-
- em->influence = MEM_callocN(sizeof(float) * em->total_cells, "smoke_flow_influence");
- if (use_velocity)
- em->velocity = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_velocity");
-
- /* allocate high resolution map if required */
- if (hires_mul > 1) {
- int total_cells_high = em->total_cells * (hires_mul * hires_mul * hires_mul);
-
- for (i = 0; i < 3; i++) {
- em->hmin[i] = em->min[i] * hires_mul;
- em->hmax[i] = em->max[i] * hires_mul;
- em->hres[i] = em->res[i] * hires_mul;
- }
-
- em->influence_high = MEM_callocN(sizeof(float) * total_cells_high, "smoke_flow_influence_high");
- }
- em->valid = 1;
+ int i, res[3];
+
+ for (i = 0; i < 3; i++) {
+ res[i] = em->max[i] - em->min[i];
+ if (res[i] <= 0)
+ return;
+ }
+ em->total_cells = res[0] * res[1] * res[2];
+ copy_v3_v3_int(em->res, res);
+
+ em->influence = MEM_callocN(sizeof(float) * em->total_cells, "smoke_flow_influence");
+ if (use_velocity)
+ em->velocity = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_velocity");
+
+ /* allocate high resolution map if required */
+ if (hires_mul > 1) {
+ int total_cells_high = em->total_cells * (hires_mul * hires_mul * hires_mul);
+
+ for (i = 0; i < 3; i++) {
+ em->hmin[i] = em->min[i] * hires_mul;
+ em->hmax[i] = em->max[i] * hires_mul;
+ em->hres[i] = em->res[i] * hires_mul;
+ }
+
+ em->influence_high = MEM_callocN(sizeof(float) * total_cells_high,
+ "smoke_flow_influence_high");
+ }
+ em->valid = 1;
}
static void em_freeData(EmissionMap *em)
{
- if (em->influence)
- MEM_freeN(em->influence);
- if (em->influence_high)
- MEM_freeN(em->influence_high);
- if (em->velocity)
- MEM_freeN(em->velocity);
+ if (em->influence)
+ MEM_freeN(em->influence);
+ if (em->influence_high)
+ MEM_freeN(em->influence_high);
+ if (em->velocity)
+ MEM_freeN(em->velocity);
}
-static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size)
+static void em_combineMaps(
+ EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size)
{
- int i, x, y, z;
-
- /* copyfill input 1 struct and clear output for new allocation */
- EmissionMap em1;
- memcpy(&em1, output, sizeof(EmissionMap));
- memset(output, 0, sizeof(EmissionMap));
-
- for (i = 0; i < 3; i++) {
- if (em1.valid) {
- output->min[i] = MIN2(em1.min[i], em2->min[i]);
- output->max[i] = MAX2(em1.max[i], em2->max[i]);
- }
- else {
- output->min[i] = em2->min[i];
- output->max[i] = em2->max[i];
- }
- }
- /* allocate output map */
- em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier);
-
- /* base resolution inputs */
- for (x = output->min[0]; x < output->max[0]; x++)
- for (y = output->min[1]; y < output->max[1]; y++)
- for (z = output->min[2]; z < output->max[2]; z++) {
- int index_out = smoke_get_index(x - output->min[0], output->res[0], y - output->min[1], output->res[1], z - output->min[2]);
-
- /* initialize with first input if in range */
- if (x >= em1.min[0] && x < em1.max[0] &&
- y >= em1.min[1] && y < em1.max[1] &&
- z >= em1.min[2] && z < em1.max[2])
- {
- int index_in = smoke_get_index(x - em1.min[0], em1.res[0], y - em1.min[1], em1.res[1], z - em1.min[2]);
-
- /* values */
- output->influence[index_out] = em1.influence[index_in];
- if (output->velocity && em1.velocity) {
- copy_v3_v3(&output->velocity[index_out * 3], &em1.velocity[index_in * 3]);
- }
- }
-
- /* apply second input if in range */
- if (x >= em2->min[0] && x < em2->max[0] &&
- y >= em2->min[1] && y < em2->max[1] &&
- z >= em2->min[2] && z < em2->max[2])
- {
- int index_in = smoke_get_index(x - em2->min[0], em2->res[0], y - em2->min[1], em2->res[1], z - em2->min[2]);
-
- /* values */
- if (additive) {
- output->influence[index_out] += em2->influence[index_in] * sample_size;
- }
- else {
- output->influence[index_out] = MAX2(em2->influence[index_in], output->influence[index_out]);
- }
- if (output->velocity && em2->velocity) {
- /* last sample replaces the velocity */
- output->velocity[index_out * 3] = ADD_IF_LOWER(output->velocity[index_out * 3], em2->velocity[index_in * 3]);
- output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1], em2->velocity[index_in * 3 + 1]);
- output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2], em2->velocity[index_in * 3 + 2]);
- }
- }
- } // low res loop
-
-
-
- /* initialize high resolution input if available */
- if (output->influence_high) {
- for (x = output->hmin[0]; x < output->hmax[0]; x++)
- for (y = output->hmin[1]; y < output->hmax[1]; y++)
- for (z = output->hmin[2]; z < output->hmax[2]; z++) {
- int index_out = smoke_get_index(x - output->hmin[0], output->hres[0], y - output->hmin[1], output->hres[1], z - output->hmin[2]);
-
- /* initialize with first input if in range */
- if (x >= em1.hmin[0] && x < em1.hmax[0] &&
- y >= em1.hmin[1] && y < em1.hmax[1] &&
- z >= em1.hmin[2] && z < em1.hmax[2])
- {
- int index_in = smoke_get_index(x - em1.hmin[0], em1.hres[0], y - em1.hmin[1], em1.hres[1], z - em1.hmin[2]);
- /* values */
- output->influence_high[index_out] = em1.influence_high[index_in];
- }
-
- /* apply second input if in range */
- if (x >= em2->hmin[0] && x < em2->hmax[0] &&
- y >= em2->hmin[1] && y < em2->hmax[1] &&
- z >= em2->hmin[2] && z < em2->hmax[2])
- {
- int index_in = smoke_get_index(x - em2->hmin[0], em2->hres[0], y - em2->hmin[1], em2->hres[1], z - em2->hmin[2]);
-
- /* values */
- if (additive) {
- output->influence_high[index_out] += em2->influence_high[index_in] * sample_size;
- }
- else {
- output->influence_high[index_out] = MAX2(em2->influence_high[index_in], output->influence_high[index_out]);
- }
- }
- } // high res loop
- }
-
- /* free original data */
- em_freeData(&em1);
+ int i, x, y, z;
+
+ /* copyfill input 1 struct and clear output for new allocation */
+ EmissionMap em1;
+ memcpy(&em1, output, sizeof(EmissionMap));
+ memset(output, 0, sizeof(EmissionMap));
+
+ for (i = 0; i < 3; i++) {
+ if (em1.valid) {
+ output->min[i] = MIN2(em1.min[i], em2->min[i]);
+ output->max[i] = MAX2(em1.max[i], em2->max[i]);
+ }
+ else {
+ output->min[i] = em2->min[i];
+ output->max[i] = em2->max[i];
+ }
+ }
+ /* allocate output map */
+ em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier);
+
+ /* base resolution inputs */
+ for (x = output->min[0]; x < output->max[0]; x++)
+ for (y = output->min[1]; y < output->max[1]; y++)
+ for (z = output->min[2]; z < output->max[2]; z++) {
+ int index_out = smoke_get_index(x - output->min[0],
+ output->res[0],
+ y - output->min[1],
+ output->res[1],
+ z - output->min[2]);
+
+ /* initialize with first input if in range */
+ if (x >= em1.min[0] && x < em1.max[0] && y >= em1.min[1] && y < em1.max[1] &&
+ z >= em1.min[2] && z < em1.max[2]) {
+ int index_in = smoke_get_index(
+ x - em1.min[0], em1.res[0], y - em1.min[1], em1.res[1], z - em1.min[2]);
+
+ /* values */
+ output->influence[index_out] = em1.influence[index_in];
+ if (output->velocity && em1.velocity) {
+ copy_v3_v3(&output->velocity[index_out * 3], &em1.velocity[index_in * 3]);
+ }
+ }
+
+ /* apply second input if in range */
+ if (x >= em2->min[0] && x < em2->max[0] && y >= em2->min[1] && y < em2->max[1] &&
+ z >= em2->min[2] && z < em2->max[2]) {
+ int index_in = smoke_get_index(
+ x - em2->min[0], em2->res[0], y - em2->min[1], em2->res[1], z - em2->min[2]);
+
+ /* values */
+ if (additive) {
+ output->influence[index_out] += em2->influence[index_in] * sample_size;
+ }
+ else {
+ output->influence[index_out] = MAX2(em2->influence[index_in],
+ output->influence[index_out]);
+ }
+ if (output->velocity && em2->velocity) {
+ /* last sample replaces the velocity */
+ output->velocity[index_out * 3] = ADD_IF_LOWER(output->velocity[index_out * 3],
+ em2->velocity[index_in * 3]);
+ output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1],
+ em2->velocity[index_in * 3 + 1]);
+ output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2],
+ em2->velocity[index_in * 3 + 2]);
+ }
+ }
+ } // low res loop
+
+ /* initialize high resolution input if available */
+ if (output->influence_high) {
+ for (x = output->hmin[0]; x < output->hmax[0]; x++)
+ for (y = output->hmin[1]; y < output->hmax[1]; y++)
+ for (z = output->hmin[2]; z < output->hmax[2]; z++) {
+ int index_out = smoke_get_index(x - output->hmin[0],
+ output->hres[0],
+ y - output->hmin[1],
+ output->hres[1],
+ z - output->hmin[2]);
+
+ /* initialize with first input if in range */
+ if (x >= em1.hmin[0] && x < em1.hmax[0] && y >= em1.hmin[1] && y < em1.hmax[1] &&
+ z >= em1.hmin[2] && z < em1.hmax[2]) {
+ int index_in = smoke_get_index(
+ x - em1.hmin[0], em1.hres[0], y - em1.hmin[1], em1.hres[1], z - em1.hmin[2]);
+ /* values */
+ output->influence_high[index_out] = em1.influence_high[index_in];
+ }
+
+ /* apply second input if in range */
+ if (x >= em2->hmin[0] && x < em2->hmax[0] && y >= em2->hmin[1] && y < em2->hmax[1] &&
+ z >= em2->hmin[2] && z < em2->hmax[2]) {
+ int index_in = smoke_get_index(
+ x - em2->hmin[0], em2->hres[0], y - em2->hmin[1], em2->hres[1], z - em2->hmin[2]);
+
+ /* values */
+ if (additive) {
+ output->influence_high[index_out] += em2->influence_high[index_in] * sample_size;
+ }
+ else {
+ output->influence_high[index_out] = MAX2(em2->influence_high[index_in],
+ output->influence_high[index_out]);
+ }
+ }
+ } // high res loop
+ }
+
+ /* free original data */
+ em_freeData(&em1);
}
typedef struct EmitFromParticlesData {
- SmokeFlowSettings *sfs;
- KDTree_3d *tree;
- int hires_multiplier;
+ SmokeFlowSettings *sfs;
+ KDTree_3d *tree;
+ int hires_multiplier;
- EmissionMap *em;
- float *particle_vel;
- float hr;
+ EmissionMap *em;
+ float *particle_vel;
+ float hr;
- int *min, *max, *res;
+ int *min, *max, *res;
- float solid;
- float smooth;
- float hr_smooth;
+ float solid;
+ float smooth;
+ float hr_smooth;
} EmitFromParticlesData;
-static void emit_from_particles_task_cb(
- void *__restrict userdata,
- const int z,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void emit_from_particles_task_cb(void *__restrict userdata,
+ const int z,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- EmitFromParticlesData *data = userdata;
- SmokeFlowSettings *sfs = data->sfs;
- EmissionMap *em = data->em;
- const int hires_multiplier = data->hires_multiplier;
-
- for (int x = data->min[0]; x < data->max[0]; x++) {
- for (int y = data->min[1]; y < data->max[1]; y++) {
- /* take low res samples where possible */
- if (hires_multiplier <= 1 || !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
- /* get low res space coordinates */
- const int lx = x / hires_multiplier;
- const int ly = y / hires_multiplier;
- const int lz = z / hires_multiplier;
-
- const int index = smoke_get_index(lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
- const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
-
- /* find particle distance from the kdtree */
- KDTreeNearest_3d nearest;
- const float range = data->solid + data->smooth;
- BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
-
- if (nearest.dist < range) {
- em->influence[index] = (nearest.dist < data->solid) ?
- 1.0f : (1.0f - (nearest.dist - data->solid) / data->smooth);
- /* Uses particle velocity as initial velocity for smoke */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (sfs->psys->part->phystype != PART_PHYS_NO)) {
- madd_v3_v3fl(&em->velocity[index * 3], &data->particle_vel[nearest.index * 3], sfs->vel_multi);
- }
- }
- }
-
- /* take high res samples if required */
- if (hires_multiplier > 1) {
- /* get low res space coordinates */
- const float lx = ((float)x) * data->hr;
- const float ly = ((float)y) * data->hr;
- const float lz = ((float)z) * data->hr;
-
- const int index = smoke_get_index(
- x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
- const float ray_start[3] = {lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
-
- /* find particle distance from the kdtree */
- KDTreeNearest_3d nearest;
- const float range = data->solid + data->hr_smooth;
- BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
-
- if (nearest.dist < range) {
- em->influence_high[index] = (nearest.dist < data->solid) ?
- 1.0f : (1.0f - (nearest.dist - data->solid) / data->smooth);
- }
- }
-
- }
- }
+ EmitFromParticlesData *data = userdata;
+ SmokeFlowSettings *sfs = data->sfs;
+ EmissionMap *em = data->em;
+ const int hires_multiplier = data->hires_multiplier;
+
+ for (int x = data->min[0]; x < data->max[0]; x++) {
+ for (int y = data->min[1]; y < data->max[1]; y++) {
+ /* take low res samples where possible */
+ if (hires_multiplier <= 1 ||
+ !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
+ /* get low res space coordinates */
+ const int lx = x / hires_multiplier;
+ const int ly = y / hires_multiplier;
+ const int lz = z / hires_multiplier;
+
+ const int index = smoke_get_index(
+ lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
+ const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
+
+ /* find particle distance from the kdtree */
+ KDTreeNearest_3d nearest;
+ const float range = data->solid + data->smooth;
+ BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
+
+ if (nearest.dist < range) {
+ em->influence[index] = (nearest.dist < data->solid) ?
+ 1.0f :
+ (1.0f - (nearest.dist - data->solid) / data->smooth);
+ /* Uses particle velocity as initial velocity for smoke */
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY &&
+ (sfs->psys->part->phystype != PART_PHYS_NO)) {
+ madd_v3_v3fl(
+ &em->velocity[index * 3], &data->particle_vel[nearest.index * 3], sfs->vel_multi);
+ }
+ }
+ }
+
+ /* take high res samples if required */
+ if (hires_multiplier > 1) {
+ /* get low res space coordinates */
+ const float lx = ((float)x) * data->hr;
+ const float ly = ((float)y) * data->hr;
+ const float lz = ((float)z) * data->hr;
+
+ const int index = smoke_get_index(
+ x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
+ const float ray_start[3] = {
+ lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
+
+ /* find particle distance from the kdtree */
+ KDTreeNearest_3d nearest;
+ const float range = data->solid + data->hr_smooth;
+ BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
+
+ if (nearest.dist < range) {
+ em->influence_high[index] = (nearest.dist < data->solid) ?
+ 1.0f :
+ (1.0f - (nearest.dist - data->solid) / data->smooth);
+ }
+ }
+ }
+ }
}
-static void emit_from_particles(
- Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, Depsgraph *depsgraph, Scene *scene, float dt)
+static void emit_from_particles(Object *flow_ob,
+ SmokeDomainSettings *sds,
+ SmokeFlowSettings *sfs,
+ EmissionMap *em,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ float dt)
{
- if (sfs && sfs->psys && sfs->psys->part && ELEM(sfs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected
- {
- ParticleSimulationData sim;
- ParticleSystem *psys = sfs->psys;
- float *particle_pos;
- float *particle_vel;
- int totpart = psys->totpart, totchild;
- int p = 0;
- int valid_particles = 0;
- int bounds_margin = 1;
-
- /* radius based flow */
- const float solid = sfs->particle_size * 0.5f;
- const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */
- int hires_multiplier = 1;
- KDTree_3d *tree = NULL;
-
- sim.depsgraph = depsgraph;
- sim.scene = scene;
- sim.ob = flow_ob;
- sim.psys = psys;
- sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
-
- /* prepare curvemapping tables */
- if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve)
- curvemapping_changed_all(psys->part->clumpcurve);
- if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve)
- curvemapping_changed_all(psys->part->roughcurve);
- if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve)
- curvemapping_changed_all(psys->part->twistcurve);
-
- /* initialize particle cache */
- if (psys->part->type == PART_HAIR) {
- // TODO: PART_HAIR not supported whatsoever
- totchild = 0;
- }
- else {
- totchild = psys->totchild * psys->part->disp / 100;
- }
-
- particle_pos = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles");
- particle_vel = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles");
-
- /* setup particle radius emission if enabled */
- if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
- tree = BLI_kdtree_3d_new(psys->totpart + psys->totchild);
-
- /* check need for high resolution map */
- if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
- hires_multiplier = sds->amplify + 1;
- }
-
- bounds_margin = (int)ceil(solid + smooth);
- }
-
- /* calculate local position for each particle */
- for (p = 0; p < totpart + totchild; p++)
- {
- ParticleKey state;
- float *pos;
- if (p < totpart) {
- if (psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST))
- continue;
- }
- else {
- /* handle child particle */
- ChildParticle *cpa = &psys->child[p - totpart];
- if (psys->particles[cpa->parent].flag & (PARS_NO_DISP | PARS_UNEXIST))
- continue;
- }
-
- state.time = DEG_get_ctime(depsgraph); /* use depsgraph time */
- if (psys_get_particle_state(&sim, p, &state, 0) == 0)
- continue;
-
- /* location */
- pos = &particle_pos[valid_particles * 3];
- copy_v3_v3(pos, state.co);
- smoke_pos_to_cell(sds, pos);
-
- /* velocity */
- copy_v3_v3(&particle_vel[valid_particles * 3], state.vel);
- mul_mat3_m4_v3(sds->imat, &particle_vel[valid_particles * 3]);
-
- if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
- BLI_kdtree_3d_insert(tree, valid_particles, pos);
- }
-
- /* calculate emission map bounds */
- em_boundInsert(em, pos);
- valid_particles++;
- }
-
- /* set emission map */
- clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, bounds_margin, dt);
- em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier);
-
- if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
- for (p = 0; p < valid_particles; p++)
- {
- int cell[3];
- size_t i = 0;
- size_t index = 0;
- int badcell = 0;
-
- /* 1. get corresponding cell */
- cell[0] = floor(particle_pos[p * 3]) - em->min[0];
- cell[1] = floor(particle_pos[p * 3 + 1]) - em->min[1];
- cell[2] = floor(particle_pos[p * 3 + 2]) - em->min[2];
- /* check if cell is valid (in the domain boundary) */
- for (i = 0; i < 3; i++) {
- if ((cell[i] > em->res[i] - 1) || (cell[i] < 0)) {
- badcell = 1;
- break;
- }
- }
- if (badcell)
- continue;
- /* get cell index */
- index = smoke_get_index(cell[0], em->res[0], cell[1], em->res[1], cell[2]);
- /* Add influence to emission map */
- em->influence[index] = 1.0f;
- /* Uses particle velocity as initial velocity for smoke */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO))
- {
- madd_v3_v3fl(&em->velocity[index * 3], &particle_vel[p * 3], sfs->vel_multi);
- }
- } // particles loop
- }
- else if (valid_particles > 0) { // MOD_SMOKE_FLOW_USE_PART_SIZE
- int min[3], max[3], res[3];
- const float hr = 1.0f / ((float)hires_multiplier);
- /* slightly adjust high res antialias smoothness based on number of divisions
- * to allow smaller details but yet not differing too much from the low res size */
- const float hr_smooth = smooth * powf(hr, 1.0f / 3.0f);
-
- /* setup loop bounds */
- for (int i = 0; i < 3; i++) {
- min[i] = em->min[i] * hires_multiplier;
- max[i] = em->max[i] * hires_multiplier;
- res[i] = em->res[i] * hires_multiplier;
- }
-
- BLI_kdtree_3d_balance(tree);
-
- EmitFromParticlesData data = {
- .sfs = sfs, .tree = tree, .hires_multiplier = hires_multiplier, .hr = hr,
- .em = em, .particle_vel = particle_vel, .min = min, .max = max, .res = res,
- .solid = solid, .smooth = smooth, .hr_smooth = hr_smooth,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(min[2], max[2],
- &data,
- emit_from_particles_task_cb,
- &settings);
- }
-
- if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
- BLI_kdtree_3d_free(tree);
- }
-
- /* free data */
- if (particle_pos)
- MEM_freeN(particle_pos);
- if (particle_vel)
- MEM_freeN(particle_vel);
- }
+ if (sfs && sfs->psys && sfs->psys->part &&
+ ELEM(sfs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected
+ {
+ ParticleSimulationData sim;
+ ParticleSystem *psys = sfs->psys;
+ float *particle_pos;
+ float *particle_vel;
+ int totpart = psys->totpart, totchild;
+ int p = 0;
+ int valid_particles = 0;
+ int bounds_margin = 1;
+
+ /* radius based flow */
+ const float solid = sfs->particle_size * 0.5f;
+ const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */
+ int hires_multiplier = 1;
+ KDTree_3d *tree = NULL;
+
+ sim.depsgraph = depsgraph;
+ sim.scene = scene;
+ sim.ob = flow_ob;
+ sim.psys = psys;
+ sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+
+ /* prepare curvemapping tables */
+ if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve)
+ curvemapping_changed_all(psys->part->clumpcurve);
+ if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve)
+ curvemapping_changed_all(psys->part->roughcurve);
+ if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve)
+ curvemapping_changed_all(psys->part->twistcurve);
+
+ /* initialize particle cache */
+ if (psys->part->type == PART_HAIR) {
+ // TODO: PART_HAIR not supported whatsoever
+ totchild = 0;
+ }
+ else {
+ totchild = psys->totchild * psys->part->disp / 100;
+ }
+
+ particle_pos = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles");
+ particle_vel = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles");
+
+ /* setup particle radius emission if enabled */
+ if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
+ tree = BLI_kdtree_3d_new(psys->totpart + psys->totchild);
+
+ /* check need for high resolution map */
+ if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
+ hires_multiplier = sds->amplify + 1;
+ }
+
+ bounds_margin = (int)ceil(solid + smooth);
+ }
+
+ /* calculate local position for each particle */
+ for (p = 0; p < totpart + totchild; p++) {
+ ParticleKey state;
+ float *pos;
+ if (p < totpart) {
+ if (psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST))
+ continue;
+ }
+ else {
+ /* handle child particle */
+ ChildParticle *cpa = &psys->child[p - totpart];
+ if (psys->particles[cpa->parent].flag & (PARS_NO_DISP | PARS_UNEXIST))
+ continue;
+ }
+
+ state.time = DEG_get_ctime(depsgraph); /* use depsgraph time */
+ if (psys_get_particle_state(&sim, p, &state, 0) == 0)
+ continue;
+
+ /* location */
+ pos = &particle_pos[valid_particles * 3];
+ copy_v3_v3(pos, state.co);
+ smoke_pos_to_cell(sds, pos);
+
+ /* velocity */
+ copy_v3_v3(&particle_vel[valid_particles * 3], state.vel);
+ mul_mat3_m4_v3(sds->imat, &particle_vel[valid_particles * 3]);
+
+ if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
+ BLI_kdtree_3d_insert(tree, valid_particles, pos);
+ }
+
+ /* calculate emission map bounds */
+ em_boundInsert(em, pos);
+ valid_particles++;
+ }
+
+ /* set emission map */
+ clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, bounds_margin, dt);
+ em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier);
+
+ if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
+ for (p = 0; p < valid_particles; p++) {
+ int cell[3];
+ size_t i = 0;
+ size_t index = 0;
+ int badcell = 0;
+
+ /* 1. get corresponding cell */
+ cell[0] = floor(particle_pos[p * 3]) - em->min[0];
+ cell[1] = floor(particle_pos[p * 3 + 1]) - em->min[1];
+ cell[2] = floor(particle_pos[p * 3 + 2]) - em->min[2];
+ /* check if cell is valid (in the domain boundary) */
+ for (i = 0; i < 3; i++) {
+ if ((cell[i] > em->res[i] - 1) || (cell[i] < 0)) {
+ badcell = 1;
+ break;
+ }
+ }
+ if (badcell)
+ continue;
+ /* get cell index */
+ index = smoke_get_index(cell[0], em->res[0], cell[1], em->res[1], cell[2]);
+ /* Add influence to emission map */
+ em->influence[index] = 1.0f;
+ /* Uses particle velocity as initial velocity for smoke */
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO)) {
+ madd_v3_v3fl(&em->velocity[index * 3], &particle_vel[p * 3], sfs->vel_multi);
+ }
+ } // particles loop
+ }
+ else if (valid_particles > 0) { // MOD_SMOKE_FLOW_USE_PART_SIZE
+ int min[3], max[3], res[3];
+ const float hr = 1.0f / ((float)hires_multiplier);
+ /* slightly adjust high res antialias smoothness based on number of divisions
+ * to allow smaller details but yet not differing too much from the low res size */
+ const float hr_smooth = smooth * powf(hr, 1.0f / 3.0f);
+
+ /* setup loop bounds */
+ for (int i = 0; i < 3; i++) {
+ min[i] = em->min[i] * hires_multiplier;
+ max[i] = em->max[i] * hires_multiplier;
+ res[i] = em->res[i] * hires_multiplier;
+ }
+
+ BLI_kdtree_3d_balance(tree);
+
+ EmitFromParticlesData data = {
+ .sfs = sfs,
+ .tree = tree,
+ .hires_multiplier = hires_multiplier,
+ .hr = hr,
+ .em = em,
+ .particle_vel = particle_vel,
+ .min = min,
+ .max = max,
+ .res = res,
+ .solid = solid,
+ .smooth = smooth,
+ .hr_smooth = hr_smooth,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(min[2], max[2], &data, emit_from_particles_task_cb, &settings);
+ }
+
+ if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
+ BLI_kdtree_3d_free(tree);
+ }
+
+ /* free data */
+ if (particle_pos)
+ MEM_freeN(particle_pos);
+ if (particle_vel)
+ MEM_freeN(particle_vel);
+ }
}
-static void sample_mesh(
- SmokeFlowSettings *sfs,
- const MVert *mvert, const MLoop *mloop, const MLoopTri *mlooptri, const MLoopUV *mloopuv,
- float *influence_map, float *velocity_map, int index, const int base_res[3], float flow_center[3],
- BVHTreeFromMesh *treeData, const float ray_start[3], const float *vert_vel,
- bool has_velocity, int defgrp_index, MDeformVert *dvert,
- float x, float y, float z)
+static void sample_mesh(SmokeFlowSettings *sfs,
+ const MVert *mvert,
+ const MLoop *mloop,
+ const MLoopTri *mlooptri,
+ const MLoopUV *mloopuv,
+ float *influence_map,
+ float *velocity_map,
+ int index,
+ const int base_res[3],
+ float flow_center[3],
+ BVHTreeFromMesh *treeData,
+ const float ray_start[3],
+ const float *vert_vel,
+ bool has_velocity,
+ int defgrp_index,
+ MDeformVert *dvert,
+ float x,
+ float y,
+ float z)
{
- float ray_dir[3] = {1.0f, 0.0f, 0.0f};
- BVHTreeRayHit hit = {0};
- BVHTreeNearest nearest = {0};
-
- float volume_factor = 0.0f;
- float sample_str = 0.0f;
-
- hit.index = -1;
- hit.dist = 9999;
- nearest.index = -1;
- nearest.dist_sq = sfs->surface_distance * sfs->surface_distance; /* find_nearest uses squared distance */
-
- /* Check volume collision */
- if (sfs->volume_density) {
- if (BLI_bvhtree_ray_cast(treeData->tree, ray_start, ray_dir, 0.0f, &hit, treeData->raycast_callback, treeData) != -1) {
- float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2];
- /* If ray and hit face normal are facing same direction
- * hit point is inside a closed mesh. */
- if (dot >= 0) {
- /* Also cast a ray in opposite direction to make sure
- * point is at least surrounded by two faces */
- negate_v3(ray_dir);
- hit.index = -1;
- hit.dist = 9999;
-
- BLI_bvhtree_ray_cast(treeData->tree, ray_start, ray_dir, 0.0f, &hit, treeData->raycast_callback, treeData);
- if (hit.index != -1) {
- volume_factor = sfs->volume_density;
- }
- }
- }
- }
-
- /* find the nearest point on the mesh */
- if (BLI_bvhtree_find_nearest(treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) {
- float weights[3];
- int v1, v2, v3, f_index = nearest.index;
- float n1[3], n2[3], n3[3], hit_normal[3];
-
- /* emit from surface based on distance */
- if (sfs->surface_distance) {
- sample_str = sqrtf(nearest.dist_sq) / sfs->surface_distance;
- CLAMP(sample_str, 0.0f, 1.0f);
- sample_str = pow(1.0f - sample_str, 0.5f);
- }
- else
- sample_str = 0.0f;
-
- /* calculate barycentric weights for nearest point */
- v1 = mloop[mlooptri[f_index].tri[0]].v;
- v2 = mloop[mlooptri[f_index].tri[1]].v;
- v3 = mloop[mlooptri[f_index].tri[2]].v;
- interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
-
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) {
- /* apply normal directional velocity */
- if (sfs->vel_normal) {
- /* interpolate vertex normal vectors to get nearest point normal */
- normal_short_to_float_v3(n1, mvert[v1].no);
- normal_short_to_float_v3(n2, mvert[v2].no);
- normal_short_to_float_v3(n3, mvert[v3].no);
- interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights);
- normalize_v3(hit_normal);
- /* apply normal directional and random velocity
- * - TODO: random disabled for now since it doesn't really work well as pressure calc smoothens it out... */
- velocity_map[index * 3] += hit_normal[0] * sfs->vel_normal * 0.25f;
- velocity_map[index * 3 + 1] += hit_normal[1] * sfs->vel_normal * 0.25f;
- velocity_map[index * 3 + 2] += hit_normal[2] * sfs->vel_normal * 0.25f;
- /* TODO: for fire emitted from mesh surface we can use
- * Vf = Vs + (Ps/Pf - 1)*S to model gaseous expansion from solid to fuel */
- }
- /* apply object velocity */
- if (has_velocity && sfs->vel_multi) {
- float hit_vel[3];
- interp_v3_v3v3v3(hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights);
- velocity_map[index * 3] += hit_vel[0] * sfs->vel_multi;
- velocity_map[index * 3 + 1] += hit_vel[1] * sfs->vel_multi;
- velocity_map[index * 3 + 2] += hit_vel[2] * sfs->vel_multi;
- }
- }
-
- /* apply vertex group influence if used */
- if (defgrp_index != -1 && dvert) {
- float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] +
- defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] +
- defvert_find_weight(&dvert[v3], defgrp_index) * weights[2];
- sample_str *= weight_mask;
- }
-
- /* apply emission texture */
- if ((sfs->flags & MOD_SMOKE_FLOW_TEXTUREEMIT) && sfs->noise_texture) {
- float tex_co[3] = {0};
- TexResult texres;
-
- if (sfs->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO) {
- tex_co[0] = ((x - flow_center[0]) / base_res[0]) / sfs->texture_size;
- tex_co[1] = ((y - flow_center[1]) / base_res[1]) / sfs->texture_size;
- tex_co[2] = ((z - flow_center[2]) / base_res[2] - sfs->texture_offset) / sfs->texture_size;
- }
- else if (mloopuv) {
- const float *uv[3];
- uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv;
- uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv;
- uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv;
-
- interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights);
-
- /* map between -1.0f and 1.0f */
- tex_co[0] = tex_co[0] * 2.0f - 1.0f;
- tex_co[1] = tex_co[1] * 2.0f - 1.0f;
- tex_co[2] = sfs->texture_offset;
- }
- texres.nor = NULL;
- BKE_texture_get_value(NULL, sfs->noise_texture, tex_co, &texres, false);
- sample_str *= texres.tin;
- }
- }
-
- /* multiply initial velocity by emitter influence */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) {
- mul_v3_fl(&velocity_map[index * 3], sample_str);
- }
-
- /* apply final influence based on volume factor */
- influence_map[index] = MAX2(volume_factor, sample_str);
+ float ray_dir[3] = {1.0f, 0.0f, 0.0f};
+ BVHTreeRayHit hit = {0};
+ BVHTreeNearest nearest = {0};
+
+ float volume_factor = 0.0f;
+ float sample_str = 0.0f;
+
+ hit.index = -1;
+ hit.dist = 9999;
+ nearest.index = -1;
+ nearest.dist_sq = sfs->surface_distance *
+ sfs->surface_distance; /* find_nearest uses squared distance */
+
+ /* Check volume collision */
+ if (sfs->volume_density) {
+ if (BLI_bvhtree_ray_cast(treeData->tree,
+ ray_start,
+ ray_dir,
+ 0.0f,
+ &hit,
+ treeData->raycast_callback,
+ treeData) != -1) {
+ float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2];
+ /* If ray and hit face normal are facing same direction
+ * hit point is inside a closed mesh. */
+ if (dot >= 0) {
+ /* Also cast a ray in opposite direction to make sure
+ * point is at least surrounded by two faces */
+ negate_v3(ray_dir);
+ hit.index = -1;
+ hit.dist = 9999;
+
+ BLI_bvhtree_ray_cast(
+ treeData->tree, ray_start, ray_dir, 0.0f, &hit, treeData->raycast_callback, treeData);
+ if (hit.index != -1) {
+ volume_factor = sfs->volume_density;
+ }
+ }
+ }
+ }
+
+ /* find the nearest point on the mesh */
+ if (BLI_bvhtree_find_nearest(
+ treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) {
+ float weights[3];
+ int v1, v2, v3, f_index = nearest.index;
+ float n1[3], n2[3], n3[3], hit_normal[3];
+
+ /* emit from surface based on distance */
+ if (sfs->surface_distance) {
+ sample_str = sqrtf(nearest.dist_sq) / sfs->surface_distance;
+ CLAMP(sample_str, 0.0f, 1.0f);
+ sample_str = pow(1.0f - sample_str, 0.5f);
+ }
+ else
+ sample_str = 0.0f;
+
+ /* calculate barycentric weights for nearest point */
+ v1 = mloop[mlooptri[f_index].tri[0]].v;
+ v2 = mloop[mlooptri[f_index].tri[1]].v;
+ v3 = mloop[mlooptri[f_index].tri[2]].v;
+ interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
+
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) {
+ /* apply normal directional velocity */
+ if (sfs->vel_normal) {
+ /* interpolate vertex normal vectors to get nearest point normal */
+ normal_short_to_float_v3(n1, mvert[v1].no);
+ normal_short_to_float_v3(n2, mvert[v2].no);
+ normal_short_to_float_v3(n3, mvert[v3].no);
+ interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights);
+ normalize_v3(hit_normal);
+ /* apply normal directional and random velocity
+ * - TODO: random disabled for now since it doesn't really work well as pressure calc smoothens it out... */
+ velocity_map[index * 3] += hit_normal[0] * sfs->vel_normal * 0.25f;
+ velocity_map[index * 3 + 1] += hit_normal[1] * sfs->vel_normal * 0.25f;
+ velocity_map[index * 3 + 2] += hit_normal[2] * sfs->vel_normal * 0.25f;
+ /* TODO: for fire emitted from mesh surface we can use
+ * Vf = Vs + (Ps/Pf - 1)*S to model gaseous expansion from solid to fuel */
+ }
+ /* apply object velocity */
+ if (has_velocity && sfs->vel_multi) {
+ float hit_vel[3];
+ interp_v3_v3v3v3(
+ hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights);
+ velocity_map[index * 3] += hit_vel[0] * sfs->vel_multi;
+ velocity_map[index * 3 + 1] += hit_vel[1] * sfs->vel_multi;
+ velocity_map[index * 3 + 2] += hit_vel[2] * sfs->vel_multi;
+ }
+ }
+
+ /* apply vertex group influence if used */
+ if (defgrp_index != -1 && dvert) {
+ float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] +
+ defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] +
+ defvert_find_weight(&dvert[v3], defgrp_index) * weights[2];
+ sample_str *= weight_mask;
+ }
+
+ /* apply emission texture */
+ if ((sfs->flags & MOD_SMOKE_FLOW_TEXTUREEMIT) && sfs->noise_texture) {
+ float tex_co[3] = {0};
+ TexResult texres;
+
+ if (sfs->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO) {
+ tex_co[0] = ((x - flow_center[0]) / base_res[0]) / sfs->texture_size;
+ tex_co[1] = ((y - flow_center[1]) / base_res[1]) / sfs->texture_size;
+ tex_co[2] = ((z - flow_center[2]) / base_res[2] - sfs->texture_offset) / sfs->texture_size;
+ }
+ else if (mloopuv) {
+ const float *uv[3];
+ uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv;
+ uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv;
+ uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv;
+
+ interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights);
+
+ /* map between -1.0f and 1.0f */
+ tex_co[0] = tex_co[0] * 2.0f - 1.0f;
+ tex_co[1] = tex_co[1] * 2.0f - 1.0f;
+ tex_co[2] = sfs->texture_offset;
+ }
+ texres.nor = NULL;
+ BKE_texture_get_value(NULL, sfs->noise_texture, tex_co, &texres, false);
+ sample_str *= texres.tin;
+ }
+ }
+
+ /* multiply initial velocity by emitter influence */
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) {
+ mul_v3_fl(&velocity_map[index * 3], sample_str);
+ }
+
+ /* apply final influence based on volume factor */
+ influence_map[index] = MAX2(volume_factor, sample_str);
}
typedef struct EmitFromDMData {
- SmokeDomainSettings *sds;
- SmokeFlowSettings *sfs;
- const MVert *mvert;
- const MLoop *mloop;
- const MLoopTri *mlooptri;
- const MLoopUV *mloopuv;
- MDeformVert *dvert;
- int defgrp_index;
-
- BVHTreeFromMesh *tree;
- int hires_multiplier;
- float hr;
-
- EmissionMap *em;
- bool has_velocity;
- float *vert_vel;
-
- float *flow_center;
- int *min, *max, *res;
+ SmokeDomainSettings *sds;
+ SmokeFlowSettings *sfs;
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MLoopTri *mlooptri;
+ const MLoopUV *mloopuv;
+ MDeformVert *dvert;
+ int defgrp_index;
+
+ BVHTreeFromMesh *tree;
+ int hires_multiplier;
+ float hr;
+
+ EmissionMap *em;
+ bool has_velocity;
+ float *vert_vel;
+
+ float *flow_center;
+ int *min, *max, *res;
} EmitFromDMData;
-static void emit_from_mesh_task_cb(
- void *__restrict userdata,
- const int z,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void emit_from_mesh_task_cb(void *__restrict userdata,
+ const int z,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- EmitFromDMData *data = userdata;
- EmissionMap *em = data->em;
- const int hires_multiplier = data->hires_multiplier;
-
- for (int x = data->min[0]; x < data->max[0]; x++) {
- for (int y = data->min[1]; y < data->max[1]; y++) {
- /* take low res samples where possible */
- if (hires_multiplier <= 1 || !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
- /* get low res space coordinates */
- const int lx = x / hires_multiplier;
- const int ly = y / hires_multiplier;
- const int lz = z / hires_multiplier;
-
- const int index = smoke_get_index(
- lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
- const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
-
- sample_mesh(
- data->sfs, data->mvert, data->mloop, data->mlooptri, data->mloopuv,
- em->influence, em->velocity, index, data->sds->base_res, data->flow_center,
- data->tree, ray_start, data->vert_vel, data->has_velocity, data->defgrp_index, data->dvert,
- (float)lx, (float)ly, (float)lz);
- }
-
- /* take high res samples if required */
- if (hires_multiplier > 1) {
- /* get low res space coordinates */
- const float lx = ((float)x) * data->hr;
- const float ly = ((float)y) * data->hr;
- const float lz = ((float)z) * data->hr;
-
- const int index = smoke_get_index(
- x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
- const float ray_start[3] = {lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
-
- sample_mesh(
- data->sfs, data->mvert, data->mloop, data->mlooptri, data->mloopuv,
- em->influence_high, NULL, index, data->sds->base_res, data->flow_center,
- data->tree, ray_start, data->vert_vel, data->has_velocity, data->defgrp_index, data->dvert,
- /* x,y,z needs to be always lowres */
- lx, ly, lz);
- }
- }
- }
+ EmitFromDMData *data = userdata;
+ EmissionMap *em = data->em;
+ const int hires_multiplier = data->hires_multiplier;
+
+ for (int x = data->min[0]; x < data->max[0]; x++) {
+ for (int y = data->min[1]; y < data->max[1]; y++) {
+ /* take low res samples where possible */
+ if (hires_multiplier <= 1 ||
+ !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
+ /* get low res space coordinates */
+ const int lx = x / hires_multiplier;
+ const int ly = y / hires_multiplier;
+ const int lz = z / hires_multiplier;
+
+ const int index = smoke_get_index(
+ lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
+ const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
+
+ sample_mesh(data->sfs,
+ data->mvert,
+ data->mloop,
+ data->mlooptri,
+ data->mloopuv,
+ em->influence,
+ em->velocity,
+ index,
+ data->sds->base_res,
+ data->flow_center,
+ data->tree,
+ ray_start,
+ data->vert_vel,
+ data->has_velocity,
+ data->defgrp_index,
+ data->dvert,
+ (float)lx,
+ (float)ly,
+ (float)lz);
+ }
+
+ /* take high res samples if required */
+ if (hires_multiplier > 1) {
+ /* get low res space coordinates */
+ const float lx = ((float)x) * data->hr;
+ const float ly = ((float)y) * data->hr;
+ const float lz = ((float)z) * data->hr;
+
+ const int index = smoke_get_index(
+ x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
+ const float ray_start[3] = {
+ lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
+
+ sample_mesh(data->sfs,
+ data->mvert,
+ data->mloop,
+ data->mlooptri,
+ data->mloopuv,
+ em->influence_high,
+ NULL,
+ index,
+ data->sds->base_res,
+ data->flow_center,
+ data->tree,
+ ray_start,
+ data->vert_vel,
+ data->has_velocity,
+ data->defgrp_index,
+ data->dvert,
+ /* x,y,z needs to be always lowres */
+ lx,
+ ly,
+ lz);
+ }
+ }
+ }
}
-static void emit_from_mesh(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt)
+static void emit_from_mesh(
+ Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt)
{
- if (sfs->mesh) {
- Mesh *me;
- int defgrp_index = sfs->vgroup_density - 1;
- MDeformVert *dvert = NULL;
- MVert *mvert = NULL;
- const MLoopTri *mlooptri = NULL;
- const MLoopUV *mloopuv = NULL;
- const MLoop *mloop = NULL;
- BVHTreeFromMesh treeData = {NULL};
- int numOfVerts, i;
- float flow_center[3] = {0};
-
- float *vert_vel = NULL;
- int has_velocity = 0;
- int min[3], max[3], res[3];
- int hires_multiplier = 1;
-
- /* copy mesh for thread safety because we modify it,
- * main issue is its VertArray being modified, then replaced and freed
- */
- me = BKE_mesh_copy_for_eval(sfs->mesh, true);
-
- /* Duplicate vertices to modify. */
- if (me->mvert) {
- me->mvert = MEM_dupallocN(me->mvert);
- CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
- }
-
- BKE_mesh_ensure_normals(me);
- mvert = me->mvert;
- numOfVerts = me->totvert;
- dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
- mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, sfs->uvlayer_name);
- mloop = me->mloop;
- mlooptri = BKE_mesh_runtime_looptri_ensure(me);
-
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
- vert_vel = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_velocity");
-
- if (sfs->numverts != numOfVerts || !sfs->verts_old) {
- if (sfs->verts_old) MEM_freeN(sfs->verts_old);
- sfs->verts_old = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_verts_old");
- sfs->numverts = numOfVerts;
- }
- else {
- has_velocity = 1;
- }
- }
-
- /* Transform mesh vertices to
- * domain grid space for fast lookups */
- for (i = 0; i < numOfVerts; i++) {
- float n[3];
- /* vert pos */
- mul_m4_v3(flow_ob->obmat, mvert[i].co);
- smoke_pos_to_cell(sds, mvert[i].co);
- /* vert normal */
- normal_short_to_float_v3(n, mvert[i].no);
- mul_mat3_m4_v3(flow_ob->obmat, n);
- mul_mat3_m4_v3(sds->imat, n);
- normalize_v3(n);
- normal_float_to_short_v3(mvert[i].no, n);
- /* vert velocity */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
- float co[3];
- add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift);
- if (has_velocity) {
- sub_v3_v3v3(&vert_vel[i * 3], co, &sfs->verts_old[i * 3]);
- mul_v3_fl(&vert_vel[i * 3], sds->dx / dt);
- }
- copy_v3_v3(&sfs->verts_old[i * 3], co);
- }
-
- /* calculate emission map bounds */
- em_boundInsert(em, mvert[i].co);
- }
- mul_m4_v3(flow_ob->obmat, flow_center);
- smoke_pos_to_cell(sds, flow_center);
-
- /* check need for high resolution map */
- if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
- hires_multiplier = sds->amplify + 1;
- }
-
- /* set emission map */
- clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, (int)ceil(sfs->surface_distance), dt);
- em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier);
-
- /* setup loop bounds */
- for (i = 0; i < 3; i++) {
- min[i] = em->min[i] * hires_multiplier;
- max[i] = em->max[i] * hires_multiplier;
- res[i] = em->res[i] * hires_multiplier;
- }
-
- if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
- const float hr = 1.0f / ((float)hires_multiplier);
-
- EmitFromDMData data = {
- .sds = sds, .sfs = sfs,
- .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri, .mloopuv = mloopuv,
- .dvert = dvert, .defgrp_index = defgrp_index,
- .tree = &treeData, .hires_multiplier = hires_multiplier, .hr = hr,
- .em = em, .has_velocity = has_velocity, .vert_vel = vert_vel,
- .flow_center = flow_center, .min = min, .max = max, .res = res,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(min[2], max[2],
- &data,
- emit_from_mesh_task_cb,
- &settings);
- }
- /* free bvh tree */
- free_bvhtree_from_mesh(&treeData);
-
- if (vert_vel) {
- MEM_freeN(vert_vel);
- }
-
- if (me->mvert) {
- MEM_freeN(me->mvert);
- }
- BKE_id_free(NULL, me);
- }
+ if (sfs->mesh) {
+ Mesh *me;
+ int defgrp_index = sfs->vgroup_density - 1;
+ MDeformVert *dvert = NULL;
+ MVert *mvert = NULL;
+ const MLoopTri *mlooptri = NULL;
+ const MLoopUV *mloopuv = NULL;
+ const MLoop *mloop = NULL;
+ BVHTreeFromMesh treeData = {NULL};
+ int numOfVerts, i;
+ float flow_center[3] = {0};
+
+ float *vert_vel = NULL;
+ int has_velocity = 0;
+ int min[3], max[3], res[3];
+ int hires_multiplier = 1;
+
+ /* copy mesh for thread safety because we modify it,
+ * main issue is its VertArray being modified, then replaced and freed
+ */
+ me = BKE_mesh_copy_for_eval(sfs->mesh, true);
+
+ /* Duplicate vertices to modify. */
+ if (me->mvert) {
+ me->mvert = MEM_dupallocN(me->mvert);
+ CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
+ }
+
+ BKE_mesh_ensure_normals(me);
+ mvert = me->mvert;
+ numOfVerts = me->totvert;
+ dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
+ mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, sfs->uvlayer_name);
+ mloop = me->mloop;
+ mlooptri = BKE_mesh_runtime_looptri_ensure(me);
+
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
+ vert_vel = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_velocity");
+
+ if (sfs->numverts != numOfVerts || !sfs->verts_old) {
+ if (sfs->verts_old)
+ MEM_freeN(sfs->verts_old);
+ sfs->verts_old = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_verts_old");
+ sfs->numverts = numOfVerts;
+ }
+ else {
+ has_velocity = 1;
+ }
+ }
+
+ /* Transform mesh vertices to
+ * domain grid space for fast lookups */
+ for (i = 0; i < numOfVerts; i++) {
+ float n[3];
+ /* vert pos */
+ mul_m4_v3(flow_ob->obmat, mvert[i].co);
+ smoke_pos_to_cell(sds, mvert[i].co);
+ /* vert normal */
+ normal_short_to_float_v3(n, mvert[i].no);
+ mul_mat3_m4_v3(flow_ob->obmat, n);
+ mul_mat3_m4_v3(sds->imat, n);
+ normalize_v3(n);
+ normal_float_to_short_v3(mvert[i].no, n);
+ /* vert velocity */
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
+ float co[3];
+ add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift);
+ if (has_velocity) {
+ sub_v3_v3v3(&vert_vel[i * 3], co, &sfs->verts_old[i * 3]);
+ mul_v3_fl(&vert_vel[i * 3], sds->dx / dt);
+ }
+ copy_v3_v3(&sfs->verts_old[i * 3], co);
+ }
+
+ /* calculate emission map bounds */
+ em_boundInsert(em, mvert[i].co);
+ }
+ mul_m4_v3(flow_ob->obmat, flow_center);
+ smoke_pos_to_cell(sds, flow_center);
+
+ /* check need for high resolution map */
+ if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
+ hires_multiplier = sds->amplify + 1;
+ }
+
+ /* set emission map */
+ clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, (int)ceil(sfs->surface_distance), dt);
+ em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier);
+
+ /* setup loop bounds */
+ for (i = 0; i < 3; i++) {
+ min[i] = em->min[i] * hires_multiplier;
+ max[i] = em->max[i] * hires_multiplier;
+ res[i] = em->res[i] * hires_multiplier;
+ }
+
+ if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
+ const float hr = 1.0f / ((float)hires_multiplier);
+
+ EmitFromDMData data = {
+ .sds = sds,
+ .sfs = sfs,
+ .mvert = mvert,
+ .mloop = mloop,
+ .mlooptri = mlooptri,
+ .mloopuv = mloopuv,
+ .dvert = dvert,
+ .defgrp_index = defgrp_index,
+ .tree = &treeData,
+ .hires_multiplier = hires_multiplier,
+ .hr = hr,
+ .em = em,
+ .has_velocity = has_velocity,
+ .vert_vel = vert_vel,
+ .flow_center = flow_center,
+ .min = min,
+ .max = max,
+ .res = res,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(min[2], max[2], &data, emit_from_mesh_task_cb, &settings);
+ }
+ /* free bvh tree */
+ free_bvhtree_from_mesh(&treeData);
+
+ if (vert_vel) {
+ MEM_freeN(vert_vel);
+ }
+
+ if (me->mvert) {
+ MEM_freeN(me->mvert);
+ }
+ BKE_id_free(NULL, me);
+ }
}
/**********************************************************
* Smoke step
**********************************************************/
-static void adjustDomainResolution(SmokeDomainSettings *sds, int new_shift[3], EmissionMap *emaps, unsigned int numflowobj, float dt)
+static void adjustDomainResolution(SmokeDomainSettings *sds,
+ int new_shift[3],
+ EmissionMap *emaps,
+ unsigned int numflowobj,
+ float dt)
{
- const int block_size = sds->amplify + 1;
- int min[3] = {32767, 32767, 32767}, max[3] = {-32767, -32767, -32767}, res[3];
- int total_cells = 1, res_changed = 0, shift_changed = 0;
- float min_vel[3], max_vel[3];
- int x, y, z;
- float *density = smoke_get_density(sds->fluid);
- float *fuel = smoke_get_fuel(sds->fluid);
- float *bigdensity = smoke_turbulence_get_density(sds->wt);
- float *bigfuel = smoke_turbulence_get_fuel(sds->wt);
- float *vx = smoke_get_velocity_x(sds->fluid);
- float *vy = smoke_get_velocity_y(sds->fluid);
- float *vz = smoke_get_velocity_z(sds->fluid);
- int wt_res[3];
-
- if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
- smoke_turbulence_get_res(sds->wt, wt_res);
- }
-
- INIT_MINMAX(min_vel, max_vel);
-
- /* Calculate bounds for current domain content */
- for (x = sds->res_min[0]; x < sds->res_max[0]; x++)
- for (y = sds->res_min[1]; y < sds->res_max[1]; y++)
- for (z = sds->res_min[2]; z < sds->res_max[2]; z++)
- {
- int xn = x - new_shift[0];
- int yn = y - new_shift[1];
- int zn = z - new_shift[2];
- int index;
- float max_den;
-
- /* skip if cell already belongs to new area */
- if (xn >= min[0] && xn <= max[0] && yn >= min[1] && yn <= max[1] && zn >= min[2] && zn <= max[2])
- continue;
-
- index = smoke_get_index(x - sds->res_min[0], sds->res[0], y - sds->res_min[1], sds->res[1], z - sds->res_min[2]);
- max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index];
-
- /* check high resolution bounds if max density isnt already high enough */
- if (max_den < sds->adapt_threshold && sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
- int i, j, k;
- /* high res grid index */
- int xx = (x - sds->res_min[0]) * block_size;
- int yy = (y - sds->res_min[1]) * block_size;
- int zz = (z - sds->res_min[2]) * block_size;
-
- for (i = 0; i < block_size; i++)
- for (j = 0; j < block_size; j++)
- for (k = 0; k < block_size; k++)
- {
- int big_index = smoke_get_index(xx + i, wt_res[0], yy + j, wt_res[1], zz + k);
- float den = (bigfuel) ? MAX2(bigdensity[big_index], bigfuel[big_index]) : bigdensity[big_index];
- if (den > max_den) {
- max_den = den;
- }
- }
- }
-
- /* content bounds (use shifted coordinates) */
- if (max_den >= sds->adapt_threshold) {
- if (min[0] > xn) min[0] = xn;
- if (min[1] > yn) min[1] = yn;
- if (min[2] > zn) min[2] = zn;
- if (max[0] < xn) max[0] = xn;
- if (max[1] < yn) max[1] = yn;
- if (max[2] < zn) max[2] = zn;
- }
-
- /* velocity bounds */
- if (min_vel[0] > vx[index]) min_vel[0] = vx[index];
- if (min_vel[1] > vy[index]) min_vel[1] = vy[index];
- if (min_vel[2] > vz[index]) min_vel[2] = vz[index];
- if (max_vel[0] < vx[index]) max_vel[0] = vx[index];
- if (max_vel[1] < vy[index]) max_vel[1] = vy[index];
- if (max_vel[2] < vz[index]) max_vel[2] = vz[index];
- }
-
- /* also apply emission maps */
- for (int i = 0; i < numflowobj; i++) {
- EmissionMap *em = &emaps[i];
-
- for (x = em->min[0]; x < em->max[0]; x++)
- for (y = em->min[1]; y < em->max[1]; y++)
- for (z = em->min[2]; z < em->max[2]; z++)
- {
- int index = smoke_get_index(x - em->min[0], em->res[0], y - em->min[1], em->res[1], z - em->min[2]);
- float max_den = em->influence[index];
-
- /* density bounds */
- if (max_den >= sds->adapt_threshold) {
- if (min[0] > x) min[0] = x;
- if (min[1] > y) min[1] = y;
- if (min[2] > z) min[2] = z;
- if (max[0] < x) max[0] = x;
- if (max[1] < y) max[1] = y;
- if (max[2] < z) max[2] = z;
- }
- }
- }
-
- /* calculate new bounds based on these values */
- mul_v3_fl(min_vel, 1.0f / sds->dx);
- mul_v3_fl(max_vel, 1.0f / sds->dx);
- clampBoundsInDomain(sds, min, max, min_vel, max_vel, sds->adapt_margin + 1, dt);
-
- for (int i = 0; i < 3; i++) {
- /* calculate new resolution */
- res[i] = max[i] - min[i];
- total_cells *= res[i];
-
- if (new_shift[i])
- shift_changed = 1;
-
- /* if no content set minimum dimensions */
- if (res[i] <= 0) {
- int j;
- for (j = 0; j < 3; j++) {
- min[j] = 0;
- max[j] = 1;
- res[j] = 1;
- }
- res_changed = 1;
- total_cells = 1;
- break;
- }
- if (min[i] != sds->res_min[i] || max[i] != sds->res_max[i])
- res_changed = 1;
- }
-
- if (res_changed || shift_changed) {
- struct FLUID_3D *fluid_old = sds->fluid;
- struct WTURBULENCE *turb_old = sds->wt;
- /* allocate new fluid data */
- BKE_smoke_reallocate_fluid(sds, sds->dx, res, 0);
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- BKE_smoke_reallocate_highres_fluid(sds, sds->dx, res, 0);
- }
-
- /* copy values from old fluid to new */
- if (sds->total_cells > 1 && total_cells > 1) {
- /* low res smoke */
- float *o_dens, *o_react, *o_flame, *o_fuel, *o_heat, *o_heatold, *o_vx, *o_vy, *o_vz, *o_r, *o_g, *o_b;
- float *n_dens, *n_react, *n_flame, *n_fuel, *n_heat, *n_heatold, *n_vx, *n_vy, *n_vz, *n_r, *n_g, *n_b;
- float dummy;
- unsigned char *dummy_p;
- /* high res smoke */
- int wt_res_old[3];
- float *o_wt_dens, *o_wt_react, *o_wt_flame, *o_wt_fuel, *o_wt_tcu, *o_wt_tcv, *o_wt_tcw, *o_wt_r, *o_wt_g, *o_wt_b;
- float *n_wt_dens, *n_wt_react, *n_wt_flame, *n_wt_fuel, *n_wt_tcu, *n_wt_tcv, *n_wt_tcw, *n_wt_r, *n_wt_g, *n_wt_b;
-
- smoke_export(fluid_old, &dummy, &dummy, &o_dens, &o_react, &o_flame, &o_fuel, &o_heat, &o_heatold, &o_vx, &o_vy, &o_vz, &o_r, &o_g, &o_b, &dummy_p);
- smoke_export(sds->fluid, &dummy, &dummy, &n_dens, &n_react, &n_flame, &n_fuel, &n_heat, &n_heatold, &n_vx, &n_vy, &n_vz, &n_r, &n_g, &n_b, &dummy_p);
-
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- smoke_turbulence_export(turb_old, &o_wt_dens, &o_wt_react, &o_wt_flame, &o_wt_fuel, &o_wt_r, &o_wt_g, &o_wt_b, &o_wt_tcu, &o_wt_tcv, &o_wt_tcw);
- smoke_turbulence_get_res(turb_old, wt_res_old);
- smoke_turbulence_export(sds->wt, &n_wt_dens, &n_wt_react, &n_wt_flame, &n_wt_fuel, &n_wt_r, &n_wt_g, &n_wt_b, &n_wt_tcu, &n_wt_tcv, &n_wt_tcw);
- }
-
-
- for (x = sds->res_min[0]; x < sds->res_max[0]; x++)
- for (y = sds->res_min[1]; y < sds->res_max[1]; y++)
- for (z = sds->res_min[2]; z < sds->res_max[2]; z++)
- {
- /* old grid index */
- int xo = x - sds->res_min[0];
- int yo = y - sds->res_min[1];
- int zo = z - sds->res_min[2];
- int index_old = smoke_get_index(xo, sds->res[0], yo, sds->res[1], zo);
- /* new grid index */
- int xn = x - min[0] - new_shift[0];
- int yn = y - min[1] - new_shift[1];
- int zn = z - min[2] - new_shift[2];
- int index_new = smoke_get_index(xn, res[0], yn, res[1], zn);
-
- /* skip if outside new domain */
- if (xn < 0 || xn >= res[0] ||
- yn < 0 || yn >= res[1] ||
- zn < 0 || zn >= res[2])
- continue;
-
- /* copy data */
- n_dens[index_new] = o_dens[index_old];
- /* heat */
- if (n_heat && o_heat) {
- n_heat[index_new] = o_heat[index_old];
- n_heatold[index_new] = o_heatold[index_old];
- }
- /* fuel */
- if (n_fuel && o_fuel) {
- n_flame[index_new] = o_flame[index_old];
- n_fuel[index_new] = o_fuel[index_old];
- n_react[index_new] = o_react[index_old];
- }
- /* color */
- if (o_r && n_r) {
- n_r[index_new] = o_r[index_old];
- n_g[index_new] = o_g[index_old];
- n_b[index_new] = o_b[index_old];
- }
- n_vx[index_new] = o_vx[index_old];
- n_vy[index_new] = o_vy[index_old];
- n_vz[index_new] = o_vz[index_old];
-
- if (sds->flags & MOD_SMOKE_HIGHRES && turb_old) {
- int i, j, k;
- /* old grid index */
- int xx_o = xo * block_size;
- int yy_o = yo * block_size;
- int zz_o = zo * block_size;
- /* new grid index */
- int xx_n = xn * block_size;
- int yy_n = yn * block_size;
- int zz_n = zn * block_size;
-
- n_wt_tcu[index_new] = o_wt_tcu[index_old];
- n_wt_tcv[index_new] = o_wt_tcv[index_old];
- n_wt_tcw[index_new] = o_wt_tcw[index_old];
-
- for (i = 0; i < block_size; i++)
- for (j = 0; j < block_size; j++)
- for (k = 0; k < block_size; k++)
- {
- int big_index_old = smoke_get_index(xx_o + i, wt_res_old[0], yy_o + j, wt_res_old[1], zz_o + k);
- int big_index_new = smoke_get_index(xx_n + i, sds->res_wt[0], yy_n + j, sds->res_wt[1], zz_n + k);
- /* copy data */
- n_wt_dens[big_index_new] = o_wt_dens[big_index_old];
- if (n_wt_flame && o_wt_flame) {
- n_wt_flame[big_index_new] = o_wt_flame[big_index_old];
- n_wt_fuel[big_index_new] = o_wt_fuel[big_index_old];
- n_wt_react[big_index_new] = o_wt_react[big_index_old];
- }
- if (n_wt_r && o_wt_r) {
- n_wt_r[big_index_new] = o_wt_r[big_index_old];
- n_wt_g[big_index_new] = o_wt_g[big_index_old];
- n_wt_b[big_index_new] = o_wt_b[big_index_old];
- }
- }
- }
- }
- }
- smoke_free(fluid_old);
- if (turb_old)
- smoke_turbulence_free(turb_old);
-
- /* set new domain dimensions */
- copy_v3_v3_int(sds->res_min, min);
- copy_v3_v3_int(sds->res_max, max);
- copy_v3_v3_int(sds->res, res);
- sds->total_cells = total_cells;
- }
+ const int block_size = sds->amplify + 1;
+ int min[3] = {32767, 32767, 32767}, max[3] = {-32767, -32767, -32767}, res[3];
+ int total_cells = 1, res_changed = 0, shift_changed = 0;
+ float min_vel[3], max_vel[3];
+ int x, y, z;
+ float *density = smoke_get_density(sds->fluid);
+ float *fuel = smoke_get_fuel(sds->fluid);
+ float *bigdensity = smoke_turbulence_get_density(sds->wt);
+ float *bigfuel = smoke_turbulence_get_fuel(sds->wt);
+ float *vx = smoke_get_velocity_x(sds->fluid);
+ float *vy = smoke_get_velocity_y(sds->fluid);
+ float *vz = smoke_get_velocity_z(sds->fluid);
+ int wt_res[3];
+
+ if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
+ smoke_turbulence_get_res(sds->wt, wt_res);
+ }
+
+ INIT_MINMAX(min_vel, max_vel);
+
+ /* Calculate bounds for current domain content */
+ for (x = sds->res_min[0]; x < sds->res_max[0]; x++)
+ for (y = sds->res_min[1]; y < sds->res_max[1]; y++)
+ for (z = sds->res_min[2]; z < sds->res_max[2]; z++) {
+ int xn = x - new_shift[0];
+ int yn = y - new_shift[1];
+ int zn = z - new_shift[2];
+ int index;
+ float max_den;
+
+ /* skip if cell already belongs to new area */
+ if (xn >= min[0] && xn <= max[0] && yn >= min[1] && yn <= max[1] && zn >= min[2] &&
+ zn <= max[2])
+ continue;
+
+ index = smoke_get_index(x - sds->res_min[0],
+ sds->res[0],
+ y - sds->res_min[1],
+ sds->res[1],
+ z - sds->res_min[2]);
+ max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index];
+
+ /* check high resolution bounds if max density isnt already high enough */
+ if (max_den < sds->adapt_threshold && sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
+ int i, j, k;
+ /* high res grid index */
+ int xx = (x - sds->res_min[0]) * block_size;
+ int yy = (y - sds->res_min[1]) * block_size;
+ int zz = (z - sds->res_min[2]) * block_size;
+
+ for (i = 0; i < block_size; i++)
+ for (j = 0; j < block_size; j++)
+ for (k = 0; k < block_size; k++) {
+ int big_index = smoke_get_index(xx + i, wt_res[0], yy + j, wt_res[1], zz + k);
+ float den = (bigfuel) ? MAX2(bigdensity[big_index], bigfuel[big_index]) :
+ bigdensity[big_index];
+ if (den > max_den) {
+ max_den = den;
+ }
+ }
+ }
+
+ /* content bounds (use shifted coordinates) */
+ if (max_den >= sds->adapt_threshold) {
+ if (min[0] > xn)
+ min[0] = xn;
+ if (min[1] > yn)
+ min[1] = yn;
+ if (min[2] > zn)
+ min[2] = zn;
+ if (max[0] < xn)
+ max[0] = xn;
+ if (max[1] < yn)
+ max[1] = yn;
+ if (max[2] < zn)
+ max[2] = zn;
+ }
+
+ /* velocity bounds */
+ if (min_vel[0] > vx[index])
+ min_vel[0] = vx[index];
+ if (min_vel[1] > vy[index])
+ min_vel[1] = vy[index];
+ if (min_vel[2] > vz[index])
+ min_vel[2] = vz[index];
+ if (max_vel[0] < vx[index])
+ max_vel[0] = vx[index];
+ if (max_vel[1] < vy[index])
+ max_vel[1] = vy[index];
+ if (max_vel[2] < vz[index])
+ max_vel[2] = vz[index];
+ }
+
+ /* also apply emission maps */
+ for (int i = 0; i < numflowobj; i++) {
+ EmissionMap *em = &emaps[i];
+
+ for (x = em->min[0]; x < em->max[0]; x++)
+ for (y = em->min[1]; y < em->max[1]; y++)
+ for (z = em->min[2]; z < em->max[2]; z++) {
+ int index = smoke_get_index(
+ x - em->min[0], em->res[0], y - em->min[1], em->res[1], z - em->min[2]);
+ float max_den = em->influence[index];
+
+ /* density bounds */
+ if (max_den >= sds->adapt_threshold) {
+ if (min[0] > x)
+ min[0] = x;
+ if (min[1] > y)
+ min[1] = y;
+ if (min[2] > z)
+ min[2] = z;
+ if (max[0] < x)
+ max[0] = x;
+ if (max[1] < y)
+ max[1] = y;
+ if (max[2] < z)
+ max[2] = z;
+ }
+ }
+ }
+
+ /* calculate new bounds based on these values */
+ mul_v3_fl(min_vel, 1.0f / sds->dx);
+ mul_v3_fl(max_vel, 1.0f / sds->dx);
+ clampBoundsInDomain(sds, min, max, min_vel, max_vel, sds->adapt_margin + 1, dt);
+
+ for (int i = 0; i < 3; i++) {
+ /* calculate new resolution */
+ res[i] = max[i] - min[i];
+ total_cells *= res[i];
+
+ if (new_shift[i])
+ shift_changed = 1;
+
+ /* if no content set minimum dimensions */
+ if (res[i] <= 0) {
+ int j;
+ for (j = 0; j < 3; j++) {
+ min[j] = 0;
+ max[j] = 1;
+ res[j] = 1;
+ }
+ res_changed = 1;
+ total_cells = 1;
+ break;
+ }
+ if (min[i] != sds->res_min[i] || max[i] != sds->res_max[i])
+ res_changed = 1;
+ }
+
+ if (res_changed || shift_changed) {
+ struct FLUID_3D *fluid_old = sds->fluid;
+ struct WTURBULENCE *turb_old = sds->wt;
+ /* allocate new fluid data */
+ BKE_smoke_reallocate_fluid(sds, sds->dx, res, 0);
+ if (sds->flags & MOD_SMOKE_HIGHRES) {
+ BKE_smoke_reallocate_highres_fluid(sds, sds->dx, res, 0);
+ }
+
+ /* copy values from old fluid to new */
+ if (sds->total_cells > 1 && total_cells > 1) {
+ /* low res smoke */
+ float *o_dens, *o_react, *o_flame, *o_fuel, *o_heat, *o_heatold, *o_vx, *o_vy, *o_vz, *o_r,
+ *o_g, *o_b;
+ float *n_dens, *n_react, *n_flame, *n_fuel, *n_heat, *n_heatold, *n_vx, *n_vy, *n_vz, *n_r,
+ *n_g, *n_b;
+ float dummy;
+ unsigned char *dummy_p;
+ /* high res smoke */
+ int wt_res_old[3];
+ float *o_wt_dens, *o_wt_react, *o_wt_flame, *o_wt_fuel, *o_wt_tcu, *o_wt_tcv, *o_wt_tcw,
+ *o_wt_r, *o_wt_g, *o_wt_b;
+ float *n_wt_dens, *n_wt_react, *n_wt_flame, *n_wt_fuel, *n_wt_tcu, *n_wt_tcv, *n_wt_tcw,
+ *n_wt_r, *n_wt_g, *n_wt_b;
+
+ smoke_export(fluid_old,
+ &dummy,
+ &dummy,
+ &o_dens,
+ &o_react,
+ &o_flame,
+ &o_fuel,
+ &o_heat,
+ &o_heatold,
+ &o_vx,
+ &o_vy,
+ &o_vz,
+ &o_r,
+ &o_g,
+ &o_b,
+ &dummy_p);
+ smoke_export(sds->fluid,
+ &dummy,
+ &dummy,
+ &n_dens,
+ &n_react,
+ &n_flame,
+ &n_fuel,
+ &n_heat,
+ &n_heatold,
+ &n_vx,
+ &n_vy,
+ &n_vz,
+ &n_r,
+ &n_g,
+ &n_b,
+ &dummy_p);
+
+ if (sds->flags & MOD_SMOKE_HIGHRES) {
+ smoke_turbulence_export(turb_old,
+ &o_wt_dens,
+ &o_wt_react,
+ &o_wt_flame,
+ &o_wt_fuel,
+ &o_wt_r,
+ &o_wt_g,
+ &o_wt_b,
+ &o_wt_tcu,
+ &o_wt_tcv,
+ &o_wt_tcw);
+ smoke_turbulence_get_res(turb_old, wt_res_old);
+ smoke_turbulence_export(sds->wt,
+ &n_wt_dens,
+ &n_wt_react,
+ &n_wt_flame,
+ &n_wt_fuel,
+ &n_wt_r,
+ &n_wt_g,
+ &n_wt_b,
+ &n_wt_tcu,
+ &n_wt_tcv,
+ &n_wt_tcw);
+ }
+
+ for (x = sds->res_min[0]; x < sds->res_max[0]; x++)
+ for (y = sds->res_min[1]; y < sds->res_max[1]; y++)
+ for (z = sds->res_min[2]; z < sds->res_max[2]; z++) {
+ /* old grid index */
+ int xo = x - sds->res_min[0];
+ int yo = y - sds->res_min[1];
+ int zo = z - sds->res_min[2];
+ int index_old = smoke_get_index(xo, sds->res[0], yo, sds->res[1], zo);
+ /* new grid index */
+ int xn = x - min[0] - new_shift[0];
+ int yn = y - min[1] - new_shift[1];
+ int zn = z - min[2] - new_shift[2];
+ int index_new = smoke_get_index(xn, res[0], yn, res[1], zn);
+
+ /* skip if outside new domain */
+ if (xn < 0 || xn >= res[0] || yn < 0 || yn >= res[1] || zn < 0 || zn >= res[2])
+ continue;
+
+ /* copy data */
+ n_dens[index_new] = o_dens[index_old];
+ /* heat */
+ if (n_heat && o_heat) {
+ n_heat[index_new] = o_heat[index_old];
+ n_heatold[index_new] = o_heatold[index_old];
+ }
+ /* fuel */
+ if (n_fuel && o_fuel) {
+ n_flame[index_new] = o_flame[index_old];
+ n_fuel[index_new] = o_fuel[index_old];
+ n_react[index_new] = o_react[index_old];
+ }
+ /* color */
+ if (o_r && n_r) {
+ n_r[index_new] = o_r[index_old];
+ n_g[index_new] = o_g[index_old];
+ n_b[index_new] = o_b[index_old];
+ }
+ n_vx[index_new] = o_vx[index_old];
+ n_vy[index_new] = o_vy[index_old];
+ n_vz[index_new] = o_vz[index_old];
+
+ if (sds->flags & MOD_SMOKE_HIGHRES && turb_old) {
+ int i, j, k;
+ /* old grid index */
+ int xx_o = xo * block_size;
+ int yy_o = yo * block_size;
+ int zz_o = zo * block_size;
+ /* new grid index */
+ int xx_n = xn * block_size;
+ int yy_n = yn * block_size;
+ int zz_n = zn * block_size;
+
+ n_wt_tcu[index_new] = o_wt_tcu[index_old];
+ n_wt_tcv[index_new] = o_wt_tcv[index_old];
+ n_wt_tcw[index_new] = o_wt_tcw[index_old];
+
+ for (i = 0; i < block_size; i++)
+ for (j = 0; j < block_size; j++)
+ for (k = 0; k < block_size; k++) {
+ int big_index_old = smoke_get_index(
+ xx_o + i, wt_res_old[0], yy_o + j, wt_res_old[1], zz_o + k);
+ int big_index_new = smoke_get_index(
+ xx_n + i, sds->res_wt[0], yy_n + j, sds->res_wt[1], zz_n + k);
+ /* copy data */
+ n_wt_dens[big_index_new] = o_wt_dens[big_index_old];
+ if (n_wt_flame && o_wt_flame) {
+ n_wt_flame[big_index_new] = o_wt_flame[big_index_old];
+ n_wt_fuel[big_index_new] = o_wt_fuel[big_index_old];
+ n_wt_react[big_index_new] = o_wt_react[big_index_old];
+ }
+ if (n_wt_r && o_wt_r) {
+ n_wt_r[big_index_new] = o_wt_r[big_index_old];
+ n_wt_g[big_index_new] = o_wt_g[big_index_old];
+ n_wt_b[big_index_new] = o_wt_b[big_index_old];
+ }
+ }
+ }
+ }
+ }
+ smoke_free(fluid_old);
+ if (turb_old)
+ smoke_turbulence_free(turb_old);
+
+ /* set new domain dimensions */
+ copy_v3_v3_int(sds->res_min, min);
+ copy_v3_v3_int(sds->res_max, max);
+ copy_v3_v3_int(sds->res, res);
+ sds->total_cells = total_cells;
+ }
}
-BLI_INLINE void apply_outflow_fields(int index, float *density, float *heat, float *fuel, float *react, float *color_r, float *color_g, float *color_b)
+BLI_INLINE void apply_outflow_fields(int index,
+ float *density,
+ float *heat,
+ float *fuel,
+ float *react,
+ float *color_r,
+ float *color_g,
+ float *color_b)
{
- density[index] = 0.f;
- if (heat) {
- heat[index] = 0.f;
- }
- if (fuel) {
- fuel[index] = 0.f;
- react[index] = 0.f;
- }
- if (color_r) {
- color_r[index] = 0.f;
- color_g[index] = 0.f;
- color_b[index] = 0.f;
- }
+ density[index] = 0.f;
+ if (heat) {
+ heat[index] = 0.f;
+ }
+ if (fuel) {
+ fuel[index] = 0.f;
+ react[index] = 0.f;
+ }
+ if (color_r) {
+ color_r[index] = 0.f;
+ color_g[index] = 0.f;
+ color_b[index] = 0.f;
+ }
}
-BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value, int index, float *density, float *heat, float *fuel, float *react, float *color_r, float *color_g, float *color_b)
+BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs,
+ float emission_value,
+ int index,
+ float *density,
+ float *heat,
+ float *fuel,
+ float *react,
+ float *color_r,
+ float *color_g,
+ float *color_b)
{
- int absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE);
- float dens_old = density[index];
- // float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */
- float dens_flow = (sfs->type == MOD_SMOKE_FLOW_TYPE_FIRE) ? 0.0f : emission_value * sfs->density;
- float fuel_flow = emission_value * sfs->fuel_amount;
- /* add heat */
- if (heat && emission_value > 0.0f) {
- heat[index] = ADD_IF_LOWER(heat[index], sfs->temp);
- }
- /* absolute */
- if (absolute_flow) {
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) {
- if (dens_flow > density[index])
- density[index] = dens_flow;
- }
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && fuel_flow) {
- if (fuel_flow > fuel[index])
- fuel[index] = fuel_flow;
- }
- }
- /* additive */
- else {
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) {
- density[index] += dens_flow;
- CLAMP(density[index], 0.0f, 1.0f);
- }
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && sfs->fuel_amount) {
- fuel[index] += fuel_flow;
- CLAMP(fuel[index], 0.0f, 10.0f);
- }
- }
-
- /* set color */
- if (color_r && dens_flow) {
- float total_dens = density[index] / (dens_old + dens_flow);
- color_r[index] = (color_r[index] + sfs->color[0] * dens_flow) * total_dens;
- color_g[index] = (color_g[index] + sfs->color[1] * dens_flow) * total_dens;
- color_b[index] = (color_b[index] + sfs->color[2] * dens_flow) * total_dens;
- }
-
- /* set fire reaction coordinate */
- if (fuel && fuel[index] > FLT_EPSILON) {
- /* instead of using 1.0 for all new fuel add slight falloff
- * to reduce flow blockiness */
- float value = 1.0f - pow2f(1.0f - emission_value);
-
- if (value > react[index]) {
- float f = fuel_flow / fuel[index];
- react[index] = value * f + (1.0f - f) * react[index];
- CLAMP(react[index], 0.0f, value);
- }
- }
+ int absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE);
+ float dens_old = density[index];
+ // float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */
+ float dens_flow = (sfs->type == MOD_SMOKE_FLOW_TYPE_FIRE) ? 0.0f : emission_value * sfs->density;
+ float fuel_flow = emission_value * sfs->fuel_amount;
+ /* add heat */
+ if (heat && emission_value > 0.0f) {
+ heat[index] = ADD_IF_LOWER(heat[index], sfs->temp);
+ }
+ /* absolute */
+ if (absolute_flow) {
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) {
+ if (dens_flow > density[index])
+ density[index] = dens_flow;
+ }
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && fuel_flow) {
+ if (fuel_flow > fuel[index])
+ fuel[index] = fuel_flow;
+ }
+ }
+ /* additive */
+ else {
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) {
+ density[index] += dens_flow;
+ CLAMP(density[index], 0.0f, 1.0f);
+ }
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && sfs->fuel_amount) {
+ fuel[index] += fuel_flow;
+ CLAMP(fuel[index], 0.0f, 10.0f);
+ }
+ }
+
+ /* set color */
+ if (color_r && dens_flow) {
+ float total_dens = density[index] / (dens_old + dens_flow);
+ color_r[index] = (color_r[index] + sfs->color[0] * dens_flow) * total_dens;
+ color_g[index] = (color_g[index] + sfs->color[1] * dens_flow) * total_dens;
+ color_b[index] = (color_b[index] + sfs->color[2] * dens_flow) * total_dens;
+ }
+
+ /* set fire reaction coordinate */
+ if (fuel && fuel[index] > FLT_EPSILON) {
+ /* instead of using 1.0 for all new fuel add slight falloff
+ * to reduce flow blockiness */
+ float value = 1.0f - pow2f(1.0f - emission_value);
+
+ if (value > react[index]) {
+ float f = fuel_flow / fuel[index];
+ react[index] = value * f + (1.0f - f) * react[index];
+ CLAMP(react[index], 0.0f, value);
+ }
+ }
}
static void update_flowsfluids(
- Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt)
+ Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt)
{
- Object **flowobjs = NULL;
- EmissionMap *emaps = NULL;
- unsigned int numflowobj = 0;
- unsigned int flowIndex;
- int new_shift[3] = {0};
- int active_fields = sds->active_fields;
-
- /* calculate domain shift for current frame if using adaptive domain */
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- int total_shift[3];
- float frame_shift_f[3];
- float ob_loc[3] = {0};
-
- mul_m4_v3(ob->obmat, ob_loc);
-
- sub_v3_v3v3(frame_shift_f, ob_loc, sds->prev_loc);
- copy_v3_v3(sds->prev_loc, ob_loc);
- /* convert global space shift to local "cell" space */
- mul_mat3_m4_v3(sds->imat, frame_shift_f);
- frame_shift_f[0] = frame_shift_f[0] / sds->cell_size[0];
- frame_shift_f[1] = frame_shift_f[1] / sds->cell_size[1];
- frame_shift_f[2] = frame_shift_f[2] / sds->cell_size[2];
- /* add to total shift */
- add_v3_v3(sds->shift_f, frame_shift_f);
- /* convert to integer */
- total_shift[0] = (int)(floorf(sds->shift_f[0]));
- total_shift[1] = (int)(floorf(sds->shift_f[1]));
- total_shift[2] = (int)(floorf(sds->shift_f[2]));
- sub_v3_v3v3_int(new_shift, total_shift, sds->shift);
- copy_v3_v3_int(sds->shift, total_shift);
-
- /* calculate new domain boundary points so that smoke doesn't slide on sub-cell movement */
- sds->p0[0] = sds->dp0[0] - sds->cell_size[0] * (sds->shift_f[0] - total_shift[0] - 0.5f);
- sds->p0[1] = sds->dp0[1] - sds->cell_size[1] * (sds->shift_f[1] - total_shift[1] - 0.5f);
- sds->p0[2] = sds->dp0[2] - sds->cell_size[2] * (sds->shift_f[2] - total_shift[2] - 0.5f);
- sds->p1[0] = sds->p0[0] + sds->cell_size[0] * sds->base_res[0];
- sds->p1[1] = sds->p0[1] + sds->cell_size[1] * sds->base_res[1];
- sds->p1[2] = sds->p0[2] + sds->cell_size[2] * sds->base_res[2];
- }
-
- flowobjs = BKE_collision_objects_create(depsgraph, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke);
-
- /* init emission maps for each flow */
- emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "smoke_flow_maps");
-
- /* Prepare flow emission maps */
- for (flowIndex = 0; flowIndex < numflowobj; flowIndex++)
- {
- Object *collob = flowobjs[flowIndex];
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob, eModifierType_Smoke);
-
- // check for initialized smoke object
- if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow)
- {
- // we got nice flow object
- SmokeFlowSettings *sfs = smd2->flow;
- int subframes = sfs->subframes;
- EmissionMap *em = &emaps[flowIndex];
-
- /* just sample flow directly to emission map if no subframes */
- if (!subframes) {
- if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
- emit_from_particles(collob, sds, sfs, em, depsgraph, scene, dt);
- }
- else {
- emit_from_mesh(collob, sds, sfs, em, dt);
- }
- }
- /* sample subframes */
- else {
-#if 0
- int scene_frame = (int)DEG_get_ctime(depsgraph);
-#endif
- // float scene_subframe = scene->r.subframe; // UNUSED
- int subframe;
- for (subframe = 0; subframe <= subframes; subframe++) {
- EmissionMap em_temp = {NULL};
- float sample_size = 1.0f / (float)(subframes+1);
-#if 0
- float prev_frame_pos = sample_size * (float)(subframe+1);
-#endif
- float sdt = dt * sample_size;
- int hires_multiplier = 1;
-
- if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
- hires_multiplier = sds->amplify + 1;
- }
-
- /* TODO: setting the scene frame no longer works with the new depsgraph. */
-#if 0
- /* set scene frame to match previous frame + subframe
- * or use current frame for last sample */
- if (subframe < subframes) {
- scene->r.cfra = scene_frame - 1;
- scene->r.subframe = prev_frame_pos;
- }
- else {
- scene->r.cfra = scene_frame;
- scene->r.subframe = 0.0f;
- }
-#endif
-
- if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
- /* emit_from_particles() updates timestep internally */
- emit_from_particles(collob, sds, sfs, &em_temp, depsgraph, scene, sdt);
- if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
- hires_multiplier = 1;
- }
- }
- else { /* MOD_SMOKE_FLOW_SOURCE_MESH */
- /* update flow object frame */
- BLI_mutex_lock(&object_update_lock);
- BKE_object_modifier_update_subframe(depsgraph, scene, collob, true, 5, DEG_get_ctime(depsgraph), eModifierType_Smoke);
- BLI_mutex_unlock(&object_update_lock);
-
- /* apply flow */
- emit_from_mesh(collob, sds, sfs, &em_temp, sdt);
- }
-
- /* combine emission maps */
- em_combineMaps(em, &em_temp, hires_multiplier, !(sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE), sample_size);
- em_freeData(&em_temp);
- }
- }
-
- /* update required data fields */
- if (em->total_cells && sfs->type != MOD_SMOKE_FLOW_TYPE_OUTFLOW) {
- /* activate heat field if flow produces any heat */
- if (sfs->temp) {
- active_fields |= SM_ACTIVE_HEAT;
- }
- /* activate fuel field if flow adds any fuel */
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && sfs->fuel_amount) {
- active_fields |= SM_ACTIVE_FIRE;
- }
- /* activate color field if flows add smoke with varying colors */
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE && sfs->density) {
- if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
- copy_v3_v3(sds->active_color, sfs->color);
- active_fields |= SM_ACTIVE_COLOR_SET;
- }
- else if (!equals_v3v3(sds->active_color, sfs->color)) {
- copy_v3_v3(sds->active_color, sfs->color);
- active_fields |= SM_ACTIVE_COLORS;
- }
- }
- }
- }
- }
-
- /* monitor active fields based on domain settings */
- /* if domain has fire, activate new fields if required */
- if (active_fields & SM_ACTIVE_FIRE) {
- /* heat is always needed for fire */
- active_fields |= SM_ACTIVE_HEAT;
- /* also activate colors if domain smoke color differs from active color */
- if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
- copy_v3_v3(sds->active_color, sds->flame_smoke_color);
- active_fields |= SM_ACTIVE_COLOR_SET;
- }
- else if (!equals_v3v3(sds->active_color, sds->flame_smoke_color)) {
- copy_v3_v3(sds->active_color, sds->flame_smoke_color);
- active_fields |= SM_ACTIVE_COLORS;
- }
- }
-
- /* Adjust domain size if needed */
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- adjustDomainResolution(sds, new_shift, emaps, numflowobj, dt);
- }
-
- /* Initialize new data fields if any */
- if (active_fields & SM_ACTIVE_HEAT) {
- smoke_ensure_heat(sds->fluid);
- }
- if (active_fields & SM_ACTIVE_FIRE) {
- smoke_ensure_fire(sds->fluid, sds->wt);
- }
- if (active_fields & SM_ACTIVE_COLORS) {
- /* initialize all smoke with "active_color" */
- smoke_ensure_colors(sds->fluid, sds->wt, sds->active_color[0], sds->active_color[1], sds->active_color[2]);
- }
- sds->active_fields = active_fields;
-
- /* Apply emission data */
- if (sds->fluid) {
- for (flowIndex = 0; flowIndex < numflowobj; flowIndex++)
- {
- Object *collob = flowobjs[flowIndex];
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob, eModifierType_Smoke);
-
- // check for initialized smoke object
- if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow)
- {
- // we got nice flow object
- SmokeFlowSettings *sfs = smd2->flow;
- EmissionMap *em = &emaps[flowIndex];
-
- float *density = smoke_get_density(sds->fluid);
- float *color_r = smoke_get_color_r(sds->fluid);
- float *color_g = smoke_get_color_g(sds->fluid);
- float *color_b = smoke_get_color_b(sds->fluid);
- float *fuel = smoke_get_fuel(sds->fluid);
- float *react = smoke_get_react(sds->fluid);
- float *bigdensity = smoke_turbulence_get_density(sds->wt);
- float *bigfuel = smoke_turbulence_get_fuel(sds->wt);
- float *bigreact = smoke_turbulence_get_react(sds->wt);
- float *bigcolor_r = smoke_turbulence_get_color_r(sds->wt);
- float *bigcolor_g = smoke_turbulence_get_color_g(sds->wt);
- float *bigcolor_b = smoke_turbulence_get_color_b(sds->wt);
- float *heat = smoke_get_heat(sds->fluid);
- float *velocity_x = smoke_get_velocity_x(sds->fluid);
- float *velocity_y = smoke_get_velocity_y(sds->fluid);
- float *velocity_z = smoke_get_velocity_z(sds->fluid);
- //unsigned char *obstacle = smoke_get_obstacle(sds->fluid);
- // DG TODO UNUSED unsigned char *obstacleAnim = smoke_get_obstacle_anim(sds->fluid);
- int bigres[3];
- float *velocity_map = em->velocity;
- float *emission_map = em->influence;
- float *emission_map_high = em->influence_high;
-
- int ii, jj, kk, gx, gy, gz, ex, ey, ez, dx, dy, dz, block_size;
- size_t e_index, d_index, index_big;
-
- // loop through every emission map cell
- for (gx = em->min[0]; gx < em->max[0]; gx++)
- for (gy = em->min[1]; gy < em->max[1]; gy++)
- for (gz = em->min[2]; gz < em->max[2]; gz++)
- {
- /* get emission map index */
- ex = gx - em->min[0];
- ey = gy - em->min[1];
- ez = gz - em->min[2];
- e_index = smoke_get_index(ex, em->res[0], ey, em->res[1], ez);
-
- /* get domain index */
- dx = gx - sds->res_min[0];
- dy = gy - sds->res_min[1];
- dz = gz - sds->res_min[2];
- d_index = smoke_get_index(dx, sds->res[0], dy, sds->res[1], dz);
- /* make sure emission cell is inside the new domain boundary */
- if (dx < 0 || dy < 0 || dz < 0 || dx >= sds->res[0] || dy >= sds->res[1] || dz >= sds->res[2]) continue;
-
- if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow
- apply_outflow_fields(d_index, density, heat, fuel, react, color_r, color_g, color_b);
- }
- else { // inflow
- apply_inflow_fields(sfs, emission_map[e_index], d_index, density, heat, fuel, react, color_r, color_g, color_b);
-
- /* initial velocity */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
- velocity_x[d_index] = ADD_IF_LOWER(velocity_x[d_index], velocity_map[e_index * 3]);
- velocity_y[d_index] = ADD_IF_LOWER(velocity_y[d_index], velocity_map[e_index * 3 + 1]);
- velocity_z[d_index] = ADD_IF_LOWER(velocity_z[d_index], velocity_map[e_index * 3 + 2]);
- }
- }
-
- /* loop through high res blocks if high res enabled */
- if (bigdensity) {
- // neighbor cell emission densities (for high resolution smoke smooth interpolation)
- float c000, c001, c010, c011, c100, c101, c110, c111;
-
- smoke_turbulence_get_res(sds->wt, bigres);
- block_size = sds->amplify + 1; // high res block size
-
- c000 = (ex > 0 && ey > 0 && ez > 0) ? emission_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez - 1)] : 0;
- c001 = (ex > 0 && ey > 0) ? emission_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez)] : 0;
- c010 = (ex > 0 && ez > 0) ? emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez - 1)] : 0;
- c011 = (ex > 0) ? emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez)] : 0;
-
- c100 = (ey > 0 && ez > 0) ? emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez - 1)] : 0;
- c101 = (ey > 0) ? emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez)] : 0;
- c110 = (ez > 0) ? emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez - 1)] : 0;
- c111 = emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez)]; // this cell
-
- for (ii = 0; ii < block_size; ii++)
- for (jj = 0; jj < block_size; jj++)
- for (kk = 0; kk < block_size; kk++)
- {
-
- float fx, fy, fz, interpolated_value;
- int shift_x = 0, shift_y = 0, shift_z = 0;
-
-
- /* Use full sample emission map if enabled and available */
- if ((sds->highres_sampling == SM_HRES_FULLSAMPLE) && emission_map_high) {
- interpolated_value = emission_map_high[smoke_get_index(ex * block_size + ii, em->res[0] * block_size, ey * block_size + jj, em->res[1] * block_size, ez * block_size + kk)]; // this cell
- }
- else if (sds->highres_sampling == SM_HRES_NEAREST) {
- /* without interpolation use same low resolution
- * block value for all hi-res blocks */
- interpolated_value = c111;
- }
- /* Fall back to interpolated */
- else
- {
- /* get relative block position
- * for interpolation smoothing */
- fx = (float)ii / block_size + 0.5f / block_size;
- fy = (float)jj / block_size + 0.5f / block_size;
- fz = (float)kk / block_size + 0.5f / block_size;
-
- /* calculate trilinear interpolation */
- interpolated_value = c000 * (1 - fx) * (1 - fy) * (1 - fz) +
- c100 * fx * (1 - fy) * (1 - fz) +
- c010 * (1 - fx) * fy * (1 - fz) +
- c001 * (1 - fx) * (1 - fy) * fz +
- c101 * fx * (1 - fy) * fz +
- c011 * (1 - fx) * fy * fz +
- c110 * fx * fy * (1 - fz) +
- c111 * fx * fy * fz;
-
-
- /* add some contrast / sharpness
- * depending on hi-res block size */
- interpolated_value = (interpolated_value - 0.4f) * (block_size / 2) + 0.4f;
- CLAMP(interpolated_value, 0.0f, 1.0f);
-
- /* shift smoke block index
- * (because pixel center is actually
- * in halfway of the low res block) */
- shift_x = (dx < 1) ? 0 : block_size / 2;
- shift_y = (dy < 1) ? 0 : block_size / 2;
- shift_z = (dz < 1) ? 0 : block_size / 2;
- }
-
- /* get shifted index for current high resolution block */
- index_big = smoke_get_index(block_size * dx + ii - shift_x, bigres[0], block_size * dy + jj - shift_y, bigres[1], block_size * dz + kk - shift_z);
-
- if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow
- if (interpolated_value) {
- apply_outflow_fields(index_big, bigdensity, NULL, bigfuel, bigreact, bigcolor_r, bigcolor_g, bigcolor_b);
- }
- }
- else { // inflow
- apply_inflow_fields(sfs, interpolated_value, index_big, bigdensity, NULL, bigfuel, bigreact, bigcolor_r, bigcolor_g, bigcolor_b);
- }
- } // hires loop
- } // bigdensity
- } // low res loop
-
- // free emission maps
- em_freeData(em);
-
- } // end emission
- }
- }
-
- BKE_collision_objects_free(flowobjs);
- if (emaps)
- MEM_freeN(emaps);
+ Object **flowobjs = NULL;
+ EmissionMap *emaps = NULL;
+ unsigned int numflowobj = 0;
+ unsigned int flowIndex;
+ int new_shift[3] = {0};
+ int active_fields = sds->active_fields;
+
+ /* calculate domain shift for current frame if using adaptive domain */
+ if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ int total_shift[3];
+ float frame_shift_f[3];
+ float ob_loc[3] = {0};
+
+ mul_m4_v3(ob->obmat, ob_loc);
+
+ sub_v3_v3v3(frame_shift_f, ob_loc, sds->prev_loc);
+ copy_v3_v3(sds->prev_loc, ob_loc);
+ /* convert global space shift to local "cell" space */
+ mul_mat3_m4_v3(sds->imat, frame_shift_f);
+ frame_shift_f[0] = frame_shift_f[0] / sds->cell_size[0];
+ frame_shift_f[1] = frame_shift_f[1] / sds->cell_size[1];
+ frame_shift_f[2] = frame_shift_f[2] / sds->cell_size[2];
+ /* add to total shift */
+ add_v3_v3(sds->shift_f, frame_shift_f);
+ /* convert to integer */
+ total_shift[0] = (int)(floorf(sds->shift_f[0]));
+ total_shift[1] = (int)(floorf(sds->shift_f[1]));
+ total_shift[2] = (int)(floorf(sds->shift_f[2]));
+ sub_v3_v3v3_int(new_shift, total_shift, sds->shift);
+ copy_v3_v3_int(sds->shift, total_shift);
+
+ /* calculate new domain boundary points so that smoke doesn't slide on sub-cell movement */
+ sds->p0[0] = sds->dp0[0] - sds->cell_size[0] * (sds->shift_f[0] - total_shift[0] - 0.5f);
+ sds->p0[1] = sds->dp0[1] - sds->cell_size[1] * (sds->shift_f[1] - total_shift[1] - 0.5f);
+ sds->p0[2] = sds->dp0[2] - sds->cell_size[2] * (sds->shift_f[2] - total_shift[2] - 0.5f);
+ sds->p1[0] = sds->p0[0] + sds->cell_size[0] * sds->base_res[0];
+ sds->p1[1] = sds->p0[1] + sds->cell_size[1] * sds->base_res[1];
+ sds->p1[2] = sds->p0[2] + sds->cell_size[2] * sds->base_res[2];
+ }
+
+ flowobjs = BKE_collision_objects_create(
+ depsgraph, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke);
+
+ /* init emission maps for each flow */
+ emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "smoke_flow_maps");
+
+ /* Prepare flow emission maps */
+ for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) {
+ Object *collob = flowobjs[flowIndex];
+ SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob,
+ eModifierType_Smoke);
+
+ // check for initialized smoke object
+ if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
+ // we got nice flow object
+ SmokeFlowSettings *sfs = smd2->flow;
+ int subframes = sfs->subframes;
+ EmissionMap *em = &emaps[flowIndex];
+
+ /* just sample flow directly to emission map if no subframes */
+ if (!subframes) {
+ if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
+ emit_from_particles(collob, sds, sfs, em, depsgraph, scene, dt);
+ }
+ else {
+ emit_from_mesh(collob, sds, sfs, em, dt);
+ }
+ }
+ /* sample subframes */
+ else {
+# if 0
+ int scene_frame = (int)DEG_get_ctime(depsgraph);
+# endif
+ // float scene_subframe = scene->r.subframe; // UNUSED
+ int subframe;
+ for (subframe = 0; subframe <= subframes; subframe++) {
+ EmissionMap em_temp = {NULL};
+ float sample_size = 1.0f / (float)(subframes + 1);
+# if 0
+ float prev_frame_pos = sample_size * (float)(subframe+1);
+# endif
+ float sdt = dt * sample_size;
+ int hires_multiplier = 1;
+
+ if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
+ hires_multiplier = sds->amplify + 1;
+ }
+
+ /* TODO: setting the scene frame no longer works with the new depsgraph. */
+# if 0
+ /* set scene frame to match previous frame + subframe
+ * or use current frame for last sample */
+ if (subframe < subframes) {
+ scene->r.cfra = scene_frame - 1;
+ scene->r.subframe = prev_frame_pos;
+ }
+ else {
+ scene->r.cfra = scene_frame;
+ scene->r.subframe = 0.0f;
+ }
+# endif
+
+ if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
+ /* emit_from_particles() updates timestep internally */
+ emit_from_particles(collob, sds, sfs, &em_temp, depsgraph, scene, sdt);
+ if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
+ hires_multiplier = 1;
+ }
+ }
+ else { /* MOD_SMOKE_FLOW_SOURCE_MESH */
+ /* update flow object frame */
+ BLI_mutex_lock(&object_update_lock);
+ BKE_object_modifier_update_subframe(
+ depsgraph, scene, collob, true, 5, DEG_get_ctime(depsgraph), eModifierType_Smoke);
+ BLI_mutex_unlock(&object_update_lock);
+
+ /* apply flow */
+ emit_from_mesh(collob, sds, sfs, &em_temp, sdt);
+ }
+
+ /* combine emission maps */
+ em_combineMaps(em,
+ &em_temp,
+ hires_multiplier,
+ !(sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE),
+ sample_size);
+ em_freeData(&em_temp);
+ }
+ }
+
+ /* update required data fields */
+ if (em->total_cells && sfs->type != MOD_SMOKE_FLOW_TYPE_OUTFLOW) {
+ /* activate heat field if flow produces any heat */
+ if (sfs->temp) {
+ active_fields |= SM_ACTIVE_HEAT;
+ }
+ /* activate fuel field if flow adds any fuel */
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && sfs->fuel_amount) {
+ active_fields |= SM_ACTIVE_FIRE;
+ }
+ /* activate color field if flows add smoke with varying colors */
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE && sfs->density) {
+ if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
+ copy_v3_v3(sds->active_color, sfs->color);
+ active_fields |= SM_ACTIVE_COLOR_SET;
+ }
+ else if (!equals_v3v3(sds->active_color, sfs->color)) {
+ copy_v3_v3(sds->active_color, sfs->color);
+ active_fields |= SM_ACTIVE_COLORS;
+ }
+ }
+ }
+ }
+ }
+
+ /* monitor active fields based on domain settings */
+ /* if domain has fire, activate new fields if required */
+ if (active_fields & SM_ACTIVE_FIRE) {
+ /* heat is always needed for fire */
+ active_fields |= SM_ACTIVE_HEAT;
+ /* also activate colors if domain smoke color differs from active color */
+ if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
+ copy_v3_v3(sds->active_color, sds->flame_smoke_color);
+ active_fields |= SM_ACTIVE_COLOR_SET;
+ }
+ else if (!equals_v3v3(sds->active_color, sds->flame_smoke_color)) {
+ copy_v3_v3(sds->active_color, sds->flame_smoke_color);
+ active_fields |= SM_ACTIVE_COLORS;
+ }
+ }
+
+ /* Adjust domain size if needed */
+ if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ adjustDomainResolution(sds, new_shift, emaps, numflowobj, dt);
+ }
+
+ /* Initialize new data fields if any */
+ if (active_fields & SM_ACTIVE_HEAT) {
+ smoke_ensure_heat(sds->fluid);
+ }
+ if (active_fields & SM_ACTIVE_FIRE) {
+ smoke_ensure_fire(sds->fluid, sds->wt);
+ }
+ if (active_fields & SM_ACTIVE_COLORS) {
+ /* initialize all smoke with "active_color" */
+ smoke_ensure_colors(
+ sds->fluid, sds->wt, sds->active_color[0], sds->active_color[1], sds->active_color[2]);
+ }
+ sds->active_fields = active_fields;
+
+ /* Apply emission data */
+ if (sds->fluid) {
+ for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) {
+ Object *collob = flowobjs[flowIndex];
+ SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob,
+ eModifierType_Smoke);
+
+ // check for initialized smoke object
+ if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
+ // we got nice flow object
+ SmokeFlowSettings *sfs = smd2->flow;
+ EmissionMap *em = &emaps[flowIndex];
+
+ float *density = smoke_get_density(sds->fluid);
+ float *color_r = smoke_get_color_r(sds->fluid);
+ float *color_g = smoke_get_color_g(sds->fluid);
+ float *color_b = smoke_get_color_b(sds->fluid);
+ float *fuel = smoke_get_fuel(sds->fluid);
+ float *react = smoke_get_react(sds->fluid);
+ float *bigdensity = smoke_turbulence_get_density(sds->wt);
+ float *bigfuel = smoke_turbulence_get_fuel(sds->wt);
+ float *bigreact = smoke_turbulence_get_react(sds->wt);
+ float *bigcolor_r = smoke_turbulence_get_color_r(sds->wt);
+ float *bigcolor_g = smoke_turbulence_get_color_g(sds->wt);
+ float *bigcolor_b = smoke_turbulence_get_color_b(sds->wt);
+ float *heat = smoke_get_heat(sds->fluid);
+ float *velocity_x = smoke_get_velocity_x(sds->fluid);
+ float *velocity_y = smoke_get_velocity_y(sds->fluid);
+ float *velocity_z = smoke_get_velocity_z(sds->fluid);
+ //unsigned char *obstacle = smoke_get_obstacle(sds->fluid);
+ // DG TODO UNUSED unsigned char *obstacleAnim = smoke_get_obstacle_anim(sds->fluid);
+ int bigres[3];
+ float *velocity_map = em->velocity;
+ float *emission_map = em->influence;
+ float *emission_map_high = em->influence_high;
+
+ int ii, jj, kk, gx, gy, gz, ex, ey, ez, dx, dy, dz, block_size;
+ size_t e_index, d_index, index_big;
+
+ // loop through every emission map cell
+ for (gx = em->min[0]; gx < em->max[0]; gx++)
+ for (gy = em->min[1]; gy < em->max[1]; gy++)
+ for (gz = em->min[2]; gz < em->max[2]; gz++) {
+ /* get emission map index */
+ ex = gx - em->min[0];
+ ey = gy - em->min[1];
+ ez = gz - em->min[2];
+ e_index = smoke_get_index(ex, em->res[0], ey, em->res[1], ez);
+
+ /* get domain index */
+ dx = gx - sds->res_min[0];
+ dy = gy - sds->res_min[1];
+ dz = gz - sds->res_min[2];
+ d_index = smoke_get_index(dx, sds->res[0], dy, sds->res[1], dz);
+ /* make sure emission cell is inside the new domain boundary */
+ if (dx < 0 || dy < 0 || dz < 0 || dx >= sds->res[0] || dy >= sds->res[1] ||
+ dz >= sds->res[2])
+ continue;
+
+ if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow
+ apply_outflow_fields(
+ d_index, density, heat, fuel, react, color_r, color_g, color_b);
+ }
+ else { // inflow
+ apply_inflow_fields(sfs,
+ emission_map[e_index],
+ d_index,
+ density,
+ heat,
+ fuel,
+ react,
+ color_r,
+ color_g,
+ color_b);
+
+ /* initial velocity */
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
+ velocity_x[d_index] = ADD_IF_LOWER(velocity_x[d_index],
+ velocity_map[e_index * 3]);
+ velocity_y[d_index] = ADD_IF_LOWER(velocity_y[d_index],
+ velocity_map[e_index * 3 + 1]);
+ velocity_z[d_index] = ADD_IF_LOWER(velocity_z[d_index],
+ velocity_map[e_index * 3 + 2]);
+ }
+ }
+
+ /* loop through high res blocks if high res enabled */
+ if (bigdensity) {
+ // neighbor cell emission densities (for high resolution smoke smooth interpolation)
+ float c000, c001, c010, c011, c100, c101, c110, c111;
+
+ smoke_turbulence_get_res(sds->wt, bigres);
+ block_size = sds->amplify + 1; // high res block size
+
+ c000 = (ex > 0 && ey > 0 && ez > 0) ?
+ emission_map[smoke_get_index(
+ ex - 1, em->res[0], ey - 1, em->res[1], ez - 1)] :
+ 0;
+ c001 =
+ (ex > 0 && ey > 0) ?
+ emission_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez)] :
+ 0;
+ c010 =
+ (ex > 0 && ez > 0) ?
+ emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez - 1)] :
+ 0;
+ c011 = (ex > 0) ?
+ emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez)] :
+ 0;
+
+ c100 =
+ (ey > 0 && ez > 0) ?
+ emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez - 1)] :
+ 0;
+ c101 = (ey > 0) ?
+ emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez)] :
+ 0;
+ c110 = (ez > 0) ?
+ emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez - 1)] :
+ 0;
+ c111 = emission_map[smoke_get_index(
+ ex, em->res[0], ey, em->res[1], ez)]; // this cell
+
+ for (ii = 0; ii < block_size; ii++)
+ for (jj = 0; jj < block_size; jj++)
+ for (kk = 0; kk < block_size; kk++) {
+
+ float fx, fy, fz, interpolated_value;
+ int shift_x = 0, shift_y = 0, shift_z = 0;
+
+ /* Use full sample emission map if enabled and available */
+ if ((sds->highres_sampling == SM_HRES_FULLSAMPLE) && emission_map_high) {
+ interpolated_value =
+ emission_map_high[smoke_get_index(ex * block_size + ii,
+ em->res[0] * block_size,
+ ey * block_size + jj,
+ em->res[1] * block_size,
+ ez * block_size + kk)]; // this cell
+ }
+ else if (sds->highres_sampling == SM_HRES_NEAREST) {
+ /* without interpolation use same low resolution
+ * block value for all hi-res blocks */
+ interpolated_value = c111;
+ }
+ /* Fall back to interpolated */
+ else {
+ /* get relative block position
+ * for interpolation smoothing */
+ fx = (float)ii / block_size + 0.5f / block_size;
+ fy = (float)jj / block_size + 0.5f / block_size;
+ fz = (float)kk / block_size + 0.5f / block_size;
+
+ /* calculate trilinear interpolation */
+ interpolated_value = c000 * (1 - fx) * (1 - fy) * (1 - fz) +
+ c100 * fx * (1 - fy) * (1 - fz) +
+ c010 * (1 - fx) * fy * (1 - fz) +
+ c001 * (1 - fx) * (1 - fy) * fz +
+ c101 * fx * (1 - fy) * fz +
+ c011 * (1 - fx) * fy * fz +
+ c110 * fx * fy * (1 - fz) + c111 * fx * fy * fz;
+
+ /* add some contrast / sharpness
+ * depending on hi-res block size */
+ interpolated_value = (interpolated_value - 0.4f) * (block_size / 2) + 0.4f;
+ CLAMP(interpolated_value, 0.0f, 1.0f);
+
+ /* shift smoke block index
+ * (because pixel center is actually
+ * in halfway of the low res block) */
+ shift_x = (dx < 1) ? 0 : block_size / 2;
+ shift_y = (dy < 1) ? 0 : block_size / 2;
+ shift_z = (dz < 1) ? 0 : block_size / 2;
+ }
+
+ /* get shifted index for current high resolution block */
+ index_big = smoke_get_index(block_size * dx + ii - shift_x,
+ bigres[0],
+ block_size * dy + jj - shift_y,
+ bigres[1],
+ block_size * dz + kk - shift_z);
+
+ if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow
+ if (interpolated_value) {
+ apply_outflow_fields(index_big,
+ bigdensity,
+ NULL,
+ bigfuel,
+ bigreact,
+ bigcolor_r,
+ bigcolor_g,
+ bigcolor_b);
+ }
+ }
+ else { // inflow
+ apply_inflow_fields(sfs,
+ interpolated_value,
+ index_big,
+ bigdensity,
+ NULL,
+ bigfuel,
+ bigreact,
+ bigcolor_r,
+ bigcolor_g,
+ bigcolor_b);
+ }
+ } // hires loop
+ } // bigdensity
+ } // low res loop
+
+ // free emission maps
+ em_freeData(em);
+
+ } // end emission
+ }
+ }
+
+ BKE_collision_objects_free(flowobjs);
+ if (emaps)
+ MEM_freeN(emaps);
}
typedef struct UpdateEffectorsData {
- Scene *scene;
- SmokeDomainSettings *sds;
- ListBase *effectors;
-
- float *density;
- float *fuel;
- float *force_x;
- float *force_y;
- float *force_z;
- float *velocity_x;
- float *velocity_y;
- float *velocity_z;
- unsigned char *obstacle;
+ Scene *scene;
+ SmokeDomainSettings *sds;
+ ListBase *effectors;
+
+ float *density;
+ float *fuel;
+ float *force_x;
+ float *force_y;
+ float *force_z;
+ float *velocity_x;
+ float *velocity_y;
+ float *velocity_z;
+ unsigned char *obstacle;
} UpdateEffectorsData;
-static void update_effectors_task_cb(
- void *__restrict userdata,
- const int x,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void update_effectors_task_cb(void *__restrict userdata,
+ const int x,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- UpdateEffectorsData *data = userdata;
- SmokeDomainSettings *sds = data->sds;
-
- for (int y = 0; y < sds->res[1]; y++) {
- for (int z = 0; z < sds->res[2]; z++)
- {
- EffectedPoint epoint;
- float mag;
- float voxelCenter[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0};
- const unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
-
- if (((data->fuel ? MAX2(data->density[index], data->fuel[index]) : data->density[index]) < FLT_EPSILON) ||
- data->obstacle[index])
- {
- continue;
- }
-
- vel[0] = data->velocity_x[index];
- vel[1] = data->velocity_y[index];
- vel[2] = data->velocity_z[index];
-
- /* convert vel to global space */
- mag = len_v3(vel);
- mul_mat3_m4_v3(sds->obmat, vel);
- normalize_v3(vel);
- mul_v3_fl(vel, mag);
-
- voxelCenter[0] = sds->p0[0] + sds->cell_size[0] * ((float)(x + sds->res_min[0]) + 0.5f);
- voxelCenter[1] = sds->p0[1] + sds->cell_size[1] * ((float)(y + sds->res_min[1]) + 0.5f);
- voxelCenter[2] = sds->p0[2] + sds->cell_size[2] * ((float)(z + sds->res_min[2]) + 0.5f);
- mul_m4_v3(sds->obmat, voxelCenter);
-
- pd_point_from_loc(data->scene, voxelCenter, vel, index, &epoint);
- BKE_effectors_apply(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
-
- /* convert retvel to local space */
- mag = len_v3(retvel);
- mul_mat3_m4_v3(sds->imat, retvel);
- normalize_v3(retvel);
- mul_v3_fl(retvel, mag);
-
- // TODO dg - do in force!
- data->force_x[index] = min_ff(max_ff(-1.0f, retvel[0] * 0.2f), 1.0f);
- data->force_y[index] = min_ff(max_ff(-1.0f, retvel[1] * 0.2f), 1.0f);
- data->force_z[index] = min_ff(max_ff(-1.0f, retvel[2] * 0.2f), 1.0f);
- }
- }
+ UpdateEffectorsData *data = userdata;
+ SmokeDomainSettings *sds = data->sds;
+
+ for (int y = 0; y < sds->res[1]; y++) {
+ for (int z = 0; z < sds->res[2]; z++) {
+ EffectedPoint epoint;
+ float mag;
+ float voxelCenter[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0};
+ const unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
+
+ if (((data->fuel ? MAX2(data->density[index], data->fuel[index]) : data->density[index]) <
+ FLT_EPSILON) ||
+ data->obstacle[index]) {
+ continue;
+ }
+
+ vel[0] = data->velocity_x[index];
+ vel[1] = data->velocity_y[index];
+ vel[2] = data->velocity_z[index];
+
+ /* convert vel to global space */
+ mag = len_v3(vel);
+ mul_mat3_m4_v3(sds->obmat, vel);
+ normalize_v3(vel);
+ mul_v3_fl(vel, mag);
+
+ voxelCenter[0] = sds->p0[0] + sds->cell_size[0] * ((float)(x + sds->res_min[0]) + 0.5f);
+ voxelCenter[1] = sds->p0[1] + sds->cell_size[1] * ((float)(y + sds->res_min[1]) + 0.5f);
+ voxelCenter[2] = sds->p0[2] + sds->cell_size[2] * ((float)(z + sds->res_min[2]) + 0.5f);
+ mul_m4_v3(sds->obmat, voxelCenter);
+
+ pd_point_from_loc(data->scene, voxelCenter, vel, index, &epoint);
+ BKE_effectors_apply(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
+
+ /* convert retvel to local space */
+ mag = len_v3(retvel);
+ mul_mat3_m4_v3(sds->imat, retvel);
+ normalize_v3(retvel);
+ mul_v3_fl(retvel, mag);
+
+ // TODO dg - do in force!
+ data->force_x[index] = min_ff(max_ff(-1.0f, retvel[0] * 0.2f), 1.0f);
+ data->force_y[index] = min_ff(max_ff(-1.0f, retvel[1] * 0.2f), 1.0f);
+ data->force_z[index] = min_ff(max_ff(-1.0f, retvel[2] * 0.2f), 1.0f);
+ }
+ }
}
-static void update_effectors(Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt))
+static void update_effectors(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt))
{
- ListBase *effectors;
- /* make sure smoke flow influence is 0.0f */
- sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
- effectors = BKE_effectors_create(depsgraph, ob, NULL, sds->effector_weights);
-
- if (effectors) {
- // precalculate wind forces
- UpdateEffectorsData data;
- data.scene = scene;
- data.sds = sds;
- data.effectors = effectors;
- data.density = smoke_get_density(sds->fluid);
- data.fuel = smoke_get_fuel(sds->fluid);
- data.force_x = smoke_get_force_x(sds->fluid);
- data.force_y = smoke_get_force_y(sds->fluid);
- data.force_z = smoke_get_force_z(sds->fluid);
- data.velocity_x = smoke_get_velocity_x(sds->fluid);
- data.velocity_y = smoke_get_velocity_y(sds->fluid);
- data.velocity_z = smoke_get_velocity_z(sds->fluid);
- data.obstacle = smoke_get_obstacle(sds->fluid);
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(0, sds->res[0],
- &data,
- update_effectors_task_cb,
- &settings);
- }
-
- BKE_effectors_free(effectors);
+ ListBase *effectors;
+ /* make sure smoke flow influence is 0.0f */
+ sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
+ effectors = BKE_effectors_create(depsgraph, ob, NULL, sds->effector_weights);
+
+ if (effectors) {
+ // precalculate wind forces
+ UpdateEffectorsData data;
+ data.scene = scene;
+ data.sds = sds;
+ data.effectors = effectors;
+ data.density = smoke_get_density(sds->fluid);
+ data.fuel = smoke_get_fuel(sds->fluid);
+ data.force_x = smoke_get_force_x(sds->fluid);
+ data.force_y = smoke_get_force_y(sds->fluid);
+ data.force_z = smoke_get_force_z(sds->fluid);
+ data.velocity_x = smoke_get_velocity_x(sds->fluid);
+ data.velocity_y = smoke_get_velocity_y(sds->fluid);
+ data.velocity_z = smoke_get_velocity_z(sds->fluid);
+ data.obstacle = smoke_get_obstacle(sds->fluid);
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(0, sds->res[0], &data, update_effectors_task_cb, &settings);
+ }
+
+ BKE_effectors_free(effectors);
}
-static void step(
- Depsgraph *depsgraph,
- Scene *scene, Object *ob, SmokeModifierData *smd, Mesh *domain_me, float fps)
+static void step(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ SmokeModifierData *smd,
+ Mesh *domain_me,
+ float fps)
{
- SmokeDomainSettings *sds = smd->domain;
- /* stability values copied from wturbulence.cpp */
- const int maxSubSteps = 25;
- float maxVel;
- // maxVel should be 1.5 (1.5 cell max movement) * dx (cell size)
-
- float dt;
- float maxVelMag = 0.0f;
- int totalSubsteps;
- int substep = 0;
- float dtSubdiv;
- float gravity[3] = {0.0f, 0.0f, -1.0f};
- float gravity_mag;
-
- /* update object state */
- invert_m4_m4(sds->imat, ob->obmat);
- copy_m4_m4(sds->obmat, ob->obmat);
- smoke_set_domain_from_mesh(sds, ob, domain_me, (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) != 0);
-
- /* use global gravity if enabled */
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- copy_v3_v3(gravity, scene->physics_settings.gravity);
- /* map default value to 1.0 */
- mul_v3_fl(gravity, 1.0f / 9.810f);
- }
- /* convert gravity to domain space */
- gravity_mag = len_v3(gravity);
- mul_mat3_m4_v3(sds->imat, gravity);
- normalize_v3(gravity);
- mul_v3_fl(gravity, gravity_mag);
-
- /* adapt timestep for different framerates, dt = 0.1 is at 25fps */
- dt = DT_DEFAULT * (25.0f / fps);
- // maximum timestep/"CFL" constraint: dt < 5.0 *dx / maxVel
- maxVel = (sds->dx * 5.0f);
-
- maxVelMag = sqrtf(maxVelMag) * dt * sds->time_scale;
- totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */
- totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps;
- totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps;
-
- /* Disable substeps for now, since it results in numerical instability */
- totalSubsteps = 1.0f;
-
- dtSubdiv = (float)dt / (float)totalSubsteps;
-
- // printf("totalSubsteps: %d, maxVelMag: %f, dt: %f\n", totalSubsteps, maxVelMag, dt);
-
- for (substep = 0; substep < totalSubsteps; substep++)
- {
- // calc animated obstacle velocities
- update_flowsfluids(depsgraph, scene, ob, sds, dtSubdiv);
- update_obstacles(depsgraph, ob, sds, dtSubdiv, substep, totalSubsteps);
-
- if (sds->total_cells > 1) {
- update_effectors(depsgraph, scene, ob, sds, dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt
- smoke_step(sds->fluid, gravity, dtSubdiv);
- }
- }
+ SmokeDomainSettings *sds = smd->domain;
+ /* stability values copied from wturbulence.cpp */
+ const int maxSubSteps = 25;
+ float maxVel;
+ // maxVel should be 1.5 (1.5 cell max movement) * dx (cell size)
+
+ float dt;
+ float maxVelMag = 0.0f;
+ int totalSubsteps;
+ int substep = 0;
+ float dtSubdiv;
+ float gravity[3] = {0.0f, 0.0f, -1.0f};
+ float gravity_mag;
+
+ /* update object state */
+ invert_m4_m4(sds->imat, ob->obmat);
+ copy_m4_m4(sds->obmat, ob->obmat);
+ smoke_set_domain_from_mesh(sds, ob, domain_me, (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) != 0);
+
+ /* use global gravity if enabled */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ copy_v3_v3(gravity, scene->physics_settings.gravity);
+ /* map default value to 1.0 */
+ mul_v3_fl(gravity, 1.0f / 9.810f);
+ }
+ /* convert gravity to domain space */
+ gravity_mag = len_v3(gravity);
+ mul_mat3_m4_v3(sds->imat, gravity);
+ normalize_v3(gravity);
+ mul_v3_fl(gravity, gravity_mag);
+
+ /* adapt timestep for different framerates, dt = 0.1 is at 25fps */
+ dt = DT_DEFAULT * (25.0f / fps);
+ // maximum timestep/"CFL" constraint: dt < 5.0 *dx / maxVel
+ maxVel = (sds->dx * 5.0f);
+
+ maxVelMag = sqrtf(maxVelMag) * dt * sds->time_scale;
+ totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */
+ totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps;
+ totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps;
+
+ /* Disable substeps for now, since it results in numerical instability */
+ totalSubsteps = 1.0f;
+
+ dtSubdiv = (float)dt / (float)totalSubsteps;
+
+ // printf("totalSubsteps: %d, maxVelMag: %f, dt: %f\n", totalSubsteps, maxVelMag, dt);
+
+ for (substep = 0; substep < totalSubsteps; substep++) {
+ // calc animated obstacle velocities
+ update_flowsfluids(depsgraph, scene, ob, sds, dtSubdiv);
+ update_obstacles(depsgraph, ob, sds, dtSubdiv, substep, totalSubsteps);
+
+ if (sds->total_cells > 1) {
+ update_effectors(
+ depsgraph,
+ scene,
+ ob,
+ sds,
+ dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt
+ smoke_step(sds->fluid, gravity, dtSubdiv);
+ }
+ }
}
static Mesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob)
{
- Mesh *result;
- MVert *mverts;
- MPoly *mpolys;
- MLoop *mloops;
- float min[3];
- float max[3];
- float *co;
- MPoly *mp;
- MLoop *ml;
-
- int num_verts = 8;
- int num_faces = 6;
- int i;
- float ob_loc[3] = {0};
- float ob_cache_loc[3] = {0};
-
- /* dont generate any mesh if there isnt any content */
- if (sds->total_cells <= 1) {
- num_verts = 0;
- num_faces = 0;
- }
-
- result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces);
- mverts = result->mvert;
- mpolys = result->mpoly;
- mloops = result->mloop;
-
- if (num_verts) {
- /* volume bounds */
- madd_v3fl_v3fl_v3fl_v3i(min, sds->p0, sds->cell_size, sds->res_min);
- madd_v3fl_v3fl_v3fl_v3i(max, sds->p0, sds->cell_size, sds->res_max);
-
- /* set vertices */
- /* top slab */
- co = mverts[0].co; co[0] = min[0]; co[1] = min[1]; co[2] = max[2];
- co = mverts[1].co; co[0] = max[0]; co[1] = min[1]; co[2] = max[2];
- co = mverts[2].co; co[0] = max[0]; co[1] = max[1]; co[2] = max[2];
- co = mverts[3].co; co[0] = min[0]; co[1] = max[1]; co[2] = max[2];
- /* bottom slab */
- co = mverts[4].co; co[0] = min[0]; co[1] = min[1]; co[2] = min[2];
- co = mverts[5].co; co[0] = max[0]; co[1] = min[1]; co[2] = min[2];
- co = mverts[6].co; co[0] = max[0]; co[1] = max[1]; co[2] = min[2];
- co = mverts[7].co; co[0] = min[0]; co[1] = max[1]; co[2] = min[2];
-
- /* create faces */
- /* top */
- mp = &mpolys[0]; ml = &mloops[0 * 4]; mp->loopstart = 0 * 4; mp->totloop = 4;
- ml[0].v = 0; ml[1].v = 1; ml[2].v = 2; ml[3].v = 3;
- /* right */
- mp = &mpolys[1]; ml = &mloops[1 * 4]; mp->loopstart = 1 * 4; mp->totloop = 4;
- ml[0].v = 2; ml[1].v = 1; ml[2].v = 5; ml[3].v = 6;
- /* bottom */
- mp = &mpolys[2]; ml = &mloops[2 * 4]; mp->loopstart = 2 * 4; mp->totloop = 4;
- ml[0].v = 7; ml[1].v = 6; ml[2].v = 5; ml[3].v = 4;
- /* left */
- mp = &mpolys[3]; ml = &mloops[3 * 4]; mp->loopstart = 3 * 4; mp->totloop = 4;
- ml[0].v = 0; ml[1].v = 3; ml[2].v = 7; ml[3].v = 4;
- /* front */
- mp = &mpolys[4]; ml = &mloops[4 * 4]; mp->loopstart = 4 * 4; mp->totloop = 4;
- ml[0].v = 3; ml[1].v = 2; ml[2].v = 6; ml[3].v = 7;
- /* back */
- mp = &mpolys[5]; ml = &mloops[5 * 4]; mp->loopstart = 5 * 4; mp->totloop = 4;
- ml[0].v = 1; ml[1].v = 0; ml[2].v = 4; ml[3].v = 5;
-
- /* calculate required shift to match domain's global position
- * it was originally simulated at (if object moves without smoke step) */
- invert_m4_m4(ob->imat, ob->obmat);
- mul_m4_v3(ob->obmat, ob_loc);
- mul_m4_v3(sds->obmat, ob_cache_loc);
- sub_v3_v3v3(sds->obj_shift_f, ob_cache_loc, ob_loc);
- /* convert shift to local space and apply to vertices */
- mul_mat3_m4_v3(ob->imat, sds->obj_shift_f);
- /* apply */
- for (i = 0; i < num_verts; i++) {
- add_v3_v3(mverts[i].co, sds->obj_shift_f);
- }
- }
-
- BKE_mesh_calc_edges(result, false, false);
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
- return result;
+ Mesh *result;
+ MVert *mverts;
+ MPoly *mpolys;
+ MLoop *mloops;
+ float min[3];
+ float max[3];
+ float *co;
+ MPoly *mp;
+ MLoop *ml;
+
+ int num_verts = 8;
+ int num_faces = 6;
+ int i;
+ float ob_loc[3] = {0};
+ float ob_cache_loc[3] = {0};
+
+ /* dont generate any mesh if there isnt any content */
+ if (sds->total_cells <= 1) {
+ num_verts = 0;
+ num_faces = 0;
+ }
+
+ result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces);
+ mverts = result->mvert;
+ mpolys = result->mpoly;
+ mloops = result->mloop;
+
+ if (num_verts) {
+ /* volume bounds */
+ madd_v3fl_v3fl_v3fl_v3i(min, sds->p0, sds->cell_size, sds->res_min);
+ madd_v3fl_v3fl_v3fl_v3i(max, sds->p0, sds->cell_size, sds->res_max);
+
+ /* set vertices */
+ /* top slab */
+ co = mverts[0].co;
+ co[0] = min[0];
+ co[1] = min[1];
+ co[2] = max[2];
+ co = mverts[1].co;
+ co[0] = max[0];
+ co[1] = min[1];
+ co[2] = max[2];
+ co = mverts[2].co;
+ co[0] = max[0];
+ co[1] = max[1];
+ co[2] = max[2];
+ co = mverts[3].co;
+ co[0] = min[0];
+ co[1] = max[1];
+ co[2] = max[2];
+ /* bottom slab */
+ co = mverts[4].co;
+ co[0] = min[0];
+ co[1] = min[1];
+ co[2] = min[2];
+ co = mverts[5].co;
+ co[0] = max[0];
+ co[1] = min[1];
+ co[2] = min[2];
+ co = mverts[6].co;
+ co[0] = max[0];
+ co[1] = max[1];
+ co[2] = min[2];
+ co = mverts[7].co;
+ co[0] = min[0];
+ co[1] = max[1];
+ co[2] = min[2];
+
+ /* create faces */
+ /* top */
+ mp = &mpolys[0];
+ ml = &mloops[0 * 4];
+ mp->loopstart = 0 * 4;
+ mp->totloop = 4;
+ ml[0].v = 0;
+ ml[1].v = 1;
+ ml[2].v = 2;
+ ml[3].v = 3;
+ /* right */
+ mp = &mpolys[1];
+ ml = &mloops[1 * 4];
+ mp->loopstart = 1 * 4;
+ mp->totloop = 4;
+ ml[0].v = 2;
+ ml[1].v = 1;
+ ml[2].v = 5;
+ ml[3].v = 6;
+ /* bottom */
+ mp = &mpolys[2];
+ ml = &mloops[2 * 4];
+ mp->loopstart = 2 * 4;
+ mp->totloop = 4;
+ ml[0].v = 7;
+ ml[1].v = 6;
+ ml[2].v = 5;
+ ml[3].v = 4;
+ /* left */
+ mp = &mpolys[3];
+ ml = &mloops[3 * 4];
+ mp->loopstart = 3 * 4;
+ mp->totloop = 4;
+ ml[0].v = 0;
+ ml[1].v = 3;
+ ml[2].v = 7;
+ ml[3].v = 4;
+ /* front */
+ mp = &mpolys[4];
+ ml = &mloops[4 * 4];
+ mp->loopstart = 4 * 4;
+ mp->totloop = 4;
+ ml[0].v = 3;
+ ml[1].v = 2;
+ ml[2].v = 6;
+ ml[3].v = 7;
+ /* back */
+ mp = &mpolys[5];
+ ml = &mloops[5 * 4];
+ mp->loopstart = 5 * 4;
+ mp->totloop = 4;
+ ml[0].v = 1;
+ ml[1].v = 0;
+ ml[2].v = 4;
+ ml[3].v = 5;
+
+ /* calculate required shift to match domain's global position
+ * it was originally simulated at (if object moves without smoke step) */
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_v3(ob->obmat, ob_loc);
+ mul_m4_v3(sds->obmat, ob_cache_loc);
+ sub_v3_v3v3(sds->obj_shift_f, ob_cache_loc, ob_loc);
+ /* convert shift to local space and apply to vertices */
+ mul_mat3_m4_v3(ob->imat, sds->obj_shift_f);
+ /* apply */
+ for (i = 0; i < num_verts; i++) {
+ add_v3_v3(mverts[i].co, sds->obj_shift_f);
+ }
+ }
+
+ BKE_mesh_calc_edges(result, false, false);
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ return result;
}
static void smokeModifier_process(
- SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
+ SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
{
- const int scene_framenr = (int)DEG_get_ctime(depsgraph);
-
- if ((smd->type & MOD_SMOKE_TYPE_FLOW))
- {
- if (scene_framenr >= smd->time)
- smokeModifier_init(smd, ob, scene_framenr, me);
-
- if (smd->flow->mesh) BKE_id_free(NULL, smd->flow->mesh);
- smd->flow->mesh = BKE_mesh_copy_for_eval(me, false);
-
- if (scene_framenr > smd->time)
- {
- smd->time = scene_framenr;
- }
- else if (scene_framenr < smd->time)
- {
- smd->time = scene_framenr;
- smokeModifier_reset_ex(smd, false);
- }
- }
- else if (smd->type & MOD_SMOKE_TYPE_COLL)
- {
- if (scene_framenr >= smd->time)
- smokeModifier_init(smd, ob, scene_framenr, me);
-
- if (smd->coll)
- {
- if (smd->coll->mesh)
- BKE_id_free(NULL, smd->coll->mesh);
-
- smd->coll->mesh = BKE_mesh_copy_for_eval(me, false);
- }
-
- smd->time = scene_framenr;
- if (scene_framenr < smd->time)
- {
- smokeModifier_reset_ex(smd, false);
- }
- }
- else if (smd->type & MOD_SMOKE_TYPE_DOMAIN)
- {
- SmokeDomainSettings *sds = smd->domain;
- PointCache *cache = NULL;
- PTCacheID pid;
- int startframe, endframe, framenr;
- float timescale;
-
- framenr = scene_framenr;
-
- cache = sds->point_cache[0];
- BKE_ptcache_id_from_smoke(&pid, ob, smd);
- BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
-
- if (!smd->domain->fluid || framenr == startframe)
- {
- BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- smokeModifier_reset_ex(smd, false);
- BKE_ptcache_validate(cache, framenr);
- cache->flag &= ~PTCACHE_REDO_NEEDED;
- }
-
- if (!smd->domain->fluid && (framenr != startframe) && (smd->domain->flags & MOD_SMOKE_FILE_LOAD) == 0 && (cache->flag & PTCACHE_BAKED) == 0)
- return;
-
- smd->domain->flags &= ~MOD_SMOKE_FILE_LOAD;
- CLAMP(framenr, startframe, endframe);
-
- /* If already viewing a pre/after frame, no need to reload */
- if ((smd->time == framenr) && (framenr != scene_framenr))
- return;
-
- if (smokeModifier_init(smd, ob, scene_framenr, me) == 0)
- {
- printf("bad smokeModifier_init\n");
- return;
- }
-
- /* only calculate something when we advanced a single frame */
- /* don't simulate if viewing start frame, but scene frame is not real start frame */
- bool can_simulate = (framenr == (int)smd->time + 1) && (framenr == scene_framenr);
-
- /* try to read from cache */
- if (BKE_ptcache_read(&pid, (float)framenr, can_simulate) == PTCACHE_READ_EXACT) {
- BKE_ptcache_validate(cache, framenr);
- smd->time = framenr;
- return;
- }
-
- if (!can_simulate)
- return;
-
-#ifdef DEBUG_TIME
- double start = PIL_check_seconds_timer();
-#endif
-
- /* if on second frame, write cache for first frame */
- if ((int)smd->time == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) {
- BKE_ptcache_write(&pid, startframe);
- }
-
- // set new time
- smd->time = scene_framenr;
-
- /* do simulation */
-
- // simulate the actual smoke (c++ code in intern/smoke)
- // DG: interesting commenting this line + deactivating loading of noise files
- if (framenr != startframe)
- {
- if (sds->flags & MOD_SMOKE_DISSOLVE) {
- /* low res dissolve */
- smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
- /* high res dissolve */
- if (sds->wt) {
- smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
- }
-
- }
-
- step(depsgraph, scene, ob, smd, me, scene->r.frs_sec / scene->r.frs_sec_base);
- }
-
- // create shadows before writing cache so they get stored
- smoke_calc_transparency(sds, DEG_get_evaluated_view_layer(depsgraph));
-
- if (sds->wt && sds->total_cells > 1) {
- smoke_turbulence_step(sds->wt, sds->fluid);
- }
-
- BKE_ptcache_validate(cache, framenr);
- if (framenr != startframe)
- BKE_ptcache_write(&pid, framenr);
-
-#ifdef DEBUG_TIME
- double end = PIL_check_seconds_timer();
- printf("Frame: %d, Time: %f\n\n", (int)smd->time, (float)(end - start));
-#endif
- }
+ const int scene_framenr = (int)DEG_get_ctime(depsgraph);
+
+ if ((smd->type & MOD_SMOKE_TYPE_FLOW)) {
+ if (scene_framenr >= smd->time)
+ smokeModifier_init(smd, ob, scene_framenr, me);
+
+ if (smd->flow->mesh)
+ BKE_id_free(NULL, smd->flow->mesh);
+ smd->flow->mesh = BKE_mesh_copy_for_eval(me, false);
+
+ if (scene_framenr > smd->time) {
+ smd->time = scene_framenr;
+ }
+ else if (scene_framenr < smd->time) {
+ smd->time = scene_framenr;
+ smokeModifier_reset_ex(smd, false);
+ }
+ }
+ else if (smd->type & MOD_SMOKE_TYPE_COLL) {
+ if (scene_framenr >= smd->time)
+ smokeModifier_init(smd, ob, scene_framenr, me);
+
+ if (smd->coll) {
+ if (smd->coll->mesh)
+ BKE_id_free(NULL, smd->coll->mesh);
+
+ smd->coll->mesh = BKE_mesh_copy_for_eval(me, false);
+ }
+
+ smd->time = scene_framenr;
+ if (scene_framenr < smd->time) {
+ smokeModifier_reset_ex(smd, false);
+ }
+ }
+ else if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
+ SmokeDomainSettings *sds = smd->domain;
+ PointCache *cache = NULL;
+ PTCacheID pid;
+ int startframe, endframe, framenr;
+ float timescale;
+
+ framenr = scene_framenr;
+
+ cache = sds->point_cache[0];
+ BKE_ptcache_id_from_smoke(&pid, ob, smd);
+ BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
+
+ if (!smd->domain->fluid || framenr == startframe) {
+ BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
+ smokeModifier_reset_ex(smd, false);
+ BKE_ptcache_validate(cache, framenr);
+ cache->flag &= ~PTCACHE_REDO_NEEDED;
+ }
+
+ if (!smd->domain->fluid && (framenr != startframe) &&
+ (smd->domain->flags & MOD_SMOKE_FILE_LOAD) == 0 && (cache->flag & PTCACHE_BAKED) == 0)
+ return;
+
+ smd->domain->flags &= ~MOD_SMOKE_FILE_LOAD;
+ CLAMP(framenr, startframe, endframe);
+
+ /* If already viewing a pre/after frame, no need to reload */
+ if ((smd->time == framenr) && (framenr != scene_framenr))
+ return;
+
+ if (smokeModifier_init(smd, ob, scene_framenr, me) == 0) {
+ printf("bad smokeModifier_init\n");
+ return;
+ }
+
+ /* only calculate something when we advanced a single frame */
+ /* don't simulate if viewing start frame, but scene frame is not real start frame */
+ bool can_simulate = (framenr == (int)smd->time + 1) && (framenr == scene_framenr);
+
+ /* try to read from cache */
+ if (BKE_ptcache_read(&pid, (float)framenr, can_simulate) == PTCACHE_READ_EXACT) {
+ BKE_ptcache_validate(cache, framenr);
+ smd->time = framenr;
+ return;
+ }
+
+ if (!can_simulate)
+ return;
+
+# ifdef DEBUG_TIME
+ double start = PIL_check_seconds_timer();
+# endif
+
+ /* if on second frame, write cache for first frame */
+ if ((int)smd->time == startframe &&
+ (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) {
+ BKE_ptcache_write(&pid, startframe);
+ }
+
+ // set new time
+ smd->time = scene_framenr;
+
+ /* do simulation */
+
+ // simulate the actual smoke (c++ code in intern/smoke)
+ // DG: interesting commenting this line + deactivating loading of noise files
+ if (framenr != startframe) {
+ if (sds->flags & MOD_SMOKE_DISSOLVE) {
+ /* low res dissolve */
+ smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
+ /* high res dissolve */
+ if (sds->wt) {
+ smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
+ }
+ }
+
+ step(depsgraph, scene, ob, smd, me, scene->r.frs_sec / scene->r.frs_sec_base);
+ }
+
+ // create shadows before writing cache so they get stored
+ smoke_calc_transparency(sds, DEG_get_evaluated_view_layer(depsgraph));
+
+ if (sds->wt && sds->total_cells > 1) {
+ smoke_turbulence_step(sds->wt, sds->fluid);
+ }
+
+ BKE_ptcache_validate(cache, framenr);
+ if (framenr != startframe)
+ BKE_ptcache_write(&pid, framenr);
+
+# ifdef DEBUG_TIME
+ double end = PIL_check_seconds_timer();
+ printf("Frame: %d, Time: %f\n\n", (int)smd->time, (float)(end - start));
+# endif
+ }
}
struct Mesh *smokeModifier_do(
- SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
+ SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
{
- /* lock so preview render does not read smoke data while it gets modified */
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
- BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
-
- smokeModifier_process(smd, depsgraph, scene, ob, me);
-
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
- BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
-
- /* return generated geometry for adaptive domain */
- Mesh *result;
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain &&
- smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN &&
- smd->domain->base_res[0])
- {
- result = createDomainGeometry(smd->domain, ob);
- }
- else {
- result = BKE_mesh_copy_for_eval(me, false);
- }
- /* XXX This is really not a nice hack, but until root of the problem is understood,
- * this should be an acceptable workaround I think.
- * See T58492 for details on the issue. */
- result->texflag |= ME_AUTOSPACE;
- return result;
+ /* lock so preview render does not read smoke data while it gets modified */
+ if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
+ BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
+
+ smokeModifier_process(smd, depsgraph, scene, ob, me);
+
+ if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
+ BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
+
+ /* return generated geometry for adaptive domain */
+ Mesh *result;
+ if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain &&
+ smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN && smd->domain->base_res[0]) {
+ result = createDomainGeometry(smd->domain, ob);
+ }
+ else {
+ result = BKE_mesh_copy_for_eval(me, false);
+ }
+ /* XXX This is really not a nice hack, but until root of the problem is understood,
+ * this should be an acceptable workaround I think.
+ * See T58492 for details on the issue. */
+ result->texflag |= ME_AUTOSPACE;
+ return result;
}
-static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct)
+static float calc_voxel_transp(
+ float *result, float *input, int res[3], int *pixel, float *tRay, float correct)
{
- const size_t index = smoke_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]);
+ const size_t index = smoke_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]);
- // T_ray *= T_vox
- *tRay *= expf(input[index] * correct);
+ // T_ray *= T_vox
+ *tRay *= expf(input[index] * correct);
- if (result[index] < 0.0f)
- {
- result[index] = *tRay;
- }
+ if (result[index] < 0.0f) {
+ result[index] = *tRay;
+ }
- return *tRay;
+ return *tRay;
}
-static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, float *tRay, bresenham_callback cb, float *result, float *input, int res[3], float correct)
+static void bresenham_linie_3D(int x1,
+ int y1,
+ int z1,
+ int x2,
+ int y2,
+ int z2,
+ float *tRay,
+ bresenham_callback cb,
+ float *result,
+ float *input,
+ int res[3],
+ float correct)
{
- int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
- int pixel[3];
-
- pixel[0] = x1;
- pixel[1] = y1;
- pixel[2] = z1;
-
- dx = x2 - x1;
- dy = y2 - y1;
- dz = z2 - z1;
-
- x_inc = (dx < 0) ? -1 : 1;
- l = abs(dx);
- y_inc = (dy < 0) ? -1 : 1;
- m = abs(dy);
- z_inc = (dz < 0) ? -1 : 1;
- n = abs(dz);
- dx2 = l << 1;
- dy2 = m << 1;
- dz2 = n << 1;
-
- if ((l >= m) && (l >= n)) {
- err_1 = dy2 - l;
- err_2 = dz2 - l;
- for (i = 0; i < l; i++) {
- if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
- break;
- if (err_1 > 0) {
- pixel[1] += y_inc;
- err_1 -= dx2;
- }
- if (err_2 > 0) {
- pixel[2] += z_inc;
- err_2 -= dx2;
- }
- err_1 += dy2;
- err_2 += dz2;
- pixel[0] += x_inc;
- }
- }
- else if ((m >= l) && (m >= n)) {
- err_1 = dx2 - m;
- err_2 = dz2 - m;
- for (i = 0; i < m; i++) {
- if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
- break;
- if (err_1 > 0) {
- pixel[0] += x_inc;
- err_1 -= dy2;
- }
- if (err_2 > 0) {
- pixel[2] += z_inc;
- err_2 -= dy2;
- }
- err_1 += dx2;
- err_2 += dz2;
- pixel[1] += y_inc;
- }
- }
- else {
- err_1 = dy2 - n;
- err_2 = dx2 - n;
- for (i = 0; i < n; i++) {
- if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
- break;
- if (err_1 > 0) {
- pixel[1] += y_inc;
- err_1 -= dz2;
- }
- if (err_2 > 0) {
- pixel[0] += x_inc;
- err_2 -= dz2;
- }
- err_1 += dy2;
- err_2 += dx2;
- pixel[2] += z_inc;
- }
- }
- cb(result, input, res, pixel, tRay, correct);
+ int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
+ int pixel[3];
+
+ pixel[0] = x1;
+ pixel[1] = y1;
+ pixel[2] = z1;
+
+ dx = x2 - x1;
+ dy = y2 - y1;
+ dz = z2 - z1;
+
+ x_inc = (dx < 0) ? -1 : 1;
+ l = abs(dx);
+ y_inc = (dy < 0) ? -1 : 1;
+ m = abs(dy);
+ z_inc = (dz < 0) ? -1 : 1;
+ n = abs(dz);
+ dx2 = l << 1;
+ dy2 = m << 1;
+ dz2 = n << 1;
+
+ if ((l >= m) && (l >= n)) {
+ err_1 = dy2 - l;
+ err_2 = dz2 - l;
+ for (i = 0; i < l; i++) {
+ if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
+ break;
+ if (err_1 > 0) {
+ pixel[1] += y_inc;
+ err_1 -= dx2;
+ }
+ if (err_2 > 0) {
+ pixel[2] += z_inc;
+ err_2 -= dx2;
+ }
+ err_1 += dy2;
+ err_2 += dz2;
+ pixel[0] += x_inc;
+ }
+ }
+ else if ((m >= l) && (m >= n)) {
+ err_1 = dx2 - m;
+ err_2 = dz2 - m;
+ for (i = 0; i < m; i++) {
+ if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
+ break;
+ if (err_1 > 0) {
+ pixel[0] += x_inc;
+ err_1 -= dy2;
+ }
+ if (err_2 > 0) {
+ pixel[2] += z_inc;
+ err_2 -= dy2;
+ }
+ err_1 += dx2;
+ err_2 += dz2;
+ pixel[1] += y_inc;
+ }
+ }
+ else {
+ err_1 = dy2 - n;
+ err_2 = dx2 - n;
+ for (i = 0; i < n; i++) {
+ if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
+ break;
+ if (err_1 > 0) {
+ pixel[1] += y_inc;
+ err_1 -= dz2;
+ }
+ if (err_2 > 0) {
+ pixel[0] += x_inc;
+ err_2 -= dz2;
+ }
+ err_1 += dy2;
+ err_2 += dx2;
+ pixel[2] += z_inc;
+ }
+ }
+ cb(result, input, res, pixel, tRay, correct);
}
static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer)
{
- float bv[6] = {0};
- float light[3];
- int a, z, slabsize = sds->res[0] * sds->res[1], size = sds->res[0] * sds->res[1] * sds->res[2];
- float *density = smoke_get_density(sds->fluid);
- float correct = -7.0f * sds->dx;
-
- if (!get_light(view_layer, light)) return;
-
- /* convert light pos to sim cell space */
- mul_m4_v3(sds->imat, light);
- light[0] = (light[0] - sds->p0[0]) / sds->cell_size[0] - 0.5f - (float)sds->res_min[0];
- light[1] = (light[1] - sds->p0[1]) / sds->cell_size[1] - 0.5f - (float)sds->res_min[1];
- light[2] = (light[2] - sds->p0[2]) / sds->cell_size[2] - 0.5f - (float)sds->res_min[2];
-
- for (a = 0; a < size; a++)
- sds->shadow[a] = -1.0f;
-
- /* calculate domain bounds in sim cell space */
- // 0,2,4 = 0.0f
- bv[1] = (float)sds->res[0]; // x
- bv[3] = (float)sds->res[1]; // y
- bv[5] = (float)sds->res[2]; // z
-
- for (z = 0; z < sds->res[2]; z++)
- {
- size_t index = z * slabsize;
- int x, y;
-
- for (y = 0; y < sds->res[1]; y++)
- for (x = 0; x < sds->res[0]; x++, index++)
- {
- float voxelCenter[3];
- float pos[3];
- int cell[3];
- float tRay = 1.0;
-
- if (sds->shadow[index] >= 0.0f)
- continue;
- voxelCenter[0] = (float)x;
- voxelCenter[1] = (float)y;
- voxelCenter[2] = (float)z;
-
- // get starting cell (light pos)
- if (BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON)
- {
- // we're ouside -> use point on side of domain
- cell[0] = (int)floor(pos[0]);
- cell[1] = (int)floor(pos[1]);
- cell[2] = (int)floor(pos[2]);
- }
- else {
- // we're inside -> use light itself
- cell[0] = (int)floor(light[0]);
- cell[1] = (int)floor(light[1]);
- cell[2] = (int)floor(light[2]);
- }
- /* clamp within grid bounds */
- CLAMP(cell[0], 0, sds->res[0] - 1);
- CLAMP(cell[1], 0, sds->res[1] - 1);
- CLAMP(cell[2], 0, sds->res[2] - 1);
-
- bresenham_linie_3D(cell[0], cell[1], cell[2], x, y, z, &tRay, calc_voxel_transp, sds->shadow, density, sds->res, correct);
-
- // convention -> from a RGBA float array, use G value for tRay
- sds->shadow[index] = tRay;
- }
- }
+ float bv[6] = {0};
+ float light[3];
+ int a, z, slabsize = sds->res[0] * sds->res[1], size = sds->res[0] * sds->res[1] * sds->res[2];
+ float *density = smoke_get_density(sds->fluid);
+ float correct = -7.0f * sds->dx;
+
+ if (!get_light(view_layer, light))
+ return;
+
+ /* convert light pos to sim cell space */
+ mul_m4_v3(sds->imat, light);
+ light[0] = (light[0] - sds->p0[0]) / sds->cell_size[0] - 0.5f - (float)sds->res_min[0];
+ light[1] = (light[1] - sds->p0[1]) / sds->cell_size[1] - 0.5f - (float)sds->res_min[1];
+ light[2] = (light[2] - sds->p0[2]) / sds->cell_size[2] - 0.5f - (float)sds->res_min[2];
+
+ for (a = 0; a < size; a++)
+ sds->shadow[a] = -1.0f;
+
+ /* calculate domain bounds in sim cell space */
+ // 0,2,4 = 0.0f
+ bv[1] = (float)sds->res[0]; // x
+ bv[3] = (float)sds->res[1]; // y
+ bv[5] = (float)sds->res[2]; // z
+
+ for (z = 0; z < sds->res[2]; z++) {
+ size_t index = z * slabsize;
+ int x, y;
+
+ for (y = 0; y < sds->res[1]; y++)
+ for (x = 0; x < sds->res[0]; x++, index++) {
+ float voxelCenter[3];
+ float pos[3];
+ int cell[3];
+ float tRay = 1.0;
+
+ if (sds->shadow[index] >= 0.0f)
+ continue;
+ voxelCenter[0] = (float)x;
+ voxelCenter[1] = (float)y;
+ voxelCenter[2] = (float)z;
+
+ // get starting cell (light pos)
+ if (BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON) {
+ // we're ouside -> use point on side of domain
+ cell[0] = (int)floor(pos[0]);
+ cell[1] = (int)floor(pos[1]);
+ cell[2] = (int)floor(pos[2]);
+ }
+ else {
+ // we're inside -> use light itself
+ cell[0] = (int)floor(light[0]);
+ cell[1] = (int)floor(light[1]);
+ cell[2] = (int)floor(light[2]);
+ }
+ /* clamp within grid bounds */
+ CLAMP(cell[0], 0, sds->res[0] - 1);
+ CLAMP(cell[1], 0, sds->res[1] - 1);
+ CLAMP(cell[2], 0, sds->res[2] - 1);
+
+ bresenham_linie_3D(cell[0],
+ cell[1],
+ cell[2],
+ x,
+ y,
+ z,
+ &tRay,
+ calc_voxel_transp,
+ sds->shadow,
+ density,
+ sds->res,
+ correct);
+
+ // convention -> from a RGBA float array, use G value for tRay
+ sds->shadow[index] = tRay;
+ }
+ }
}
/* get smoke velocity and density at given coordinates
* returns fluid density or -1.0f if outside domain. */
float BKE_smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3])
{
- SmokeModifierData *smd = (SmokeModifierData *)modifiers_findByType(ob, eModifierType_Smoke);
- zero_v3(velocity);
-
- if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && smd->domain->fluid) {
- SmokeDomainSettings *sds = smd->domain;
- float time_mult = 25.f * DT_DEFAULT;
- float vel_mag;
- float *velX = smoke_get_velocity_x(sds->fluid);
- float *velY = smoke_get_velocity_y(sds->fluid);
- float *velZ = smoke_get_velocity_z(sds->fluid);
- float density = 0.0f, fuel = 0.0f;
- float pos[3];
- copy_v3_v3(pos, position);
- smoke_pos_to_cell(sds, pos);
-
- /* check if point is outside domain max bounds */
- if (pos[0] < sds->res_min[0] || pos[1] < sds->res_min[1] || pos[2] < sds->res_min[2]) return -1.0f;
- if (pos[0] > sds->res_max[0] || pos[1] > sds->res_max[1] || pos[2] > sds->res_max[2]) return -1.0f;
-
- /* map pos between 0.0 - 1.0 */
- pos[0] = (pos[0] - sds->res_min[0]) / ((float)sds->res[0]);
- pos[1] = (pos[1] - sds->res_min[1]) / ((float)sds->res[1]);
- pos[2] = (pos[2] - sds->res_min[2]) / ((float)sds->res[2]);
-
-
- /* check if point is outside active area */
- if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) return 0.0f;
- if (pos[0] > 1.0f || pos[1] > 1.0f || pos[2] > 1.0f) return 0.0f;
- }
-
- /* get interpolated velocity */
- velocity[0] = BLI_voxel_sample_trilinear(velX, sds->res, pos) * sds->global_size[0] * time_mult;
- velocity[1] = BLI_voxel_sample_trilinear(velY, sds->res, pos) * sds->global_size[1] * time_mult;
- velocity[2] = BLI_voxel_sample_trilinear(velZ, sds->res, pos) * sds->global_size[2] * time_mult;
-
- /* convert velocity direction to global space */
- vel_mag = len_v3(velocity);
- mul_mat3_m4_v3(sds->obmat, velocity);
- normalize_v3(velocity);
- mul_v3_fl(velocity, vel_mag);
-
- /* use max value of fuel or smoke density */
- density = BLI_voxel_sample_trilinear(smoke_get_density(sds->fluid), sds->res, pos);
- if (smoke_has_fuel(sds->fluid)) {
- fuel = BLI_voxel_sample_trilinear(smoke_get_fuel(sds->fluid), sds->res, pos);
- }
- return MAX2(density, fuel);
- }
- return -1.0f;
+ SmokeModifierData *smd = (SmokeModifierData *)modifiers_findByType(ob, eModifierType_Smoke);
+ zero_v3(velocity);
+
+ if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && smd->domain->fluid) {
+ SmokeDomainSettings *sds = smd->domain;
+ float time_mult = 25.f * DT_DEFAULT;
+ float vel_mag;
+ float *velX = smoke_get_velocity_x(sds->fluid);
+ float *velY = smoke_get_velocity_y(sds->fluid);
+ float *velZ = smoke_get_velocity_z(sds->fluid);
+ float density = 0.0f, fuel = 0.0f;
+ float pos[3];
+ copy_v3_v3(pos, position);
+ smoke_pos_to_cell(sds, pos);
+
+ /* check if point is outside domain max bounds */
+ if (pos[0] < sds->res_min[0] || pos[1] < sds->res_min[1] || pos[2] < sds->res_min[2])
+ return -1.0f;
+ if (pos[0] > sds->res_max[0] || pos[1] > sds->res_max[1] || pos[2] > sds->res_max[2])
+ return -1.0f;
+
+ /* map pos between 0.0 - 1.0 */
+ pos[0] = (pos[0] - sds->res_min[0]) / ((float)sds->res[0]);
+ pos[1] = (pos[1] - sds->res_min[1]) / ((float)sds->res[1]);
+ pos[2] = (pos[2] - sds->res_min[2]) / ((float)sds->res[2]);
+
+ /* check if point is outside active area */
+ if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f)
+ return 0.0f;
+ if (pos[0] > 1.0f || pos[1] > 1.0f || pos[2] > 1.0f)
+ return 0.0f;
+ }
+
+ /* get interpolated velocity */
+ velocity[0] = BLI_voxel_sample_trilinear(velX, sds->res, pos) * sds->global_size[0] *
+ time_mult;
+ velocity[1] = BLI_voxel_sample_trilinear(velY, sds->res, pos) * sds->global_size[1] *
+ time_mult;
+ velocity[2] = BLI_voxel_sample_trilinear(velZ, sds->res, pos) * sds->global_size[2] *
+ time_mult;
+
+ /* convert velocity direction to global space */
+ vel_mag = len_v3(velocity);
+ mul_mat3_m4_v3(sds->obmat, velocity);
+ normalize_v3(velocity);
+ mul_v3_fl(velocity, vel_mag);
+
+ /* use max value of fuel or smoke density */
+ density = BLI_voxel_sample_trilinear(smoke_get_density(sds->fluid), sds->res, pos);
+ if (smoke_has_fuel(sds->fluid)) {
+ fuel = BLI_voxel_sample_trilinear(smoke_get_fuel(sds->fluid), sds->res, pos);
+ }
+ return MAX2(density, fuel);
+ }
+ return -1.0f;
}
int BKE_smoke_get_data_flags(SmokeDomainSettings *sds)
{
- int flags = 0;
-
- if (sds->fluid) {
- if (smoke_has_heat(sds->fluid))
- flags |= SM_ACTIVE_HEAT;
- if (smoke_has_fuel(sds->fluid))
- flags |= SM_ACTIVE_FIRE;
- if (smoke_has_colors(sds->fluid))
- flags |= SM_ACTIVE_COLORS;
- }
-
- return flags;
+ int flags = 0;
+
+ if (sds->fluid) {
+ if (smoke_has_heat(sds->fluid))
+ flags |= SM_ACTIVE_HEAT;
+ if (smoke_has_fuel(sds->fluid))
+ flags |= SM_ACTIVE_FIRE;
+ if (smoke_has_colors(sds->fluid))
+ flags |= SM_ACTIVE_COLORS;
+ }
+
+ return flags;
}
#endif /* WITH_SMOKE */
bool BKE_smoke_show_highres(Scene *scene, SmokeDomainSettings *sds)
{
- if ((sds->viewsettings & MOD_SMOKE_VIEW_SHOW_HIGHRES) == 0) {
- return false;
- }
- if (scene->r.mode & R_SIMPLIFY) {
- return !scene->r.simplify_smoke_ignore_highres;
- }
- return true;
+ if ((sds->viewsettings & MOD_SMOKE_VIEW_SHOW_HIGHRES) == 0) {
+ return false;
+ }
+ if (scene->r.mode & R_SIMPLIFY) {
+ return !scene->r.simplify_smoke_ignore_highres;
+ }
+ return true;
}