1
1

Compare commits

...

2 Commits

Author SHA1 Message Date
4e84e076b2 Fluid: Initial support for 2D fluid simulations
Initial adjustments for 2D (real-time) simulations.

Basic functionality includes:
- 2D/3D switcher in domain settings
- 2D simulation support for smoke/fire, wavelet noise, liquid
particles, secondary particles
- UI switcher to choose the axis that will be simulated on
- Planar visualization in workbench render

Some things that remain to do (non-exhaustive list):
- Eevee & Cycles support
- Liquid meshing
- Liquid viscosity solver
2021-08-09 11:19:42 +02:00
23d5bbd104 Fluid: Removed noise resolution field in domain settings
There is no need to keep have noise resolution in the domain settings.

Resolutions are stored in the fluid object which also handles memory
of grids.
2021-08-09 11:14:11 +02:00
14 changed files with 286 additions and 84 deletions

View File

@@ -103,6 +103,7 @@ float *manta_get_num_guide(struct MANTA *fluid);
int manta_get_res_x(struct MANTA *fluid);
int manta_get_res_y(struct MANTA *fluid);
int manta_get_res_z(struct MANTA *fluid);
void manta_get_res(struct MANTA *fluid, int* res);
float *manta_get_phi_in(struct MANTA *fluid);
float *manta_get_phistatic_in(struct MANTA *fluid);
float *manta_get_phiobs_in(struct MANTA *fluid);

View File

@@ -204,6 +204,14 @@ MANTA::MANTA(int *res, FluidModifierData *fmd)
mResXParticle = mUpresParticle * mResX;
mResYParticle = mUpresParticle * mResY;
mResZParticle = mUpresParticle * mResZ;
if (fds->solver_res == FLUID_DOMAIN_DIMENSION_2D) {
if (fds->slice_axis == SLICE_AXIS_X)
mResXParticle = 1;
else if (fds->slice_axis == SLICE_AXIS_Y)
mResYParticle = 1;
else if (fds->slice_axis == SLICE_AXIS_Z)
mResZParticle = 1;
}
mTotalCellsParticles = mResXParticle * mResYParticle * mResZParticle;
initSuccess &= initSndParts();
@@ -266,6 +274,14 @@ MANTA::MANTA(int *res, FluidModifierData *fmd)
mResXNoise = amplify * mResX;
mResYNoise = amplify * mResY;
mResZNoise = amplify * mResZ;
if (fds->solver_res == FLUID_DOMAIN_DIMENSION_2D) {
if (fds->slice_axis == SLICE_AXIS_X)
mResXNoise = 1;
else if (fds->slice_axis == SLICE_AXIS_Y)
mResYNoise = 1;
else if (fds->slice_axis == SLICE_AXIS_Z)
mResZNoise = 1;
}
mTotalCellsHigh = mResXNoise * mResYNoise * mResZNoise;
/* Initialize Mantaflow variables in Python. */
@@ -785,8 +801,10 @@ void MANTA::initializeRNAMap(FluidModifierData *fmd)
mRNAMap["BOUND_CONDITIONS"] = borderCollisions;
mRNAMap["BOUNDARY_WIDTH"] = to_string(fds->boundary_width);
mRNAMap["RES"] = to_string(mMaxRes);
mRNAMap["RESX"] = to_string(mResX);
mRNAMap["RESY"] = (is2D) ? to_string(mResZ) : to_string(mResY);
mRNAMap["RESX"] = (is2D && fds->slice_axis == SLICE_AXIS_X) ? to_string(mResY) :
to_string(mResX);
mRNAMap["RESY"] = (is2D && fds->slice_axis != SLICE_AXIS_Z) ? to_string(mResZ) :
to_string(mResY);
mRNAMap["RESZ"] = (is2D) ? to_string(1) : to_string(mResZ);
mRNAMap["TIME_SCALE"] = to_string(fds->time_scale);
mRNAMap["FRAME_LENGTH"] = to_string(fds->frame_length);
@@ -801,14 +819,18 @@ void MANTA::initializeRNAMap(FluidModifierData *fmd)
mRNAMap["NOISE_SCALE"] = to_string(fds->noise_scale);
mRNAMap["MESH_SCALE"] = to_string(fds->mesh_scale);
mRNAMap["PARTICLE_SCALE"] = to_string(fds->particle_scale);
mRNAMap["NOISE_RESX"] = to_string(mResXNoise);
mRNAMap["NOISE_RESY"] = (is2D) ? to_string(mResZNoise) : to_string(mResYNoise);
mRNAMap["NOISE_RESX"] = (is2D && fds->slice_axis == SLICE_AXIS_X) ? to_string(mResYNoise) :
to_string(mResXNoise);
mRNAMap["NOISE_RESY"] = (is2D && fds->slice_axis != SLICE_AXIS_Z) ? to_string(mResZNoise) :
to_string(mResYNoise);
mRNAMap["NOISE_RESZ"] = (is2D) ? to_string(1) : to_string(mResZNoise);
mRNAMap["MESH_RESX"] = to_string(mResXMesh);
mRNAMap["MESH_RESY"] = (is2D) ? to_string(mResZMesh) : to_string(mResYMesh);
mRNAMap["MESH_RESZ"] = (is2D) ? to_string(1) : to_string(mResZMesh);
mRNAMap["PARTICLE_RESX"] = to_string(mResXParticle);
mRNAMap["PARTICLE_RESY"] = (is2D) ? to_string(mResZParticle) : to_string(mResYParticle);
mRNAMap["PARTICLE_RESX"] = (is2D && fds->slice_axis == SLICE_AXIS_X) ? to_string(mResYParticle) :
to_string(mResXParticle);
mRNAMap["PARTICLE_RESY"] = (is2D && fds->slice_axis != SLICE_AXIS_Z) ? to_string(mResZParticle) :
to_string(mResYParticle);
mRNAMap["PARTICLE_RESZ"] = (is2D) ? to_string(1) : to_string(mResZParticle);
mRNAMap["GUIDING_RESX"] = to_string(mResGuiding[0]);
mRNAMap["GUIDING_RESY"] = (is2D) ? to_string(mResGuiding[2]) : to_string(mResGuiding[1]);

