#version 450 // TAA resolve:时域抗锯齿。 // 1. velocity 反推历史像素位置,取历史累积色 // 2. 邻域 clamp(3×3 AABB)压制鬼影:历史色超出当前帧邻域范围的部分丢弃 // 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; 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; // 邻域 clamp:当前帧 3×3 邻域的 min/max 包围盒 vec2 ts = 1.0 / vec2(textureSize(curImage, 0)); vec3 minC = cur.rgb; vec3 maxC = cur.rgb; for (int y = -1; y <= 1; ++y) { for (int x = -1; x <= 1; ++x) { vec3 c = texture(curImage, fragUV + vec2(x, y) * ts).rgb; minC = min(minC, c); maxC = max(maxC, c); } } vec3 clamped = clamp(hist, minC, maxC); result = mix(cur.rgb, clamped, pc.alpha); } outColor = vec4(result, cur.a); }