EEVEE: Adapt Principled BSDF to closure sampling
With the new closure approach, the code can be simplified and cleaned up quite a bit. This also removes four parameters, which is helpful for future additions (!123616) since the parameter limit appears to be reached. Pull Request: https://projects.blender.org/blender/blender/pulls/123643
This commit is contained in:
committed by
Lukas Stockner
parent
3b9081d093
commit
26eb5d9899
@@ -85,13 +85,6 @@ enum eGPUMaterialFlag {
|
||||
|
||||
GPU_MATFLAG_BARYCENTRIC = (1 << 20),
|
||||
|
||||
/* Optimization to only add the branches of the principled shader that are necessary. */
|
||||
GPU_MATFLAG_PRINCIPLED_COAT = (1 << 21),
|
||||
GPU_MATFLAG_PRINCIPLED_METALLIC = (1 << 22),
|
||||
GPU_MATFLAG_PRINCIPLED_DIELECTRIC = (1 << 23),
|
||||
GPU_MATFLAG_PRINCIPLED_GLASS = (1 << 24),
|
||||
GPU_MATFLAG_PRINCIPLED_ANY = (1 << 25),
|
||||
|
||||
/* Tells the render engine the material was just compiled or updated. */
|
||||
GPU_MATFLAG_UPDATED = (1 << 29),
|
||||
|
||||
|
||||
@@ -389,24 +389,6 @@ void GPUCodegen::generate_resources()
|
||||
{
|
||||
GPUCodegenCreateInfo &info = *create_info;
|
||||
|
||||
/* Ref. #98190: Defines are optimizations for old compilers.
|
||||
* Might become unnecessary with EEVEE-Next. */
|
||||
if (GPU_material_flag_get(&mat, GPU_MATFLAG_PRINCIPLED_COAT)) {
|
||||
info.define("PRINCIPLED_COAT");
|
||||
}
|
||||
if (GPU_material_flag_get(&mat, GPU_MATFLAG_PRINCIPLED_METALLIC)) {
|
||||
info.define("PRINCIPLED_METALLIC");
|
||||
}
|
||||
if (GPU_material_flag_get(&mat, GPU_MATFLAG_PRINCIPLED_DIELECTRIC)) {
|
||||
info.define("PRINCIPLED_DIELECTRIC");
|
||||
}
|
||||
if (GPU_material_flag_get(&mat, GPU_MATFLAG_PRINCIPLED_GLASS)) {
|
||||
info.define("PRINCIPLED_GLASS");
|
||||
}
|
||||
if (GPU_material_flag_get(&mat, GPU_MATFLAG_PRINCIPLED_ANY)) {
|
||||
info.define("PRINCIPLED_ANY");
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
/* Textures. */
|
||||
|
||||
@@ -57,11 +57,7 @@ void node_bsdf_principled(vec4 base_color,
|
||||
float emission_strength,
|
||||
float thin_film_thickness,
|
||||
float thin_film_ior,
|
||||
const float do_diffuse,
|
||||
const float do_coat,
|
||||
const float do_refraction,
|
||||
const float do_multiscatter,
|
||||
const float do_sss,
|
||||
out Closure result)
|
||||
{
|
||||
/* Match cycles. */
|
||||
@@ -94,11 +90,16 @@ void node_bsdf_principled(vec4 base_color,
|
||||
vec3 V = coordinate_incoming(g_data.P);
|
||||
float NV = dot(N, V);
|
||||
|
||||
ClosureTransparency transparency_data;
|
||||
transparency_data.weight = weight;
|
||||
transparency_data.transmittance = vec3(1.0 - alpha);
|
||||
transparency_data.holdout = 0.0;
|
||||
weight *= alpha;
|
||||
/* Transparency component. */
|
||||
if (true) {
|
||||
ClosureTransparency transparency_data;
|
||||
transparency_data.weight = weight;
|
||||
transparency_data.transmittance = vec3(1.0 - alpha);
|
||||
transparency_data.holdout = 0.0;
|
||||
closure_eval(transparency_data);
|
||||
|
||||
weight *= alpha;
|
||||
}
|
||||
|
||||
/* First layer: Sheen */
|
||||
vec3 sheen_data_color = vec3(0.0);
|
||||
@@ -111,15 +112,17 @@ void node_bsdf_principled(vec4 base_color,
|
||||
}
|
||||
|
||||
/* Second layer: Coat */
|
||||
ClosureReflection coat_data;
|
||||
coat_data.N = CN;
|
||||
coat_data.roughness = coat_roughness;
|
||||
coat_data.color = vec3(1.0);
|
||||
|
||||
if (coat_weight > 0.0) {
|
||||
float coat_NV = dot(coat_data.N, V);
|
||||
float reflectance = bsdf_lut(coat_NV, coat_data.roughness, coat_ior, false).x;
|
||||
float coat_NV = dot(CN, V);
|
||||
float reflectance = bsdf_lut(coat_NV, coat_roughness, coat_ior, false).x;
|
||||
|
||||
ClosureReflection coat_data;
|
||||
coat_data.N = CN;
|
||||
coat_data.roughness = coat_roughness;
|
||||
coat_data.color = vec3(1.0);
|
||||
coat_data.weight = weight * coat_weight * reflectance;
|
||||
closure_eval(coat_data);
|
||||
|
||||
/* Attenuate lower layers */
|
||||
weight *= max((1.0 - reflectance * coat_weight), 0.0);
|
||||
|
||||
@@ -130,50 +133,38 @@ void node_bsdf_principled(vec4 base_color,
|
||||
coat_tint.rgb = mix(vec3(1.0), pow(coat_tint.rgb, vec3(1.0 / NT)), saturate(coat_weight));
|
||||
}
|
||||
}
|
||||
else {
|
||||
coat_tint.rgb = vec3(1.0);
|
||||
coat_data.weight = 0.0;
|
||||
|
||||
/* Emission component.
|
||||
* Attenuated by sheen and coat.
|
||||
*/
|
||||
if (true) {
|
||||
ClosureEmission emission_data;
|
||||
emission_data.weight = weight;
|
||||
emission_data.emission = coat_tint.rgb * emission.rgb * emission_strength;
|
||||
closure_eval(emission_data);
|
||||
}
|
||||
|
||||
/* Attenuated by sheen and coat. */
|
||||
ClosureEmission emission_data;
|
||||
emission_data.weight = weight;
|
||||
emission_data.emission = coat_tint.rgb * emission.rgb * emission_strength;
|
||||
|
||||
/* Metallic component */
|
||||
ClosureReflection reflection_data;
|
||||
reflection_data.N = N;
|
||||
reflection_data.roughness = roughness;
|
||||
vec3 reflection_tint = specular_tint.rgb;
|
||||
vec3 reflection_color = vec3(0.0);
|
||||
if (metallic > 0.0) {
|
||||
vec3 F0 = clamped_base_color.rgb;
|
||||
vec3 F82 = min(reflection_tint, vec3(1.0));
|
||||
vec3 metallic_brdf;
|
||||
brdf_f82_tint_lut(F0, F82, NV, roughness, do_multiscatter != 0.0, metallic_brdf);
|
||||
reflection_data.color = weight * metallic * metallic_brdf;
|
||||
reflection_color = weight * metallic * metallic_brdf;
|
||||
/* Attenuate lower layers */
|
||||
weight *= max((1.0 - metallic), 0.0);
|
||||
}
|
||||
else {
|
||||
reflection_data.color = vec3(0.0);
|
||||
}
|
||||
|
||||
/* Transmission component */
|
||||
ClosureRefraction refraction_data;
|
||||
refraction_data.N = N;
|
||||
refraction_data.roughness = roughness;
|
||||
refraction_data.ior = ior;
|
||||
if (transmission_weight > 0.0) {
|
||||
vec3 F0 = vec3(F0_from_ior(ior)) * reflection_tint;
|
||||
vec3 F90 = vec3(1.0);
|
||||
vec3 reflectance, transmittance;
|
||||
bsdf_lut(F0,
|
||||
F90,
|
||||
#ifdef GPU_SHADER_EEVEE_LEGACY_DEFINES
|
||||
clamped_base_color.rgb,
|
||||
#else
|
||||
sqrt(clamped_base_color.rgb),
|
||||
#endif
|
||||
NV,
|
||||
roughness,
|
||||
ior,
|
||||
@@ -181,17 +172,19 @@ void node_bsdf_principled(vec4 base_color,
|
||||
reflectance,
|
||||
transmittance);
|
||||
|
||||
reflection_data.color += weight * transmission_weight * reflectance;
|
||||
reflection_color += weight * transmission_weight * reflectance;
|
||||
|
||||
ClosureRefraction refraction_data;
|
||||
refraction_data.N = N;
|
||||
refraction_data.roughness = roughness;
|
||||
refraction_data.ior = ior;
|
||||
refraction_data.weight = weight * transmission_weight;
|
||||
refraction_data.color = transmittance * coat_tint.rgb;
|
||||
closure_eval(refraction_data);
|
||||
|
||||
/* Attenuate lower layers */
|
||||
weight *= max((1.0 - transmission_weight), 0.0);
|
||||
}
|
||||
else {
|
||||
refraction_data.weight = 0.0;
|
||||
refraction_data.color = vec3(0.0);
|
||||
}
|
||||
|
||||
/* Specular component */
|
||||
if (true) {
|
||||
@@ -211,103 +204,53 @@ void node_bsdf_principled(vec4 base_color,
|
||||
vec3 reflectance, unused;
|
||||
bsdf_lut(F0, F90, vec3(0.0), NV, roughness, eta, do_multiscatter != 0.0, reflectance, unused);
|
||||
|
||||
reflection_data.color += weight * reflectance;
|
||||
ClosureReflection reflection_data;
|
||||
reflection_data.N = N;
|
||||
reflection_data.roughness = roughness;
|
||||
reflection_data.color = (reflection_color + weight * reflectance) * coat_tint.rgb;
|
||||
|
||||
/* Adjust the weight of picking the closure. */
|
||||
reflection_data.color *= coat_tint.rgb;
|
||||
reflection_data.weight = math_average(reflection_data.color);
|
||||
reflection_data.color *= safe_rcp(reflection_data.weight);
|
||||
closure_eval(reflection_data);
|
||||
|
||||
/* Attenuate lower layers */
|
||||
weight *= max((1.0 - math_reduce_max(reflectance)), 0.0);
|
||||
}
|
||||
|
||||
#ifdef GPU_SHADER_EEVEE_LEGACY_DEFINES
|
||||
/* EEVEE Legacy evaluates the subsurface as a diffuse closure.
|
||||
* So this has no performance penalty. However, using a separate closure for subsurface
|
||||
* (just like for EEVEE-Next) would induce a huge performance hit. */
|
||||
ClosureSubsurface diffuse_data;
|
||||
/* Flag subsurface as disabled by default. */
|
||||
diffuse_data.sss_radius.b = -1.0;
|
||||
#else
|
||||
ClosureDiffuse diffuse_data;
|
||||
#endif
|
||||
diffuse_data.N = N;
|
||||
|
||||
subsurface_radius = max(subsurface_radius * subsurface_scale, vec3(0.0));
|
||||
|
||||
/* Subsurface component */
|
||||
if (subsurface_weight > 0.0) {
|
||||
#ifdef GPU_SHADER_EEVEE_LEGACY_DEFINES
|
||||
/* For Legacy EEVEE, Subsurface is just part of the diffuse. Just evaluate the mixed color. */
|
||||
/* Subsurface Scattering materials behave unpredictably with values greater than 1.0 in
|
||||
* Cycles. So it's clamped there and we clamp here for consistency with Cycles. */
|
||||
base_color = mix(base_color, clamped_base_color, subsurface_weight);
|
||||
if (do_sss != 0.0) {
|
||||
diffuse_data.sss_radius = subsurface_weight * subsurface_radius;
|
||||
}
|
||||
#else
|
||||
ClosureSubsurface sss_data;
|
||||
sss_data.N = N;
|
||||
sss_data.sss_radius = subsurface_radius;
|
||||
sss_data.sss_radius = max(subsurface_radius * subsurface_scale, vec3(0.0));
|
||||
/* Subsurface Scattering materials behave unpredictably with values greater than 1.0 in
|
||||
* Cycles. So it's clamped there and we clamp here for consistency with Cycles. */
|
||||
sss_data.color = (subsurface_weight * weight) * clamped_base_color.rgb * coat_tint.rgb;
|
||||
/* Add energy of the sheen layer until we have proper sheen BSDF. */
|
||||
sss_data.color += sheen_data_color;
|
||||
|
||||
/* Adjust the weight of picking the closure. */
|
||||
sss_data.weight = math_average(sss_data.color);
|
||||
sss_data.color *= safe_rcp(sss_data.weight);
|
||||
result = closure_eval(sss_data);
|
||||
closure_eval(sss_data);
|
||||
|
||||
/* Attenuate lower layers */
|
||||
weight *= max((1.0 - subsurface_weight), 0.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Diffuse component */
|
||||
if (true) {
|
||||
ClosureDiffuse diffuse_data;
|
||||
diffuse_data.N = N;
|
||||
diffuse_data.color = weight * base_color.rgb * coat_tint.rgb;
|
||||
/* Add energy of the sheen layer until we have proper sheen BSDF. */
|
||||
diffuse_data.color += sheen_data_color;
|
||||
|
||||
diffuse_data.weight = math_average(diffuse_data.color);
|
||||
diffuse_data.color *= safe_rcp(diffuse_data.weight);
|
||||
|
||||
closure_eval(diffuse_data);
|
||||
}
|
||||
|
||||
/* Ref. #98190: Defines are optimizations for old compilers.
|
||||
* Might become unnecessary with EEVEE-Next. */
|
||||
if (do_diffuse == 0.0 && do_refraction == 0.0 && do_coat != 0.0) {
|
||||
#ifdef PRINCIPLED_COAT
|
||||
/* Metallic & Coat case. */
|
||||
result = closure_eval(reflection_data, coat_data);
|
||||
#endif
|
||||
}
|
||||
else if (do_diffuse == 0.0 && do_refraction == 0.0 && do_coat == 0.0) {
|
||||
#ifdef PRINCIPLED_METALLIC
|
||||
/* Metallic case. */
|
||||
result = closure_eval(reflection_data);
|
||||
#endif
|
||||
}
|
||||
else if (do_diffuse != 0.0 && do_refraction == 0.0 && do_coat == 0.0) {
|
||||
#ifdef PRINCIPLED_DIELECTRIC
|
||||
/* Dielectric case. */
|
||||
result = closure_eval(diffuse_data, reflection_data);
|
||||
#endif
|
||||
}
|
||||
else if (do_diffuse == 0.0 && do_refraction != 0.0 && do_coat == 0.0) {
|
||||
#ifdef PRINCIPLED_GLASS
|
||||
/* Glass case. */
|
||||
result = closure_eval(reflection_data, refraction_data);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#ifdef PRINCIPLED_ANY
|
||||
/* Un-optimized case. */
|
||||
result = closure_eval(diffuse_data, reflection_data, coat_data, refraction_data);
|
||||
#endif
|
||||
}
|
||||
Closure emission_cl = closure_eval(emission_data);
|
||||
Closure transparency_cl = closure_eval(transparency_data);
|
||||
result = closure_add(result, emission_cl);
|
||||
result = closure_add(result, transparency_cl);
|
||||
result = Closure(0);
|
||||
}
|
||||
|
||||
@@ -332,24 +332,6 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
|
||||
flag |= GPU_MATFLAG_COAT;
|
||||
}
|
||||
|
||||
/* Ref. #98190: Defines are optimizations for old compilers.
|
||||
* Might become unnecessary with EEVEE-Next. */
|
||||
if (use_diffuse == false && use_refract == false && use_coat == true) {
|
||||
flag |= GPU_MATFLAG_PRINCIPLED_COAT;
|
||||
}
|
||||
else if (use_diffuse == false && use_refract == false && use_coat == false) {
|
||||
flag |= GPU_MATFLAG_PRINCIPLED_METALLIC;
|
||||
}
|
||||
else if (use_diffuse == true && use_refract == false && use_coat == false) {
|
||||
flag |= GPU_MATFLAG_PRINCIPLED_DIELECTRIC;
|
||||
}
|
||||
else if (use_diffuse == false && use_refract == true && use_coat == false) {
|
||||
flag |= GPU_MATFLAG_PRINCIPLED_GLASS;
|
||||
}
|
||||
else {
|
||||
flag |= GPU_MATFLAG_PRINCIPLED_ANY;
|
||||
}
|
||||
|
||||
if (use_subsurf) {
|
||||
bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->runtime->original->inputs,
|
||||
SOCK_SUBSURFACE_RADIUS_ID);
|
||||
@@ -359,10 +341,6 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
|
||||
}
|
||||
|
||||
float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
|
||||
float use_sss = (use_subsurf) ? 1.0f : 0.0f;
|
||||
float use_diffuse_f = (use_diffuse) ? 1.0f : 0.0f;
|
||||
float use_coat_f = (use_coat) ? 1.0f : 0.0f;
|
||||
float use_refract_f = (use_refract) ? 1.0f : 0.0f;
|
||||
|
||||
GPU_material_flag_set(mat, flag);
|
||||
|
||||
@@ -371,11 +349,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
|
||||
"node_bsdf_principled",
|
||||
in,
|
||||
out,
|
||||
GPU_constant(&use_diffuse_f),
|
||||
GPU_constant(&use_coat_f),
|
||||
GPU_constant(&use_refract_f),
|
||||
GPU_constant(&use_multi_scatter),
|
||||
GPU_constant(&use_sss));
|
||||
GPU_constant(&use_multi_scatter));
|
||||
}
|
||||
|
||||
static void node_shader_update_principled(bNodeTree *ntree, bNode *node)
|
||||
|
||||
Reference in New Issue
Block a user