Smoke: put density/color in separate textures, fixes for workbench shader

This is more in line with standard grids and means we don't have to make
many special exceptions in the upcoming change for arbitrary number of volume
grids support in Eevee.

The workbench shader was also changed to fix bugs where squared density was
used, and the smoke color would affect the density so that black smoke would
be invisible. This can change the look of smoke in workbench significantly.

When using the color grid when smoke has a constant color, the color grid
will no longer be premultiplied by the density. If the color is constant
we want to be able not to store a grid at all. This breaks one test for
Cycles and Eevee, but the setup in that test using a color without density
does not make sense. It suffers from artifacts since the unpremultiplied
color grid by itself will not have smooth boundaries.

Differential Revision: https://developer.blender.org/D6951
This commit is contained in:
Brecht Van Lommel 2020-03-11 13:56:28 +01:00 committed by Brecht Van Lommel
parent f3a33a9298
commit c8acb6dd6c
17 changed files with 137 additions and 118 deletions

View File

@ -132,14 +132,14 @@ void manta_smoke_turbulence_export(struct MANTA *smoke,
float **tcw2);
void manta_smoke_get_rgba(struct MANTA *smoke, float *data, int sequential);
void manta_smoke_turbulence_get_rgba(struct MANTA *smoke, float *data, int sequential);
void manta_smoke_get_rgba_from_density(struct MANTA *smoke,
float color[3],
float *data,
int sequential);
void manta_smoke_turbulence_get_rgba_from_density(struct MANTA *smoke,
float color[3],
float *data,
int sequential);
void manta_smoke_get_rgba_fixed_color(struct MANTA *smoke,
float color[3],
float *data,
int sequential);
void manta_smoke_turbulence_get_rgba_fixed_color(struct MANTA *smoke,
float color[3],
float *data,
int sequential);
void manta_smoke_ensure_heat(struct MANTA *smoke, struct FluidModifierData *mmd);
void manta_smoke_ensure_fire(struct MANTA *smoke, struct FluidModifierData *mmd);
void manta_smoke_ensure_colors(struct MANTA *smoke, struct FluidModifierData *mmd);

View File

@ -455,14 +455,9 @@ static void get_rgba(
for (i = 0; i < total_cells; i++) {
float alpha = a[i];
if (alpha) {
data[i * m] = r[i];
data[i * m + i_g] = g[i];
data[i * m + i_b] = b[i];
}
else {
data[i * m] = data[i * m + i_g] = data[i * m + i_b] = 0.0f;
}
data[i * m] = r[i] * alpha;
data[i * m + i_g] = g[i] * alpha;
data[i * m + i_b] = b[i] * alpha;
data[i * m + i_a] = alpha;
}
}
@ -489,8 +484,7 @@ void manta_smoke_turbulence_get_rgba(MANTA *smoke, float *data, int sequential)
sequential);
}
static void get_rgba_from_density(
float color[3], float *a, int total_cells, float *data, int sequential)
static void get_rgba_fixed_color(float color[3], int total_cells, float *data, int sequential)
{
int i;
int m = 4, i_g = 1, i_b = 2, i_a = 3;
@ -502,31 +496,24 @@ static void get_rgba_from_density(
}
for (i = 0; i < total_cells; i++) {
float alpha = a[i];
if (alpha) {
data[i * m] = color[0] * alpha;
data[i * m + i_g] = color[1] * alpha;
data[i * m + i_b] = color[2] * alpha;
}
else {
data[i * m] = data[i * m + i_g] = data[i * m + i_b] = 0.0f;
}
data[i * m + i_a] = alpha;
data[i * m] = color[0];
data[i * m + i_g] = color[1];
data[i * m + i_b] = color[2];
data[i * m + i_a] = 1.0f;
}
}
void manta_smoke_get_rgba_from_density(MANTA *smoke, float color[3], float *data, int sequential)
void manta_smoke_get_rgba_fixed_color(MANTA *smoke, float color[3], float *data, int sequential)
{
get_rgba_from_density(color, smoke->getDensity(), smoke->getTotalCells(), data, sequential);
get_rgba_fixed_color(color, smoke->getTotalCells(), data, sequential);
}
void manta_smoke_turbulence_get_rgba_from_density(MANTA *smoke,
float color[3],
float *data,
int sequential)
void manta_smoke_turbulence_get_rgba_fixed_color(MANTA *smoke,
float color[3],
float *data,
int sequential)
{
get_rgba_from_density(
color, smoke->getDensityHigh(), smoke->getTotalCellsHigh(), data, sequential);
get_rgba_fixed_color(color, smoke->getTotalCellsHigh(), data, sequential);
}
void manta_smoke_ensure_heat(MANTA *smoke, struct FluidModifierData *mmd)