View File

@@ -279,6 +279,12 @@ int manta_get_res_z(MANTA *fluid)
{
return fluid->getResZ();
}
void manta_get_res(MANTA *smoke, int *res)
{
res[0] = smoke->getResX();
res[1] = smoke->getResY();
res[2] = smoke->getResZ();
}
float *manta_get_phi_in(MANTA *fluid)
{

View File

@@ -62,22 +62,22 @@ s$ID$ = Solver(name='solver_base$ID$', gridSize=gs_s$ID$, dim=dim_s$ID$)\n";
const std::string fluid_solver_noise =
"\n\
mantaMsg('Solver noise')\n\
sn$ID$ = Solver(name='solver_noise$ID$', gridSize=gs_sn$ID$)\n";
sn$ID$ = Solver(name='solver_noise$ID$', gridSize=gs_sn$ID$, dim=dim_s$ID$)\n";
const std::string fluid_solver_mesh =
"\n\
mantaMsg('Solver mesh')\n\
sm$ID$ = Solver(name='solver_mesh$ID$', gridSize=gs_sm$ID$)\n";
sm$ID$ = Solver(name='solver_mesh$ID$', gridSize=gs_sm$ID$, dim=dim_s$ID$)\n";
const std::string fluid_solver_particles =
"\n\
mantaMsg('Solver particles')\n\
sp$ID$ = Solver(name='solver_particles$ID$', gridSize=gs_sp$ID$)\n";
sp$ID$ = Solver(name='solver_particles$ID$', gridSize=gs_sp$ID$, dim=dim_s$ID$)\n";
const std::string fluid_solver_guiding =
"\n\
mantaMsg('Solver guiding')\n\
sg$ID$ = Solver(name='solver_guiding$ID$', gridSize=gs_sg$ID$)\n";
sg$ID$ = Solver(name='solver_guiding$ID$', gridSize=gs_sg$ID$, dim=dim_s$ID$)\n";
const std::string fluid_solver_viscosity =
"\n\
@@ -95,6 +95,11 @@ dim_s$ID$ = $SOLVER_DIM$\n\
res_s$ID$ = $RES$\n\
gravity_s$ID$ = vec3($GRAVITY_X$, $GRAVITY_Y$, $GRAVITY_Z$) # in SI unit (e.g. m/s^2)\n\
gs_s$ID$ = vec3($RESX$, $RESY$, $RESZ$)\n\
if dim_s$ID$ == 2:\n\
gs_s$ID$.z = 1\n\
gravity_s$ID$.y = gravity_s$ID$.z\n\
gravity_s$ID$.z = 0\n\
\n\
maxVel_s$ID$ = 0\n\
\n\
domainClosed_s$ID$ = $DOMAIN_CLOSED$\n\
@@ -178,24 +183,32 @@ const std::string fluid_variables_noise =
"\n\
mantaMsg('Fluid variables noise')\n\
upres_sn$ID$ = $NOISE_SCALE$\n\
gs_sn$ID$ = vec3(upres_sn$ID$*gs_s$ID$.x, upres_sn$ID$*gs_s$ID$.y, upres_sn$ID$*gs_s$ID$.z)\n";
gs_sn$ID$ = vec3(upres_sn$ID$*gs_s$ID$.x, upres_sn$ID$*gs_s$ID$.y, upres_sn$ID$*gs_s$ID$.z)\n\
if dim_s$ID$ == 2:\n\
gs_sn$ID$.z = 1\n";
const std::string fluid_variables_mesh =
"\n\
mantaMsg('Fluid variables mesh')\n\
upres_sm$ID$ = $MESH_SCALE$\n\
gs_sm$ID$ = vec3(upres_sm$ID$*gs_s$ID$.x, upres_sm$ID$*gs_s$ID$.y, upres_sm$ID$*gs_s$ID$.z)\n";
gs_sm$ID$ = vec3(upres_sm$ID$*gs_s$ID$.x, upres_sm$ID$*gs_s$ID$.y, upres_sm$ID$*gs_s$ID$.z)\n\
if dim_s$ID$ == 2:\n\
gs_sm$ID$.z = 1\n";
const std::string fluid_variables_particles =
"\n\
mantaMsg('Fluid variables particles')\n\
upres_sp$ID$ = $PARTICLE_SCALE$\n\
gs_sp$ID$ = vec3(upres_sp$ID$*gs_s$ID$.x, upres_sp$ID$*gs_s$ID$.y, upres_sp$ID$*gs_s$ID$.z)\n";
gs_sp$ID$ = vec3(upres_sp$ID$*gs_s$ID$.x, upres_sp$ID$*gs_s$ID$.y, upres_sp$ID$*gs_s$ID$.z)\n\
if dim_s$ID$ == 2:\n\
gs_sp$ID$.z = 1\n";
const std::string fluid_variables_guiding =
"\n\
mantaMsg('Fluid variables guiding')\n\
gs_sg$ID$ = vec3($GUIDING_RESX$, $GUIDING_RESY$, $GUIDING_RESZ$)\n\
if dim_s$ID$ == 2:\n\
gs_sg$ID$.z = 1\n\
\n\
alpha_sg$ID$ = $GUIDING_ALPHA$\n\
beta_sg$ID$ = $GUIDING_BETA$\n\
@@ -206,7 +219,9 @@ theta_sg$ID$ = 1.0\n";
const std::string fluid_variables_viscosity =
"\n\
gs_sv$ID$ = vec3($RESX$*2, $RESY$*2, $RESZ$*2)\n";
gs_sv$ID$ = vec3($RESX$*2, $RESY$*2, $RESZ$*2)\n\
if dim_s$ID$ == 2:\n\
gs_sv$ID$.z = 1\n";
const std::string fluid_with_obstacle =
"\n\

View File

@@ -197,6 +197,9 @@ class PHYSICS_PT_settings(PhysicButtonsPanel, Panel):
if PhysicButtonsPanel.poll_gas_domain(context):
col.prop(domain, "clipping", text="Empty Space")
col.prop(domain, "delete_in_obstacle", text="Delete in Obstacle")
col.prop(domain, "solver_res", text="Dimension")
if domain.solver_res == '2D':
col.prop(domain, "slice_axis", text="Axis")
if domain.cache_type == 'MODULAR':
col.separator()
@@ -1379,7 +1382,8 @@ class PHYSICS_PT_viewport_display_slicing(PhysicButtonsPanel, Panel):
layout.active = domain.use_slice
col = layout.column()
col.prop(domain, "slice_axis")
if domain.solver_res == '3D':
col.prop(domain, "slice_axis")
col.prop(domain, "slice_depth")
sub = col.column()

View File

@@ -89,6 +89,9 @@ void BKE_fluid_particles_set(struct FluidDomainSettings *settings, int value, bo
void BKE_fluid_domain_type_set(struct Object *object,
struct FluidDomainSettings *settings,
int type);
void BKE_fluid_domain_solver_res_set(struct Object *object,
struct FluidDomainSettings *settings,
int type);
void BKE_fluid_flow_type_set(struct Object *object, struct FluidFlowSettings *settings, int type);
void BKE_fluid_effector_type_set(struct Object *object,
struct FluidEffectorSettings *settings,

View File

@@ -126,10 +126,6 @@ bool BKE_fluid_reallocate_fluid(FluidDomainSettings *fds, int res[3], int free_o
}
else {
fds->fluid = manta_init(res, fds->fmd);
fds->res_noise[0] = res[0] * fds->noise_scale;
fds->res_noise[1] = res[1] * fds->noise_scale;
fds->res_noise[2] = res[2] * fds->noise_scale;
}
return (fds->fluid != NULL);
@@ -145,7 +141,10 @@ void BKE_fluid_reallocate_copy_fluid(FluidDomainSettings *fds,
int n_shift[3])
{
struct MANTA *fluid_old = fds->fluid;
const int block_size = fds->noise_scale;
int block_size[3] = {fds->noise_scale, fds->noise_scale, fds->noise_scale};
if (fds->solver_res == FLUID_DOMAIN_DIMENSION_2D) {
block_size[fds->slice_axis - 1] = 1;
}
int new_shift[3] = {0};
sub_v3_v3v3_int(new_shift, n_shift, o_shift);
@@ -210,8 +209,9 @@ void BKE_fluid_reallocate_copy_fluid(FluidDomainSettings *fds,
float *n_wt_tcv2 = manta_noise_get_texture_v2(fds->fluid);
float *n_wt_tcw2 = manta_noise_get_texture_w2(fds->fluid);
int wt_res_old[3];
manta_noise_get_res(fluid_old, wt_res_old);
int res_noise[3], res_noise_old[3];
manta_noise_get_res(fds->fluid, res_noise);
manta_noise_get_res(fluid_old, res_noise_old);
for (int z = o_min[2]; z < o_max[2]; z++) {
for (int y = o_min[1]; y < o_max[1]; y++) {
@@ -257,13 +257,13 @@ void BKE_fluid_reallocate_copy_fluid(FluidDomainSettings *fds,
if (fds->flags & FLUID_DOMAIN_USE_NOISE) {
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;
int xx_o = xo * block_size[0];
int yy_o = yo * block_size[1];
int zz_o = zo * block_size[2];
/* new grid index */
int xx_n = xn * block_size;
int yy_n = yn * block_size;
int zz_n = zn * block_size;
int xx_n = xn * block_size[0];
int yy_n = yn * block_size[1];
int zz_n = zn * block_size[2];
/* insert old texture values into new texture grids */
n_wt_tcu[index_new] = o_wt_tcu[index_old];
@@ -274,13 +274,13 @@ void BKE_fluid_reallocate_copy_fluid(FluidDomainSettings *fds,
n_wt_tcv2[index_new] = o_wt_tcv2[index_old];
n_wt_tcw2[index_new] = o_wt_tcw2[index_old];
for (i = 0; i < block_size; i++) {
for (j = 0; j < block_size; j++) {
for (k = 0; k < block_size; k++) {
for (i = 0; i < block_size[0]; i++) {
for (j = 0; j < block_size[1]; j++) {
for (k = 0; k < block_size[2]; k++) {
int big_index_old = manta_get_index(
xx_o + i, wt_res_old[0], yy_o + j, wt_res_old[1], zz_o + k);
xx_o + i, res_noise_old[0], yy_o + j, res_noise_old[1], zz_o + k);
int big_index_new = manta_get_index(
xx_n + i, fds->res_noise[0], yy_n + j, fds->res_noise[1], zz_n + k);
xx_n + i, res_noise[0], yy_n + j, res_noise[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) {
@@ -455,27 +455,32 @@ static void manta_set_domain_from_mesh(FluidDomainSettings *fds,
return;
}
const bool is_2D = (fds->solver_res == FLUID_DOMAIN_DIMENSION_2D);
const bool is_axis_X = (fds->slice_axis == SLICE_AXIS_X);
const bool is_axis_Y = (fds->slice_axis == SLICE_AXIS_Y);
const bool is_axis_Z = (fds->slice_axis == SLICE_AXIS_Z);
/* Define grid resolutions from longest domain side. */
if (size[0] >= MAX2(size[1], size[2])) {
scale = res / size[0];
fds->scale = size[0] / fabsf(ob->scale[0]);
fds->base_res[0] = res;
fds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
fds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
fds->base_res[0] = (is_2D && is_axis_X) ? 1 : res;
fds->base_res[1] = (is_2D && is_axis_Y) ? 1 : max_ii((int)(size[1] * scale + 0.5f), 4);
fds->base_res[2] = (is_2D && is_axis_Z) ? 1 : max_ii((int)(size[2] * scale + 0.5f), 4);
}
else if (size[1] >= MAX2(size[0], size[2])) {
scale = res / size[1];
fds->scale = size[1] / fabsf(ob->scale[1]);
fds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
fds->base_res[1] = res;
fds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
fds->base_res[0] = (is_2D && is_axis_X) ? 1 : max_ii((int)(size[0] * scale + 0.5f), 4);
fds->base_res[1] = (is_2D && is_axis_Y) ? 1 : res;
fds->base_res[2] = (is_2D && is_axis_Z) ? 1 : max_ii((int)(size[2] * scale + 0.5f), 4);
}
else {
scale = res / size[2];
fds->scale = size[2] / fabsf(ob->scale[2]);
fds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
fds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
fds->base_res[2] = res;
fds->base_res[0] = (is_2D && is_axis_X) ? 1 : max_ii((int)(size[0] * scale + 0.5f), 4);
fds->base_res[1] = (is_2D && is_axis_Y) ? 1 : max_ii((int)(size[1] * scale + 0.5f), 4);
fds->base_res[2] = (is_2D && is_axis_Z) ? 1 : res;
}
/* Set cell size. */
@@ -2270,7 +2275,10 @@ static void adaptive_domain_adjust(
fds->p1[2] = fds->p0[2] + fds->cell_size[2] * fds->base_res[2];
/* adjust domain resolution */
const int block_size = fds->noise_scale;
int block_size[3] = {fds->noise_scale, fds->noise_scale, fds->noise_scale};
if (fds->solver_res == FLUID_DOMAIN_DIMENSION_2D) {
block_size[fds->slice_axis - 1] = 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];
@@ -2282,10 +2290,10 @@ static void adaptive_domain_adjust(
float *vx = manta_get_velocity_x(fds->fluid);
float *vy = manta_get_velocity_y(fds->fluid);
float *vz = manta_get_velocity_z(fds->fluid);
int wt_res[3];
int res_noise[3];
if (fds->flags & FLUID_DOMAIN_USE_NOISE && fds->fluid) {
manta_noise_get_res(fds->fluid, wt_res);
manta_noise_get_res(fds->fluid, res_noise);
}
INIT_MINMAX(min_vel, max_vel);
@@ -2317,14 +2325,15 @@ static void adaptive_domain_adjust(
if (max_den < fds->adapt_threshold && fds->flags & FLUID_DOMAIN_USE_NOISE && fds->fluid) {
int i, j, k;
/* high res grid index */
int xx = (x - fds->res_min[0]) * block_size;
int yy = (y - fds->res_min[1]) * block_size;
int zz = (z - fds->res_min[2]) * block_size;
int xx = (x - fds->res_min[0]) * block_size[0];
int yy = (y - fds->res_min[1]) * block_size[1];
int zz = (z - fds->res_min[2]) * block_size[2];
for (i = 0; i < block_size; i++) {
for (j = 0; j < block_size; j++) {
for (k = 0; k < block_size; k++) {
int big_index = manta_get_index(xx + i, wt_res[0], yy + j, wt_res[1], zz + k);
for (i = 0; i < block_size[0]; i++) {
for (j = 0; j < block_size[1]; j++) {
for (k = 0; k < block_size[2]; k++) {
int big_index = manta_get_index(
xx + i, res_noise[0], yy + j, res_noise[1], zz + k);
float den = (bigfuel) ? MAX2(bigdensity[big_index], bigfuel[big_index]) :
bigdensity[big_index];
if (den > max_den) {
@@ -4708,6 +4717,16 @@ void BKE_fluid_effector_type_set(Object *UNUSED(object), FluidEffectorSettings *
settings->type = type;
}
void BKE_fluid_domain_solver_res_set(Object *UNUSED(object),
FluidDomainSettings *settings,
int res)
{
if (res == FLUID_DOMAIN_DIMENSION_2D && settings->slice_axis == SLICE_AXIS_AUTO) {
settings->slice_axis = SLICE_AXIS_X;
}
settings->solver_res = res;
}
void BKE_fluid_fields_sanitize(FluidDomainSettings *settings)
{
/* Based on the domain type, certain fields are defaulted accordingly if the selected field

View File

@@ -4379,6 +4379,21 @@ static void particles_fluid_step(ParticleSimulationData *sim,
const float posParticle[3] = {posX, posY, posZ};
copy_v3_v3(pa->state.co, posParticle);
/* Adjust particle position for 2d representation. */
if (fds->solver_res == FLUID_DOMAIN_DIMENSION_2D) {
if (fds->slice_axis == SLICE_AXIS_X) {
float tmp = pa->state.co[1];
pa->state.co[1] = pa->state.co[0];
pa->state.co[0] = pa->state.co[2];
pa->state.co[2] = tmp;
}
if (fds->slice_axis == SLICE_AXIS_Y) {
float tmp = pa->state.co[1];
pa->state.co[1] = pa->state.co[2];
pa->state.co[2] = tmp;
}
}
/* Normalize to unit cube around 0. */
float resDomain[3] = {resX, resY, resZ};
mul_v3_fl(resDomain, 0.5f);
@@ -4412,6 +4427,21 @@ static void particles_fluid_step(ParticleSimulationData *sim,
const float velParticle[3] = {velX, velY, velZ};
copy_v3_v3(pa->state.vel, velParticle);
mul_v3_fl(pa->state.vel, fds->dx);
/* Adjust particle velocity for 2d representation. */
if (fds->solver_res == FLUID_DOMAIN_DIMENSION_2D) {
if (fds->slice_axis == SLICE_AXIS_X) {
float tmp = pa->state.vel[1];
pa->state.vel[0] = pa->state.vel[2];
pa->state.vel[1] = pa->state.vel[0];
pa->state.vel[2] = tmp;
}
else if (fds->slice_axis == SLICE_AXIS_Y) {
float tmp = pa->state.vel[1];
pa->state.vel[1] = pa->state.vel[2];
pa->state.vel[2] = tmp;
}
}
# if 0
/* Debugging: Print particle velocity. */
printf("pa->state.vel[0]: %f, pa->state.vel[1]: %f, pa->state.vel[2]: %f\n",

View File

@@ -1392,15 +1392,20 @@ static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb,
const bool color_range = (fds->gridlines_color_field == FLUID_GRIDLINE_COLOR_TYPE_RANGE &&
fds->use_coba && fds->coba_field != FLUID_DOMAIN_FIELD_FLAGS);
const bool is_2D = (fds->solver_res == FLUID_DOMAIN_DIMENSION_2D);
const bool is_axis_X = (fds->slice_axis == SLICE_AXIS_X);
const bool is_axis_Y = (fds->slice_axis == SLICE_AXIS_Y);
const bool is_axis_Z = (fds->slice_axis == SLICE_AXIS_Z);
/* Small cube showing voxel size. */
{
float min[3];
madd_v3fl_v3fl_v3fl_v3i(min, fds->p0, fds->cell_size, fds->res_min);
float voxel_cubemat[4][4] = {{0.0f}};
/* scale small cube to voxel size */
voxel_cubemat[0][0] = fds->cell_size[0] / 2.0f;
voxel_cubemat[1][1] = fds->cell_size[1] / 2.0f;
voxel_cubemat[2][2] = fds->cell_size[2] / 2.0f;
voxel_cubemat[0][0] = (is_2D && is_axis_X) ? 0.0f : (fds->cell_size[0] / 2.0f);
voxel_cubemat[1][1] = (is_2D && is_axis_Y) ? 0.0f : (fds->cell_size[1] / 2.0f);
voxel_cubemat[2][2] = (is_2D && is_axis_Z) ? 0.0f : (fds->cell_size[2] / 2.0f);
voxel_cubemat[3][3] = 1.0f;
/* translate small cube to corner */
copy_v3_v3(voxel_cubemat[3], min);

View File

@@ -92,7 +92,8 @@ static void workbench_volume_modifier_cache_populate(WORKBENCH_Data *vedata,
return;
}
const bool use_slice = (fds->axis_slice_method == AXIS_SLICE_SINGLE);
const bool use_slice = (fds->axis_slice_method == AXIS_SLICE_SINGLE) ||
(fds->solver_res == FLUID_DOMAIN_DIMENSION_2D);
const bool show_phi = ELEM(fds->coba_field,
FLUID_DOMAIN_FIELD_PHI,
FLUID_DOMAIN_FIELD_PHI_IN,

View File

@@ -327,7 +327,13 @@ static GPUTexture *create_field_texture(FluidDomainSettings *fds, bool single_pr
static GPUTexture *create_density_texture(FluidDomainSettings *fds, int highres)
{
int *dim = (highres) ? fds->res_noise : fds->res;
int res[3];
if (highres) {
manta_noise_get_res(fds->fluid, res);
}
else {
manta_get_res(fds->fluid, res);
}
float *data;
if (highres) {
@@ -341,7 +347,7 @@ static GPUTexture *create_density_texture(FluidDomainSettings *fds, int highres)
return NULL;
}
GPUTexture *tex = create_volume_texture(dim, GPU_R8, GPU_DATA_FLOAT, data);
GPUTexture *tex = create_volume_texture(res, GPU_R8, GPU_DATA_FLOAT, data);
swizzle_texture_channel_single(tex);
return tex;
}
@@ -356,7 +362,15 @@ static GPUTexture *create_color_texture(FluidDomainSettings *fds, int highres)
}
int cell_count = (highres) ? manta_noise_get_cells(fds->fluid) : fds->total_cells;
int *dim = (highres) ? fds->res_noise : fds->res;
int res[3];
if (highres) {
manta_noise_get_res(fds->fluid, res);
}
else {
manta_get_res(fds->fluid, res);
}
float *data = (float *)MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture");
if (data == NULL) {
@@ -370,7 +384,7 @@ static GPUTexture *create_color_texture(FluidDomainSettings *fds, int highres)
manta_smoke_get_rgba(fds->fluid, data, 0);
}
GPUTexture *tex = create_volume_texture(dim, GPU_RGBA8, GPU_DATA_FLOAT, data);
GPUTexture *tex = create_volume_texture(res, GPU_RGBA8, GPU_DATA_FLOAT, data);
MEM_freeN(data);
@@ -382,7 +396,14 @@ static GPUTexture *create_flame_texture(FluidDomainSettings *fds, int highres)
float *source = NULL;
const bool has_fuel = (highres) ? manta_noise_has_fuel(fds->fluid) :
manta_smoke_has_fuel(fds->fluid);
int *dim = (highres) ? fds->res_noise : fds->res;
int res[3];
if (highres) {
manta_noise_get_res(fds->fluid, res);
}
else {
manta_get_res(fds->fluid, res);
}
if (!has_fuel) {
return NULL;
@@ -395,7 +416,7 @@ static GPUTexture *create_flame_texture(FluidDomainSettings *fds, int highres)
source = manta_smoke_get_flame(fds->fluid);
}
GPUTexture *tex = create_volume_texture(dim, GPU_R8, GPU_DATA_FLOAT, source);
GPUTexture *tex = create_volume_texture(res, GPU_R8, GPU_DATA_FLOAT, source);
swizzle_texture_channel_single(tex);
return tex;
}

View File

@@ -99,7 +99,6 @@
.noise_strength = 1.0f, \
.noise_pos_scale = 2.0f, \
.noise_time_anim = 0.1f, \
.res_noise = {0, 0, 0}, \
.noise_scale = 2, \
.particle_randomness = 0.1f, \
.particle_number = 2, \

View File

@@ -198,6 +198,12 @@ enum {
FLUID_DOMAIN_TYPE_LIQUID = 1,
};
/* Fluid domain dimension. */
enum {
FLUID_DOMAIN_DIMENSION_2D = 2,
FLUID_DOMAIN_DIMENSION_3D = 3,
};
/* Mesh levelset generator types. */
enum {
FLUID_DOMAIN_MESH_IMPROVED = 0,
@@ -573,9 +579,7 @@ typedef struct FluidDomainSettings {
float noise_strength;
float noise_pos_scale;
float noise_time_anim;
int res_noise[3];
int noise_scale;
char _pad3[4]; /* Unused. */
/* Liquid domain options. */
float particle_randomness;
@@ -589,11 +593,11 @@ typedef struct FluidDomainSettings {
float flip_ratio;
int sys_particle_maximum;
short simulation_method;
char _pad4[6];
char _pad3[6];
/* Viscosity options. */
float viscosity_value;
char _pad5[4];
char _pad4[4];
/* Diffusion options. */
float surface_tension;
@@ -609,7 +613,7 @@ typedef struct FluidDomainSettings {
int mesh_scale;
int totvert;
short mesh_generator;
char _pad6[6]; /* Unused. */
char _pad5[6]; /* Unused. */
/* Secondary particle options. */
int particle_type;
@@ -630,7 +634,7 @@ typedef struct FluidDomainSettings {
int sndparticle_update_radius;
char sndparticle_boundary;
char sndparticle_combined_export;
char _pad7[6]; /* Unused. */
char _pad6[6]; /* Unused. */
/* Fluid guiding options. */
float guide_alpha; /* Guiding weight scalar (determines strength). */
@@ -638,7 +642,7 @@ typedef struct FluidDomainSettings {
float guide_vel_factor; /* Multiply guiding velocity by this factor. */
int guide_res[3]; /* Res for velocity guide grids - independent from base res. */
short guide_source;
char _pad8[2]; /* Unused. */
char _pad7[2]; /* Unused. */
/* Cache options. */
int cache_frame_start;
@@ -658,7 +662,7 @@ typedef struct FluidDomainSettings {
char error[64]; /* Bake error description. */
short cache_type;
char cache_id[4]; /* Run-time only */
char _pad9[2]; /* Unused. */
char _pad8[2]; /* Unused. */
/* Time options. */
float dt;
@@ -693,19 +697,19 @@ typedef struct FluidDomainSettings {
char interp_method;
char gridlines_color_field; /* Simulation field used to color map onto gridlines. */
char gridlines_cell_filter;
char _pad10[7]; /* Unused. */
char _pad9[7]; /* Unused. */
/* OpenVDB cache options. */
int openvdb_compression;
float clipping;
char openvdb_data_depth;
char _pad11[7]; /* Unused. */
char _pad10[7]; /* Unused. */
/* -- Deprecated / unsed options (below). -- */
/* View options. */
int viewsettings;
char _pad12[4]; /* Unused. */
char _pad11[4]; /* Unused. */
/* Pointcache options. */
/* Smoke uses only one cache from now on (index [0]), but keeping the array for now for reading
@@ -715,7 +719,7 @@ typedef struct FluidDomainSettings {
int cache_comp;
int cache_high_comp;
char cache_file_format;
char _pad13[7]; /* Unused. */
char _pad12[7]; /* Unused. */
} FluidDomainSettings;

View File

@@ -220,6 +220,16 @@ static void rna_Fluid_reset_dependency(Main *bmain, Scene *scene, PointerRNA *pt
rna_Fluid_dependency_update(bmain, scene, ptr);
}
static void rna_Fluid_slice_axis_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
{
# ifdef WITH_FLUID
FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
if (settings->solver_res == FLUID_DOMAIN_DIMENSION_2D) {
rna_Fluid_domain_data_reset(bmain, scene, ptr);
}
# endif
}
static void rna_Fluid_parts_create(Main *bmain,
PointerRNA *ptr,
const char *pset_name,
@@ -863,6 +873,60 @@ static const EnumPropertyItem *rna_Fluid_data_depth_itemf(bContext *UNUSED(C),
return item;
}
static const EnumPropertyItem *rna_Fluid_slice_axis_itemf(bContext *UNUSED(C),
PointerRNA *ptr,
PropertyRNA *UNUSED(prop),
bool *r_free)
{
FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
EnumPropertyItem *item = NULL;
EnumPropertyItem tmp = {0, "", 0, "", ""};
int totitem = 0;
if (settings->solver_res == FLUID_DOMAIN_DIMENSION_3D) {
tmp.value = SLICE_AXIS_AUTO;
tmp.identifier = "AUTO";
tmp.icon = 0;
tmp.name = "Auto";
tmp.description = "Adjust slice direction according to the view direction";
RNA_enum_item_add(&item, &totitem, &tmp);
}
tmp.value = SLICE_AXIS_X;
tmp.identifier = "X";
tmp.icon = 0;
tmp.name = "X";
tmp.description = "Slice along the X axis";
RNA_enum_item_add(&item, &totitem, &tmp);
tmp.value = SLICE_AXIS_Y;
tmp.identifier = "Y";
tmp.icon = 0;
tmp.name = "Y";
tmp.description = "Slice along the Y axis";
RNA_enum_item_add(&item, &totitem, &tmp);
tmp.value = SLICE_AXIS_Z;
tmp.identifier = "Z";
tmp.icon = 0;
tmp.name = "Z";
tmp.description = "Slice along the Z axis";
RNA_enum_item_add(&item, &totitem, &tmp);
RNA_enum_item_end(&item, &totitem);
*r_free = true;
return item;
}
static void rna_Fluid_solver_res_set(struct PointerRNA *ptr, int value)
{
FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
Object *ob = (Object *)ptr->owner_id;
BKE_fluid_domain_solver_res_set(ob, settings, value);
}
static void rna_Fluid_domaintype_set(struct PointerRNA *ptr, int value)
{
FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
@@ -1268,6 +1332,12 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
{FLUID_DOMAIN_TYPE_LIQUID, "LIQUID", 0, "Liquid", "Create domain for liquids"},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem solver_res_items[] = {
{FLUID_DOMAIN_DIMENSION_2D, "2D", 0, "2D", "Create 2D domain"},
{FLUID_DOMAIN_DIMENSION_3D, "3D", 0, "3D", "Create 3D domain"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem prop_compression_items[] = {
{VDB_COMPRESSION_ZIP, "ZIP", 0, "Zip", "Effective but slow compression"},
# ifdef WITH_OPENVDB_BLOSC
@@ -1351,15 +1421,9 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
/* Axis options are generated dynamically based on domain dimension (2D or 3D). */
static const EnumPropertyItem axis_slice_position_items[] = {
{SLICE_AXIS_AUTO,
"AUTO",
0,
"Auto",
"Adjust slice direction according to the view direction"},
{SLICE_AXIS_X, "X", 0, "X", "Slice along the X axis"},
{SLICE_AXIS_Y, "Y", 0, "Y", "Slice along the Y axis"},
{SLICE_AXIS_Z, "Z", 0, "Z", "Slice along the Z axis"},
{0, "NONE", 0, "", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -1670,6 +1734,13 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_flip_parts_update");
prop = RNA_def_property(srna, "solver_res", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, solver_res_items);
RNA_def_property_enum_funcs(prop, NULL, "rna_Fluid_solver_res_set", NULL);
RNA_def_property_ui_text(prop, "Dimension", "Change the solver resolution");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "delete_in_obstacle", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_DELETE_IN_OBSTACLE);
RNA_def_property_ui_text(prop, "Clear In Obstacle", "Delete fluid inside obstacles");
@@ -2518,8 +2589,9 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "slice_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "slice_axis");
RNA_def_property_enum_items(prop, axis_slice_position_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Fluid_slice_axis_itemf");
RNA_def_property_ui_text(prop, "Axis", "");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_slice_axis_reset");
prop = RNA_def_property(srna, "slice_per_voxel", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "slice_per_voxel");