Eevee: SSS: Add separated Albedo option.

This option prevent from automatically blurring the albedo color applied to the SSS.

While this is great for preserving details it can bleed more light onto the nearby objects since the blurring will be done on pure "white" irradiance.
This issue is to be tackled in a separate commit.
This commit is contained in:
Clément Foucault 2017-11-24 22:29:18 +01:00
parent 8d4aa6bf44
commit 7cbc7dd904
10 changed files with 97 additions and 11 deletions

View File

@ -780,6 +780,7 @@ class RENDER_PT_eevee_subsurface_scattering(RenderButtonsPanel, Panel):
col = layout.column()
col.prop(props, "sss_samples")
col.prop(props, "sss_jitter_threshold")
col.prop(props, "sss_separate_albedo")
class RENDER_PT_eevee_screen_space_reflections(RenderButtonsPanel, Panel):

View File

@ -346,6 +346,7 @@ class VIEWLAYER_PT_eevee_subsurface_scattering(ViewLayerButtonsPanel, Panel):
col = layout.column()
col.template_override_property(layer_props, scene_props, "sss_samples")
col.template_override_property(layer_props, scene_props, "sss_jitter_threshold")
col.template_override_property(layer_props, scene_props, "sss_separate_albedo")
class VIEWLAYER_PT_eevee_screen_space_reflections(ViewLayerButtonsPanel, Panel):

View File

