#type vertex #version 430 layout(location = 0) in vec3 a_Position; layout(location = 1) in vec2 a_TexCoord; out vec2 v_TexCoord; void main() { vec4 position = vec4(a_Position.xy, 0.0, 1.0); v_TexCoord = a_TexCoord; gl_Position = position; } #type fragment #version 430 layout(location = 0) out vec4 o_Color; layout(location = 1) out vec4 o_BloomTexture; in vec2 v_TexCoord; uniform sampler2DMS u_Texture; uniform sampler2DMS u_DepthTexture; uniform sampler2D u_BloomTexture; uniform mat4 u_InvProjection; uniform mat4 u_InvView; // Fog uniform float u_FogEnabled; uniform vec3 u_FogColor; uniform float u_FogDensity; // 雾密度,典型值 0.01~0.05 uniform float u_FogHeight; // 雾的起始高度(世界 Y 坐标),低于此高度雾最浓 uniform float u_FogHeightFalloff; // 高度衰减系数,值越大高度影响越剧烈(典型 0.5~2.0) uniform bool u_EnableAutoExposure; uniform float u_ManualExposure; layout(std430, binding = 2) buffer Exposure { float u_Exposure; }; uniform int u_TextureSamples; uniform bool u_EnableBloom; uniform float u_BloomThreshold; const float uFar = 1.0; vec4 SampleTexture(sampler2D tex, vec2 texCoord) { return texture(tex, texCoord); } vec4 MultiSampleTexture(sampler2DMS tex, vec2 tc) { ivec2 texSize = textureSize(tex); ivec2 texCoord = ivec2(tc * texSize); vec4 result = vec4(0.0); for (int i = 0; i < u_TextureSamples; i++) result += texelFetch(tex, texCoord, i); result /= float(u_TextureSamples); return result; } float MultiSampleDepth(sampler2DMS tex, vec2 tc) { ivec2 texSize = textureSize(tex); ivec2 texCoord = ivec2(tc * texSize); float result = 0.0; for (int i = 0; i < u_TextureSamples; i++) result += texelFetch(tex, texCoord, i).r; result /= float(u_TextureSamples); return result; } void main() { const float gamma = 2.2; const float pureWhite = 1.0; // Tonemapping vec4 msColor = MultiSampleTexture(u_Texture, v_TexCoord); vec3 color = msColor.rgb; if (u_EnableBloom) { vec3 bloomColor = texture(u_BloomTexture, v_TexCoord).rgb; color += bloomColor; } float exposure = 1.0f; if(u_EnableAutoExposure) exposure = u_Exposure; else exposure = u_ManualExposure; color *= exposure; // Reinhard tonemapping operator. // see: "Photographic Tone Reproduction for Digital Images", eq. 4 float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722)); float mappedLuminance = (luminance * (1.0 + luminance / (pureWhite * pureWhite))) / (1.0 + luminance); // Scale color by ratio of average luminances. vec3 mappedColor = (mappedLuminance / luminance) * color; if (u_FogEnabled > 0.5) { // 1. 获取深度并重建视空间坐标 float depth = MultiSampleDepth(u_DepthTexture, v_TexCoord); vec4 clipPos = vec4(v_TexCoord * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0); vec4 viewPos4 = u_InvProjection * clipPos; viewPos4 /= viewPos4.w; vec3 viewPos = viewPos4.xyz; // 视空间坐标(相机为原点,Z 轴向内) // 2. 距离雾因子(指数雾) float distance = length(viewPos); float distanceFactor = 1.0 - exp(-distance * u_FogDensity); // 可选:指数平方雾(更平滑) // float distanceFactor = 1.0 - exp(-pow(distance * u_FogDensity, 2.0)); // 3. 高度雾因子(基于世界 Y) // 将视空间坐标转换到世界空间 vec4 worldPos4 = u_InvView* vec4(viewPos, 1.0); vec3 worldPos = worldPos4.xyz / worldPos4.w; float worldY = worldPos.y; float heightFactor = 0.0; if (worldY < u_FogHeight) { // 低于起始高度:雾最浓,因子为 1 heightFactor = 1.0; } else { // 高于起始高度:指数衰减,高度越高雾越淡 float deltaY = worldY - u_FogHeight; heightFactor = exp(-deltaY * u_FogHeightFalloff); } // 可选:使用 clamp 限制范围 heightFactor = clamp(heightFactor, 0.0, 1.0); // 4. 综合雾因子(可相乘,也可取最大值,通常相乘) float fogFactor = distanceFactor * heightFactor; // 5. 混合雾颜色(雾颜色直接使用 u_FogColor,已在 LDR 空间) mappedColor = mix(mappedColor, u_FogColor, fogFactor); } // Gamma correction. o_Color = vec4(pow(mappedColor, vec3(1.0 / gamma)), 1.0); // Show over-exposed areas // if (o_Color.r > 1.0 || o_Color.g > 1.0 || o_Color.b > 1.0) // o_Color.rgb *= vec3(1.0, 0.25, 0.25); }