Eevee: Use "constant folding" for the principle shader

This is more like a static optimisation when some parameters are set to 1.0
or 0.0. In theses case we use a more optimized version of the node.

This also revisit the transmission parameter behaviour to make it closer to
cycles.
This commit is contained in:
Clément Foucault 2018-08-08 18:34:25 +02:00
parent 26d46d00cf
commit cac43e1765
7 changed files with 227 additions and 49 deletions

View File

@ -405,7 +405,7 @@ static void add_standard_uniforms(
DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1);
}
if (use_ssrefraction) {
if (use_refract || use_ssrefraction) {
BLI_assert(refract_depth != NULL);
DRW_shgroup_uniform_float(shgrp, "refractionDepth", refract_depth, 1);
DRW_shgroup_uniform_texture_ref(shgrp, "colorBuffer", &vedata->txl->refract_color);
@ -563,6 +563,8 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, E
datatoc_lit_surface_frag_glsl,
datatoc_lit_surface_frag_glsl,
datatoc_lit_surface_frag_glsl,
datatoc_lit_surface_frag_glsl,
datatoc_lit_surface_frag_glsl,
datatoc_volumetric_lib_glsl);
e_data.volume_shader_lib = BLI_string_joinN(

View File

@ -548,6 +548,14 @@ float F_eta(float eta, float cos_theta)
return result;
}
/* Fresnel color blend base on fresnel factor */
vec3 F_color_blend(float eta, float fresnel, vec3 f0_color)
{
float f0 = F_eta(eta, 1.0);
float fac = saturate((fresnel - f0) / max(1e-8, 1.0 - f0));
return mix(f0_color, vec3(1.0), fac);
}
/* Fresnel */
vec3 F_schlick(vec3 f0, float cos_theta)
{

View File

@ -54,6 +54,13 @@ uniform int hairThicknessRes = 1;
#define CLOSURE_SUBSURFACE
#endif /* SURFACE_PRINCIPLED */
#if !defined(SURFACE_CLEARCOAT) && !defined(CLOSURE_NAME)
#define SURFACE_CLEARCOAT
#define CLOSURE_NAME eevee_closure_clearcoat
#define CLOSURE_GLOSSY
#define CLOSURE_CLEARCOAT
#endif /* SURFACE_CLEARCOAT */
#if !defined(SURFACE_DIFFUSE) && !defined(CLOSURE_NAME)
#define SURFACE_DIFFUSE
#define CLOSURE_NAME eevee_closure_diffuse
@ -67,6 +74,14 @@ uniform int hairThicknessRes = 1;
#define CLOSURE_SUBSURFACE
#endif /* SURFACE_SUBSURFACE */
#if !defined(SURFACE_SKIN) && !defined(CLOSURE_NAME)
#define SURFACE_SKIN
#define CLOSURE_NAME eevee_closure_skin
#define CLOSURE_DIFFUSE
#define CLOSURE_SUBSURFACE
#define CLOSURE_GLOSSY
#endif /* SURFACE_SKIN */
#if !defined(SURFACE_GLOSSY) && !defined(CLOSURE_NAME)
#define SURFACE_GLOSSY
#define CLOSURE_NAME eevee_closure_glossy

View File

@ -128,6 +128,7 @@ typedef enum GPUMatFlag {
GPU_MATFLAG_DIFFUSE = (1 << 0),
GPU_MATFLAG_GLOSSY = (1 << 1),
GPU_MATFLAG_REFRACT = (1 << 2),
GPU_MATFLAG_SSS = (1 << 3),
} GPUMatFlag;
typedef enum GPUBlendMode {

View File

@ -1069,11 +1069,11 @@ void convert_metallic_to_specular_tinted(
vec3 basecol, float metallic, float specular_fac, float specular_tint,
out vec3 diffuse, out vec3 f0)
{
vec3 dielectric = vec3(0.034) * specular_fac * 2.0;
float lum = dot(basecol, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
vec3 tint = lum > 0 ? basecol / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
f0 = mix(dielectric * mix(vec3(1.0), tint, specular_tint), basecol, metallic);
diffuse = mix(basecol, vec3(0.0), metallic);
vec3 tmp_col = mix(vec3(1.0), tint, specular_tint);
f0 = mix((0.08 * specular_fac) * tmp_col, basecol, metallic);
diffuse = basecol * (1.0 - metallic);
}
#ifndef VOLUMETRICS
@ -1126,52 +1126,47 @@ void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure r
node_bsdf_diffuse(color, 0.0, N, result);
}
void node_bsdf_principled_clearcoat(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
float sss_id, vec3 sss_scale, out Closure result)
void node_bsdf_principled(
vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
float sss_id, vec3 sss_scale, out Closure result)
{
ior = max(ior, 1e-5);
metallic = saturate(metallic);
transmission = saturate(transmission);
float dielectric = 1.0 - metallic;
transmission *= dielectric;
subsurface_color *= dielectric;
vec3 diffuse, f0, out_diff, out_spec, out_trans, out_refr, ssr_spec;
convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0);
transmission *= 1.0 - metallic;
subsurface *= 1.0 - metallic;
clearcoat *= 0.25;
clearcoat *= 1.0 - transmission;
/* Far from being accurate, but 2 glossy evaluation is too expensive.
* Most noticeable difference is at grazing angles since the bsdf lut
* f0 color interpolation is done on top of this interpolation. */
vec3 f0_glass = mix(vec3(1.0), base_color.rgb, specular_tint);
float fresnel = F_eta(ior, dot(N, cameraVec));
vec3 spec_col = F_color_blend(ior, fresnel, f0_glass) * fresnel;
f0 = mix(f0, spec_col, transmission);
vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
#ifdef USE_SSS
diffuse = vec3(0.0);
#else
diffuse = mixed_ss_base_color;
#endif
f0 = mix(f0, vec3(1.0), transmission);
float sss_scalef = dot(sss_scale, vec3(1.0 / 3.0)) * subsurface;
eevee_closure_principled(N, mixed_ss_base_color, f0, int(ssr_id), roughness,
CN, clearcoat, clearcoat_roughness, 1.0, sss_scalef, ior,
CN, clearcoat * 0.25, clearcoat_roughness, 1.0, sss_scalef, ior,
out_diff, out_trans, out_spec, out_refr, ssr_spec);
vec3 refr_color = base_color.rgb;
refr_color *= (refractionDepth > 0.0) ? refr_color : vec3(1.0); /* Simulate 2 transmission event */
float fresnel = F_eta(ior, dot(N, cameraVec));
vec3 refr_spec_color = base_color.rgb * fresnel;
/* This bit maybe innacurate. */
out_refr = out_refr * refr_color * (1.0 - fresnel) + out_spec * refr_spec_color;
ssr_spec = mix(ssr_spec, refr_spec_color, transmission);
out_refr *= refr_color * (1.0 - fresnel) * transmission;
vec3 vN = normalize(mat3(ViewMatrix) * N);
result = CLOSURE_DEFAULT;
result.radiance = out_spec + out_diff * diffuse;
result.radiance = mix(result.radiance, out_refr, transmission);
result.radiance = out_spec + out_refr;
#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);
@ -1187,6 +1182,132 @@ void node_bsdf_principled_clearcoat(vec4 base_color, float subsurface, vec3 subs
#endif
}
void node_bsdf_principled_dielectric(
vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
float sss_id, vec3 sss_scale, out Closure result)
{
metallic = saturate(metallic);
float dielectric = 1.0 - metallic;
vec3 diffuse, f0, out_diff, out_spec, ssr_spec;
convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0);
eevee_closure_default(N, diffuse, f0, int(ssr_id), roughness, 1.0, out_diff, out_spec, ssr_spec);
vec3 vN = normalize(mat3(ViewMatrix) * N);
result = CLOSURE_DEFAULT;
result.radiance = out_spec + out_diff * diffuse;
result.ssr_data = vec4(ssr_spec, roughness);
result.ssr_normal = normal_encode(vN, viewCameraVec);
result.ssr_id = int(ssr_id);
}
void node_bsdf_principled_metallic(
vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
float sss_id, vec3 sss_scale, out Closure result)
{
vec3 out_spec, ssr_spec;
eevee_closure_glossy(N, base_color.rgb, int(ssr_id), roughness, 1.0, out_spec, ssr_spec);
vec3 vN = normalize(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);
}
void node_bsdf_principled_clearcoat(
vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
float sss_id, vec3 sss_scale, out Closure result)
{
vec3 out_spec, ssr_spec;
eevee_closure_clearcoat(N, base_color.rgb, int(ssr_id), roughness, CN, clearcoat * 0.25, clearcoat_roughness,
1.0, out_spec, ssr_spec);
vec3 vN = normalize(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);
}
void node_bsdf_principled_subsurface(
vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
float sss_id, vec3 sss_scale, out Closure result)
{
metallic = saturate(metallic);
vec3 diffuse, f0, out_diff, out_spec, out_trans, ssr_spec;
convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0);
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;
eevee_closure_skin(N, mixed_ss_base_color, f0, int(ssr_id), roughness, 1.0, sss_scalef,
out_diff, out_trans, out_spec, ssr_spec);
vec3 vN = normalize(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
#else
result.radiance += (out_diff + out_trans) * mixed_ss_base_color;
#endif
}
void node_bsdf_principled_glass(
vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
float sss_id, vec3 sss_scale, out Closure result)
{
ior = max(ior, 1e-5);
vec3 f0, out_spec, out_refr, ssr_spec;
f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
eevee_closure_glass(N, vec3(1.0), int(ssr_id), roughness, 1.0, ior, out_spec, out_refr, ssr_spec);
vec3 refr_color = base_color.rgb;
refr_color *= (refractionDepth > 0.0) ? refr_color : vec3(1.0); /* Simulate 2 transmission events */
out_refr *= refr_color;
float fresnel = F_eta(ior, dot(N, cameraVec));
vec3 spec_col = F_color_blend(ior, fresnel, f0);
out_spec *= spec_col;
ssr_spec *= spec_col * fresnel;
vec3 vN = normalize(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);
}
void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
{
node_bsdf_diffuse(color, 0.0, -N, result);
@ -1220,13 +1341,13 @@ void node_subsurface_scattering(
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;
#ifdef USE_SSS_ALBEDO
# 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
# else
result.sss_data.rgb *= color.rgb;
#endif
# endif
#else
node_bsdf_diffuse(color, 0.0, N, result);
#endif

View File

@ -64,22 +64,12 @@ static void node_shader_init_principled(bNodeTree *UNUSED(ntree), bNode *node)
node->custom2 = SHD_SUBSURFACE_BURLEY;
}
#define socket_not_zero(sock) (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) > 1e-5f))
#define socket_not_one(sock) (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) < 1.0f - 1e-5f))
static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
GPUNodeLink *sss_scale;
#if 0 /* Old 2.7 glsl viewport */
// normal
if (!in[17].link)
in[17].link = GPU_builtin(GPU_VIEW_NORMAL);
else
GPU_link(mat, "direction_transform_m4v3", in[17].link, GPU_builtin(GPU_VIEW_MATRIX), &in[17].link);
// clearcoat normal
if (!in[18].link)
in[18].link = GPU_builtin(GPU_VIEW_NORMAL);
else
GPU_link(mat, "direction_transform_m4v3", in[18].link, GPU_builtin(GPU_VIEW_MATRIX), &in[18].link);
#endif
/* Normals */
if (!in[17].link) {
@ -117,9 +107,48 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *node, bNodeE
GPU_link(mat, "set_rgb", GPU_uniform((float *)one), &sss_scale);
}
GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT);
bool use_diffuse = socket_not_one(4) && socket_not_one(15);
bool use_subsurf = socket_not_zero(1) && use_diffuse;
bool use_refract = socket_not_one(4) && socket_not_zero(15);
bool use_clear = socket_not_zero(12);
return GPU_stack_link(mat, node, "node_bsdf_principled_clearcoat", in, out, GPU_builtin(GPU_VIEW_POSITION),
/* Due to the manual effort done per config, we only optimize the most common permutations. */
char *node_name;
uint flag = 0;
if (!use_subsurf && use_diffuse && !use_refract && !use_clear) {
static char name[] = "node_bsdf_principled_dielectric";
node_name = name;
flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY;
}
else if (!use_subsurf && !use_diffuse && !use_refract && !use_clear) {
static char name[] = "node_bsdf_principled_metallic";
node_name = name;
flag = GPU_MATFLAG_GLOSSY;
}
else if (!use_subsurf && !use_diffuse && !use_refract && use_clear) {
static char name[] = "node_bsdf_principled_clearcoat";
node_name = name;
flag = GPU_MATFLAG_GLOSSY;
}
else if (use_subsurf && use_diffuse && !use_refract && !use_clear) {
static char name[] = "node_bsdf_principled_subsurface";
node_name = name;
flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS | GPU_MATFLAG_GLOSSY;
}
else if (!use_subsurf && !use_diffuse && use_refract && !use_clear && !socket_not_zero(4)) {
static char name[] = "node_bsdf_principled_glass";
node_name = name;
flag = GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT;
}
else {
static char name[] = "node_bsdf_principled";
node_name = name;
flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY | GPU_MATFLAG_SSS | GPU_MATFLAG_REFRACT;
}
GPU_material_flag_set(mat, flag);
return GPU_stack_link(mat, node, node_name, in, out, GPU_builtin(GPU_VIEW_POSITION),
GPU_uniform(&node->ssr_id), GPU_uniform(&node->sss_id), sss_scale);
}

View File

@ -67,6 +67,8 @@ static int node_shader_gpu_eevee_specular(GPUMaterial *mat, bNode *node, bNodeEx
GPU_link(mat, "set_value", GPU_uniform(&one), &in[9].link);
}
GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY);
return GPU_stack_link(mat, node, "node_eevee_specular", in, out, GPU_uniform(&node->ssr_id));
}