@ -326,6 +326,7 @@ static void EEVEE_view_layer_settings_create(RenderEngine *UNUSED(engine), IDPro
BKE_collection_engine_property_add_bool(props, "sss_enable", false);
BKE_collection_engine_property_add_int(props, "sss_samples", 7);
BKE_collection_engine_property_add_float(props, "sss_jitter_threshold", 0.3f);
BKE_collection_engine_property_add_bool(props, "sss_separate_albedo", false);
BKE_collection_engine_property_add_bool(props, "ssr_enable", false);
BKE_collection_engine_property_add_bool(props, "ssr_refraction", false);

View File

@ -307,6 +307,9 @@ static char *eevee_get_defines(int options)
if ((options & VAR_MAT_SSS) != 0) {
BLI_dynstr_appendf(ds, "#define USE_SSS\n");
}
if ((options & VAR_MAT_SSSALBED) != 0) {
BLI_dynstr_appendf(ds, "#define USE_SSS_ALBEDO\n");
}
if ((options & VAR_MAT_TRANSLUC) != 0) {
BLI_dynstr_appendf(ds, "#define USE_TRANSLUCENCY\n");
}
@ -651,6 +654,7 @@ struct GPUMaterial *EEVEE_material_mesh_get(
if (use_multiply) options |= VAR_MAT_MULT;
if (use_refract) options |= VAR_MAT_REFRACT;
if (use_sss) options |= VAR_MAT_SSS;
if (use_sss && vedata->stl->effects->sss_separate_albedo) options |= VAR_MAT_SSSALBED;
if (use_translucency) options |= VAR_MAT_TRANSLUC;
if (vedata->stl->effects->use_volumetrics && use_blend) options |= VAR_MAT_VOLUME;

View File

@ -117,6 +117,7 @@ enum {
VAR_MAT_VOLUME = (1 << 13),
VAR_MAT_SSS = (1 << 14),
VAR_MAT_TRANSLUC = (1 << 15),
VAR_MAT_SSSALBED = (1 << 16),
};
/* Shadow Technique */
@ -252,6 +253,7 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *gtao_horizons;
struct GPUTexture *sss_data;
struct GPUTexture *sss_albedo;
struct GPUTexture *sss_blur;
struct GPUTexture *sss_stencil;
@ -433,6 +435,7 @@ typedef struct EEVEE_EffectsInfo {
/* SSSS */
int sss_sample_count;
float sss_jitter_threshold;
bool sss_separate_albedo;
/* Volumetrics */
bool use_volumetrics;

View File

@ -33,7 +33,7 @@
#include "GPU_texture.h"
static struct {
struct GPUShader *sss_sh[2];
struct GPUShader *sss_sh[3];
} e_data = {NULL}; /* Engine data */
extern char datatoc_effect_subsurface_frag_glsl[];
@ -42,6 +42,8 @@ static void eevee_create_shader_subsurface(void)
{
e_data.sss_sh[0] = DRW_shader_create_fullscreen(datatoc_effect_subsurface_frag_glsl, "#define FIRST_PASS\n");
e_data.sss_sh[1] = DRW_shader_create_fullscreen(datatoc_effect_subsurface_frag_glsl, "#define SECOND_PASS\n");
e_data.sss_sh[2] = DRW_shader_create_fullscreen(datatoc_effect_subsurface_frag_glsl, "#define SECOND_PASS\n"
"#define USE_SEP_ALBEDO\n");
}
int EEVEE_subsurface_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
@ -59,6 +61,7 @@ int EEVEE_subsurface_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedat
if (BKE_collection_engine_property_value_get_bool(props, "sss_enable")) {
effects->sss_sample_count = 1 + BKE_collection_engine_property_value_get_int(props, "sss_samples") * 2;
effects->sss_jitter_threshold = BKE_collection_engine_property_value_get_float(props, "sss_jitter_threshold");
effects->sss_separate_albedo = BKE_collection_engine_property_value_get_bool(props, "sss_separate_albedo");
/* Shaders */
if (!e_data.sss_sh[0]) {
@ -79,10 +82,16 @@ int EEVEE_subsurface_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedat
DRW_framebuffer_init(&fbl->sss_clear_fb, &draw_engine_eevee_type, (int)viewport_size[0], (int)viewport_size[1],
&tex_data, 1);
if (effects->sss_separate_albedo && (txl->sss_albedo == NULL)) {
txl->sss_albedo = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1],
DRW_TEX_RGB_11_11_10, 0, NULL);
}
return EFFECT_SSS;
}
/* Cleanup to release memory */
DRW_TEXTURE_FREE_SAFE(txl->sss_albedo);
DRW_TEXTURE_FREE_SAFE(txl->sss_data);
DRW_TEXTURE_FREE_SAFE(txl->sss_blur);
DRW_TEXTURE_FREE_SAFE(txl->sss_stencil);
@ -127,7 +136,8 @@ void EEVEE_subsurface_add_pass(EEVEE_Data *vedata, unsigned int sss_id, struct G
DRW_shgroup_stencil_mask(grp, sss_id);
DRW_shgroup_call_add(grp, quad, NULL);
grp = DRW_shgroup_create(e_data.sss_sh[1], psl->sss_resolve_ps);
struct GPUShader *sh = (effects->sss_separate_albedo) ? e_data.sss_sh[2] : e_data.sss_sh[1];
grp = DRW_shgroup_create(sh, psl->sss_resolve_ps);
DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2);
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth);
@ -136,6 +146,10 @@ void EEVEE_subsurface_add_pass(EEVEE_Data *vedata, unsigned int sss_id, struct G
DRW_shgroup_uniform_float(grp, "jitterThreshold", &effects->sss_jitter_threshold, 1);
DRW_shgroup_stencil_mask(grp, sss_id);
DRW_shgroup_call_add(grp, quad, NULL);
if (effects->sss_separate_albedo) {
DRW_shgroup_uniform_buffer(grp, "sssAlbedo", &txl->sss_albedo);
}
}
void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
@ -152,38 +166,50 @@ void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat
DRW_framebuffer_bind(fbl->sss_clear_fb);
DRW_framebuffer_clear(true, false, false, clear, 0.0f);
DRW_framebuffer_texture_detach(txl->sss_data);
if ((effects->enabled_effects & EFFECT_NORMAL_BUFFER) != 0) {
DRW_framebuffer_texture_detach(txl->ssr_normal_input);
}
if ((effects->enabled_effects & EFFECT_SSR) != 0) {
DRW_framebuffer_texture_detach(txl->ssr_specrough_input);
}
/* Start at slot 1 because slot 0 is txl->color */
int tex_slot = 1;
DRW_framebuffer_texture_attach(fbl->main, txl->sss_data, tex_slot++, 0);
if (effects->sss_separate_albedo) {
DRW_framebuffer_texture_attach(fbl->main, txl->sss_albedo, tex_slot++, 0);
}
if ((effects->enabled_effects & EFFECT_NORMAL_BUFFER) != 0) {
DRW_framebuffer_texture_attach(fbl->main, txl->ssr_normal_input, 2, 0);
DRW_framebuffer_texture_attach(fbl->main, txl->ssr_normal_input, tex_slot++, 0);
}
if ((effects->enabled_effects & EFFECT_SSR) != 0) {
DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 3, 0);
DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, tex_slot++, 0);
}
DRW_framebuffer_texture_detach(txl->sss_data);
DRW_framebuffer_texture_attach(fbl->main, txl->sss_data, 1, 0);
DRW_framebuffer_bind(fbl->main);
DRW_draw_pass(psl->sss_pass);
/* Restore */
DRW_framebuffer_texture_detach(txl->sss_data);
if (effects->sss_separate_albedo) {
DRW_framebuffer_texture_detach(txl->sss_albedo);
}
if ((effects->enabled_effects & EFFECT_NORMAL_BUFFER) != 0) {
DRW_framebuffer_texture_detach(txl->ssr_normal_input);
}
if ((effects->enabled_effects & EFFECT_SSR) != 0) {
DRW_framebuffer_texture_detach(txl->ssr_specrough_input);
}
DRW_framebuffer_texture_detach(txl->sss_data);
DRW_framebuffer_texture_attach(fbl->sss_clear_fb, txl->sss_data, 0, 0);
if ((effects->enabled_effects & EFFECT_NORMAL_BUFFER) != 0) {
DRW_framebuffer_texture_attach(fbl->main, txl->ssr_normal_input, 1, 0);
}
if ((effects->enabled_effects & EFFECT_SSR) != 0) {
DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0);
}
DRW_framebuffer_texture_attach(fbl->sss_clear_fb, txl->sss_data, 0, 0);
}
}
@ -230,4 +256,5 @@ void EEVEE_subsurface_free(void)
{
DRW_SHADER_FREE_SAFE(e_data.sss_sh[0]);
DRW_SHADER_FREE_SAFE(e_data.sss_sh[1]);
DRW_SHADER_FREE_SAFE(e_data.sss_sh[2]);
}