View File

@ -5439,7 +5439,8 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb, Object *ob)
mmd->domain->fluid = NULL;
mmd->domain->fluid_mutex = BLI_rw_mutex_alloc();
mmd->domain->tex = NULL;
mmd->domain->tex_density = NULL;
mmd->domain->tex_color = NULL;
mmd->domain->tex_shadow = NULL;
mmd->domain->tex_flame = NULL;
mmd->domain->tex_flame_coba = NULL;

View File

@ -141,10 +141,10 @@ static void eevee_create_shader_volumes(void)
e_data.volumetric_accum_sh = DRW_shader_create_fullscreen(datatoc_volumetric_accum_frag_glsl,
NULL);
float color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
e_data.dummy_density = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, color);
const float density[4] = {1.0f, 1.0f, 1.0f, 1.0f};
e_data.dummy_density = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, density);
float flame = 0.0f;
const float flame = 0.0f;
e_data.dummy_flame = DRW_texture_create_3d(1, 1, 1, GPU_R8, DRW_TEX_WRAP, &flame);
}
@ -368,6 +368,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
/* Fix principle volumetric not working with world materials. */
DRW_shgroup_uniform_texture(grp, "sampdensity", e_data.dummy_density);
DRW_shgroup_uniform_texture(grp, "sampcolor", e_data.dummy_density);
DRW_shgroup_uniform_texture(grp, "sampflame", e_data.dummy_flame);
DRW_shgroup_uniform_vec2_copy(grp, "unftemperature", (float[2]){0.0f, 1.0f});
@ -477,7 +478,9 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
}
DRW_shgroup_uniform_texture_ref(
grp, "sampdensity", mds->tex ? &mds->tex : &e_data.dummy_density);
grp, "sampdensity", mds->tex_density ? &mds->tex_density : &e_data.dummy_density);
DRW_shgroup_uniform_texture_ref(
grp, "sampcolor", mds->tex_color ? &mds->tex_color : &e_data.dummy_density);
DRW_shgroup_uniform_texture_ref(
grp, "sampflame", mds->tex_flame ? &mds->tex_flame : &e_data.dummy_flame);
@ -493,6 +496,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
}
else {
DRW_shgroup_uniform_texture(grp, "sampdensity", e_data.dummy_density);
DRW_shgroup_uniform_texture(grp, "sampcolor", e_data.dummy_density);
DRW_shgroup_uniform_texture(grp, "sampflame", e_data.dummy_flame);
DRW_shgroup_uniform_vec3(grp, "volumeColor", white, 1);
DRW_shgroup_uniform_vec2(grp, "unftemperature", (float[2]){0.0f, 1.0f}, 1);

View File

@ -134,8 +134,9 @@ void volume_properties(vec3 ls_pos, out vec3 scattering, out float extinction)
float shadows = sample_volume_texture(shadowTexture, co).r;
vec4 density = sample_volume_texture(densityTexture, co); /* rgb: color, a: density */
scattering = density.rgb * (density.a * densityScale) * activeColor;
scattering = density.rgb * densityScale;
extinction = max(1e-4, dot(scattering, vec3(0.33333)));
scattering *= activeColor;
/* Scale shadows in log space and clamp them to avoid completely black shadows. */
scattering *= exp(clamp(log(shadows) * densityScale * 0.1, -2.5, 0.0)) * M_PI;

View File

@ -146,7 +146,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
GPU_create_smoke(mmd, 1);
}
if ((!mds->use_coba && mds->tex == NULL) || (mds->use_coba && mds->tex_field == NULL)) {
if ((!mds->use_coba && (mds->tex_density == NULL && mds->tex_color == NULL)) ||
(mds->use_coba && mds->tex_field == NULL)) {
return;
}
@ -201,7 +202,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
static float white[3] = {1.0f, 1.0f, 1.0f};
bool use_constant_color = ((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
(mds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0);
DRW_shgroup_uniform_texture(grp, "densityTexture", mds->tex);
DRW_shgroup_uniform_texture(
grp, "densityTexture", (mds->tex_color) ? mds->tex_color : mds->tex_density);
DRW_shgroup_uniform_texture(grp, "shadowTexture", mds->tex_shadow);
DRW_shgroup_uniform_texture(
grp, "flameTexture", (mds->tex_flame) ? mds->tex_flame : e_data.dummy_tex);

View File

@ -99,11 +99,12 @@ typedef enum eGPUBuiltin {
GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14),
GPU_OBJECT_INFO = (1 << 15),
GPU_VOLUME_DENSITY = (1 << 16),
GPU_VOLUME_FLAME = (1 << 17),
GPU_VOLUME_TEMPERATURE = (1 << 18),
GPU_BARYCENTRIC_TEXCO = (1 << 19),
GPU_BARYCENTRIC_DIST = (1 << 20),
GPU_WORLD_NORMAL = (1 << 21),
GPU_VOLUME_COLOR = (1 << 17),
GPU_VOLUME_FLAME = (1 << 18),
GPU_VOLUME_TEMPERATURE = (1 << 19),
GPU_BARYCENTRIC_TEXCO = (1 << 20),
GPU_BARYCENTRIC_DIST = (1 << 21),
GPU_WORLD_NORMAL = (1 << 22),
} eGPUBuiltin;
typedef enum eGPUMatFlag {

View File

@ -238,6 +238,7 @@ void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat);
void GPU_texture_filters(GPUTexture *tex,
eGPUFilterFunction min_filter,
eGPUFilterFunction mag_filter);
void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels);
void GPU_texture_attach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb, int attachment);
int GPU_texture_detach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb);

