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.c694
1 files changed, 663 insertions, 31 deletions
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 28a2c42546d..c8fc991a645 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -91,6 +91,10 @@
#include "smoke_API.h"
+#ifdef WITH_OPENVDB
+# include "openvdb_capi.h"
+#endif
+
#ifdef WITH_SMOKE
#ifdef _WIN32
@@ -153,7 +157,7 @@ struct SmokeModifierData;
#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), int UNUSED(use_sim)) { 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; }
@@ -196,6 +200,8 @@ void smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, float dx, int res[
{
int use_fire = (sds->active_fields & (SM_ACTIVE_HEAT | SM_ACTIVE_FIRE));
int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
+ int use_sim = !((sds->point_cache[0] != NULL) &&
+ (sds->point_cache[0]->flag & (PTCACHE_BAKED|PTCACHE_DISK_CACHE)) == (PTCACHE_BAKED|PTCACHE_DISK_CACHE));
if (free_old && sds->wt)
smoke_turbulence_free(sds->wt);
@@ -207,7 +213,7 @@ void smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, float dx, int res[
/* smoke_turbulence_init uses non-threadsafe functions from fftw3 lib (like fftw_plan & co). */
BLI_lock_thread(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, use_sim);
BLI_unlock_thread(LOCK_FFTW);
@@ -347,6 +353,9 @@ static int smokeModifier_init(SmokeModifierData *smd, Object *ob, Scene *scene,
if (!sds->shadow)
sds->shadow = MEM_callocN(sizeof(float) * sds->res[0] * sds->res[1] * sds->res[2], "SmokeDomainShadow");
+ sds->density = NULL;
+ sds->density_high = NULL;
+
return 1;
}
else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow)
@@ -376,6 +385,8 @@ static void smokeModifier_freeDomain(SmokeModifierData *smd)
{
if (smd->domain)
{
+ OpenVDBCache *cache;
+
if (smd->domain->shadow)
MEM_freeN(smd->domain->shadow);
smd->domain->shadow = NULL;
@@ -396,6 +407,14 @@ static void smokeModifier_freeDomain(SmokeModifierData *smd)
BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
smd->domain->point_cache[0] = NULL;
+ while ((cache = BLI_pophead(&(smd->domain->vdb_caches)))) {
+#ifdef WITH_OPENVDB
+ OpenVDBWriter_free(cache->writer);
+ OpenVDBReader_free(cache->reader);
+#endif
+ MEM_freeN(cache);
+ }
+
MEM_freeN(smd->domain);
smd->domain = NULL;
}
@@ -564,6 +583,10 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOWBIG;
smd->domain->effector_weights = BKE_add_effector_weights(NULL);
+
+ smd->domain->display_thickness = 1.0f;
+
+ smd->domain->use_openvdb = false;
}
else if (smd->type & MOD_SMOKE_TYPE_FLOW)
{
@@ -1027,6 +1050,7 @@ typedef struct EmissionMap {
float *velocity;
int min[3], max[3], res[3];
int hmin[3], hmax[3], hres[3];
+ float *color;
int total_cells, valid;
} EmissionMap;
@@ -1071,7 +1095,7 @@ static void clampBoundsInDomain(SmokeDomainSettings *sds, int min[3], int max[3]
}
}
-static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul)
+static void em_allocateData(EmissionMap *em, bool use_velocity, bool use_color, int hires_mul)
{
int i, res[3];
@@ -1087,6 +1111,8 @@ static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul)
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");
+ if (use_color)
+ em->color = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_color");
/* allocate high resolution map if required */
if (hires_mul > 1) {
@@ -1111,6 +1137,8 @@ static void em_freeData(EmissionMap *em)
MEM_freeN(em->influence_high);
if (em->velocity)
MEM_freeN(em->velocity);
+ if (em->color)
+ MEM_freeN(em->color);
}
static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size)
@@ -1133,7 +1161,7 @@ static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_mult
}
}
/* allocate output map */
- em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier);
+ em_allocateData(output, (em1.velocity || em2->velocity), (em1.color || em2->color), hires_multiplier);
/* base resolution inputs */
for (x = output->min[0]; x < output->max[0]; x++)
@@ -1152,6 +1180,9 @@ static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_mult
if (output->velocity && em1.velocity) {
copy_v3_v3(&output->velocity[index_out * 3], &em1.velocity[index_in * 3]);
}
+ if (output->color && em1.color) {
+ copy_v3_v3(&output->color[index_out * 3], &em1.color[index_in * 3]);
+ }
}
/* apply second input if in range */
@@ -1173,6 +1204,13 @@ static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_mult
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]);
}
+ if (output->color && em2->color) {
+ /* mix by influence */
+ float f1 = output->influence[index_out];
+ float f2 = em2->influence[index_in];
+ float f = f1 + f2 > 0.0f ? f1 / (f1 + f2) : 0.5f;
+ interp_v3_v3v3(&output->color[index_out * 3], &output->color[index_out * 3], &em2->color[index_in * 3], f);
+ }
}
} // low res loop
@@ -1224,6 +1262,7 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
ParticleSystem *psys = sfs->psys;
float *particle_pos;
float *particle_vel;
+ float *particle_texcol;
int totpart = psys->totpart, totchild;
int p = 0;
int valid_particles = 0;
@@ -1270,6 +1309,11 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
bounds_margin = (int)ceil(solid + smooth);
}
+ if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_TEXCOLOR)
+ particle_texcol = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles");
+ else
+ particle_texcol = NULL;
+
/* calculate local position for each particle */
for (p = 0; p < totpart + totchild; p++)
{
@@ -1303,6 +1347,16 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
BLI_kdtree_insert(tree, valid_particles, pos);
}
+ if (particle_texcol) {
+ if (p < totpart) {
+ ParticleTexture ptex;
+ psys_get_texture(&sim, &psys->particles[p], &ptex, PAMAP_COLOR, state.time);
+ copy_v3_v3(&particle_texcol[valid_particles * 3], ptex.color);
+ }
+ else
+ zero_v3(&particle_texcol[valid_particles * 3]);
+ }
+
/* calculate emission map bounds */
em_boundInsert(em, pos);
valid_particles++;
@@ -1310,7 +1364,7 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
/* 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);
+ em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, sfs->flags & MOD_SMOKE_FLOW_USE_PART_TEXCOLOR, hires_multiplier);
if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
for (p = 0; p < valid_particles; p++)
@@ -1342,6 +1396,9 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
{
VECADDFAC(&em->velocity[index * 3], &em->velocity[index * 3], &particle_vel[p * 3], sfs->vel_multi);
}
+ if (particle_texcol && em->color) {
+ copy_v3_v3(&em->color[index * 3], &particle_texcol[p * 3]);
+ }
} // particles loop
}
else if (valid_particles > 0) { // MOD_SMOKE_FLOW_USE_PART_SIZE
@@ -1391,6 +1448,9 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
{
VECADDFAC(&em->velocity[index * 3], &em->velocity[index * 3], &particle_vel[nearest.index * 3], sfs->vel_multi);
}
+ if (particle_texcol && em->color) {
+ copy_v3_v3(&em->color[index * 3], &particle_texcol[nearest.index * 3]);
+ }
}
}
@@ -1428,6 +1488,8 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
MEM_freeN(particle_pos);
if (particle_vel)
MEM_freeN(particle_vel);
+ if (particle_texcol)
+ MEM_freeN(particle_texcol);
}
}
@@ -1641,7 +1703,7 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo
/* 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);
+ em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, false, hires_multiplier);
/* setup loop bounds */
for (i = 0; i < 3; i++) {
@@ -1983,7 +2045,7 @@ BLI_INLINE void apply_outflow_fields(int index, float *density, float *heat, flo
}
}
-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, const float *color_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];
@@ -2020,9 +2082,10 @@ BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value
/* 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;
+ const float *color = (color_value ? color_value : sfs->color);
+ color_r[index] = (color_r[index] + color[0] * dens_flow) * total_dens;
+ color_g[index] = (color_g[index] + color[1] * dens_flow) * total_dens;
+ color_b[index] = (color_b[index] + color[2] * dens_flow) * total_dens;
}
/* set fire reaction coordinate */
@@ -2169,7 +2232,10 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
}
/* 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)) {
+ if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_TEXCOLOR) {
+ active_fields |= SM_ACTIVE_COLORS;
+ }
+ else if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
copy_v3_v3(sds->active_color, sfs->color);
active_fields |= SM_ACTIVE_COLOR_SET;
}
@@ -2250,6 +2316,7 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
float *velocity_map = em->velocity;
float *emission_map = em->influence;
float *emission_map_high = em->influence_high;
+ float *color_map = em->color;
int ii, jj, kk, gx, gy, gz, ex, ey, ez, dx, dy, dz, block_size;
size_t e_index, d_index, index_big;
@@ -2277,7 +2344,7 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
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);
+ apply_inflow_fields(sfs, emission_map[e_index], color_map ? &color_map[e_index * 3] : NULL, d_index, density, heat, fuel, react, color_r, color_g, color_b);
/* initial velocity */
if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
@@ -2291,6 +2358,7 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
if (bigdensity) {
// neighbor cell emission densities (for high resolution smoke smooth interpolation)
float c000, c001, c010, c011, c100, c101, c110, c111;
+ float col000[3], col001[3], col010[3], col011[3], col100[3], col101[3], col110[3], col111[3];
smoke_turbulence_get_res(sds->wt, bigres);
block_size = sds->amplify + 1; // high res block size
@@ -2305,14 +2373,67 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
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
+ if (color_map) {
+ static const float Z[3] = {0.0f, 0.0f, 0.0f};
+
+ copy_v3_v3(col000, (ex > 0 && ey > 0 && ez > 0) ? &color_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez - 1) * 3] : Z);
+ copy_v3_v3(col001, (ex > 0 && ey > 0) ? &color_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez) * 3] : Z);
+ copy_v3_v3(col010, (ex > 0 && ez > 0) ? &color_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez - 1) * 3] : Z);
+ copy_v3_v3(col011, (ex > 0) ? &color_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez) * 3] : Z);
+
+ copy_v3_v3(col100, (ey > 0 && ez > 0) ? &color_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez - 1) * 3] : Z);
+ copy_v3_v3(col101, (ey > 0) ? &color_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez) * 3] : Z);
+ copy_v3_v3(col110, (ez > 0) ? &color_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez - 1) * 3] : Z);
+ copy_v3_v3(col111, &color_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez) * 3]); // this cell
+ }
+ else {
+ zero_v3(col000);
+ zero_v3(col001);
+ zero_v3(col010);
+ zero_v3(col011);
+ zero_v3(col100);
+ zero_v3(col101);
+ zero_v3(col110);
+ zero_v3(col111);
+ }
+
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;
+ float col[3], interpolated_value, *interpolated_color;
int shift_x = 0, shift_y = 0, shift_z = 0;
+ float w[2][2][2];
+ bool do_interpolation = ((!((sds->highres_sampling == SM_HRES_FULLSAMPLE) && emission_map_high) &&
+ !(sds->highres_sampling == SM_HRES_NEAREST)) ||
+ color_map);
+
+ /* weights are used for both density and color,
+ * so calculate them once in advance
+ */
+ if (do_interpolation) {
+ /* get relative block position
+ * for interpolation smoothing */
+ float fx = (float)ii / block_size + 0.5f / block_size;
+ float fy = (float)jj / block_size + 0.5f / block_size;
+ float fz = (float)kk / block_size + 0.5f / block_size;
+ float mx = 1.0f - fx;
+ float my = 1.0f - fy;
+ float mz = 1.0f - fz;
+
+ w[0][0][0] = mx * my * mz;
+ w[1][0][0] = fx * my * mz;
+ w[0][1][0] = mx * fy * mz;
+ w[1][1][0] = fx * fy * mz;
+ w[0][0][1] = mx * my * fz;
+ w[1][0][1] = fx * my * fz;
+ w[0][1][1] = mx * fy * fz;
+ w[1][1][1] = fx * fy * fz;
+ }
+ else
+ memset(w, 0, sizeof(float) * 8);
/* Use full sample emission map if enabled and available */
if ((sds->highres_sampling == SM_HRES_FULLSAMPLE) && emission_map_high) {
@@ -2326,22 +2447,17 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
/* 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;
-
+ interpolated_value = 0.0f;
+ interpolated_value += c000 * w[0][0][0];
+ interpolated_value += c100 * w[1][0][0];
+ interpolated_value += c010 * w[0][1][0];
+ interpolated_value += c110 * w[1][1][0];
+ interpolated_value += c001 * w[0][0][1];
+ interpolated_value += c101 * w[1][0][1];
+ interpolated_value += c011 * w[0][1][1];
+ interpolated_value += c111 * w[1][1][1];
/* add some contrast / sharpness
* depending on hi-res block size */
@@ -2355,6 +2471,48 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
shift_y = (dy < 1) ? 0 : block_size / 2;
shift_z = (dz < 1) ? 0 : block_size / 2;
}
+
+ if (color_map) {
+ float wcol[2][2][2], totw, invtotw;
+
+ /* colors are zero (black) in zero-emission cells,
+ * so use weighted average based on density to avoid artifacts!
+ */
+ wcol[0][0][0] = w[0][0][0] * c000;
+ wcol[1][0][0] = w[1][0][0] * c100;
+ wcol[0][1][0] = w[0][1][0] * c010;
+ wcol[1][1][0] = w[1][1][0] * c110;
+ wcol[0][0][1] = w[0][0][1] * c001;
+ wcol[1][0][1] = w[1][0][1] * c101;
+ wcol[0][1][1] = w[0][1][1] * c011;
+ wcol[1][1][1] = w[1][1][1] * c111;
+
+ totw = wcol[0][0][0] + wcol[1][0][0] + wcol[0][1][0] + wcol[1][1][0] +
+ wcol[0][0][1] + wcol[1][0][1] + wcol[0][1][1] + wcol[1][1][1];
+ invtotw = totw > 0.0f ? 1.0f/totw : 0.0f;
+ wcol[0][0][0] *= invtotw;
+ wcol[1][0][0] *= invtotw;
+ wcol[0][1][0] *= invtotw;
+ wcol[1][1][0] *= invtotw;
+ wcol[0][0][1] *= invtotw;
+ wcol[1][0][1] *= invtotw;
+ wcol[0][1][1] *= invtotw;
+ wcol[1][1][1] *= invtotw;
+
+ zero_v3(col);
+ madd_v3_v3fl(col, col000, wcol[0][0][0]);
+ madd_v3_v3fl(col, col100, wcol[1][0][0]);
+ madd_v3_v3fl(col, col010, wcol[0][1][0]);
+ madd_v3_v3fl(col, col110, wcol[1][1][0]);
+ madd_v3_v3fl(col, col001, wcol[0][0][1]);
+ madd_v3_v3fl(col, col101, wcol[1][0][1]);
+ madd_v3_v3fl(col, col011, wcol[0][1][1]);
+ madd_v3_v3fl(col, col111, wcol[1][1][1]);
+
+ interpolated_color = col;
+ }
+ else
+ interpolated_color = NULL;
/* 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);
@@ -2365,7 +2523,7 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
}
}
else { // inflow
- apply_inflow_fields(sfs, interpolated_value, index_big, bigdensity, NULL, bigfuel, bigreact, bigcolor_r, bigcolor_g, bigcolor_b);
+ apply_inflow_fields(sfs, interpolated_value, interpolated_color, index_big, bigdensity, NULL, bigfuel, bigreact, bigcolor_r, bigcolor_g, bigcolor_b);
}
} // hires loop
} // bigdensity
@@ -2389,7 +2547,7 @@ static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds,
ListBase *effectors;
/* make sure smoke flow influence is 0.0f */
sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
- effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights, true);
+ effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights);
if (effectors)
{
@@ -2667,11 +2825,12 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
{
SmokeDomainSettings *sds = smd->domain;
PointCache *cache = NULL;
+ OpenVDBCache *vdb_cache = NULL;
PTCacheID pid;
int startframe, endframe, framenr;
float timescale;
- framenr = scene->r.cfra;
+ framenr = scene->r.cfra - sds->point_cache_offset;
//printf("time: %d\n", scene->r.cfra);
@@ -2703,8 +2862,18 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
return;
}
+ /* try to read from openvdb cache */
+// vdb_cache = BKE_openvdb_get_current_cache(sds);
+// if (sds->use_openvdb && vdb_cache) {
+// if (vdb_cache->flags & VDB_CACHE_SMOKE_EXPORTED) {
+// smokeModifier_OpenVDB_import(smd, scene, ob, vdb_cache);
+// smd->time = framenr;
+// return;
+// }
+// }
+
/* try to read from cache */
- if (BKE_ptcache_read(&pid, (float)framenr) == PTCACHE_READ_EXACT) {
+ if (/*!sds->use_openvdb && */(BKE_ptcache_read(&pid, (float)framenr) == PTCACHE_READ_EXACT)) {
BKE_ptcache_validate(cache, framenr);
smd->time = framenr;
return;
@@ -2752,6 +2921,7 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
if (sds->wt)
{
+ smoke_ensure_simulation(sds->fluid, sds->wt);
smoke_turbulence_step(sds->wt, sds->fluid);
}
@@ -3025,4 +3195,466 @@ int smoke_get_data_flags(SmokeDomainSettings *sds)
return flags;
}
+#ifdef WITH_OPENVDB
+
+/* Construct matrices which represent the fluid object, for low and high res:
+ * vs 0 0 0
+ * 0 vs 0 0
+ * 0 0 vs 0
+ * px py pz 1
+ * with vs = voxel size, and px, py, pz, the min position of the domain's
+ * bounding box.
+ */
+static void compute_fluid_matrices(SmokeDomainSettings *sds)
+{
+ float bbox_min[3];
+
+ copy_v3_v3(bbox_min, sds->p0);
+
+ if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ bbox_min[0] += (sds->cell_size[0] * (float)sds->res_min[0]);
+ bbox_min[1] += (sds->cell_size[1] * (float)sds->res_min[1]);
+ bbox_min[2] += (sds->cell_size[2] * (float)sds->res_min[2]);
+ add_v3_v3(bbox_min, sds->obj_shift_f);
+ }
+
+ /* construct low res matrix */
+ size_to_mat4(sds->fluidmat, sds->cell_size);
+ copy_v3_v3(sds->fluidmat[3], bbox_min);
+
+ /* The smoke simulator stores voxels cell-centered, whilst VDB is node
+ * centered, so we offset the matrix by half a voxel to compensate. */
+ madd_v3_v3fl(sds->fluidmat[3], sds->cell_size, 0.5f);
+
+ mul_m4_m4m4(sds->fluidmat, sds->obmat, sds->fluidmat);
+
+ if (sds->wt) {
+ float voxel_size_high[3];
+ /* construct high res matrix */
+ mul_v3_v3fl(voxel_size_high, sds->cell_size, 1.0f / (float)(sds->amplify + 1));
+ size_to_mat4(sds->fluidmat_wt, voxel_size_high);
+ copy_v3_v3(sds->fluidmat_wt[3], bbox_min);
+
+ /* Same here, add half a voxel to adjust the position of the fluid. */
+ madd_v3_v3fl(sds->fluidmat_wt[3], voxel_size_high, 0.5f);
+
+ mul_m4_m4m4(sds->fluidmat_wt, sds->obmat, sds->fluidmat_wt);
+ }
+}
+
+static void OpenVDB_read_fluid_settings(SmokeDomainSettings *sds, struct OpenVDBReader *reader)
+{
+ OpenVDBReader_get_meta_v3_int(reader, "min_resolution", sds->res_min);
+ OpenVDBReader_get_meta_v3_int(reader, "max_resolution", sds->res_max);
+ OpenVDBReader_get_meta_v3_int(reader, "base_resolution", sds->base_res);
+ OpenVDBReader_get_meta_fl(reader, "delta_x", &sds->dx);
+ OpenVDBReader_get_meta_v3(reader, "min_bbox", sds->p0);
+ OpenVDBReader_get_meta_v3(reader, "max_bbox", sds->p1);
+ OpenVDBReader_get_meta_v3(reader, "dp0", sds->dp0);
+ OpenVDBReader_get_meta_v3_int(reader, "shift", sds->shift);
+ OpenVDBReader_get_meta_v3(reader, "obj_shift_f", sds->obj_shift_f);
+ OpenVDBReader_get_meta_v3(reader, "active_color", sds->active_color);
+ OpenVDBReader_get_meta_mat4(reader, "obmat", sds->obmat);
+}
+
+static void OpenVDB_write_fluid_settings(SmokeDomainSettings *sds, struct OpenVDBWriter *writer)
+{
+ OpenVDBWriter_add_meta_int(writer, "active_fields", sds->active_fields);
+ OpenVDBWriter_add_meta_v3_int(writer, "resolution", sds->res);
+ OpenVDBWriter_add_meta_v3_int(writer, "min_resolution", sds->res_min);
+ OpenVDBWriter_add_meta_v3_int(writer, "max_resolution", sds->res_max);
+ OpenVDBWriter_add_meta_v3_int(writer, "base_resolution", sds->base_res);
+ OpenVDBWriter_add_meta_fl(writer, "delta_x", sds->dx);
+ OpenVDBWriter_add_meta_v3(writer, "min_bbox", sds->p0);
+ OpenVDBWriter_add_meta_v3(writer, "max_bbox", sds->p1);
+ OpenVDBWriter_add_meta_v3(writer, "dp0", sds->dp0);
+ OpenVDBWriter_add_meta_v3_int(writer, "shift", sds->shift);
+ OpenVDBWriter_add_meta_v3(writer, "obj_shift_f", sds->obj_shift_f);
+ OpenVDBWriter_add_meta_v3(writer, "active_color", sds->active_color);
+ OpenVDBWriter_add_meta_mat4(writer, "obmat", sds->obmat);
+}
+
+void BKE_openvdb_cache_filename(char *r_filename, const char *path, const char *fname, const char *relbase, int frame)
+{
+ char cachepath[FILE_MAX];
+
+ BLI_strncpy(cachepath, path, FILE_MAX - 10);
+ BLI_path_abs(cachepath, relbase);
+
+ if (!BLI_exists(cachepath)) {
+ BLI_dir_create_recursive(cachepath);
+ }
+
+ BLI_join_dirfile(r_filename, sizeof(cachepath), cachepath, fname);
+ BLI_path_suffix(r_filename, FILE_MAX, "", "_");
+ BLI_path_frame(r_filename, frame, 4);
+ BLI_ensure_extension(r_filename, FILE_MAX, ".vdb");
+}
+
+static void OpenVDB_export_smoke(SmokeDomainSettings *sds, struct OpenVDBWriter *writer)
+{
+ int fluid_fields = smoke_get_data_flags(sds);
+ struct OpenVDBFloatGrid *clip_grid = NULL;
+
+ compute_fluid_matrices(sds);
+
+ OpenVDBWriter_add_meta_int(writer, "fluid_fields", fluid_fields);
+
+ if (sds->wt) {
+ struct OpenVDBFloatGrid *wt_density_grid;
+ float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
+
+ smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
+
+ wt_density_grid = OpenVDB_export_grid_fl(writer, "Density High", dens, sds->res_wt, sds->fluidmat_wt, NULL);
+ clip_grid = wt_density_grid;
+
+ if (fluid_fields & SM_ACTIVE_FIRE) {
+ OpenVDB_export_grid_fl(writer, "Flame High", flame, sds->res_wt, sds->fluidmat_wt, wt_density_grid);
+ OpenVDB_export_grid_fl(writer, "Fuel High", fuel, sds->res_wt, sds->fluidmat_wt, wt_density_grid);
+ OpenVDB_export_grid_fl(writer, "React High", react, sds->res_wt, sds->fluidmat_wt, wt_density_grid);
+ }
+
+ if (fluid_fields & SM_ACTIVE_COLORS) {
+ OpenVDB_export_grid_vec(writer, "Color High", r, g, b, sds->res_wt, sds->fluidmat_wt, VEC_INVARIANT, true, wt_density_grid);
+ }
+
+ OpenVDB_export_grid_vec(writer, "Texture Coordinates", tcu, tcv, tcw, sds->res, sds->fluidmat, VEC_INVARIANT, false, wt_density_grid);
+ }
+
+ if (sds->fluid) {
+ struct OpenVDBFloatGrid *density_grid;
+ float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
+ unsigned char *obstacles;
+
+ smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat,
+ &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
+
+ OpenVDBWriter_add_meta_fl(writer, "dx", dx);
+ OpenVDBWriter_add_meta_fl(writer, "dt", dt);
+
+ density_grid = OpenVDB_export_grid_fl(writer, "Density", dens, sds->res, sds->fluidmat, NULL);
+ clip_grid = sds->wt ? clip_grid : density_grid;
+
+ OpenVDB_export_grid_fl(writer, "Shadow", sds->shadow, sds->res, sds->fluidmat, density_grid);
+
+ if (fluid_fields & SM_ACTIVE_HEAT) {
+ OpenVDB_export_grid_fl(writer, "Heat", heat, sds->res, sds->fluidmat, clip_grid);
+ OpenVDB_export_grid_fl(writer, "Heat Old", heatold, sds->res, sds->fluidmat, clip_grid);
+ }
+
+ if (fluid_fields & SM_ACTIVE_FIRE) {
+ OpenVDB_export_grid_fl(writer, "Flame", flame, sds->res, sds->fluidmat, density_grid);
+ OpenVDB_export_grid_fl(writer, "Fuel", fuel, sds->res, sds->fluidmat, density_grid);
+ OpenVDB_export_grid_fl(writer, "React", react, sds->res, sds->fluidmat, density_grid);
+ }
+
+ if (fluid_fields & SM_ACTIVE_COLORS) {
+ OpenVDB_export_grid_vec(writer, "Color", r, g, b, sds->res, sds->fluidmat, VEC_INVARIANT, true, density_grid);
+ }
+
+ OpenVDB_export_grid_vec(writer, "Velocity", vx, vy, vz, sds->res, sds->fluidmat, VEC_CONTRAVARIANT_RELATIVE, false, clip_grid);
+ //OpenVDB_export_grid_ch(writer, "Obstacles", obstacles, sds->res, sds->fluidmat, NULL);
+ }
+}
+
+static void OpenVDB_import_smoke(SmokeDomainSettings *sds, struct OpenVDBReader *reader, bool for_display)
+{
+ int fluid_fields = smoke_get_data_flags(sds);
+ int active_fields, cache_fields = 0;
+ int cache_res[3];
+ float cache_dx;
+ bool reallocate = false;
+
+ OpenVDBReader_get_meta_int(reader, "fluid_fields", &cache_fields);
+ OpenVDBReader_get_meta_int(reader, "active_fields", &active_fields);
+ OpenVDBReader_get_meta_fl(reader, "dx", &cache_dx);
+ OpenVDBReader_get_meta_v3_int(reader, "resolution", cache_res);
+
+ /* check if resolution has changed */
+ if (sds->res[0] != cache_res[0] ||
+ sds->res[1] != cache_res[1] ||
+ sds->res[2] != cache_res[2])
+ {
+ if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ reallocate = true;
+ }
+ else {
+ return;
+ }
+ }
+
+ /* check if active fields have changed */
+ if ((fluid_fields != cache_fields) || (active_fields != sds->active_fields)) {
+ reallocate = true;
+ }
+
+ /* reallocate fluid if needed*/
+ if (reallocate) {
+ sds->active_fields = active_fields | cache_fields;
+ smoke_reallocate_fluid(sds, cache_dx, cache_res, 1);
+ sds->dx = cache_dx;
+ copy_v3_v3_int(sds->res, cache_res);
+ sds->total_cells = cache_res[0] * cache_res[1] * cache_res[2];
+
+ if (sds->flags & MOD_SMOKE_HIGHRES) {
+ smoke_reallocate_highres_fluid(sds, cache_dx, cache_res, 1);
+ }
+ }
+
+ if (sds->fluid) {
+ float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
+ unsigned char *obstacles;
+ bool for_low_display = for_display && (!sds->wt || !(sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG));
+
+ smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat,
+ &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
+
+ OpenVDBReader_get_meta_fl(reader, "dt", &dt);
+
+ OpenVDB_import_grid_fl(reader, "Shadow", &sds->shadow, sds->res);
+
+ if (for_low_display) {
+ sds->density = OpenVDB_import_grid_fl(reader, "Density", &dens, sds->res);
+ }
+
+ if (fluid_fields & SM_ACTIVE_HEAT && !for_low_display) {
+ OpenVDB_import_grid_fl(reader, "Heat", &heat, sds->res);
+ OpenVDB_import_grid_fl(reader, "Heat Old", &heatold, sds->res);
+ }
+
+ if (fluid_fields & SM_ACTIVE_FIRE && for_low_display) {
+ OpenVDB_import_grid_fl(reader, "Flame", &flame, sds->res);
+
+ if (!for_low_display) { // should be "for_sim_cont" or so
+ OpenVDB_import_grid_fl(reader, "Fuel", &fuel, sds->res);
+ OpenVDB_import_grid_fl(reader, "React", &react, sds->res);
+ }
+ }
+
+ if (fluid_fields & SM_ACTIVE_COLORS && for_low_display) {
+ OpenVDB_import_grid_vec(reader, "Color", &r, &g, &b, sds->res);
+ }
+
+ if (!for_low_display) {
+ OpenVDB_import_grid_vec(reader, "Velocity", &vx, &vy, &vz, sds->res);
+ //OpenVDB_import_grid_ch(reader, "Obstacles", &obstacles, sds->res);
+ }
+ }
+
+ if (sds->wt) {
+ float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
+ bool for_wt_display = for_display && (sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG);
+
+ smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
+
+ if (for_wt_display) {
+ sds->density_high = OpenVDB_import_grid_fl(reader, "Density High", &dens, sds->res_wt);
+ }
+
+ if (fluid_fields & SM_ACTIVE_FIRE && for_wt_display) {
+ OpenVDB_import_grid_fl(reader, "Flame High", &flame, sds->res_wt);
+
+ if (!for_wt_display) { // should be "for_sim_cont" or so
+ OpenVDB_import_grid_fl(reader, "Fuel High", &fuel, sds->res_wt);
+ OpenVDB_import_grid_fl(reader, "React High", &react, sds->res_wt);
+ }
+ }
+
+ if (fluid_fields & SM_ACTIVE_COLORS && for_wt_display) {
+ OpenVDB_import_grid_vec(reader, "Color High", &r, &g, &b, sds->res_wt);
+ }
+
+ if (!for_wt_display) {
+ OpenVDB_import_grid_vec(reader, "Texture Coordinates", &tcu, &tcv, &tcw, sds->res);
+ }
+ }
+}
+
+void smokeModifier_OpenVDB_export(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm,
+ update_cb update, void *update_cb_data)
+{
+ SmokeDomainSettings *sds = smd->domain;
+ OpenVDBCache *cache;
+ int orig_frame, fr, cancel = 0;
+ float progress;
+ const char *relbase = modifier_path_relbase(ob);
+ char filename[FILE_MAX];
+
+ orig_frame = scene->r.cfra;
+
+ cache = BKE_openvdb_get_current_cache(sds);
+
+ if (cache->writer == NULL) {
+ cache->writer = OpenVDBWriter_create();
+ }
+
+ OpenVDBWriter_set_compression(cache->writer, cache->compression);
+
+ for (fr = cache->startframe; fr <= cache->endframe; fr++) {
+ /* smd->time is overwritten with scene->r.cfra in smokeModifier_process,
+ * so we can't use it here... */
+ scene->r.cfra = fr;
+
+ BKE_openvdb_cache_filename(filename, cache->path, cache->name, relbase, fr);
+
+ smokeModifier_process(smd, scene, ob, dm, false);
+
+ /* XXX hack: for some reason the smoke sim stores zero matrix for frame 1 */
+ {
+ PTCacheID pid;
+ int ptcache_start, ptcache_end;
+ float ptcache_timescale;
+ BKE_ptcache_id_from_smoke(&pid, ob, smd);
+ BKE_ptcache_id_time(&pid, scene, fr, &ptcache_start, &ptcache_end, &ptcache_timescale);
+
+ if (fr == ptcache_start) {
+ unit_m4(sds->obmat);
+ }
+ }
+
+ OpenVDB_write_fluid_settings(sds, cache->writer);
+ OpenVDB_export_smoke(sds, cache->writer);
+
+ progress = (fr - cache->startframe) / (float)cache->endframe;
+
+ OpenVDBWriter_write(cache->writer, filename);
+
+ update(update_cb_data, progress, &cancel);
+
+ if (cancel) {
+ scene->r.cfra = orig_frame;
+ return;
+ }
+ }
+
+ cache->flags |= VDB_CACHE_SMOKE_EXPORTED;
+
+ scene->r.cfra = orig_frame;
+}
+
+void smokeModifier_OpenVDB_import(SmokeModifierData *smd, Scene *scene, Object *ob, OpenVDBCache *cache)
+{
+ SmokeDomainSettings *sds = smd->domain;
+ int startframe, endframe;
+ char filename[FILE_MAX];
+ const char *relbase = modifier_path_relbase(ob);
+ int ret = OPENVDB_NO_ERROR;
+ bool for_display = false;
+
+ cache = BKE_openvdb_get_current_cache(sds);
+ startframe = cache->startframe;
+ endframe = cache->endframe;
+
+ if (CFRA < startframe || CFRA > endframe) {
+ return;
+ }
+
+ if (cache->reader == NULL) {
+ cache->reader = OpenVDBReader_create();
+ }
+
+ for_display = true;
+
+ BKE_openvdb_cache_filename(filename, cache->path, cache->name, relbase, CFRA);
+ OpenVDBReader_open(cache->reader, filename);
+ OpenVDB_read_fluid_settings(sds, cache->reader);
+ OpenVDB_import_smoke(sds, cache->reader, for_display);
+
+ if (ret == OPENVDB_IO_ERROR) {
+ /* TODO(kevin): report error "OpenVDB import error, see console for details" */
+ return;
+ }
+
+ if (ret == OPENVDB_KEY_ERROR) {
+ /* It may happen that some grids are missing on the first frame if the
+ * simulation hasn't started yet, so it's safe to ignore it. */
+ if (CFRA > startframe) {
+ /* TODO(kevin): report error "OpenVDB import error, see console for details" */
+ return;
+ }
+ }
+}
+
+void smokeModifier_OpenVDB_update_transform(SmokeModifierData *smd,
+ Scene *scene,
+ Object *ob,
+ update_cb update,
+ void *update_cb_data)
+{
+ SmokeDomainSettings *sds = smd->domain;
+ OpenVDBCache *cache;
+ int orig_frame, fr, cancel = 0;
+ float progress;
+ const char *relbase = modifier_path_relbase(ob);
+ char filename[FILE_MAX];
+
+ orig_frame = scene->r.cfra;
+
+ cache = BKE_openvdb_get_current_cache(sds);
+
+ for (fr = cache->startframe; fr <= cache->endframe; fr++) {
+ /* smd->time is overwritten with scene->r.cfra in smokeModifier_process,
+ * so we can't use it here... */
+ scene->r.cfra = fr;
+
+ BKE_openvdb_cache_filename(filename, cache->path, cache->name, relbase, fr);
+ compute_fluid_matrices(sds);
+ OpenVDB_update_fluid_transform(filename, sds->fluidmat, sds->fluidmat_wt);
+
+ progress = (fr - cache->startframe) / (float)cache->endframe;
+
+ update(update_cb_data, progress, &cancel);
+
+ if (cancel) {
+ scene->r.cfra = orig_frame;
+ return;
+ }
+ }
+
+ scene->r.cfra = orig_frame;
+}
+
+#endif /* WITH_OPENVDB */
+
#endif /* WITH_SMOKE */
+
+#if !defined(WITH_SMOKE) || !defined(WITH_OPENVDB)
+
+void smokeModifier_OpenVDB_export(SmokeModifierData *smd, Scene *scene, Object *ob,
+ DerivedMesh *dm, update_cb update, void *update_cb_data)
+{
+ UNUSED_VARS(smd, scene, ob, dm, update, update_cb_data);
+}
+
+void smokeModifier_OpenVDB_import(SmokeModifierData *smd, Scene *scene, Object *ob, OpenVDBCache *cache)
+{
+ UNUSED_VARS(smd, scene, ob, cache);
+}
+
+void smokeModifier_OpenVDB_update_transform(SmokeModifierData *smd, Scene *scene,
+ Object *ob, update_cb update, void *update_cb_data)
+{
+ UNUSED_VARS(smd, scene, ob, update, update_cb_data);
+}
+
+void BKE_openvdb_cache_filename(char *r_filename, const char *path, const char *fname, const char *relbase, int frame)
+{
+ r_filename[0] = '\0';
+ UNUSED_VARS(path, fname, relbase, frame);
+}
+
+#endif
+
+OpenVDBCache *BKE_openvdb_get_current_cache(SmokeDomainSettings *sds)
+{
+ OpenVDBCache *cache = sds->vdb_caches.first;
+
+ for (; cache; cache = cache->next) {
+ if (cache->flags & VDB_CACHE_CURRENT) {
+ break;
+ }
+ }
+
+ return cache;
+}