Workbench: Smoke: Port back Flame display

The appearance is a bit different than 2.79 where the flame was just added
on top of the smoke without correct blending.

Now it's much more realistic and using volumetric integration. You can see
the smoke actually masking the flame.

The other difference is that the flame color was not using proper color
managed blending. Now with the use of filmic it shows bright yellow.
This could be adjusted and displayed as a user parameter in the future.
This commit is contained in:
Clément Foucault 2018-10-08 17:20:02 +02:00
parent 8c4a7593f2
commit e5c7c21630
5 changed files with 134 additions and 3 deletions

View File

@ -5168,6 +5168,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
smd->domain->tex = NULL;
smd->domain->tex_shadow = NULL;
smd->domain->tex_flame = NULL;
smd->domain->tex_flame_coba = NULL;
smd->domain->tex_velocity_x = NULL;
smd->domain->tex_velocity_y = NULL;
smd->domain->tex_velocity_z = NULL;

View File

@ -6,8 +6,11 @@ uniform mat4 ModelMatrix;
uniform vec3 OrcoTexCoFactors[2];
uniform sampler2D depthBuffer;
uniform sampler3D densityTexture;
uniform sampler3D shadowTexture;
uniform sampler3D flameTexture;
uniform sampler1D flameColorTexture;
uniform int samplesLen = 256;
uniform float stepLength; /* Step length in local space. */
@ -65,6 +68,10 @@ float line_unit_box_intersect_dist(vec3 lineorigin, vec3 linedirection)
void volume_properties(vec3 ls_pos, out vec3 scattering, out float extinction)
{
vec3 co = ls_pos * 0.5 + 0.5;
float flame = texture(flameTexture, co).r;
vec4 emission = texture(flameColorTexture, flame);
float shadows = texture(shadowTexture, co).r;
vec4 density = texture(densityTexture, co); /* rgb: color, a: density */
density.a *= densityScale;
@ -72,6 +79,8 @@ void volume_properties(vec3 ls_pos, out vec3 scattering, out float extinction)
scattering = density.rgb * density.a;
extinction = max(1e-4, dot(scattering, vec3(0.33333)));
scattering *= shadows * M_PI;
/* 800 is arbitrary and here to mimic old viewport. TODO make it a parameter */
scattering += pow(emission.rgb, vec3(2.2)) * emission.a * 800.0f;
}
void eval_volume_step(inout vec3 Lscat, float extinction, float step_len, out float Tr)

View File

@ -36,6 +36,8 @@
static struct {
struct GPUShader *volume_sh;
struct GPUShader *volume_slice_sh;
struct GPUTexture *dummy_tex;
struct GPUTexture *dummy_coba_tex;
} e_data = {NULL};
extern char datatoc_workbench_volume_vert_glsl[];
@ -50,6 +52,10 @@ void workbench_volume_engine_init(void)
e_data.volume_slice_sh = DRW_shader_create(
datatoc_workbench_volume_vert_glsl, NULL,
datatoc_workbench_volume_frag_glsl, "#define VOLUME_SLICE");
float pixel[4] = {0.0f, 0.0f, 0.0f, 0.0f};
e_data.dummy_tex = GPU_texture_create_3D(1, 1, 1, GPU_RGBA8, pixel, NULL);
e_data.dummy_coba_tex = GPU_texture_create_1D(1, GPU_RGBA8, pixel, NULL);
}
}
@ -57,6 +63,8 @@ void workbench_volume_engine_free(void)
{
DRW_SHADER_FREE_SAFE(e_data.volume_sh);
DRW_SHADER_FREE_SAFE(e_data.volume_slice_sh);
DRW_TEXTURE_FREE_SAFE(e_data.dummy_tex);
DRW_TEXTURE_FREE_SAFE(e_data.dummy_coba_tex);
}
void workbench_volume_cache_init(WORKBENCH_Data *vedata)
@ -102,6 +110,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, Scene *scene, Objec
DRWShadingGroup *grp = DRW_shgroup_create(e_data.volume_slice_sh, vedata->psl->volume_pass);
DRW_shgroup_uniform_texture(grp, "densityTexture", sds->tex);
DRW_shgroup_uniform_texture(grp, "shadowTexture", sds->tex_shadow);
DRW_shgroup_uniform_texture(grp, "flameTexture", (sds->tex_flame) ? sds->tex_flame : e_data.dummy_tex);
DRW_shgroup_uniform_texture(grp, "flameColorTexture", (sds->tex_flame) ? sds->tex_flame_coba : e_data.dummy_coba_tex);
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
DRW_shgroup_uniform_float_copy(grp, "densityScale", 10.0f * sds->display_thickness);
DRW_shgroup_uniform_float_copy(grp, "slicePosition", sds->slice_depth);
@ -109,7 +119,6 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, Scene *scene, Objec
DRW_shgroup_state_disable(grp, DRW_STATE_CULL_FRONT);
BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(smd));
/* TODO Flame rendering */
/* TODO COBA Rendering */
DRW_shgroup_call_object_add(grp, DRW_cache_quad_get(), ob);
@ -122,6 +131,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, Scene *scene, Objec
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
DRW_shgroup_uniform_texture(grp, "densityTexture", sds->tex);
DRW_shgroup_uniform_texture(grp, "shadowTexture", sds->tex_shadow);
DRW_shgroup_uniform_texture(grp, "flameTexture", (sds->tex_flame) ? sds->tex_flame : e_data.dummy_tex);
DRW_shgroup_uniform_texture(grp, "flameColorTexture", (sds->tex_flame) ? sds->tex_flame_coba : e_data.dummy_coba_tex);
DRW_shgroup_uniform_float_copy(grp, "densityScale", 10.0f * sds->display_thickness);
DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slices);
/* TODO FIXME : This step size is in object space but the ray itself
@ -131,7 +142,6 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, Scene *scene, Objec
DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT);
BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(smd));
/* TODO Flame rendering */
/* TODO COBA Rendering */
DRW_shgroup_call_object_add(grp, DRW_cache_cube_get(), ob);