View File

@ -583,6 +583,9 @@ struct Closure {
float opacity;
#ifdef USE_SSS
vec4 sss_data;
#ifdef USE_SSS_ALBEDO
vec3 sss_albedo;
#endif
#endif
vec4 ssr_data;
vec2 ssr_normal;
@ -594,7 +597,11 @@ struct Closure {
#define REFRACT_CLOSURE_FLAG -3
#ifdef USE_SSS
#ifdef USE_SSS_ALBEDO
#define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec3(0.0), vec4(0.0), vec2(0.0), -1)
#else
#define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec4(0.0), vec2(0.0), -1)
#endif
#else
#define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec2(0.0), -1)
#endif
@ -608,6 +615,9 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac)
#ifdef USE_SSS
cl.sss_data.rgb = mix(cl1.sss_data.rgb, cl2.sss_data.rgb, fac);
cl.sss_data.a = (cl1.sss_data.a > 0.0) ? cl1.sss_data.a : cl2.sss_data.a;
#ifdef USE_SSS_ALBEDO
cl.sss_albedo = (cl1.sss_data.a > 0.0) ? cl1.sss_albedo : cl2.sss_albedo;
#endif
#endif
if (cl1.ssr_id == outputSsrId) {
@ -637,6 +647,9 @@ Closure closure_add(Closure cl1, Closure cl2)
Closure cl = (cl1.ssr_id == outputSsrId) ? cl1 : cl2;
#ifdef USE_SSS
cl.sss_data = (cl1.sss_data.a > 0.0) ? cl1.sss_data : cl2.sss_data;
#ifdef USE_SSS_ALBEDO
cl.sss_albedo = (cl1.sss_data.a > 0.0) ? cl1.sss_albedo : cl2.sss_albedo;
#endif
#endif
cl.radiance = cl1.radiance + cl2.radiance;
cl.opacity = cl1.opacity + cl2.opacity;
@ -646,13 +659,20 @@ Closure closure_add(Closure cl1, Closure cl2)
#if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER) && !defined(USE_MULTIPLY)
layout(location = 0) out vec4 fragColor;
#ifdef USE_SSS
#ifdef USE_SSS_ALBEDO
layout(location = 1) out vec4 sssData;
layout(location = 2) out vec4 sssAlbedo;
layout(location = 3) out vec4 ssrNormals;
layout(location = 4) out vec4 ssrData;
#else
layout(location = 1) out vec4 sssData;
layout(location = 2) out vec4 ssrNormals;
layout(location = 3) out vec4 ssrData;
#endif /* USE_SSS_ALBEDO */
#else
layout(location = 1) out vec4 ssrNormals;
layout(location = 2) out vec4 ssrData;
#endif
#endif /* USE_SSS */
Closure nodetree_exec(void); /* Prototype */
@ -678,6 +698,9 @@ void main()
ssrData = cl.ssr_data;
#ifdef USE_SSS
sssData = cl.sss_data;
#ifdef USE_SSS_ALBEDO
sssAlbedo = cl.sss_albedo.rgbb;
#endif
#endif
}

View File

@ -11,6 +11,7 @@ layout(std140) uniform sssProfile {
uniform float jitterThreshold;
uniform sampler2D depthBuffer;
uniform sampler2D sssData;
uniform sampler2D sssAlbedo;
uniform sampler2DArray utilTex;
out vec4 FragColor;
@ -80,6 +81,10 @@ void main(void)
#ifdef FIRST_PASS
FragColor = vec4(accum, sss_data.a);
#else /* SECOND_PASS */
#ifdef USE_SEP_ALBEDO
FragColor = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0);
#else
FragColor = vec4(accum, 1.0);
#endif
#endif
}

