TAA 时域速度链路贯通:天空盒补写 velocity(此前恒 0,相机移动时天空/背景重投影错误 → 闪烁);skyPrevVP(上一帧未抖动 proj × 去平移视图)落帧;TAA 加去遮挡深度检测(重投影点历史深度与当前像素比对,新暴露区拒历史,需 near/far + 投影模式落帧);移除 min-depth dilation(把前景速度泄漏给轮廓旁背景像素 → 边界闪);Forward 不透明段 velocity 附件 Clear→Load 承接天空结果;velocity 不入抖动注释订正(抖动进 velocity = 静止画面持续亚纹素重采样发糊)

This commit is contained in:
2026-10-18 15:22:48 +08:00
parent beba491bcb
commit 2024772bac
13 changed files with 178 additions and 45 deletions
@@ -35,7 +35,8 @@ namespace Engine {
// env 可为空(HDR 资产缺失):仅承担清屏,天空保持清屏色
SkyboxPass(Device& device, ShaderManager& shaders,
DescriptorManager& descriptors, FrameSceneData& frame,
RG::TextureHandle hdrColor, const Cubemap* env);
RG::TextureHandle hdrColor, RG::TextureHandle velocity,
const Cubemap* env);
~SkyboxPass();
SkyboxPass(const SkyboxPass&) = delete;
@@ -49,10 +50,11 @@ namespace Engine {
DescriptorManager& m_Descriptors;
FrameSceneData& m_Frame;
RG::TextureHandle m_HDRColor;
RG::TextureHandle m_Velocity; // 天空 velocity 附件(TAA)
const Cubemap* m_Env; // 可空
vk::DescriptorSetLayout m_SetLayout; // Set0 = {samplerCube}
vk::PipelineLayout m_Layout; // push = invVP 64B
vk::PipelineLayout m_Layout; // push = {invVP, prevVP} 128B
ShaderManager::ShaderRef m_Vert, m_Frag; // 析构自动销毁
std::array<vk::DescriptorSet, kMaxFramesInFlight> m_Sets{};
};
@@ -22,7 +22,7 @@ namespace Engine::Passes {
public:
TAAPass(FullscreenGpu& gpu, FrameSceneData& frame, f32 historyAlpha,
RG::TextureHandle hdrColor, RG::TextureHandle velocity,
RG::TextureHandle taaColor);
RG::TextureHandle depth, RG::TextureHandle taaColor);
~TAAPass() override = default;
void Register(RG::RenderGraph& rg) override;
@@ -34,6 +34,7 @@ namespace Engine::Passes {
f32 m_HistoryAlpha; // 开启时的历史权重
RG::TextureHandle m_HDR;
RG::TextureHandle m_Velocity;
RG::TextureHandle m_Depth; // 场景深度(深度感知 dilation 用)
RG::TextureHandle m_TAAColor; // 输出 = 下一帧的历史
std::vector<vk::DescriptorSet> m_Sets; // per-slot
@@ -183,7 +183,7 @@ namespace Engine {
// ---- TAA 时域状态 ----
u64 m_FrameIndex = 0; // 抖动序列游标(Halton 2,3 ×8 采样)
glm::mat4 m_LastView{1.0f}; // 上一帧视图(velocity)
glm::mat4 m_LastProjNoJitter{1.0f}; // 上一帧未抖动投影(velocity)
glm::mat4 m_LastProjNoJitter{1.0f}; // 上一帧未抖动投影(velocity 用)
// 实体的上一帧世界矩阵(key = entt 实体 integral)。
// 用 sorted vector + binary_search 替代 unordered_map:
// unordered_map 在每帧大量 emplace 时 rehash 抖动明显,
+15 -2
View File
@@ -164,9 +164,9 @@ namespace Engine {
LightData lights[kMaxLights];
// ---- TAA(velocity 在 vertex 里算)----
glm::mat4 projNoJitter; // 未抖动投影(velocity 当前帧 clip 用)
glm::mat4 projNoJitter; // 未抖动投影(天空盒反投影/折射同位采样/静态预览)
glm::mat4 prevView; // 上一帧视图(velocity)
glm::mat4 prevProj; // 上一帧未抖动投影(velocity)
glm::mat4 prevProj; // 上一帧"已抖动"投影(velocity 历史 UV 对齐)
glm::vec4 cameraPos; // 相机世界位置(高光 V 向量)
};
@@ -183,6 +183,13 @@ namespace Engine {
struct FrameSceneData {
UniformBufferObject ubo{};
// 相机裁剪面 + 投影模式(TAA 去遮挡检测用:把 [0,1] 深度线性化为
// 视图空间距离再比较。透视深度非线性,需 n·f/(f−d(f−n));正交
// 深度本身线性,用 cameraOrtho 分支)
f32 cameraNearZ = 0.1f;
f32 cameraFarZ = 10000.0f;
bool cameraOrtho = false;
glm::vec4 ClearColor{0.1, 0.1, 0.1, 1.0};
bool DrawSkybox = true;
// 本帧生效的环境贴图资产路径(来自第一个 active 的
@@ -194,6 +201,12 @@ namespace Engine {
//(视图去平移只留旋转 → 反投影结果即世界方向;Skybox pass push)
glm::mat4 skyInvVP{1.0f};
// 天空盒 velocity 用:上一帧未抖动 proj × 上一帧视图(去平移)。
// 天空是"无限远"表面,只受相机旋转影响:frag 把当前世界方向过
// 此矩阵得上一帧屏幕位置,差即天空的运动向量(相机移动时天空/
// 背景不再闪烁的根治点——此前天空从不写 velocity = 恒 0)
glm::mat4 skyPrevVP{1.0f};
// 实例矩阵数组 = [主视图段 | 阴影视图段](共享同一 per-slot SSBO)
std::vector<glm::mat4> instanceModels;
// 上一帧世界矩阵,与 instanceModels 平行对齐(同一下标 = 同一