View File

@ -63,6 +63,7 @@
#include "IMB_imbuf_types.h"
#include "BKE_bmfont.h"
#include "BKE_colorband.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
@ -883,6 +884,106 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
BKE_image_release_ibuf(ima, ibuf, NULL);
}
/* *************************** Transfer functions *************************** */
enum {
TFUNC_FLAME_SPECTRUM = 0,
TFUNC_COLOR_RAMP = 1,
};
#define TFUNC_WIDTH 256
static void create_flame_spectrum_texture(float *data)
{
#define FIRE_THRESH 7
#define MAX_FIRE_ALPHA 0.06f
#define FULL_ON_FIRE 100
float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels");
blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000);
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
for (int k = 0; k < TFUNC_WIDTH; k++) {
int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4;
if (k >= FIRE_THRESH) {
spec_pixels[index] = (data[k * 4]);
spec_pixels[index + 1] = (data[k * 4 + 1]);
spec_pixels[index + 2] = (data[k * 4 + 2]);
spec_pixels[index + 3] = MAX_FIRE_ALPHA * (
(k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH));
}
else {
zero_v4(&spec_pixels[index]);
}
}
}
}
memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH);
MEM_freeN(spec_pixels);
#undef FIRE_THRESH
#undef MAX_FIRE_ALPHA
#undef FULL_ON_FIRE
}
static void create_color_ramp(const ColorBand *coba, float *data)
{
for (int i = 0; i < TFUNC_WIDTH; i++) {
BKE_colorband_evaluate(coba, (float)i / TFUNC_WIDTH, &data[i * 4]);
}
}
static GPUTexture *create_transfer_function(int type, const ColorBand *coba)
{
float *data = MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__);
switch (type) {
case TFUNC_FLAME_SPECTRUM:
create_flame_spectrum_texture(data);
break;
case TFUNC_COLOR_RAMP:
create_color_ramp(coba, data);
break;
}
GPUTexture *tex = GPU_texture_create_1D(TFUNC_WIDTH, GPU_RGBA8, data, NULL);
MEM_freeN(data);
return tex;
}
static GPUTexture *create_field_texture(SmokeDomainSettings *sds)
{
float *field = NULL;
switch (sds->coba_field) {
#ifdef WITH_SMOKE
case FLUID_FIELD_DENSITY: field = smoke_get_density(sds->fluid); break;
case FLUID_FIELD_HEAT: field = smoke_get_heat(sds->fluid); break;
case FLUID_FIELD_FUEL: field = smoke_get_fuel(sds->fluid); break;
case FLUID_FIELD_REACT: field = smoke_get_react(sds->fluid); break;
case FLUID_FIELD_FLAME: field = smoke_get_flame(sds->fluid); break;
case FLUID_FIELD_VELOCITY_X: field = smoke_get_velocity_x(sds->fluid); break;
case FLUID_FIELD_VELOCITY_Y: field = smoke_get_velocity_y(sds->fluid); break;
case FLUID_FIELD_VELOCITY_Z: field = smoke_get_velocity_z(sds->fluid); break;
case FLUID_FIELD_COLOR_R: field = smoke_get_color_r(sds->fluid); break;
case FLUID_FIELD_COLOR_G: field = smoke_get_color_g(sds->fluid); break;
case FLUID_FIELD_COLOR_B: field = smoke_get_color_b(sds->fluid); break;
case FLUID_FIELD_FORCE_X: field = smoke_get_force_x(sds->fluid); break;
case FLUID_FIELD_FORCE_Y: field = smoke_get_force_y(sds->fluid); break;
case FLUID_FIELD_FORCE_Z: field = smoke_get_force_z(sds->fluid); break;
#endif
default: return NULL;
}
return GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], GPU_R8, field, NULL);
}
void GPU_free_smoke(SmokeModifierData *smd)
{
if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain) {
@ -897,6 +998,10 @@ void GPU_free_smoke(SmokeModifierData *smd)
if (smd->domain->tex_flame)
GPU_texture_free(smd->domain->tex_flame);
smd->domain->tex_flame = NULL;
if (smd->domain->tex_flame_coba)
GPU_texture_free(smd->domain->tex_flame_coba);
smd->domain->tex_flame_coba = NULL;
}
}
@ -966,12 +1071,16 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres)
sds->tex_flame = (
smoke_turbulence_has_fuel(sds->wt) ?
GPU_texture_create_nD(
sds->res[0], sds->res[1], sds->res[2], 3,
sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 3,
smoke_turbulence_get_flame(sds->wt),
GPU_R8, GPU_DATA_FLOAT, 0, true, NULL) :
NULL);
}
if (sds->tex_flame) {
sds->tex_flame_coba = create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL);
}
sds->tex_shadow = GPU_texture_create_nD(
sds->res[0], sds->res[1], sds->res[2], 3,
sds->shadow,
@ -982,6 +1091,7 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres)
(void)highres;
smd->domain->tex = NULL;
smd->domain->tex_flame = NULL;
smd->domain->tex_flame_coba = NULL;
smd->domain->tex_shadow = NULL;
#endif // WITH_SMOKE
}

View File

@ -137,6 +137,7 @@ typedef struct SmokeDomainSettings {
struct GPUTexture *tex_wt;
struct GPUTexture *tex_shadow;
struct GPUTexture *tex_flame;
struct GPUTexture *tex_flame_coba;
struct GPUTexture *tex_velocity_x;
struct GPUTexture *tex_velocity_y;
struct GPUTexture *tex_velocity_z;