Files
Prism/Editor/assets/shaders/Lighting.glsl

348 lines
11 KiB
GLSL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#type vertex
#version 430 core
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec2 a_TexCoord;
out vec2 v_TexCoord;
void main()
{
v_TexCoord = a_TexCoord;
gl_Position = vec4(a_Position.xy, 0.0, 1.0);
}
#type fragment
#version 430 core
// ==================== 输入 ====================
in vec2 v_TexCoord;
// G-buffer 纹理
uniform sampler2D u_AlbedoMetallic; // RGB: albedo, A: metallic
uniform sampler2D u_NormalRoughness; // RGB: normal (encoded), A: roughness
uniform sampler2D u_EmissiveAO; // RGB: emissive, A: AO
uniform sampler2D u_Depth; // depth
// 相机参数
uniform mat4 u_InvViewProj; // 逆视图投影矩阵,用于重建世界坐标
uniform vec3 u_CameraPosition;
// 光源结构体与你的PBR着色器一致
struct DirectionalLight {
vec3 Direction;
vec3 Radiance;
float Intensity;
bool CastShadows;
};
struct PointLight {
vec3 Position;
vec3 Radiance;
float Intensity;
float Range;
bool CastShadows;
};
struct SpotLight {
vec3 Position;
vec3 Direction;
vec3 Radiance;
float Intensity;
float Range;
float InnerConeCos;
float OuterConeCos;
bool CastShadows;
};
uniform DirectionalLight u_DirectionalLights; // 仅一个方向光
uniform int u_PointLightCount;
uniform PointLight u_PointLights[16]; // 假设最多16个点光源
uniform int u_SpotLightCount;
uniform SpotLight u_SpotLights[16]; // 最多16个聚光源
// IBL 相关
uniform samplerCube u_EnvRadianceTex;
uniform samplerCube u_EnvIrradianceTex;
uniform sampler2D u_BRDFLUTTexture;
uniform float u_IBLContribution;
uniform float u_EnvMapRotation;
// 阴影相关
uniform sampler2D u_ShadowMap;
uniform float u_ShadowBias;
uniform float u_ShadowSoftness;
uniform int u_ShadowEnabled;
uniform float u_ShadowIntensity; // 阴影强度0-1
uniform mat4 u_LightSpaceMatrix; // 方向光光源空间矩阵
// 天空盒(可选)
uniform samplerCube u_Skybox; // 如果深度为1.0则采样天空盒
uniform float u_SkyIntensity;
uniform float u_SkyTextureLod;
// 输出
layout(location = 0) out vec4 o_Color;
// ==================== 常量 ====================
const float PI = 3.14159265359;
const float Epsilon = 0.00001;
const vec3 Fdielectric = vec3(0.04);
// ==================== 工具函数 ====================
// 从深度重建世界坐标
vec3 worldPosFromDepth(vec2 uv, float depth) {
vec4 clipPos = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
vec4 worldPos = u_InvViewProj * clipPos;
return worldPos.xyz / worldPos.w;
}
// 从深度重建世界空间方向(用于天空盒采样)
vec3 worldDirFromUV(vec2 uv) {
// 假设深度为1.0时,得到远平面方向
vec4 clipPos = vec4(uv * 2.0 - 1.0, 1.0, 1.0);
vec4 worldPos = u_InvViewProj * clipPos;
return normalize(worldPos.xyz / worldPos.w);
}
// 旋转向量绕Y轴
vec3 RotateVectorAboutY(float angle, vec3 vec) {
angle = radians(angle);
mat3 rotationMatrix = mat3(
vec3(cos(angle), 0.0, sin(angle)),
vec3(0.0, 1.0, 0.0),
vec3(-sin(angle), 0.0, cos(angle))
);
return rotationMatrix * vec;
}
// ==================== PBR 函数(复用你的代码) ====================
float ndfGGX(float cosLh, float roughness) {
float alpha = roughness * roughness;
float alphaSq = alpha * alpha;
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
return alphaSq / (PI * denom * denom);
}
float GeometrySchlickGGX(float NdotV, float roughness) {
float r = (roughness + 1.0);
float k = (r * r) / 8.0;
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
}
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
float NdotV = max(dot(N, V), 0.0);
float NdotL = max(dot(N, L), 0.0);
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
return ggx1 * ggx2;
}
vec3 fresnelSchlick(vec3 F0, float cosTheta) {
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
vec3 fresnelSchlickRoughness(vec3 F0, float cosTheta, float roughness) {
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
}
// ---------- 方向光 ----------
vec3 ComputeDirectionalLight(DirectionalLight light, vec3 F0, vec3 N, vec3 V, float NdotV, vec3 albedo, float roughness, float metallic) {
vec3 L = normalize(-light.Direction);
vec3 Lradiance = light.Radiance * light.Intensity;
vec3 Lh = normalize(L + V);
float cosLi = max(dot(N, L), 0.0);
float cosLh = max(dot(N, Lh), 0.0);
vec3 F = fresnelSchlick(F0, max(dot(Lh, V), 0.0));
float D = ndfGGX(cosLh, roughness);
float G = GeometrySmith(N, V, L, roughness);
vec3 kd = (1.0 - F) * (1.0 - metallic);
vec3 diffuseBRDF = kd * albedo;
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * NdotV);
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
}
// ---------- 点光源 ----------
vec3 ComputePointLight(PointLight light, vec3 F0, vec3 N, vec3 V, float NdotV, vec3 albedo, float roughness, float metallic, vec3 worldPos) {
vec3 lightVec = light.Position - worldPos;
float dist = length(lightVec);
if (dist > light.Range) return vec3(0.0);
vec3 L = lightVec / dist;
vec3 Lradiance = light.Radiance * light.Intensity;
float attenuation = 1.0 / (dist * dist + 0.0001);
float rangeFactor = clamp(1.0 - (dist / light.Range), 0.0, 1.0);
rangeFactor = rangeFactor * rangeFactor;
attenuation *= rangeFactor;
vec3 Lh = normalize(L + V);
float cosLi = max(dot(N, L), 0.0);
float cosLh = max(dot(N, Lh), 0.0);
vec3 F = fresnelSchlick(F0, max(dot(Lh, V), 0.0));
float D = ndfGGX(cosLh, roughness);
float G = GeometrySmith(N, V, L, roughness);
vec3 kd = (1.0 - F) * (1.0 - metallic);
vec3 diffuseBRDF = kd * albedo;
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * NdotV);
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation;
}
// ---------- 聚光源 ----------
vec3 ComputeSpotLight(SpotLight light, vec3 F0, vec3 N, vec3 V, float NdotV, vec3 albedo, float roughness, float metallic, vec3 worldPos) {
vec3 lightVec = light.Position - worldPos;
float dist = length(lightVec);
if (dist > light.Range) return vec3(0.0);
vec3 L = lightVec / dist;
vec3 Lradiance = light.Radiance * light.Intensity;
float attenuation = 1.0 / (dist * dist + 0.0001);
float rangeFactor = clamp(1.0 - (dist / light.Range), 0.0, 1.0);
rangeFactor = rangeFactor * rangeFactor;
attenuation *= rangeFactor;
float cosAngle = dot(-L, normalize(light.Direction));
if (cosAngle < light.OuterConeCos) return vec3(0.0);
float angleFalloff = (cosAngle - light.OuterConeCos) / (light.InnerConeCos - light.OuterConeCos);
angleFalloff = clamp(angleFalloff, 0.0, 1.0);
attenuation *= angleFalloff;
vec3 Lh = normalize(L + V);
float cosLi = max(dot(N, L), 0.0);
float cosLh = max(dot(N, Lh), 0.0);
vec3 F = fresnelSchlick(F0, max(dot(Lh, V), 0.0));
float D = ndfGGX(cosLh, roughness);
float G = GeometrySmith(N, V, L, roughness);
vec3 kd = (1.0 - F) * (1.0 - metallic);
vec3 diffuseBRDF = kd * albedo;
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * NdotV);
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation;
}
// ---------- IBL ----------
vec3 IBL(vec3 F0, vec3 N, vec3 V, float NdotV, float roughness, float metallic, vec3 albedo) {
vec3 irradiance = texture(u_EnvIrradianceTex, N).rgb;
vec3 F = fresnelSchlickRoughness(F0, NdotV, roughness);
vec3 kd = (1.0 - F) * (1.0 - metallic);
vec3 diffuseIBL = albedo * irradiance;
vec3 R = 2.0 * NdotV * N - V; // 反射向量
int u_EnvRadianceTexLevels = textureQueryLevels(u_EnvRadianceTex);
vec3 specularIrradiance = textureLod(
u_EnvRadianceTex,
RotateVectorAboutY(u_EnvMapRotation, R),
roughness * u_EnvRadianceTexLevels
).rgb;
vec2 specularBRDF = texture(u_BRDFLUTTexture, vec2(NdotV, 1.0 - roughness)).rg;
vec3 specularIBL = specularIrradiance * (F * specularBRDF.x + specularBRDF.y);
return kd * diffuseIBL + specularIBL;
}
// ---------- 阴影 ----------
float calculateShadow(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir) {
if (u_ShadowEnabled == 0) return 0.0;
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 closestDepth = texture(u_ShadowMap, projCoords.xy).r;
float currentDepth = projCoords.z;
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 += (currentDepth - bias > pcfDepth) ? 1.0 : 0.0;
sampleCount++;
}
}
shadow /= float(sampleCount);
return shadow * u_ShadowIntensity; // 应用阴影强度
}
// ==================== 主函数 ====================
void main() {
vec2 uv = v_TexCoord;
float depth = texture(u_Depth, uv).r;
if (depth >= 1.0) {
vec3 dir = worldDirFromUV(uv);
vec3 skyColor = textureLod(u_Skybox, dir, u_SkyTextureLod).rgb * u_SkyIntensity;
o_Color = vec4(skyColor, 1.0);
return;
}
vec4 albedoMetal = texture(u_AlbedoMetallic, uv);
vec4 normalRough = texture(u_NormalRoughness, uv);
vec4 emissiveAO = texture(u_EmissiveAO, uv);
vec3 albedo = albedoMetal.rgb;
float metallic = albedoMetal.a;
vec3 normal = normalRough.rgb * 2.0 - 1.0;
float roughness = normalRough.a;
vec3 emissive = emissiveAO.rgb;
float ao = emissiveAO.a;
vec3 worldPos = worldPosFromDepth(uv, depth);
vec3 V = normalize(u_CameraPosition - worldPos);
float NdotV = clamp(dot(normal, V), 0.0, 1.0);
vec3 F0 = mix(Fdielectric, albedo, metallic);
vec3 Lo = vec3(0.0);
// Direction Light
if (u_DirectionalLights.Intensity > 0.0) {
Lo += ComputeDirectionalLight(u_DirectionalLights, F0, normal, V, NdotV, albedo, roughness, metallic);
}
// Point Light
for (int i = 0; i < u_PointLightCount; ++i) {
Lo += ComputePointLight(u_PointLights[i], F0, normal, V, NdotV, albedo, roughness, metallic, worldPos);
}
// Spot light
for (int i = 0; i < u_SpotLightCount; ++i) {
Lo += ComputeSpotLight(u_SpotLights[i], F0, normal, V, NdotV, albedo, roughness, metallic, worldPos);
}
float shadowFactor = 1.0;
if (u_ShadowEnabled > 0 && u_DirectionalLights.CastShadows && u_DirectionalLights.Intensity > 0.0) {
vec4 fragPosLightSpace = u_LightSpaceMatrix * vec4(worldPos, 1.0);
float shadow = calculateShadow(fragPosLightSpace, normal, u_DirectionalLights.Direction);
shadowFactor = 1.0 - shadow;
}
Lo *= shadowFactor;
// 计算 IBL
vec3 ibl = IBL(F0, normal, V, NdotV, roughness, metallic, albedo) * u_IBLContribution;
vec3 finalColor = Lo + ibl + emissive;
o_Color = vec4(finalColor, 1.0);
}