View File

@ -272,6 +272,9 @@ static const char *gpu_builtin_name(eGPUBuiltin builtin)
else if (builtin == GPU_VOLUME_DENSITY) {
return "sampdensity";
}
else if (builtin == GPU_VOLUME_COLOR) {
return "sampcolor";
}
else if (builtin == GPU_VOLUME_FLAME) {
return "sampflame";
}
@ -351,7 +354,8 @@ static int codegen_process_uniforms_functions(GPUMaterial *material,
name = gpu_builtin_name(input->builtin);
if (BLI_str_startswith(name, "samp")) {
if ((input->builtin == GPU_VOLUME_DENSITY) || (input->builtin == GPU_VOLUME_FLAME)) {
if ((input->builtin == GPU_VOLUME_DENSITY) || (input->builtin == GPU_VOLUME_COLOR) ||
(input->builtin == GPU_VOLUME_FLAME)) {
BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", name);
}
}

View File

@ -122,13 +122,10 @@ static GPUTexture *create_transfer_function(int type, const struct ColorBand *co
return tex;
}
static void swizzle_texture_channel_rrrr(GPUTexture *tex)
static void swizzle_texture_channel_single(GPUTexture *tex)
{
GPU_texture_bind(tex, 0);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED);
GPU_texture_swizzle_channel_auto(tex, 1);
GPU_texture_unbind(tex);
}
@ -186,60 +183,59 @@ static GPUTexture *create_field_texture(FluidDomainSettings *mds)
GPUTexture *tex = GPU_texture_create_nD(
mds->res[0], mds->res[1], mds->res[2], 3, field, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
swizzle_texture_channel_rrrr(tex);
swizzle_texture_channel_single(tex);
return tex;
}
static GPUTexture *create_density_texture(FluidDomainSettings *mds, int highres)
{
float *data = NULL, *source;
int cell_count = (highres) ? manta_smoke_turbulence_get_cells(mds->fluid) : mds->total_cells;
int *dim = (highres) ? mds->res_noise : mds->res;
float *data;
if (highres) {
data = manta_smoke_turbulence_get_density(mds->fluid);
}
else {
data = manta_smoke_get_density(mds->fluid);
}
GPUTexture *tex = GPU_texture_create_nD(
dim[0], dim[1], dim[2], 3, data, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
swizzle_texture_channel_single(tex);
return tex;
}
static GPUTexture *create_color_texture(FluidDomainSettings *mds, int highres)
{
const bool has_color = (highres) ? manta_smoke_turbulence_has_colors(mds->fluid) :
manta_smoke_has_colors(mds->fluid);
int *dim = (highres) ? mds->res_noise : mds->res;
eGPUTextureFormat format = (has_color) ? GPU_RGBA8 : GPU_R8;
if (has_color) {
data = MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture");
if (!has_color) {
return NULL;
}
int cell_count = (highres) ? manta_smoke_turbulence_get_cells(mds->fluid) : mds->total_cells;
int *dim = (highres) ? mds->res_noise : mds->res;
float *data = MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture");
if (data == NULL) {
return NULL;
}
if (highres) {
if (has_color) {
manta_smoke_turbulence_get_rgba(mds->fluid, data, 0);
}
else {
source = manta_smoke_turbulence_get_density(mds->fluid);
}
manta_smoke_turbulence_get_rgba(mds->fluid, data, 0);
}
else {
if (has_color) {
manta_smoke_get_rgba(mds->fluid, data, 0);
}
else {
source = manta_smoke_get_density(mds->fluid);
}
manta_smoke_get_rgba(mds->fluid, data, 0);
}
GPUTexture *tex = GPU_texture_create_nD(dim[0],
dim[1],
dim[2],
3,
(has_color) ? data : source,
format,
GPU_DATA_FLOAT,
0,
true,
NULL);
if (data) {
MEM_freeN(data);
}
GPUTexture *tex = GPU_texture_create_nD(
dim[0], dim[1], dim[2], 3, data, GPU_RGBA8, GPU_DATA_FLOAT, 0, true, NULL);
MEM_freeN(data);
if (format == GPU_R8) {
/* Swizzle the RGBA components to read the Red channel so
* that the shader stay the same for colored and non color
* density textures. */
swizzle_texture_channel_rrrr(tex);
}
return tex;
}
@ -264,7 +260,7 @@ static GPUTexture *create_flame_texture(FluidDomainSettings *mds, int highres)
GPUTexture *tex = GPU_texture_create_nD(
dim[0], dim[1], dim[2], 3, source, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
swizzle_texture_channel_rrrr(tex);
swizzle_texture_channel_single(tex);
return tex;
}
@ -280,35 +276,40 @@ static GPUTexture *create_flame_texture(FluidDomainSettings *mds, int highres)
void GPU_free_smoke(FluidModifierData *mmd)
{
if (mmd->type & MOD_FLUID_TYPE_DOMAIN && mmd->domain) {
if (mmd->domain->tex) {
GPU_texture_free(mmd->domain->tex);
if (mmd->domain->tex_density) {
GPU_texture_free(mmd->domain->tex_density);
mmd->domain->tex_density = NULL;
}
if (mmd->domain->tex_color) {
GPU_texture_free(mmd->domain->tex_color);
mmd->domain->tex_color = NULL;
}
mmd->domain->tex = NULL;
if (mmd->domain->tex_shadow) {
GPU_texture_free(mmd->domain->tex_shadow);
mmd->domain->tex_shadow = NULL;
}
mmd->domain->tex_shadow = NULL;
if (mmd->domain->tex_flame) {
GPU_texture_free(mmd->domain->tex_flame);
mmd->domain->tex_flame = NULL;
}
mmd->domain->tex_flame = NULL;
if (mmd->domain->tex_flame_coba) {
GPU_texture_free(mmd->domain->tex_flame_coba);
mmd->domain->tex_flame_coba = NULL;
}
mmd->domain->tex_flame_coba = NULL;
if (mmd->domain->tex_coba) {
GPU_texture_free(mmd->domain->tex_coba);
mmd->domain->tex_coba = NULL;
}
mmd->domain->tex_coba = NULL;
if (mmd->domain->tex_field) {
GPU_texture_free(mmd->domain->tex_field);
mmd->domain->tex_field = NULL;
}
mmd->domain->tex_field = NULL;
}
}
@ -338,8 +339,11 @@ void GPU_create_smoke(FluidModifierData *mmd, int highres)
if (mmd->type & MOD_FLUID_TYPE_DOMAIN) {
FluidDomainSettings *mds = mmd->domain;
if (!mds->tex) {
mds->tex = create_density_texture(mds, highres);
if (!mds->tex_density) {
mds->tex_density = create_density_texture(mds, highres);
}
if (!mds->tex_color) {
mds->tex_color = create_color_texture(mds, highres);
}
if (!mds->tex_flame) {
mds->tex_flame = create_flame_texture(mds, highres);

View File

@ -1648,6 +1648,17 @@ void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat)
}
}
void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels)
{
WARN_NOT_BOUND(tex);
glActiveTexture(GL_TEXTURE0 + tex->number);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, (channels >= 2) ? GL_GREEN : GL_RED);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, (channels >= 3) ? GL_BLUE : GL_RED);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, (channels >= 4) ? GL_ALPHA : GL_ONE);
}
static GLenum gpu_get_gl_filterfunction(eGPUFilterFunction filter)
{
switch (filter) {

View File

@ -5,9 +5,9 @@ void node_attribute_volume_density(sampler3D tex, out vec4 outcol, out vec3 outv
#else
vec3 cos = vec3(0.0);
#endif
outvec = texture(tex, cos).aaa;
outcol = vec4(outvec, 1.0);
outf = avg(outvec);
outf = texture(tex, cos).r;
outvec = vec3(outf, outf, outf);
outcol = vec4(outf, outf, outf, 1.0);
}
uniform vec3 volumeColor = vec3(1.0);
@ -59,6 +59,7 @@ void node_attribute_volume_temperature(
}
void node_volume_info(sampler3D densitySampler,
sampler3D colorSampler,
sampler3D flameSampler,
vec2 temperature,
out vec4 outColor,
@ -72,14 +73,14 @@ void node_volume_info(sampler3D densitySampler,
vec3 p = vec3(0.0);
#endif
vec4 density = texture(densitySampler, p);
outDensity = density.a;
outDensity = texture(densitySampler, p).r;
/* Density is premultiplied for interpolation, divide it out here. */
if (density.a > 1e-8) {
density.rgb /= density.a;
/* Color is premultiplied for interpolation, divide it out here. */
vec4 color = texture(colorSampler, p);
if (color.a > 1e-8) {
color.rgb /= color.a;
}
outColor = vec4(density.rgb * volumeColor, 1.0);
outColor = vec4(color.rgb * volumeColor, 1.0);
float flame = texture(flameSampler, p).r;
outFlame = flame;

View File

@ -256,7 +256,8 @@ typedef struct FluidDomainSettings {
struct Collection *fluid_group;
struct Collection *force_group; /* UNUSED */
struct Collection *effector_group; /* Effector objects group. */
struct GPUTexture *tex;
struct GPUTexture *tex_density;
struct GPUTexture *tex_color;
struct GPUTexture *tex_wt;
struct GPUTexture *tex_shadow;
struct GPUTexture *tex_flame;

View File

@ -720,7 +720,7 @@ static void rna_FluidModifier_color_grid_get(PointerRNA *ptr, float *values)
manta_smoke_turbulence_get_rgba(mds->fluid, values, 0);
}
else {
manta_smoke_turbulence_get_rgba_from_density(mds->fluid, mds->active_color, values, 0);
manta_smoke_turbulence_get_rgba_fixed_color(mds->fluid, mds->active_color, values, 0);
}
}
else {
@ -728,7 +728,7 @@ static void rna_FluidModifier_color_grid_get(PointerRNA *ptr, float *values)
manta_smoke_get_rgba(mds->fluid, values, 0);
}
else {
manta_smoke_get_rgba_from_density(mds->fluid, mds->active_color, values, 0);
manta_smoke_get_rgba_fixed_color(mds->fluid, mds->active_color, values, 0);
}
}
}

View File

@ -50,7 +50,7 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
}
else if (strcmp(attr->name, "color") == 0) {
return GPU_stack_link(
mat, node, "node_attribute_volume_color", in, out, GPU_builtin(GPU_VOLUME_DENSITY));
mat, node, "node_attribute_volume_color", in, out, GPU_builtin(GPU_VOLUME_COLOR));
}
else if (strcmp(attr->name, "flame") == 0) {
return GPU_stack_link(

View File

@ -40,6 +40,7 @@ static int node_shader_gpu_volume_info(GPUMaterial *mat,
in,
out,
GPU_builtin(GPU_VOLUME_DENSITY),
GPU_builtin(GPU_VOLUME_COLOR),
GPU_builtin(GPU_VOLUME_FLAME),
GPU_builtin(GPU_VOLUME_TEMPERATURE));
}

View File

@ -70,7 +70,7 @@ static void node_shader_gpu_volume_attribute(GPUMaterial *mat,
}
else if (strcmp(name, "color") == 0) {
GPU_link(
mat, "node_attribute_volume_color", GPU_builtin(GPU_VOLUME_DENSITY), outcol, outvec, outf);
mat, "node_attribute_volume_color", GPU_builtin(GPU_VOLUME_COLOR), outcol, outvec, outf);
}
else if (strcmp(name, "flame") == 0) {
GPU_link(