From eb5404c74e68fe4548dd166b41f7f81eaf044f80 Mon Sep 17 00:00:00 2001 From: Cody Winchester Date: Mon, 29 Sep 2025 09:40:03 -0500 Subject: [PATCH] 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 --- .../shaders/infos/eevee_legacy_common_info.hh | 4 +- source/blender/gpu/GPU_material.hh | 11 + source/blender/gpu/intern/gpu_codegen.cc | 20 ++ .../gpu/intern/gpu_material_library.hh | 2 +- .../gpu_shader_material_principled.glsl | 197 ++++++++++++++++++ .../gpu_shader_material_vector_math.glsl | 15 +- .../nodes/node_shader_bsdf_principled.cc | 34 ++- 7 files changed, 277 insertions(+), 6 deletions(-) diff --git a/source/blender/draw/engines/gooengine/shaders/infos/eevee_legacy_common_info.hh b/source/blender/draw/engines/gooengine/shaders/infos/eevee_legacy_common_info.hh index 34ecf7146f5..421bf7de8df 100644 --- a/source/blender/draw/engines/gooengine/shaders/infos/eevee_legacy_common_info.hh +++ b/source/blender/draw/engines/gooengine/shaders/infos/eevee_legacy_common_info.hh @@ -62,8 +62,8 @@ GPU_SHADER_CREATE_INFO(eevee_legacy_lights_lib) .sampler(8, ImageType::SHADOW_2D_ARRAY, "shadowCubeTexture") .sampler(9, ImageType::SHADOW_2D_ARRAY, "shadowCascadeTexture") /* GooEngine: Use slots 15,16 as others are already taken. */ - .sampler(15, ImageType::UINT_2D_ARRAY, "shadowCubeIDTexture") - .sampler(16, ImageType::UINT_2D_ARRAY, "shadowCascadeIDTexture"); + .sampler(23, ImageType::UINT_2D_ARRAY, "shadowCubeIDTexture") + .sampler(24, ImageType::UINT_2D_ARRAY, "shadowCascadeIDTexture"); /* Hair lib. */ GPU_SHADER_CREATE_INFO(eevee_legacy_hair_lib) diff --git a/source/blender/gpu/GPU_material.hh b/source/blender/gpu/GPU_material.hh index f67c09316a1..a500c7bb5d0 100644 --- a/source/blender/gpu/GPU_material.hh +++ b/source/blender/gpu/GPU_material.hh @@ -84,6 +84,13 @@ 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), @@ -220,6 +227,10 @@ char *GPU_material_split_sub_function(GPUMaterial *material, GPUNodeLink **link); 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. */ diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc index a3c7f32f893..9b09e7b489c 100644 --- a/source/blender/gpu/intern/gpu_codegen.cc +++ b/source/blender/gpu/intern/gpu_codegen.cc @@ -397,6 +397,24 @@ 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. */ @@ -944,6 +962,7 @@ bool GPU_pass_async_compilation_try_finalize(GPUPass *pass) bool GPU_pass_compile(GPUPass *pass, const char *shname) { BLI_mutex_lock(&pass->shader_creation_mutex); + bool success = true; if (pass->async_compilation_handle > 0) { /* 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); success = GPU_pass_finalize_compilation(pass, shader); } + BLI_mutex_unlock(&pass->shader_creation_mutex); return success; } diff --git a/source/blender/gpu/intern/gpu_material_library.hh b/source/blender/gpu/intern/gpu_material_library.hh index 7ac0610460d..b74ca32e6f0 100644 --- a/source/blender/gpu/intern/gpu_material_library.hh +++ b/source/blender/gpu/intern/gpu_material_library.hh @@ -12,7 +12,7 @@ #include "GPU_material.hh" #define MAX_FUNCTION_NAME 64 -#define MAX_PARAMETER 36 +#define MAX_PARAMETER 38 struct GSet; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl index 5506eeb2c55..12292537956 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl @@ -58,7 +58,11 @@ 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. */ @@ -91,6 +95,198 @@ void node_bsdf_principled(vec4 base_color, vec3 V = coordinate_incoming(g_data.P); 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. */ if (true) { ClosureTransparency transparency_data; @@ -251,4 +447,5 @@ void node_bsdf_principled(vec4 base_color, } result = Closure(0); +#endif } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl index ed285ca8002..6efd0320d3e 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl @@ -4,10 +4,23 @@ #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) { /* 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); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc index 85c410c7075..2fa1e9f8fee 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -343,6 +343,24 @@ 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); @@ -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_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); - return GPU_stack_link( - mat, node, "node_bsdf_principled", in, out, GPU_constant(&use_multi_scatter)); + return GPU_stack_link(mat, + 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)