Files
XCEngine/参考/Fermion/Boson/Resources/Shaders/DeferredLighting.glsl

358 lines
10 KiB
Plaintext
Raw Normal View History

#type vertex
#version 450 core
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec2 a_TexCoords;
out vec2 v_TexCoords;
void main()
{
v_TexCoords = a_TexCoords;
gl_Position = vec4(a_Position, 1.0);
}
#type fragment
#version 450 core
layout(location = 0) out vec4 o_Color;
in vec2 v_TexCoords;
const float PI = 3.14159265359;
const float F0_NON_METAL = 0.04;
const float MIN_ROUGHNESS = 0.045;
#define MAX_DIR_LIGHTS 4
#define MAX_POINT_LIGHTS 16
#define MAX_SPOT_LIGHTS 16
// 优化的数学函数
float pow5(float x) {
float x2 = x * x;
return x2 * x2 * x;
}
float sq(float x) {
return x * x;
}
float saturate(float x) {
return clamp(x, 0.0, 1.0);
}
vec3 saturate(vec3 x) {
return clamp(x, 0.0, 1.0);
}
struct DirectionalLight {
vec3 direction;
vec3 color;
float intensity;
};
struct PointLight {
vec3 position;
vec3 color;
float intensity;
float range;
};
struct SpotLight {
vec3 position;
vec3 direction;
vec3 color;
float intensity;
float range;
float innerConeAngle;
float outerConeAngle;
};
uniform int u_DirLightCount;
uniform DirectionalLight u_DirLights[MAX_DIR_LIGHTS];
uniform int u_PointLightCount;
uniform PointLight u_PointLights[MAX_POINT_LIGHTS];
uniform int u_SpotLightCount;
uniform SpotLight u_SpotLights[MAX_SPOT_LIGHTS];
// Camera uniform buffer (binding = 0)
layout(std140, binding = 0) uniform CameraData
{
mat4 u_ViewProjection;
mat4 u_View;
mat4 u_Projection;
vec3 u_CameraPosition;
};
// Light uniform buffer (binding = 2)
layout(std140, binding = 2) uniform LightData
{
mat4 u_LightSpaceMatrix;
vec3 u_DirLightDirection;
float u_DirLightIntensity;
vec3 u_DirLightColor;
float _lightPadding0;
float u_ShadowBias;
float u_ShadowSoftness;
int u_EnableShadows;
int u_NumDirLights;
float u_AmbientIntensity;
int u_NumPointLights;
int u_NumSpotLights;
};
uniform sampler2D u_GBufferAlbedo;
uniform sampler2D u_GBufferNormal;
uniform sampler2D u_GBufferMaterial;
uniform sampler2D u_GBufferEmissive;
uniform sampler2D u_GBufferDepth;
uniform mat4 u_InverseViewProjection;
// Shadow mapping
uniform sampler2D u_ShadowMap;
// IBL
uniform bool u_UseIBL;
uniform samplerCube u_IrradianceMap;
uniform samplerCube u_PrefilterMap;
uniform sampler2D u_BRDFLT;
uniform float u_PrefilterMaxLOD;
// ============================================================================
// BRDF 函数
// ============================================================================
float D_GGX(float roughness, float NoH) {
float a = roughness * roughness;
float a2 = a * a;
float NoH2 = NoH * NoH;
float nom = a2;
float denom = (NoH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;
return nom / max(denom, 1e-7);
}
float V_SmithGGXCorrelated(float roughness, float NoV, float NoL) {
float a = roughness * roughness;
float a2 = a * a;
float lambdaV = NoL * sqrt(NoV * NoV * (1.0 - a2) + a2);
float lambdaL = NoV * sqrt(NoL * NoL * (1.0 - a2) + a2);
return 0.5 / max(lambdaV + lambdaL, 1e-5);
}
vec3 fresnelSchlick(float cosTheta, vec3 F0) {
return F0 + (1.0 - F0) * pow5(saturate(1.0 - cosTheta));
}
vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) {
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow5(saturate(1.0 - cosTheta));
}
float Fd_Burley(float roughness, float NoV, float NoL, float LoH) {
float f90 = 0.5 + 2.0 * roughness * LoH * LoH;
float lightScatter = 1.0 + (f90 - 1.0) * pow5(1.0 - NoL);
float viewScatter = 1.0 + (f90 - 1.0) * pow5(1.0 - NoV);
return lightScatter * viewScatter * (1.0 / PI);
}
vec3 ACESFilm(vec3 x) {
float a = 2.51;
float b = 0.03;
float c = 2.43;
float d = 0.59;
float e = 0.14;
return saturate((x * (a * x + b)) / (x * (c * x + d) + e));
}
float computeSpecularOcclusion(float NoV, float ao, float roughness) {
return clamp(pow(NoV + ao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ao, 0.0, 1.0);
}
float calculateShadow(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir) {
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
projCoords = projCoords * 0.5 + 0.5;
if (projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 ||
projCoords.y < 0.0 || projCoords.y > 1.0)
return 0.0;
float bias = max(u_ShadowBias * (1.0 - dot(normal, lightDir)), u_ShadowBias * 0.1);
float shadow = 0.0;
vec2 texelSize = 1.0 / textureSize(u_ShadowMap, 0);
int pcfRange = int(u_ShadowSoftness);
int sampleCount = 0;
for (int x = -pcfRange; x <= pcfRange; ++x) {
for (int y = -pcfRange; y <= pcfRange; ++y) {
float pcfDepth = texture(u_ShadowMap, projCoords.xy + vec2(x, y) * texelSize).r;
shadow += projCoords.z - bias > pcfDepth ? 1.0 : 0.0;
sampleCount++;
}
}
shadow /= float(sampleCount);
return shadow;
}
vec3 reconstructWorldPosition(vec2 uv, float depth) {
vec4 clip = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
vec4 world = u_InverseViewProjection * clip;
return world.xyz / max(world.w, 0.0001);
}
// ============================================================================
// 综合光照评估
// ============================================================================
vec3 evaluateLighting(vec3 N, vec3 V, vec3 L, vec3 albedo, float roughness,
float metallic, vec3 F0, float NoV, vec3 radiance, float occlusion) {
vec3 H = normalize(V + L);
float NoL = max(dot(N, L), 0.0);
float NoH = saturate(dot(N, H));
float LoH = saturate(dot(L, H));
// 标准 BRDF
float D = D_GGX(roughness, NoH);
float V_term = V_SmithGGXCorrelated(roughness, NoV, NoL);
vec3 kS = fresnelSchlick(LoH, F0);
vec3 specularBRDF = (D * V_term) * kS;
// Burley 漫反射
vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic);
vec3 diffuseBRDF = kD * albedo * Fd_Burley(roughness, NoV, NoL, LoH);
vec3 color = (diffuseBRDF + specularBRDF) * NoL;
return color * radiance * occlusion;
}
// ============================================================================
// 主渲染函数
// ============================================================================
void main() {
float depth = texture(u_GBufferDepth, v_TexCoords).r;
if (depth >= 1.0)
discard;
vec3 albedo = texture(u_GBufferAlbedo, v_TexCoords).rgb;
vec3 N = normalize(texture(u_GBufferNormal, v_TexCoords).rgb);
vec3 material = texture(u_GBufferMaterial, v_TexCoords).rgb;
vec3 emissive = texture(u_GBufferEmissive, v_TexCoords).rgb;
float roughness = max(material.r, MIN_ROUGHNESS);
float metallic = saturate(material.g);
float ao = saturate(material.b);
vec3 worldPos = reconstructWorldPosition(v_TexCoords, depth);
vec3 V = normalize(u_CameraPosition - worldPos);
float NoV = max(dot(N, V), 1e-4);
vec3 F0 = mix(vec3(F0_NON_METAL), albedo, metallic);
vec3 Lo = vec3(0.0);
// Main directional light (with shadow)
{
vec3 L = normalize(-u_DirLightDirection);
vec3 radiance = u_DirLightColor * u_DirLightIntensity;
float shadow = 0.0;
if (u_EnableShadows != 0) {
vec4 fragPosLightSpace = u_LightSpaceMatrix * vec4(worldPos, 1.0);
shadow = calculateShadow(fragPosLightSpace, N, L);
}
Lo += evaluateLighting(N, V, L, albedo, roughness, metallic, F0, NoV, radiance, 1.0 - shadow);
}
// Additional directional lights
for (int i = 0; i < u_DirLightCount; i++) {
DirectionalLight light = u_DirLights[i];
vec3 L = normalize(-light.direction);
vec3 radiance = light.color * light.intensity;
Lo += evaluateLighting(N, V, L, albedo, roughness, metallic, F0, NoV, radiance, 1.0);
}
// Point lights
for (int i = 0; i < u_PointLightCount; i++) {
PointLight light = u_PointLights[i];
vec3 L = light.position - worldPos;
float dist = length(L);
if (dist > light.range)
continue;
L = normalize(L);
float distanceAttenuation = 1.0 / (dist * dist + 1.0);
float windowFactor = sq(saturate(1.0 - sq(sq(dist / light.range))));
float attenuation = distanceAttenuation * windowFactor;
vec3 radiance = light.color * light.intensity * attenuation;
Lo += evaluateLighting(N, V, L, albedo, roughness, metallic, F0, NoV, radiance, 1.0);
}
// Spot lights
for (int i = 0; i < u_SpotLightCount; i++) {
SpotLight light = u_SpotLights[i];
vec3 L = light.position - worldPos;
float dist = length(L);
if (dist > light.range)
continue;
L = normalize(L);
float theta = dot(L, normalize(light.direction));
float epsilon = light.innerConeAngle - light.outerConeAngle;
float spotIntensity = saturate((theta - light.outerConeAngle) / epsilon);
if (spotIntensity <= 0.0)
continue;
float distanceAttenuation = 1.0 / (dist * dist + 1.0);
float windowFactor = sq(saturate(1.0 - sq(sq(dist / light.range))));
float attenuation = distanceAttenuation * windowFactor;
vec3 radiance = light.color * light.intensity * attenuation * spotIntensity;
Lo += evaluateLighting(N, V, L, albedo, roughness, metallic, F0, NoV, radiance, 1.0);
}
// IBL
vec3 ambient = vec3(0.0);
if (u_UseIBL) {
vec3 F = fresnelSchlickRoughness(NoV, F0, roughness);
vec3 kS = F;
vec3 kD = (1.0 - kS) * (1.0 - metallic);
vec3 irradiance = texture(u_IrradianceMap, N).rgb;
if (dot(irradiance, irradiance) < 0.000001)
irradiance = vec3(0.03);
vec3 diffuse = irradiance * albedo;
vec3 R = reflect(-V, N);
float lod = roughness * u_PrefilterMaxLOD;
vec3 prefilteredColor = textureLod(u_PrefilterMap, R, lod).rgb;
if (dot(prefilteredColor, prefilteredColor) < 0.000001)
prefilteredColor = vec3(0.03);
vec2 brdf = texture(u_BRDFLT, vec2(NoV, roughness)).rg;
float specOcclusion = computeSpecularOcclusion(NoV, ao, roughness);
vec3 specular = prefilteredColor * (F * brdf.x + brdf.y) * specOcclusion;
ambient = (kD * diffuse + specular) * ao;
} else {
ambient = vec3(u_AmbientIntensity) * albedo * ao;
}
vec3 color = ambient + Lo + emissive;
color = ACESFilm(color);
color = pow(color, vec3(1.0 / 2.2));
o_Color = vec4(color, 1.0);
}