GOOENGINE: Principled bsdf versioning

Increase max parameters to 38 and version the old and new principled bsdf for eevee legacy
Version vector math length squared function. A hacky solution but will look for a proper fix later
This commit is contained in:
2025-09-29 09:40:03 -05:00
parent 5bb765141e
commit eb5404c74e
7 changed files with 277 additions and 6 deletions
@@ -62,8 +62,8 @@ GPU_SHADER_CREATE_INFO(eevee_legacy_lights_lib)
.sampler(8, ImageType::SHADOW_2D_ARRAY, "shadowCubeTexture") .sampler(8, ImageType::SHADOW_2D_ARRAY, "shadowCubeTexture")
.sampler(9, ImageType::SHADOW_2D_ARRAY, "shadowCascadeTexture") .sampler(9, ImageType::SHADOW_2D_ARRAY, "shadowCascadeTexture")
/* GooEngine: Use slots 15,16 as others are already taken. */ /* GooEngine: Use slots 15,16 as others are already taken. */
.sampler(15, ImageType::UINT_2D_ARRAY, "shadowCubeIDTexture") .sampler(23, ImageType::UINT_2D_ARRAY, "shadowCubeIDTexture")
.sampler(16, ImageType::UINT_2D_ARRAY, "shadowCascadeIDTexture"); .sampler(24, ImageType::UINT_2D_ARRAY, "shadowCascadeIDTexture");
/* Hair lib. */ /* Hair lib. */
GPU_SHADER_CREATE_INFO(eevee_legacy_hair_lib) GPU_SHADER_CREATE_INFO(eevee_legacy_hair_lib)
+11
View File
@@ -84,6 +84,13 @@ enum eGPUMaterialFlag {
GPU_MATFLAG_BARYCENTRIC = (1 << 20), 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. */ /* Tells the render engine the material was just compiled or updated. */
GPU_MATFLAG_UPDATED = (1 << 29), GPU_MATFLAG_UPDATED = (1 << 29),
@@ -220,6 +227,10 @@ char *GPU_material_split_sub_function(GPUMaterial *material,
GPUNodeLink **link); GPUNodeLink **link);
bool GPU_material_sss_profile_create(GPUMaterial *material, float radii[3]); bool GPU_material_sss_profile_create(GPUMaterial *material, float radii[3]);
GPUUniformBuf *GPU_material_sss_profile_get(GPUMaterial *material,
int sample_len,
GPUTexture **tex_profile);
/** /**
* High level functions to create and use GPU materials. * High level functions to create and use GPU materials.
*/ */
+20
View File
@@ -397,6 +397,24 @@ void GPUCodegen::generate_resources()
{ {
GPUCodegenCreateInfo &info = *create_info; 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; std::stringstream ss;
/* Textures. */ /* Textures. */
@@ -944,6 +962,7 @@ bool GPU_pass_async_compilation_try_finalize(GPUPass *pass)
bool GPU_pass_compile(GPUPass *pass, const char *shname) bool GPU_pass_compile(GPUPass *pass, const char *shname)
{ {
BLI_mutex_lock(&pass->shader_creation_mutex); BLI_mutex_lock(&pass->shader_creation_mutex);
bool success = true; bool success = true;
if (pass->async_compilation_handle > 0) { if (pass->async_compilation_handle > 0) {
/* We're trying to compile this pass synchronously, but there's a pending asynchronous /* We're trying to compile this pass synchronously, but there's a pending asynchronous
@@ -955,6 +974,7 @@ bool GPU_pass_compile(GPUPass *pass, const char *shname)
GPUShader *shader = GPU_shader_create_from_info(info); GPUShader *shader = GPU_shader_create_from_info(info);
success = GPU_pass_finalize_compilation(pass, shader); success = GPU_pass_finalize_compilation(pass, shader);
} }
BLI_mutex_unlock(&pass->shader_creation_mutex); BLI_mutex_unlock(&pass->shader_creation_mutex);
return success; return success;
} }
@@ -12,7 +12,7 @@
#include "GPU_material.hh" #include "GPU_material.hh"
#define MAX_FUNCTION_NAME 64 #define MAX_FUNCTION_NAME 64
#define MAX_PARAMETER 36 #define MAX_PARAMETER 38
struct GSet; struct GSet;
@@ -58,7 +58,11 @@ void node_bsdf_principled(vec4 base_color,
float emission_strength, float emission_strength,
float thin_film_thickness, float thin_film_thickness,
float thin_film_ior, float thin_film_ior,
const float do_diffuse,
const float do_coat,
const float do_refraction,
const float do_multiscatter, const float do_multiscatter,
const float do_sss,
out Closure result) out Closure result)
{ {
/* Match cycles. */ /* Match cycles. */
@@ -91,6 +95,198 @@ void node_bsdf_principled(vec4 base_color,
vec3 V = coordinate_incoming(g_data.P); vec3 V = coordinate_incoming(g_data.P);
float NV = dot(N, V); float NV = dot(N, V);
#ifdef GPU_SHADER_EEVEE_LEGACY_DEFINES
ClosureTransparency transparency_data;
transparency_data.weight = weight;
transparency_data.transmittance = vec3(1.0 - alpha);
transparency_data.holdout = 0.0;
weight *= alpha;
/* First layer: Sheen */
vec3 sheen_data_color = vec3(0.0);
if (sheen_weight > 0.0) {
/* TODO: Maybe sheen_weight should be specular. */
vec3 sheen_color = sheen_weight * sheen_tint.rgb * principled_sheen(NV, sheen_roughness);
sheen_data_color = weight * sheen_color;
/* Attenuate lower layers */
weight *= max((1.0 - math_reduce_max(sheen_color)), 0.0);
}
/* 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;
coat_data.weight = weight * coat_weight * reflectance;
/* Attenuate lower layers */
weight *= max((1.0 - reflectance * coat_weight), 0.0);
if (!all(equal(coat_tint.rgb, vec3(1.0)))) {
float coat_neta = 1.0 / coat_ior;
float NT = sqrt_fast(1.0 - coat_neta * coat_neta * (1 - NV * NV));
/* Tint lower layers. */
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;
}
/* 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;
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;
/* 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,
clamped_base_color.rgb,
NV,
roughness,
ior,
do_multiscatter != 0.0,
reflectance,
transmittance);
reflection_data.color += weight * transmission_weight * reflectance;
refraction_data.weight = weight * transmission_weight;
refraction_data.color = transmittance * coat_tint.rgb;
/* 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) {
float eta = ior;
float f0 = F0_from_ior(eta);
if (specular_ior_level != 0.5) {
f0 *= 2.0 * specular_ior_level;
eta = ior_from_F0(f0);
if (ior < 1.0) {
eta = 1.0 / eta;
}
}
vec3 F0 = vec3(f0) * reflection_tint;
F0 = clamp(F0, vec3(0.0), vec3(1.0));
vec3 F90 = vec3(1.0);
vec3 reflectance, unused;
bsdf_lut(F0, F90, vec3(0.0), NV, roughness, eta, do_multiscatter != 0.0, reflectance, unused);
reflection_data.color += weight * reflectance;
/* 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);
/* Attenuate lower layers */
weight *= max((1.0 - math_reduce_max(reflectance)), 0.0);
}
/* 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;
diffuse_data.N = N;
subsurface_radius = max(subsurface_radius * subsurface_scale, vec3(0.0));
/* Subsurface component */
if (subsurface_weight > 0.0) {
/* 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;
}
}
/* Diffuse component */
if (true) {
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);
}
/* 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);
#else
/* Transparency component. */ /* Transparency component. */
if (true) { if (true) {
ClosureTransparency transparency_data; ClosureTransparency transparency_data;
@@ -251,4 +447,5 @@ void node_bsdf_principled(vec4 base_color,
} }
result = Closure(0); result = Closure(0);
#endif
} }
@@ -4,10 +4,23 @@
#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl) #pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
float len_sqred(vec2 a)
{
return dot(a, a);
}
float len_sqred(vec3 a)
{
return dot(a, a);
}
float len_sqred(vec4 a)
{
return dot(a, a);
}
vec3 vector_math_safe_normalize(vec3 a) vec3 vector_math_safe_normalize(vec3 a)
{ {
/* Match the safe normalize function in Cycles by defaulting to vec3(0.0) */ /* Match the safe normalize function in Cycles by defaulting to vec3(0.0) */
float length_sqr = length_squared(a); float length_sqr = len_sqred(a);
return (length_sqr > 1e-35f) ? a * inversesqrt(length_sqr) : vec3(0.0); return (length_sqr > 1e-35f) ? a * inversesqrt(length_sqr) : vec3(0.0);
} }
@@ -343,6 +343,24 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
flag |= GPU_MATFLAG_COAT; 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) { if (use_subsurf) {
bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->runtime->original->inputs, bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->runtime->original->inputs,
SOCK_SUBSURFACE_RADIUS_ID); SOCK_SUBSURFACE_RADIUS_ID);
@@ -352,11 +370,23 @@ 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_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); GPU_material_flag_set(mat, flag);
return GPU_stack_link( return GPU_stack_link(mat,
mat, node, "node_bsdf_principled", in, out, GPU_constant(&use_multi_scatter)); node,
"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));
} }
static void node_shader_update_principled(bNodeTree *ntree, bNode *node) static void node_shader_update_principled(bNodeTree *ntree, bNode *node)