Eevee: Improve Transparent BSDF behavior

Alpha blended Transparency is now using dual source blending making it
fully compatible with cycles Transparent BSDF.

Multiply and additive blend mode can be achieved using some nodes and are
going to be removed.
This commit is contained in:
Clément Foucault 2019-08-12 01:47:30 +02:00
parent 8a338950c6
commit d5002f007e
Notes: blender-bot 2023-02-14 01:17:53 +01:00
Referenced by issue #74401, Eevee: Crash upon expanding material preview
Referenced by issue #68689, Part of a shader seem to crash blender (open file, copy/paste, link or attach)
Referenced by issue #68454, Better Transparent BSDF
11 changed files with 251 additions and 250 deletions

View File

@ -295,7 +295,13 @@ static void eevee_draw_background(void *vedata)
EEVEE_volumes_resolve(sldata, vedata);
/* Transparent */
/* TODO(fclem): should be its own Framebuffer.
* This is needed because dualsource blending only works with 1 color buffer. */
GPU_framebuffer_texture_attach(fbl->main_color_fb, dtxl->depth, 0, 0);
GPU_framebuffer_bind(fbl->main_color_fb);
DRW_draw_pass(psl->transparent_pass);
GPU_framebuffer_bind(fbl->main_fb);
GPU_framebuffer_texture_detach(fbl->main_color_fb, dtxl->depth);
/* Post Process */
DRW_stats_group_start("Post FX");

View File