View File

@ -2909,7 +2909,12 @@ void node_bsdf_principled_clearcoat(vec4 base_color, float subsurface, vec3 subs
result.ssr_id = int(ssr_id);
#ifdef USE_SSS
result.sss_data.a = sss_scalef;
result.sss_data.rgb = (out_diff + out_trans) * mix(vec3(0.0), subsurface_color.rgb, subsurface);
result.sss_data.rgb = out_diff + out_trans;
#ifdef USE_SSS_ALBEDO
result.sss_albedo.rgb = mix(vec3(0.0), subsurface_color.rgb, subsurface);
#else
result.sss_data.rgb *= mix(vec3(0.0), subsurface_color.rgb, subsurface);
#endif
result.sss_data.rgb *= (1.0 - transmission);
#endif
@ -2954,7 +2959,14 @@ void node_subsurface_scattering(
result.ssr_id = -1;
result.sss_data.a = scale;
eevee_closure_subsurface(N, color.rgb, 1.0, scale, out_diff, out_trans);
result.sss_data.rgb = (out_diff + out_trans) * color.rgb;
result.sss_data.rgb = out_diff + out_trans;
#ifdef USE_SSS_ALBEDO
/* Not perfect for texture_blur not exaclty equal to 0.0 or 1.0. */
result.sss_albedo.rgb = mix(color.rgb, vec3(1.0), texture_blur);
result.sss_data.rgb *= mix(vec3(1.0), color.rgb, texture_blur);
#else
result.sss_data.rgb *= color.rgb;
#endif
#else
node_bsdf_diffuse(color, 0.0, N, result);
#endif

View File

@ -370,6 +370,7 @@ RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(volumetric_colored_transmittance)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(sss_enable)
RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(sss_samples)
RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(sss_jitter_threshold)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(sss_separate_albedo)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_refraction)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_enable)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_halfres)
@ -1217,6 +1218,14 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update");
prop = RNA_def_property(srna, "sss_separate_albedo", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_sss_separate_albedo_get",
"rna_LayerEngineSettings_Eevee_sss_separate_albedo_set");
RNA_def_property_ui_text(prop, "Separate Albedo", "Avoid albedo being blured by the subsurface scattering "
"but uses more video memory");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update");
/* Screen Space Reflection */
prop = RNA_def_property(srna, "ssr_enable", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_enable_get",