#version 450 // TAA resolve:时域抗锯齿。 // 1. velocity 反推历史像素位置,取历史累积色 // 2. 方差裁剪(YCoCg):历史色钳向邻域均值 ± γσ(∩ AABB 极值盒)—— // 比 RGB min/max 盒稳得多:AABB 盒子被逐帧抖动的高亮像素拽来拽去, // 收敛历史持续被重钳 → 周期性残差经 bloom 阈值放大 = 静态模型泛光闪烁 // 3. mix(cur, hist, alpha) 时域累积 // 输出写入 TAAColor,它同时也是下一帧的历史(ReadHistory 自引用)。 layout(location = 0) in vec2 fragUV; layout(location = 0) out vec4 outColor; layout(set = 0, binding = 0) uniform sampler2D curImage; // 当前帧 HDR layout(set = 0, binding = 1) uniform sampler2D velocityImage; // 运动向量(UV 空间) layout(set = 0, binding = 2) uniform sampler2D historyImage; // 上一帧累积结果 // 全屏 pass 通用 push(16B,程序级统一声明,VUID-08878) layout(push_constant) uniform PushConstants { float exposure; // 与其它全屏 pass 布局一致(本 pass 不用) float alpha; // 历史权重(0.9 = 90% 历史) float param1; float param2; } pc; // YCoCg 感知空间:亮度/色度分离,方差裁剪不在 HDR RGB 直接做 //(RGB 各通道独立 σ 会偏色;Y 通道主导几何相关性) vec3 RgbToYCoCg(vec3 c) { return vec3(0.25 * c.r + 0.5 * c.g + 0.25 * c.b, 0.5 * c.r - 0.5 * c.b, -0.25 * c.r + 0.5 * c.g - 0.25 * c.b); } vec3 YCoCgToRgb(vec3 c) { return vec3(c.x + c.y - c.z, c.x + c.z, c.x - c.y - c.z); } void main() { vec4 cur = texture(curImage, fragUV); vec2 vel = texture(velocityImage, fragUV).xy; vec2 histUV = fragUV - vel; vec3 result = cur.rgb; // 历史采样:越出画面(相机快速平移)直接用当前帧,不累积 if (all(greaterThanEqual(histUV, vec2(0.0))) && all(lessThanEqual(histUV, vec2(1.0)))) { vec3 hist = texture(historyImage, histUV).rgb; // 邻域统计(3×3,YCoCg):均值 m1、均方 m2、极值盒 [mn, mx] vec2 ts = 1.0 / vec2(textureSize(curImage, 0)); vec3 m1 = vec3(0.0); vec3 m2 = vec3(0.0); vec3 mn = vec3(1e9); vec3 mx = vec3(-1e9); for (int y = -1; y <= 1; ++y) { for (int x = -1; x <= 1; ++x) { vec3 c = RgbToYCoCg(texture(curImage, fragUV + vec2(x, y) * ts).rgb); m1 += c; m2 += c * c; mn = min(mn, c); mx = max(mx, c); } } m1 /= 9.0; m2 /= 9.0; vec3 sigma = sqrt(max(m2 - m1 * m1, vec3(0.0))); // 方差裁剪盒:均值 ± 1.25σ 再 ∩ 极值盒。历史被钳向"稳定均值" // 而非抖动极值 → 收敛残差大幅下降(泛光闪烁的治本点)。 // 极值盒交集保证不引入邻域外颜色(鬼影上界) const float kGamma = 1.25; vec3 lo = max(m1 - kGamma * sigma, mn); vec3 hi = min(m1 + kGamma * sigma, mx); vec3 clamped = YCoCgToRgb(clamp(RgbToYCoCg(hist), lo, hi)); result = mix(cur.rgb, clamped, pc.alpha); } outColor = vec4(result, cur.a); }