@ -382,11 +382,6 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp,
LightCache *lcache = vedata->stl->g_data->light_cache;
EEVEE_EffectsInfo *effects = vedata->stl->effects;
if (ssr_id == NULL) {
static int no_ssr = -1.0f;
ssr_id = &no_ssr;
}
DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo);
DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo);
DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo);
@ -394,6 +389,8 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp,
DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo);
DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
DRW_shgroup_uniform_int_copy(shgrp, "outputSssId", 1);
if (use_diffuse || use_glossy || use_refract) {
DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
DRW_shgroup_uniform_texture_ref(shgrp, "shadowCubeTexture", &sldata->shadow_cube_pool);
@ -411,7 +408,7 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp,
}
if (use_glossy) {
DRW_shgroup_uniform_texture_ref(shgrp, "probePlanars", &vedata->txl->planar_pool);
DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1);
DRW_shgroup_uniform_int_copy(shgrp, "outputSsrId", ssr_id ? *ssr_id : 0);
}
if (use_refract) {
DRW_shgroup_uniform_float_copy(
@ -736,7 +733,6 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene,
Material *ma,
EEVEE_Data *vedata,
bool use_blend,
bool use_multiply,
bool use_refract,
bool use_translucency,
int shadow_method)
@ -746,7 +742,6 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene,
int options = VAR_MAT_MESH;
SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND);
SET_FLAG_FROM_TEST(options, use_multiply, VAR_MAT_MULT);
SET_FLAG_FROM_TEST(options, use_refract, VAR_MAT_REFRACT);
SET_FLAG_FROM_TEST(options, effects->sss_separate_albedo, VAR_MAT_SSSALBED);
SET_FLAG_FROM_TEST(options, use_translucency, VAR_MAT_TRANSLUC);
@ -1191,15 +1186,11 @@ static void material_opaque(Material *ma,
*shgrp_depth_clip = emsg->depth_clip_grp;
/* This will have been created already, just perform a lookup. */
*gpumat = (use_gpumat) ? EEVEE_material_mesh_get(scene,
ma,
vedata,
false,
false,
use_ssrefract,
use_translucency,
linfo->shadow_method) :
NULL;
*gpumat =
(use_gpumat) ?
EEVEE_material_mesh_get(
scene, ma, vedata, false, use_ssrefract, use_translucency, linfo->shadow_method) :
NULL;
*gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get(
scene, ma, (ma->blend_method == MA_BM_HASHED), false) :
NULL;
@ -1213,7 +1204,7 @@ static void material_opaque(Material *ma,
/* Shading */
*gpumat = EEVEE_material_mesh_get(
scene, ma, vedata, false, false, use_ssrefract, use_translucency, linfo->shadow_method);
scene, ma, vedata, false, use_ssrefract, use_translucency, linfo->shadow_method);
eGPUMaterialStatus status_mat_surface = GPU_material_status(*gpumat);
@ -1286,7 +1277,7 @@ static void material_opaque(Material *ma,
switch (status_mat_surface) {
case GPU_MAT_SUCCESS: {
static int no_ssr = -1;
static int no_ssr = 0;
static int first_ssr = 1;
int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_ssrefract) ?
&first_ssr :
@ -1426,22 +1417,16 @@ static void material_transparent(Material *ma,
static float half = 0.5f;
/* Shading */
*gpumat = EEVEE_material_mesh_get(scene,
ma,
vedata,
true,
(ma->blend_method == MA_BM_MULTIPLY),
use_ssrefract,
false,
linfo->shadow_method);
*gpumat = EEVEE_material_mesh_get(
scene, ma, vedata, true, use_ssrefract, false, linfo->shadow_method);
switch (GPU_material_status(*gpumat)) {
case GPU_MAT_SUCCESS: {
static int ssr_id = -1; /* TODO transparent SSR */
bool use_blend = (ma->blend_method & MA_BM_BLEND) != 0;
*shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass);
bool use_blend = true;
bool use_diffuse = GPU_material_flag_get(*gpumat, GPU_MATFLAG_DIFFUSE);
bool use_glossy = GPU_material_flag_get(*gpumat, GPU_MATFLAG_GLOSSY);
bool use_refract = GPU_material_flag_get(*gpumat, GPU_MATFLAG_REFRACT);
@ -1487,7 +1472,7 @@ static void material_transparent(Material *ma,
DRWState all_state = (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_CULL_BACK |
DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL |
DRW_STATE_BLEND_ALPHA | DRW_STATE_BLEND_ADD | DRW_STATE_BLEND_MUL);
DRW_STATE_BLEND_CUSTOM);
DRWState cur_state = DRW_STATE_WRITE_COLOR;
cur_state |= (use_prepass) ? DRW_STATE_DEPTH_EQUAL : DRW_STATE_DEPTH_LESS_EQUAL;
@ -1495,13 +1480,9 @@ static void material_transparent(Material *ma,
switch (ma->blend_method) {
case MA_BM_ADD:
cur_state |= DRW_STATE_BLEND_ADD;
break;
case MA_BM_MULTIPLY:
cur_state |= DRW_STATE_BLEND_MUL;
break;
case MA_BM_BLEND:
cur_state |= DRW_STATE_BLEND_ALPHA;
cur_state |= DRW_STATE_BLEND_CUSTOM;
break;
default:
BLI_assert(0);

View File

@ -897,7 +897,6 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene,
Material *ma,
EEVEE_Data *vedata,
bool use_blend,
bool use_multiply,
bool use_refract,
bool use_translucency,
int shadow_method);

View File

@ -628,7 +628,11 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
/* Mist output */
EEVEE_mist_output_accumulate(sldata, vedata);
/* Transparent */
GPU_framebuffer_texture_attach(fbl->main_color_fb, dtxl->depth, 0, 0);
GPU_framebuffer_bind(fbl->main_color_fb);
DRW_draw_pass(psl->transparent_pass);
GPU_framebuffer_bind(fbl->main_fb);
GPU_framebuffer_texture_detach(fbl->main_color_fb, dtxl->depth);
/* Result Z */
eevee_render_result_z(rl, viewname, rect, vedata, sldata);
/* Post Process */

View File

@ -164,6 +164,19 @@ float sum(vec4 v)
return dot(vec4(1.0), v);
}
float avg(vec2 v)
{
return dot(vec2(1.0 / 2.0), v);
}
float avg(vec3 v)
{
return dot(vec3(1.0 / 3.0), v);
}
float avg(vec4 v)
{
return dot(vec4(1.0 / 4.0), v);
}
float saturate(float a)
{
return clamp(a, 0.0, 1.0);
@ -716,6 +729,7 @@ float cone_cosine(float r)
}
/* --------- Closure ---------- */
#ifdef VOLUMETRICS
struct Closure {
@ -725,6 +739,8 @@ struct Closure {
float anisotropy;
};
Closure nodetree_exec(void); /* Prototype */
# define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), vec3(0.0), 0.0)
Closure closure_mix(Closure cl1, Closure cl2, float fac)
@ -758,7 +774,7 @@ Closure closure_emission(vec3 rgb)
struct Closure {
vec3 radiance;
float opacity;
vec3 transmittance;
# ifdef USE_SSS
vec4 sss_data;
# ifdef USE_SSS_ALBEDO
@ -767,110 +783,113 @@ struct Closure {
# endif
vec4 ssr_data;
vec2 ssr_normal;
int ssr_id;
int flag;
};
/* This is hacking ssr_id to tag transparent bsdf */
# define TRANSPARENT_CLOSURE_FLAG -2
# define REFRACT_CLOSURE_FLAG -3
# define NO_SSR -999
Closure nodetree_exec(void); /* Prototype */
# define FLAG_TEST(flag, val) (((flag) & (val)) != 0)
# define CLOSURE_SSR_FLAG 1
# define CLOSURE_SSS_FLAG 2
# 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)
Closure(vec3(0.0), vec3(0.0), vec4(0.0), vec3(0.0), vec4(0.0), vec2(0.0), 0)
# else
# define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec4(0.0), vec2(0.0), -1)
# define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), vec4(0.0), vec4(0.0), vec2(0.0), 0)
# endif
# else
# define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec2(0.0), -1)
# define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), vec4(0.0), vec2(0.0), 0)
# endif
uniform int outputSsrId;
uniform int outputSsrId = 1;
uniform int outputSssId = 1;
void closure_load_ssr_data(
vec3 ssr_spec, float roughness, vec3 N, vec3 viewVec, int ssr_id, inout Closure cl)
{
/* Still encode to avoid artifacts in the SSR pass. */
vec3 vN = normalize(mat3(ViewMatrix) * N);
cl.ssr_normal = normal_encode(vN, viewVec);
if (ssr_id == outputSsrId) {
cl.ssr_data = vec4(ssr_spec, roughness);
cl.flag |= CLOSURE_SSR_FLAG;
}
}
# ifdef USE_SSS
void closure_load_sss_data(float radius,
vec3 sss_radiance,
# ifdef USE_SSS_ALBEDO
vec3 sss_albedo,
# endif
int sss_id,
inout Closure cl)
{
if (sss_id == outputSssId) {
cl.sss_data = vec4(sss_radiance, radius);
# ifdef USE_SSS_ALBEDO
cl.sss_albedo = sss_albedo;
# endif
cl.flag |= CLOSURE_SSS_FLAG;
}
else {
cl.radiance += sss_radiance;
# ifdef USE_SSS_ALBEDO
cl.radiance += sss_radiance * sss_albedo;
# endif
}
}
# endif
Closure closure_mix(Closure cl1, Closure cl2, float fac)
{
Closure cl;
if (cl1.ssr_id == TRANSPARENT_CLOSURE_FLAG) {
cl.ssr_normal = cl2.ssr_normal;
cl.ssr_data = cl2.ssr_data;
cl.ssr_id = cl2.ssr_id;
# ifdef USE_SSS
cl1.sss_data = cl2.sss_data;
# ifdef USE_SSS_ALBEDO
cl1.sss_albedo = cl2.sss_albedo;
# endif
# endif
}
else if (cl2.ssr_id == TRANSPARENT_CLOSURE_FLAG) {
cl.ssr_normal = cl1.ssr_normal;
cl.ssr_data = cl1.ssr_data;
cl.ssr_id = cl1.ssr_id;
# ifdef USE_SSS
cl2.sss_data = cl1.sss_data;
# ifdef USE_SSS_ALBEDO
cl2.sss_albedo = cl1.sss_albedo;
# endif
# endif
}
else if (cl1.ssr_id == outputSsrId) {
/* When mixing SSR don't blend roughness.
*
* It makes no sense to mix them really, so we take either one of them and
* tone down its specularity (ssr_data.xyz) while keeping its roughness (ssr_data.w).
*/
cl.ssr_data = mix(cl1.ssr_data.xyzw, vec4(vec3(0.0), cl1.ssr_data.w), fac);
cl.ssr_normal = cl1.ssr_normal;
cl.ssr_id = cl1.ssr_id;
}
else {
cl.ssr_data = mix(vec4(vec3(0.0), cl2.ssr_data.w), cl2.ssr_data.xyzw, fac);
cl.ssr_normal = cl2.ssr_normal;
cl.ssr_id = cl2.ssr_id;
}
cl.opacity = mix(cl1.opacity, cl2.opacity, fac);
cl.radiance = mix(cl1.radiance * cl1.opacity, cl2.radiance * cl2.opacity, fac);
cl.radiance /= max(1e-8, cl.opacity);
cl.transmittance = mix(cl1.transmittance, cl2.transmittance, fac);
cl.radiance = mix(cl1.radiance, cl2.radiance, fac);
cl.flag = cl1.flag | cl2.flag;
cl.ssr_data = mix(cl1.ssr_data, cl2.ssr_data, fac);
bool use_cl1_ssr = FLAG_TEST(cl1.flag, CLOSURE_SSR_FLAG);
/* When mixing SSR don't blend roughness and normals but only specular (ssr_data.xyz).*/
cl.ssr_data.w = (use_cl1_ssr) ? cl1.ssr_data.w : cl2.ssr_data.w;
cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
# ifdef USE_SSS
/* Apply Mix on input */
cl1.sss_data.rgb *= 1.0 - fac;
cl2.sss_data.rgb *= fac;
/* Select biggest radius. */
bool use_cl1 = (cl1.sss_data.a > cl2.sss_data.a);
cl.sss_data = (use_cl1) ? cl1.sss_data : cl2.sss_data;
cl.sss_data = mix(cl1.sss_data, cl2.sss_data, fac);
bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG);
/* It also does not make sense to mix SSS radius or albedo. */
cl.sss_data.w = (use_cl1_sss) ? cl1.sss_data.w : cl2.sss_data.w;
# ifdef USE_SSS_ALBEDO
/* TODO Find a solution to this. Dither? */
cl.sss_albedo = (use_cl1) ? cl1.sss_albedo : cl2.sss_albedo;
/* Add radiance that was supposed to be filtered but was rejected. */
cl.radiance += (use_cl1) ? cl2.sss_data.rgb * cl2.sss_albedo : cl1.sss_data.rgb * cl1.sss_albedo;
# else
/* Add radiance that was supposed to be filtered but was rejected. */
cl.radiance += (use_cl1) ? cl2.sss_data.rgb : cl1.sss_data.rgb;
cl.sss_albedo = (use_cl1_sss) ? cl1.sss_albedo : cl2.sss_albedo;
# endif
# endif
return cl;
}
Closure closure_add(Closure cl1, Closure cl2)
{
Closure cl = (cl1.ssr_id == outputSsrId) ? cl1 : cl2;
Closure cl;
cl.transmittance = cl1.transmittance + cl2.transmittance;
cl.radiance = cl1.radiance + cl2.radiance;
cl.flag = cl1.flag | cl2.flag;
cl.ssr_data = cl1.ssr_data + cl2.ssr_data;
bool use_cl1_ssr = FLAG_TEST(cl1.flag, CLOSURE_SSR_FLAG);
/* When mixing SSR don't blend roughness and normals.*/
cl.ssr_data.w = (use_cl1_ssr) ? cl1.ssr_data.w : cl2.ssr_data.w;
cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
# ifdef USE_SSS
cl.sss_data = (cl1.sss_data.a > 0.0) ? cl1.sss_data : cl2.sss_data;
/* Add radiance that was supposed to be filtered but was rejected. */
cl.radiance += (cl1.sss_data.a > 0.0) ? cl2.sss_data.rgb : cl1.sss_data.rgb;
cl.sss_data = cl1.sss_data + cl2.sss_data;
bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG);
/* It also does not make sense to mix SSS radius or albedo. */
cl.sss_data.w = (use_cl1_sss) ? cl1.sss_data.w : cl2.sss_data.w;
# ifdef USE_SSS_ALBEDO
/* TODO Find a solution to this. Dither? */
cl.sss_albedo = (cl1.sss_data.a > 0.0) ? cl1.sss_albedo : cl2.sss_albedo;
cl.sss_albedo = (use_cl1_sss) ? cl1.sss_albedo : cl2.sss_albedo;
# endif
# endif
cl.opacity = saturate(cl1.opacity + cl2.opacity);
return cl;
}
@ -883,19 +902,23 @@ Closure closure_emission(vec3 rgb)
/* Breaking this across multiple lines causes issues for some older GLSL compilers. */
/* clang-format off */
# if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER) && !defined(USE_MULTIPLY)
# if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER)
/* clang-format on */
layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec4 ssrNormals;
# ifndef USE_ALPHA_BLEND
layout(location = 0) out vec4 outRadiance;
layout(location = 1) out vec2 ssrNormals;
layout(location = 2) out vec4 ssrData;
# ifdef USE_SSS
# ifdef USE_SSS
layout(location = 3) out vec4 sssData;
# ifdef USE_SSS_ALBEDO
# ifdef USE_SSS_ALBEDO
layout(location = 4) out vec4 sssAlbedo;
# endif /* USE_SSS_ALBEDO */
# endif /* USE_SSS */
Closure nodetree_exec(void); /* Prototype */
# endif
# endif
# else /* USE_ALPHA_BLEND */
/* Use dual source blending to be able to make a whole range of effects. */
layout(location = 0, index = 0) out vec4 outRadiance;
layout(location = 0, index = 1) out vec4 outTransmittance;
# endif /* USE_ALPHA_BLEND */
# if defined(USE_ALPHA_BLEND)
/* Prototype because this file is included before volumetric_lib.glsl */
@ -909,27 +932,24 @@ void volumetric_resolve(vec2 frag_uvs,
void main()
{
Closure cl = nodetree_exec();
# ifndef USE_ALPHA_BLEND
/* Prevent alpha hash material writing into alpha channel. */
cl.opacity = 1.0;
# endif
# if defined(USE_ALPHA_BLEND)
# ifdef USE_ALPHA_BLEND
vec2 uvs = gl_FragCoord.xy * volCoordScale.zw;
vec3 transmittance, scattering;
volumetric_resolve(uvs, gl_FragCoord.z, transmittance, scattering);
fragColor.rgb = cl.radiance * transmittance + scattering;
fragColor.a = cl.opacity;
# else
fragColor = vec4(cl.radiance, cl.opacity);
# endif
vec3 vol_transmit, vol_scatter;
volumetric_resolve(uvs, gl_FragCoord.z, vol_transmit, vol_scatter);
ssrNormals = cl.ssr_normal.xyyy;
float transmit = saturate(avg(cl.transmittance));
outRadiance = vec4(cl.radiance * vol_transmit + vol_scatter, (1.0 - transmit));
outTransmittance = vec4(cl.transmittance, transmit);
# else
outRadiance = vec4(cl.radiance, 1.0);
ssrNormals = cl.ssr_normal;
ssrData = cl.ssr_data;
# ifdef USE_SSS
# ifdef USE_SSS
sssData = cl.sss_data;
# ifdef USE_SSS_ALBEDO
# ifdef USE_SSS_ALBEDO
sssAlbedo = cl.sss_albedo.rgbb;
# endif
# endif
# endif
@ -945,9 +965,9 @@ void main()
# endif
# ifdef USE_SSS_ALBEDO
fragColor.rgb += cl.sss_data.rgb * cl.sss_albedo.rgb * fac;
outRadiance.rgb += cl.sss_data.rgb * cl.sss_albedo.rgb * fac;
# else
fragColor.rgb += cl.sss_data.rgb * fac;
outRadiance.rgb += cl.sss_data.rgb * fac;
# endif
# endif
}
@ -955,18 +975,3 @@ void main()
# endif /* MESH_SHADER && !SHADOW_SHADER */
#endif /* VOLUMETRICS */
Closure nodetree_exec(void); /* Prototype */
/* TODO find a better place */
#ifdef USE_MULTIPLY
out vec4 fragColor;
# define NODETREE_EXEC
void main()
{
Closure cl = nodetree_exec();
fragColor = vec4(mix(vec3(1.0), cl.radiance, cl.opacity), 1.0);
}
#endif

View File

@ -33,15 +33,13 @@ Closure nodetree_exec(void)
vec3 out_diff, out_spec, ssr_spec;
eevee_closure_default(N, albedo, f0, f90, 1, roughness, 1.0, out_diff, out_spec, ssr_spec);
Closure result = Closure(out_spec + out_diff * albedo,
1.0,
vec4(ssr_spec, roughness),
normal_encode(vN, viewCameraVec),
0);
Closure cl = CLOSURE_DEFAULT;
cl.radiance = out_spec + out_diff * albedo;
closure_load_ssr_data(ssr_spec, roughness, N, viewCameraVec, 0, cl);
#ifdef LOOKDEV
gl_FragDepth = 0.0;
#endif
return result;
return cl;
}

View File

@ -71,14 +71,16 @@ void main()
Closure cl = nodetree_exec();
float opacity = saturate(1.0 - avg(cl.transmittance));
# if defined(USE_ALPHA_HASH)
/* Hashed Alpha Testing */
if (cl.opacity < hashed_alpha_threshold(worldPosition)) {
if (opacity < hashed_alpha_threshold(worldPosition)) {
discard;
}
# elif defined(USE_ALPHA_CLIP)
/* Alpha clip */
if (cl.opacity <= alphaThreshold) {
if (opacity <= alphaThreshold) {
discard;
}
# endif

View File

@ -934,7 +934,7 @@ static char *code_generate_fragment(GPUMaterial *material,
BLI_dynstr_append(ds, "void main()\n");
BLI_dynstr_append(ds, "{\n");
BLI_dynstr_append(ds, "\tClosure cl = nodetree_exec();\n");
BLI_dynstr_append(ds, "\tfragColor = vec4(cl.radiance, cl.opacity);\n");
BLI_dynstr_append(ds, "\tfragColor = vec4(cl.radiance, saturate(avg(cl.transmittance)));\n");
BLI_dynstr_append(ds, "}\n");
BLI_dynstr_append(ds, "#endif\n\n");

View File

@ -1239,10 +1239,9 @@ vec3 principled_sheen(float NV, vec3 basecol_tint, float sheen_tint)
void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
{
N = normalize(N);
vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.ssr_normal = normal_encode(vN, viewCameraVec);
eevee_closure_diffuse(N, color.rgb, 1.0, result.radiance);
closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
result.radiance *= color.rgb;
}
@ -1254,9 +1253,7 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Clo
vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.radiance = out_spec * color.rgb;
result.ssr_data = vec4(ssr_spec * color.rgb, roughness);
result.ssr_normal = normal_encode(vN, viewCameraVec);
result.ssr_id = int(ssr_id);
closure_load_ssr_data(ssr_spec * color.rgb, roughness, N, viewCameraVec, int(ssr_id), result);
}
void node_bsdf_anisotropic(vec4 color,
@ -1285,9 +1282,8 @@ void node_bsdf_glass(
vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.radiance = mix(out_refr, out_spec, fresnel);
result.ssr_data = vec4(ssr_spec * color.rgb * fresnel, roughness);
result.ssr_normal = normal_encode(vN, viewCameraVec);
result.ssr_id = int(ssr_id);
closure_load_ssr_data(
ssr_spec * color.rgb * fresnel, roughness, N, viewCameraVec, int(ssr_id), result);
}
void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure result)
@ -1352,7 +1348,7 @@ void node_bsdf_principled(vec4 base_color,
vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
float sss_scalef = dot(sss_scale, vec3(1.0 / 3.0)) * subsurface;
float sss_scalef = avg(sss_scale) * subsurface;
eevee_closure_principled(N,
mixed_ss_base_color,
f0,
@ -1376,28 +1372,34 @@ void node_bsdf_principled(vec4 base_color,
vec3(1.0); /* Simulate 2 transmission event */
out_refr *= refr_color * (1.0 - fresnel) * transmission;
vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.radiance = out_spec + out_refr;
result.radiance += out_diff * out_sheen; /* Coarse approx. */
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
vec3 sss_radiance = (out_diff + out_trans) * alpha;
# ifndef USE_SSS
result.radiance += (out_diff + out_trans) * mixed_ss_base_color * (1.0 - transmission);
# endif
result.ssr_data = vec4(ssr_spec, roughness);
result.ssr_normal = normal_encode(vN, viewCameraVec);
result.ssr_id = int(ssr_id);
# ifdef USE_SSS
result.sss_data.a = sss_scalef;
result.sss_data.rgb = out_diff + out_trans;
result.radiance += sss_radiance * mixed_ss_base_color * (1.0 - transmission);
# else
# ifdef USE_SSS_ALBEDO
result.sss_albedo.rgb = mixed_ss_base_color;
vec3 sss_albedo = mixed_ss_base_color;
# else
result.sss_data.rgb *= mixed_ss_base_color;
sss_radiance *= mixed_ss_base_color;
# endif
result.sss_data.rgb *= (1.0 - transmission);
# endif
sss_radiance *= (1.0 - transmission);
closure_load_sss_data(sss_scalef,
sss_radiance,
# ifdef USE_SSS_ALBEDO
sss_albedo,
# endif
int(sss_id),
result);
# endif /* USE_SSS */
result.radiance += emission.rgb;
result.opacity = alpha;
result.radiance *= alpha;
result.transmittance = vec3(1.0 - alpha);
}
void node_bsdf_principled_dielectric(vec4 base_color,
@ -1443,14 +1445,12 @@ void node_bsdf_principled_dielectric(vec4 base_color,
eevee_closure_default(
N, diffuse, f0, vec3(1.0), int(ssr_id), roughness, 1.0, out_diff, out_spec, ssr_spec);
vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.radiance = out_spec + out_diff * (diffuse + out_sheen);
result.ssr_data = vec4(ssr_spec, roughness);
result.ssr_normal = normal_encode(vN, viewCameraVec);
result.ssr_id = int(ssr_id);
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
result.radiance += emission.rgb;
result.opacity = alpha;
result.radiance *= alpha;
result.transmittance = vec3(1.0 - alpha);
}
void node_bsdf_principled_metallic(vec4 base_color,
@ -1488,14 +1488,12 @@ void node_bsdf_principled_metallic(vec4 base_color,
eevee_closure_glossy(N, base_color.rgb, f90, int(ssr_id), roughness, 1.0, out_spec, ssr_spec);
vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.radiance = out_spec;
result.ssr_data = vec4(ssr_spec, roughness);
result.ssr_normal = normal_encode(vN, viewCameraVec);
result.ssr_id = int(ssr_id);
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
result.radiance += emission.rgb;
result.opacity = alpha;
result.radiance *= alpha;
result.transmittance = vec3(1.0 - alpha);
}
void node_bsdf_principled_clearcoat(vec4 base_color,
@ -1543,14 +1541,12 @@ void node_bsdf_principled_clearcoat(vec4 base_color,
out_spec,
ssr_spec);
vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.radiance = out_spec;
result.ssr_data = vec4(ssr_spec, roughness);
result.ssr_normal = normal_encode(vN, viewCameraVec);
result.ssr_id = int(ssr_id);
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
result.radiance += emission.rgb;
result.opacity = alpha;
result.radiance *= alpha;
result.transmittance = vec3(1.0 - alpha);
}
void node_bsdf_principled_subsurface(vec4 base_color,
@ -1591,7 +1587,7 @@ void node_bsdf_principled_subsurface(vec4 base_color,
subsurface_color = subsurface_color * (1.0 - metallic);
vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
float sss_scalef = dot(sss_scale, vec3(1.0 / 3.0)) * subsurface;
float sss_scalef = avg(sss_scale) * subsurface;
float NV = dot(N, cameraVec);
vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
@ -1611,26 +1607,33 @@ void node_bsdf_principled_subsurface(vec4 base_color,
out_spec,
ssr_spec);
vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.radiance = out_spec;
result.ssr_data = vec4(ssr_spec, roughness);
result.ssr_normal = normal_encode(vN, viewCameraVec);
result.ssr_id = int(ssr_id);
# ifdef USE_SSS
result.sss_data.a = sss_scalef;
result.sss_data.rgb = out_diff + out_trans;
# ifdef USE_SSS_ALBEDO
result.sss_albedo.rgb = mixed_ss_base_color;
# else
result.sss_data.rgb *= mixed_ss_base_color;
# endif
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
vec3 sss_radiance = (out_diff + out_trans) * alpha;
# ifndef USE_SSS
result.radiance += sss_radiance * mixed_ss_base_color * (1.0 - transmission);
# else
result.radiance += (out_diff + out_trans) * mixed_ss_base_color;
# endif
# ifdef USE_SSS_ALBEDO
vec3 sss_albedo = mixed_ss_base_color;
# else
sss_radiance *= mixed_ss_base_color;
# endif
sss_radiance *= (1.0 - transmission);
closure_load_sss_data(sss_scalef,
sss_radiance,
# ifdef USE_SSS_ALBEDO
sss_albedo,
# endif
int(sss_id),
result);
# endif /* USE_SSS */
result.radiance += out_diff * out_sheen;
result.radiance += emission.rgb;
result.opacity = alpha;
result.radiance *= alpha;
result.transmittance = vec3(1.0 - alpha);
}
void node_bsdf_principled_glass(vec4 base_color,
@ -1680,14 +1683,12 @@ void node_bsdf_principled_glass(vec4 base_color,
out_spec *= spec_col;
ssr_spec *= spec_col * fresnel;
vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.radiance = mix(out_refr, out_spec, fresnel);
result.ssr_data = vec4(ssr_spec, roughness);
result.ssr_normal = normal_encode(vN, viewCameraVec);
result.ssr_id = int(ssr_id);
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
result.radiance += emission.rgb;
result.opacity = alpha;
result.radiance *= alpha;
result.transmittance = vec3(1.0 - alpha);
}
void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
@ -1697,11 +1698,9 @@ void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
void node_bsdf_transparent(vec4 color, out Closure result)
{
/* this isn't right */
result = CLOSURE_DEFAULT;
result.radiance = vec3(0.0);
result.opacity = clamp(1.0 - dot(color.rgb, vec3(0.3333334)), 0.0, 1.0);
result.ssr_id = TRANSPARENT_CLOSURE_FLAG;
result.transmittance = abs(color.rgb);
}
void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result)
@ -1723,19 +1722,25 @@ void node_subsurface_scattering(vec4 color,
vec3 out_diff, out_trans;
vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.ssr_data = vec4(0.0);
result.ssr_normal = normal_encode(vN, viewCameraVec);
result.ssr_id = -1;
result.sss_data.a = scale;
closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
eevee_closure_subsurface(N, color.rgb, 1.0, scale, out_diff, out_trans);
result.sss_data.rgb = out_diff + out_trans;
vec3 sss_radiance = out_diff + out_trans;
# ifdef USE_SSS_ALBEDO
/* Not perfect for texture_blur not exactly 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);
vec3 sss_albedo = mix(color.rgb, vec3(1.0), texture_blur);
sss_radiance *= mix(vec3(1.0), color.rgb, texture_blur);
# else
result.sss_data.rgb *= color.rgb;
sss_radiance *= color.rgb;
# endif
closure_load_sss_data(scale,
sss_radiance,
# ifdef USE_SSS_ALBEDO
sss_albedo,
# endif
int(sss_id),
result);
# else
node_bsdf_diffuse(color, 0.0, N, result);
# endif
@ -1751,7 +1756,6 @@ void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Cl
result = CLOSURE_DEFAULT;
result.ssr_normal = normal_encode(vN, viewCameraVec);
result.radiance = out_refr * color.rgb;
result.ssr_id = REFRACT_CLOSURE_FLAG;
}
void node_ambient_occlusion(
@ -1852,7 +1856,7 @@ void node_background(vec4 color, float strength, out Closure result)
color *= strength;
result = CLOSURE_DEFAULT;
result.radiance = color.rgb;
result.opacity = color.a;
result.transmittance = vec3(0.0);
#else
result = CLOSURE_DEFAULT;
#endif
@ -2034,7 +2038,7 @@ void node_attribute_volume_density(sampler3D tex, out vec4 outcol, out vec3 outv
#endif
outvec = texture(tex, cos).aaa;
outcol = vec4(outvec, 1.0);
outf = dot(vec3(1.0 / 3.0), outvec);
outf = avg(outvec);
}
uniform vec3 volumeColor = vec3(1.0);
@ -2055,7 +2059,7 @@ void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec
outvec = value.rgb * volumeColor;
outcol = vec4(outvec, 1.0);
outf = dot(vec3(1.0 / 3.0), outvec);
outf = avg(outvec);
}
void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
@ -2089,7 +2093,7 @@ void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
{
outcol = vec4(attr, 1.0);
outvec = attr;
outf = dot(vec3(1.0 / 3.0), attr);
outf = avg(attr);
}
void node_uvmap(vec3 attr_uv, out vec3 outvec)
@ -3502,7 +3506,7 @@ void node_output_world(Closure surface, Closure volume, out Closure result)
{
#ifndef VOLUMETRICS
result.radiance = surface.radiance * backgroundAlpha;
result.opacity = backgroundAlpha;
result.transmittance = vec3(0.0);
#else
result = volume;
#endif /* VOLUMETRICS */
@ -3549,6 +3553,8 @@ void node_eevee_specular(vec4 diffuse,
float ssr_id,
out Closure result)
{
normal = normalize(normal);
vec3 out_diff, out_spec, ssr_spec;
eevee_closure_default_clearcoat(normal,
diffuse.rgb,
@ -3564,19 +3570,19 @@ void node_eevee_specular(vec4 diffuse,
out_spec,
ssr_spec);
vec3 vN = normalize(mat3(ViewMatrix) * normal);
float alpha = 1.0 - transp;
result = CLOSURE_DEFAULT;
result.radiance = out_diff * diffuse.rgb + out_spec + emissive.rgb;
result.opacity = 1.0 - transp;
result.ssr_data = vec4(ssr_spec, roughness);
result.ssr_normal = normal_encode(vN, viewCameraVec);
result.ssr_id = int(ssr_id);
result.radiance *= alpha;
result.transmittance = vec3(transp);
closure_load_ssr_data(ssr_spec * alpha, roughness, normal, viewCameraVec, int(ssr_id), result);
}
void node_shader_to_rgba(Closure cl, out vec4 outcol, out float outalpha)
{
vec4 spec_accum = vec4(0.0);
if (ssrToggle && cl.ssr_id == outputSsrId) {
if (ssrToggle && FLAG_TEST(cl.flag, CLOSURE_SSR_FLAG)) {
vec3 V = cameraVec;
vec3 vN = normal_decode(cl.ssr_normal, viewCameraVec);
vec3 N = transform_direction(ViewMatrixInverse, vN);
@ -3585,7 +3591,7 @@ void node_shader_to_rgba(Closure cl, out vec4 outcol, out float outalpha)
fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum);
}
outalpha = cl.opacity;
outalpha = avg(cl.transmittance);
outcol = vec4((spec_accum.rgb * cl.ssr_data.rgb) + cl.radiance, 1.0);
# ifdef USE_SSS

View File

@ -132,8 +132,13 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
&in[21].link);
}
bool use_diffuse = socket_not_one(4) && socket_not_one(15);
bool use_subsurf = socket_not_zero(1) && use_diffuse && node->sss_id > 0;
bool use_refract = socket_not_one(4) && socket_not_zero(15);
bool use_clear = socket_not_zero(12);
/* SSS Profile */
if (node->sss_id == 1) {
if (use_subsurf) {
static short profile = SHD_SUBSURFACE_BURLEY;
bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
bNodeSocketValueRGBA *socket_data = socket->default_value;
@ -148,11 +153,6 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
GPU_link(mat, "set_rgb_one", &sss_scale);
}
bool use_diffuse = socket_not_one(4) && socket_not_one(15);
bool use_subsurf = socket_not_zero(1) && use_diffuse && node->sss_id == 1;
bool use_refract = socket_not_one(4) && socket_not_zero(15);
bool use_clear = socket_not_zero(12);
/* Due to the manual effort done per config, we only optimize the most common permutations. */
char *node_name;
uint flag = 0;

View File

@ -63,7 +63,7 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat,
GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS);
if (node->sss_id == 1) {
if (node->sss_id > 0) {
bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
bNodeSocketValueRGBA *socket_data = socket->default_value;
bNodeSocket *socket_sharp = BLI_findlink(&node->original->inputs, 3);