From c6554f7d9aba9a6dcd4d3ae1913bdf981db1c91a Mon Sep 17 00:00:00 2001 From: hydrogendeuteride Date: Sat, 15 Nov 2025 23:07:38 +0900 Subject: [PATCH] ADD: IBL glsl cleaning --- shaders/background_env.frag | 12 +----- shaders/deferred_lighting.frag | 30 +-------------- shaders/deferred_lighting_nort.frag | 31 +--------------- shaders/ibl_common.glsl | 57 +++++++++++++++++++++++++++++ shaders/mesh.frag | 25 +------------ 5 files changed, 64 insertions(+), 91 deletions(-) create mode 100644 shaders/ibl_common.glsl diff --git a/shaders/background_env.frag b/shaders/background_env.frag index 63df525..885c4ec 100644 --- a/shaders/background_env.frag +++ b/shaders/background_env.frag @@ -1,21 +1,11 @@ #version 450 #extension GL_GOOGLE_include_directive : require #include "input_structures.glsl" +#include "ibl_common.glsl" layout(location=0) in vec2 inUV; layout(location=0) out vec4 outColor; -// IBL specular equirect 2D (LOD 0 for background) -layout(set=3, binding=0) uniform sampler2D iblSpec2D; - -vec2 dir_to_equirect(vec3 d) -{ - d = normalize(d); - float phi = atan(d.z, d.x); - float theta = acos(clamp(d.y, -1.0, 1.0)); - return vec2(phi * (0.15915494309) + 0.5, theta * (0.31830988618)); -} - void main() { // Reconstruct world-space direction from screen UV diff --git a/shaders/deferred_lighting.frag b/shaders/deferred_lighting.frag index 07cf3df..9b1bb98 100644 --- a/shaders/deferred_lighting.frag +++ b/shaders/deferred_lighting.frag @@ -2,6 +2,7 @@ #extension GL_GOOGLE_include_directive : require #extension GL_EXT_ray_query : require #include "input_structures.glsl" +#include "ibl_common.glsl" layout(location=0) in vec2 inUV; layout(location=0) out vec4 outColor; @@ -10,33 +11,6 @@ layout(set=1, binding=0) uniform sampler2D posTex; layout(set=1, binding=1) uniform sampler2D normalTex; layout(set=1, binding=2) uniform sampler2D albedoTex; layout(set=2, binding=0) uniform sampler2D shadowTex[4]; -// IBL (set=3): specular prefiltered cube, diffuse irradiance cube, BRDF LUT -layout(set=3, binding=0) uniform sampler2D iblSpec2D; -layout(set=3, binding=1) uniform sampler2D iblBRDF; -layout(std140, set=3, binding=2) uniform IBL_SH { vec4 sh[9]; } iblSH; - -vec3 sh_eval_irradiance(vec3 n) -{ - float x=n.x, y=n.y, z=n.z; - const float c0=0.2820947918; - const float c1=0.4886025119; - const float c2=1.0925484306; - const float c3=0.3153915653; - const float c4=0.5462742153; - float Y[9]; - Y[0]=c0; Y[1]=c1*y; Y[2]=c1*z; Y[3]=c1*x; Y[4]=c2*x*y; Y[5]=c2*y*z; Y[6]=c3*(3.0*z*z-1.0); Y[7]=c2*x*z; Y[8]=c4*(x*x-y*y); - vec3 r=vec3(0.0); - for (int i=0;i<9;++i) r += iblSH.sh[i].rgb * Y[i]; - return r; -} - -vec2 dir_to_equirect(vec3 d) -{ - d = normalize(d); - float phi = atan(d.z, d.x); - float theta = acos(clamp(d.y, -1.0, 1.0)); - return vec2(phi * (0.15915494309) + 0.5, theta * (0.31830988618)); -} // TLAS for ray query (optional, guarded by sceneData.rtOptions.x) #ifdef GL_EXT_ray_query layout(set=0, binding=1) uniform accelerationStructureEXT topLevelAS; @@ -369,7 +343,7 @@ void main(){ // Image-Based Lighting: split-sum approximation vec3 R = reflect(-V, N); float levels = float(textureQueryLevels(iblSpec2D)); - float lod = clamp(roughness * max(levels - 1.0, 0.0), 0.0, max(levels - 1.0, 0.0)); + float lod = ibl_lod_from_roughness(roughness, levels); vec2 uv = dir_to_equirect(R); vec3 prefiltered = textureLod(iblSpec2D, uv, lod).rgb; vec2 brdf = texture(iblBRDF, vec2(max(dot(N, V), 0.0), roughness)).rg; diff --git a/shaders/deferred_lighting_nort.frag b/shaders/deferred_lighting_nort.frag index a709f38..804199f 100644 --- a/shaders/deferred_lighting_nort.frag +++ b/shaders/deferred_lighting_nort.frag @@ -1,6 +1,7 @@ #version 450 #extension GL_GOOGLE_include_directive : require #include "input_structures.glsl" +#include "ibl_common.glsl" layout(location=0) in vec2 inUV; layout(location=0) out vec4 outColor; @@ -10,34 +11,6 @@ layout(set=1, binding=1) uniform sampler2D normalTex; layout(set=1, binding=2) uniform sampler2D albedoTex; layout(set=2, binding=0) uniform sampler2D shadowTex[4]; -// IBL (set=3): specular prefiltered cube, diffuse irradiance cube, BRDF LUT -layout(set=3, binding=0) uniform sampler2D iblSpec2D; // equirect 2D with prefiltered mips -layout(set=3, binding=1) uniform sampler2D iblBRDF; // RG LUT -layout(std140, set=3, binding=2) uniform IBL_SH { vec4 sh[9]; } iblSH; - -vec3 sh_eval_irradiance(vec3 n) -{ - float x=n.x, y=n.y, z=n.z; - const float c0=0.2820947918; - const float c1=0.4886025119; - const float c2=1.0925484306; - const float c3=0.3153915653; - const float c4=0.5462742153; - float Y[9]; - Y[0]=c0; Y[1]=c1*y; Y[2]=c1*z; Y[3]=c1*x; Y[4]=c2*x*y; Y[5]=c2*y*z; Y[6]=c3*(3.0*z*z-1.0); Y[7]=c2*x*z; Y[8]=c4*(x*x-y*y); - vec3 r=vec3(0.0); - for (int i=0;i<9;++i) r += iblSH.sh[i].rgb * Y[i]; - return r; // already convolved with Lambert in CPU bake -} - -vec2 dir_to_equirect(vec3 d) -{ - d = normalize(d); - float phi = atan(d.z, d.x); - float theta = acos(clamp(d.y, -1.0, 1.0)); - return vec2(phi * (0.15915494309) + 0.5, theta * (0.31830988618)); -} - // Tunables for shadow quality and blending // Border smoothing width in light-space NDC (0..1). Larger = wider cross-fade. const float SHADOW_BORDER_SMOOTH_NDC = 0.08; @@ -299,7 +272,7 @@ void main(){ // Image-Based Lighting: split-sum approximation vec3 R = reflect(-V, N); float levels = float(textureQueryLevels(iblSpec2D)); - float lod = clamp(roughness * max(levels - 1.0, 0.0), 0.0, max(levels - 1.0, 0.0)); + float lod = ibl_lod_from_roughness(roughness, levels); vec2 uv = dir_to_equirect(R); vec3 prefiltered = textureLod(iblSpec2D, uv, lod).rgb; vec2 brdf = texture(iblBRDF, vec2(max(dot(N, V), 0.0), roughness)).rg; diff --git a/shaders/ibl_common.glsl b/shaders/ibl_common.glsl new file mode 100644 index 0000000..23873b8 --- /dev/null +++ b/shaders/ibl_common.glsl @@ -0,0 +1,57 @@ +#ifndef IBL_COMMON_GLSL +#define IBL_COMMON_GLSL + +// IBL bindings (set=3): specular equirect 2D, BRDF LUT, SH UBO. +layout(set=3, binding=0) uniform sampler2D iblSpec2D; +layout(set=3, binding=1) uniform sampler2D iblBRDF; +layout(std140, set=3, binding=2) uniform IBL_SH { vec4 sh[9]; } iblSH; + +// Evaluate diffuse irradiance from 2nd-order SH coefficients (9 coeffs). +// Coefficients are pre-convolved with the Lambert kernel on the CPU. +vec3 sh_eval_irradiance(vec3 n) +{ + float x = n.x, y = n.y, z = n.z; + const float c0 = 0.2820947918; + const float c1 = 0.4886025119; + const float c2 = 1.0925484306; + const float c3 = 0.3153915653; + const float c4 = 0.5462742153; + float Y[9]; + Y[0] = c0; + Y[1] = c1 * y; + Y[2] = c1 * z; + Y[3] = c1 * x; + Y[4] = c2 * x * y; + Y[5] = c2 * y * z; + Y[6] = c3 * (3.0 * z * z - 1.0); + Y[7] = c2 * x * z; + Y[8] = c4 * (x * x - y * y); + vec3 r = vec3(0.0); + for (int i = 0; i < 9; ++i) + { + r += iblSH.sh[i].rgb * Y[i]; + } + return r; +} + +// Map direction to equirectangular UV (same convention across shaders). +vec2 dir_to_equirect(vec3 d) +{ + d = normalize(d); + float phi = atan(d.z, d.x); + float theta = acos(clamp(d.y, -1.0, 1.0)); + // 1/(2*pi) = 0.15915494309, 1/pi = 0.31830988618 + return vec2(phi * 0.15915494309 + 0.5, theta * 0.31830988618); +} + +// Helper for selecting mip LOD from roughness and available levels. +// Uses roughness^2 to bias towards blurrier reflections at mid roughness. +float ibl_lod_from_roughness(float roughness, float levels) +{ + float maxLevel = max(levels - 1.0, 0.0); + float r = clamp(roughness, 0.0, 1.0); + return r * r * maxLevel; +} + +#endif // IBL_COMMON_GLSL + diff --git a/shaders/mesh.frag b/shaders/mesh.frag index 85ccdee..d0a23f5 100644 --- a/shaders/mesh.frag +++ b/shaders/mesh.frag @@ -2,6 +2,7 @@ #extension GL_GOOGLE_include_directive : require #include "input_structures.glsl" +#include "ibl_common.glsl" layout (location = 0) in vec3 inNormal; layout (location = 1) in vec3 inColor; @@ -13,28 +14,6 @@ layout (location = 0) out vec4 outFragColor; const float PI = 3.14159265359; -// IBL bindings (set=3): specular equirect 2D + BRDF LUT + SH UBO -layout(set=3, binding=0) uniform sampler2D iblSpec2D; -layout(set=3, binding=1) uniform sampler2D iblBRDF; -layout(std140, set=3, binding=2) uniform IBL_SH { vec4 sh[9]; } iblSH; - -vec3 sh_eval_irradiance(vec3 n) -{ - float x=n.x, y=n.y, z=n.z; - const float c0=0.2820947918; const float c1=0.4886025119; const float c2=1.0925484306; const float c3=0.3153915653; const float c4=0.5462742153; - float Y[9]; - Y[0]=c0; Y[1]=c1*y; Y[2]=c1*z; Y[3]=c1*x; Y[4]=c2*x*y; Y[5]=c2*y*z; Y[6]=c3*(3.0*z*z-1.0); Y[7]=c2*x*z; Y[8]=c4*(x*x-y*y); - vec3 r=vec3(0.0); for (int i=0;i<9;++i) r += iblSH.sh[i].rgb * Y[i]; return r; -} - -vec2 dir_to_equirect(vec3 d) -{ - d = normalize(d); - float phi = atan(d.z, d.x); - float theta = acos(clamp(d.y, -1.0, 1.0)); - return vec2(phi * (0.15915494309) + 0.5, theta * (0.31830988618)); -} - vec3 fresnelSchlick(float cosTheta, vec3 F0) { return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); @@ -118,7 +97,7 @@ void main() // IBL: specular from equirect 2D mips; diffuse from SH vec3 R = reflect(-V, N); float levels = float(textureQueryLevels(iblSpec2D)); - float lod = clamp(roughness * max(levels - 1.0, 0.0), 0.0, max(levels - 1.0, 0.0)); + float lod = ibl_lod_from_roughness(roughness, levels); vec2 uv = dir_to_equirect(R); vec3 prefiltered = textureLod(iblSpec2D, uv, lod).rgb; vec2 brdf = texture(iblBRDF, vec2(max(dot(N, V), 0.0), roughness)).rg;