#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); }