feat: TAA 时域抗锯齿(velocity + 邻域 clamp + 子像素抖动)
- Velocity buffer:Forward 第二颜色附件,vertex 计算 clip 空间运动向量 (UBO 尾部追加 projNoJitter/prevView/prevProj;上一帧实例矩阵 SSBO Set0 binding2,与当前实例数组平行对齐——转动的物体速度正确不鬼影) - 子像素抖动:SceneRenderer Halton(2,3)×8 序列,抖动只进光栅化投影 - TAA resolve pass:velocity 反推历史位置 + 3×3 邻域 clamp 去鬼影 + mix(cur,hist,0.9) 时域累积;TAAColor 自引用历史 - RG 历史读补 post-barrier:采样后恢复镜像 resting layout(TAA 的历史 是 ColorAttachment layout,不恢复则下帧 entry oldLayout 脱节) - 管线:Forward(HDR+Velocity) → TAA(TAAColor) → Bloom/Tonemap 改源 TAAColor - 编译零错误、validation 零警告、8 秒冒烟通过(10 pass 全活跃)
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include <Engine/Renderer/Passes/RenderPass.h>
|
||||
#include <Engine/Renderer/Passes/ShadowPass.h>
|
||||
#include <Engine/Renderer/Passes/ForwardPass.h>
|
||||
#include <Engine/Renderer/Passes/TAAPass.h>
|
||||
#include <Engine/Renderer/Passes/BloomPass.h>
|
||||
#include <Engine/Renderer/Passes/TonemapPass.h>
|
||||
#include <Engine/Renderer/Passes/TemporalDiffPass.h>
|
||||
@@ -48,19 +49,23 @@ namespace Engine
|
||||
m_DescriptorManager = CreateScope<DescriptorManager>(*m_Device);
|
||||
m_ShaderManager = CreateScope<ShaderManager>(*m_Device);
|
||||
|
||||
// 2. Per-frame ring:UBO + GPUDriven 实例 SSBO(同一 ring 类,
|
||||
// SSBO 只是 usage 不同;正确性保证一致)
|
||||
// 2. Per-frame ring:UBO + GPUDriven 实例 SSBO(当前/上一帧,
|
||||
// 同一 ring 类,SSBO 只是 usage 不同;正确性保证一致)
|
||||
m_UniformBuffer = CreateScope<UniformBuffer>(
|
||||
*m_Device, *m_Allocator, sizeof(UniformBufferObject), kMaxFramesInFlight);
|
||||
m_ObjectBuffer = CreateScope<UniformBuffer>(
|
||||
*m_Device, *m_Allocator,
|
||||
sizeof(glm::mat4) * kMaxInstances, kMaxFramesInFlight,
|
||||
vk::BufferUsageFlagBits::eStorageBuffer);
|
||||
m_PrevObjectBuffer = CreateScope<UniformBuffer>(
|
||||
*m_Device, *m_Allocator,
|
||||
sizeof(glm::mat4) * kMaxInstances, kMaxFramesInFlight,
|
||||
vk::BufferUsageFlagBits::eStorageBuffer);
|
||||
|
||||
// 3. pass 装配体:布局/shader/采样器/per-slot 描述符
|
||||
m_SceneGpu = CreateScope<Passes::SceneGpu>(
|
||||
*m_Device, *m_DescriptorManager, *m_ShaderManager,
|
||||
*m_UniformBuffer, *m_ObjectBuffer);
|
||||
*m_UniformBuffer, *m_ObjectBuffer, *m_PrevObjectBuffer);
|
||||
m_FullscreenGpu = CreateScope<Passes::FullscreenGpu>(
|
||||
*m_Device, *m_DescriptorManager, *m_ShaderManager);
|
||||
|
||||
@@ -183,12 +188,22 @@ namespace Engine
|
||||
"ShadowMap",
|
||||
RG::TextureDesc{vk::Format::eD32Sfloat, kShadowMapSize, kShadowMapSize});
|
||||
|
||||
// HDR 颜色图:Forward 的输出(线性光照值),Tonemap 显式完成
|
||||
// 显示变换后写入 Backbuffer(对齐 UE/Unity 管线)
|
||||
// HDR 颜色图:Forward 的输出(线性光照值 + 抖动),TAA 显式完成
|
||||
// 时域累积后写入 TAAColor(对齐 UE/Unity 管线)
|
||||
m_HDRColor = m_RenderGraph->CreateTexture(
|
||||
"HDRColor",
|
||||
RG::TextureDesc{vk::Format::eR16G16B16A16Sfloat});
|
||||
|
||||
// velocity:clip 空间运动向量(TAA 反推历史像素位置)
|
||||
m_Velocity = m_RenderGraph->CreateTexture(
|
||||
"Velocity",
|
||||
RG::TextureDesc{vk::Format::eR16G16B16A16Sfloat});
|
||||
|
||||
// TAA 累积输出:既是 resolve 结果也是下一帧的历史(自引用)
|
||||
m_TAAColor = m_RenderGraph->CreateTexture(
|
||||
"TAAColor",
|
||||
RG::TextureDesc{vk::Format::eR16G16B16A16Sfloat});
|
||||
|
||||
// Bloom ping-pong:半分辨率(sizeScale 相对目标尺寸,resize 自动跟随)
|
||||
m_BloomA = m_RenderGraph->CreateTexture(
|
||||
"BloomA",
|
||||
@@ -209,13 +224,16 @@ namespace Engine
|
||||
m_Passes.push_back(CreateScope<Passes::ShadowPass>(
|
||||
*m_SceneGpu, frame, m_ShadowMap));
|
||||
m_Passes.push_back(CreateScope<Passes::ForwardPass>(
|
||||
*m_SceneGpu, frame, m_HDRColor, m_Depth, m_ShadowMap));
|
||||
*m_SceneGpu, frame, m_HDRColor, m_Velocity, m_Depth, m_ShadowMap));
|
||||
m_Passes.push_back(CreateScope<Passes::TAAPass>(
|
||||
*m_FullscreenGpu, /*historyAlpha*/ 0.9f, m_HDRColor, m_Velocity,
|
||||
m_TAAColor));
|
||||
m_Passes.push_back(CreateScope<Passes::TemporalDiffPass>(
|
||||
*m_FullscreenGpu, /*gain*/ 8.0f, m_HDRColor, m_TemporalDiff));
|
||||
m_Passes.push_back(CreateScope<Passes::BloomPass>(
|
||||
*m_FullscreenGpu, *m_PostParams, m_HDRColor, m_BloomA, m_BloomB));
|
||||
*m_FullscreenGpu, *m_PostParams, m_TAAColor, m_BloomA, m_BloomB));
|
||||
m_Passes.push_back(CreateScope<Passes::TonemapPass>(
|
||||
*m_FullscreenGpu, *m_PostParams, m_HDRColor, m_BloomA,
|
||||
*m_FullscreenGpu, *m_PostParams, m_TAAColor, m_BloomA,
|
||||
m_TemporalDiff, m_Backbuffer));
|
||||
m_Passes.push_back(CreateScope<Passes::ImGuiPass>(
|
||||
&m_ImGuiLayer, m_Backbuffer));
|
||||
@@ -295,9 +313,7 @@ namespace Engine
|
||||
const auto& vkDevice = m_Device->GetDevice();
|
||||
|
||||
// 1. 场景 → 当帧渲染数据(相机/灯光/双视图剔除;纯 CPU,不碰 GPU)
|
||||
const f32 aspect = static_cast<f32>(m_Extent.width) /
|
||||
static_cast<f32>(m_Extent.height);
|
||||
if (!m_SceneRenderer->BuildFrame(scene, assets, aspect)) {
|
||||
if (!m_SceneRenderer->BuildFrame(scene, assets, m_Extent)) {
|
||||
return; // 无 primary 相机:跳帧
|
||||
}
|
||||
const FrameSceneData& frame = m_SceneRenderer->Frame();
|
||||
@@ -311,6 +327,10 @@ namespace Engine
|
||||
if (!frame.instanceModels.empty()) {
|
||||
m_ObjectBuffer->Update(frameSlot, frame.instanceModels.data(),
|
||||
frame.instanceModels.size() * sizeof(glm::mat4));
|
||||
// 上一帧姿态与当前帧平行对齐(velocity 顶点着色器按下标取)
|
||||
m_PrevObjectBuffer->Update(frameSlot, frame.prevInstanceModels.data(),
|
||||
frame.prevInstanceModels.size() *
|
||||
sizeof(glm::mat4));
|
||||
}
|
||||
|
||||
// 3. acquire swapchain image
|
||||
|
||||
Reference in New Issue
Block a user