feat: 特性开关 + Pass 调试视图接口(ImGui 可控,统一帧契约)
三个运行时开关(Shadows/TAA/Bloom)与 9 种调试视图(Final/ TemporalDiff/HDR/TAAColor/Bloom/Velocity/ShadowMap0-2)。 统一设计:开关状态收敛 FrameSceneData 契约,SceneRenderer 唯一 写入、各 pass 只读(零虚接口路由);调试视图经 tonemap push int 路由已绑定的中间目标(声明超集、运行时零重绑);HDR 域 资源过同一 tonemap 保证观感可比。 - Shadows:ShadowPass lambda 空转 + frag cascadeSplits.w 短路 - TAA:alpha=0 直通 + SceneRenderer 停投影抖动(同一持有者同步) - Bloom:3 子 pass 空转 + tonemap 强度归零 - Renderer 门面 Get/Set 转发,App ImGui 3 Checkbox + Combo - PostProcessParams 瘦身为纯数值参数,showTemporalDiff 被取缔
This commit is contained in:
@@ -8,9 +8,10 @@
|
||||
namespace Engine::Passes
|
||||
{
|
||||
BloomPass::BloomPass(FullscreenGpu& gpu, PostProcessParams& params,
|
||||
FrameSceneData& frame,
|
||||
RG::TextureHandle hdrColor,
|
||||
RG::TextureHandle bloomA, RG::TextureHandle bloomB)
|
||||
: m_Gpu(gpu), m_Params(params),
|
||||
: m_Gpu(gpu), m_Params(params), m_Frame(frame),
|
||||
m_HDR(hdrColor), m_A(bloomA), m_B(bloomB)
|
||||
{
|
||||
m_ExtractSets.resize(kMaxFramesInFlight);
|
||||
@@ -25,9 +26,13 @@ namespace Engine::Passes
|
||||
|
||||
void BloomPass::Register(RG::RenderGraph& rg)
|
||||
{
|
||||
// Extract:HDR → 半分辨率 A(软阈值由 frag 的 param0 传入)
|
||||
// bloom 关闭:三个子 pass 全部空转(省两次模糊 + 一次提取),
|
||||
// tonemap 侧强度同步归零不采样叠加。
|
||||
// 注意开关判断必须在录制 lambda 内(每帧评估),Register 只在
|
||||
// RG 编译时跑一次
|
||||
rg.AddPass("BloomExtract",
|
||||
[this](RG::RenderGraphContext& ctx) {
|
||||
if (!m_Frame.bloomEnabled) return;
|
||||
m_Gpu.RecordFullscreen(ctx, ctx.View(m_A), m_Gpu.extractFrag,
|
||||
m_ExtractSets[ctx.frame.frameSlot],
|
||||
FullscreenPush{0.0f, m_Params.bloomThreshold, 0.0f, 0.0f});
|
||||
@@ -39,6 +44,7 @@ namespace Engine::Passes
|
||||
// BlurH:A → B(水平步长经 push 传入)
|
||||
rg.AddPass("BloomBlurH",
|
||||
[this](RG::RenderGraphContext& ctx) {
|
||||
if (!m_Frame.bloomEnabled) return;
|
||||
m_Gpu.RecordFullscreen(ctx, ctx.View(m_B), m_Gpu.blurFrag,
|
||||
m_BlurHSets[ctx.frame.frameSlot],
|
||||
FullscreenPush{0.0f,
|
||||
@@ -52,6 +58,7 @@ namespace Engine::Passes
|
||||
// BlurV:B → A(垂直步长)
|
||||
rg.AddPass("BloomBlurV",
|
||||
[this](RG::RenderGraphContext& ctx) {
|
||||
if (!m_Frame.bloomEnabled) return;
|
||||
m_Gpu.RecordFullscreen(ctx, ctx.View(m_A), m_Gpu.blurFrag,
|
||||
m_BlurVSets[ctx.frame.frameSlot],
|
||||
FullscreenPush{0.0f, 0.0f,
|
||||
|
||||
@@ -16,17 +16,16 @@ namespace Engine::Passes
|
||||
ShaderManager& shaders)
|
||||
: m_Device(device), m_Descriptors(descriptors)
|
||||
{
|
||||
// Set0 = {HDR 颜色图, Bloom 图, 调试输入},push = 16B 通用结构
|
||||
//(binding2 只被 tonemap 的调试视图使用;bloom 系 shader 静态
|
||||
// 使用的 binding 是布局的子集,合法)
|
||||
std::vector<DescriptorBinding> bindings = {
|
||||
{0, vk::DescriptorType::eCombinedImageSampler,
|
||||
vk::ShaderStageFlagBits::eFragment},
|
||||
{1, vk::DescriptorType::eCombinedImageSampler,
|
||||
vk::ShaderStageFlagBits::eFragment},
|
||||
{2, vk::DescriptorType::eCombinedImageSampler,
|
||||
vk::ShaderStageFlagBits::eFragment},
|
||||
};
|
||||
// Set0 = {HDR 颜色图, Bloom 图, 调试输入, TAA, Velocity,
|
||||
// ShadowMap0/1/2},push = 16B 通用结构(VUID-08878)。
|
||||
// 后 6 个 binding 供 Tonemap 调试视图使用;其余全屏 shader
|
||||
// 静态使用的 binding 是布局的子集,合法
|
||||
std::vector<DescriptorBinding> bindings;
|
||||
for (u32 b = 0; b < 8; ++b) {
|
||||
bindings.push_back(
|
||||
{b, vk::DescriptorType::eCombinedImageSampler,
|
||||
vk::ShaderStageFlagBits::eFragment});
|
||||
}
|
||||
setLayout = descriptors.CreateLayout(bindings);
|
||||
|
||||
layout = descriptors.CreatePipelineLayout(
|
||||
|
||||
@@ -16,6 +16,10 @@ namespace Engine::Passes
|
||||
// 材质/实体数据驱动剔除,而非 pass 逻辑特判。
|
||||
// (每级联独立剔除是后续优化点:shadowView 细分为 per-cascade 列表)
|
||||
rg.AddPass("Shadow", [this](RG::RenderGraphContext& ctx) {
|
||||
// 阴影关闭:整 pass 空转(省一整趟场景绘制)。图仍是
|
||||
// Clear=1.0,frag 侧 cascadeSplits.w 短路根本不采样
|
||||
if (!m_Frame.shadowsEnabled) return;
|
||||
|
||||
const vk::CommandBuffer cmd = ctx.cmd;
|
||||
|
||||
for (u32 c = 0; c < kMaxCascades; ++c) {
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
|
||||
namespace Engine::Passes
|
||||
{
|
||||
TAAPass::TAAPass(FullscreenGpu& gpu, f32 historyAlpha,
|
||||
TAAPass::TAAPass(FullscreenGpu& gpu, FrameSceneData& frame, f32 historyAlpha,
|
||||
RG::TextureHandle hdrColor, RG::TextureHandle velocity,
|
||||
RG::TextureHandle taaColor)
|
||||
: m_Gpu(gpu), m_HistoryAlpha(historyAlpha),
|
||||
: m_Gpu(gpu), m_Frame(frame), m_HistoryAlpha(historyAlpha),
|
||||
m_HDR(hdrColor), m_Velocity(velocity), m_TAAColor(taaColor)
|
||||
{
|
||||
m_Sets.resize(kMaxFramesInFlight);
|
||||
@@ -23,9 +23,12 @@ namespace Engine::Passes
|
||||
{
|
||||
rg.AddPass("TAA",
|
||||
[this](RG::RenderGraphContext& ctx) {
|
||||
// TAA 关闭:alpha=0 → mix(cur, hist, 0) 直通当前帧
|
||||
//(抖动已由 SceneRenderer 同步停掉,画面静止无锯齿晃动)
|
||||
const f32 alpha = m_Frame.taaEnabled ? m_HistoryAlpha : 0.0f;
|
||||
m_Gpu.RecordFullscreen(ctx, ctx.View(m_TAAColor), m_Gpu.taaFrag,
|
||||
m_Sets[ctx.frame.frameSlot],
|
||||
FullscreenPush{0.0f, m_HistoryAlpha, 0.0f, 0.0f});
|
||||
FullscreenPush{0.0f, alpha, 0.0f, 0.0f});
|
||||
})
|
||||
.Read(m_HDR, RG::ResourceUse::ShaderRead,
|
||||
vk::ShaderStageFlagBits::eFragment)
|
||||
|
||||
@@ -8,12 +8,20 @@
|
||||
namespace Engine::Passes
|
||||
{
|
||||
TonemapPass::TonemapPass(FullscreenGpu& gpu, PostProcessParams& params,
|
||||
FrameSceneData& frame,
|
||||
RG::TextureHandle hdrColor, RG::TextureHandle bloomA,
|
||||
RG::TextureHandle temporalDiff,
|
||||
RG::TextureHandle backbuffer)
|
||||
: m_Gpu(gpu), m_Params(params),
|
||||
RG::TextureHandle backbuffer,
|
||||
RG::TextureHandle rawHdr,
|
||||
RG::TextureHandle velocity,
|
||||
RG::TextureHandle shadowMap0,
|
||||
RG::TextureHandle shadowMap1,
|
||||
RG::TextureHandle shadowMap2)
|
||||
: m_Gpu(gpu), m_Params(params), m_Frame(frame),
|
||||
m_HDR(hdrColor), m_A(bloomA), m_TemporalDiff(temporalDiff),
|
||||
m_Backbuffer(backbuffer)
|
||||
m_Backbuffer(backbuffer),
|
||||
m_RawHDR(rawHdr), m_Velocity(velocity),
|
||||
m_ShadowMaps{shadowMap0, shadowMap1, shadowMap2}
|
||||
{
|
||||
m_Sets.resize(kMaxFramesInFlight);
|
||||
for (u32 slot = 0; slot < kMaxFramesInFlight; ++slot) {
|
||||
@@ -30,17 +38,31 @@ namespace Engine::Passes
|
||||
m_Sets[ctx.frame.frameSlot],
|
||||
FullscreenPush{m_Params.exposure,
|
||||
m_Params.useACES ? 1.0f : 0.0f,
|
||||
m_Params.bloomStrength,
|
||||
m_Params.showTemporalDiff ? 1.0f : 0.0f});
|
||||
m_Frame.bloomEnabled
|
||||
? m_Params.bloomStrength
|
||||
: 0.0f,
|
||||
static_cast<f32>(
|
||||
m_Frame.debugView)});
|
||||
})
|
||||
.Write(m_Backbuffer, RG::ResourceUse::ColorAttachment)
|
||||
.Read(m_HDR, RG::ResourceUse::ShaderRead,
|
||||
vk::ShaderStageFlagBits::eFragment)
|
||||
.Read(m_A, RG::ResourceUse::ShaderRead,
|
||||
vk::ShaderStageFlagBits::eFragment)
|
||||
// shader 静态采样 binding2(调试视图开关在 push constant 里),
|
||||
// 声明读否则本 pass 的产出无人消费会被剔除、镜像也不会分配
|
||||
// 调试视图源全部声明读:路由开关在 push constant(每帧变),
|
||||
// 绑定集与 barrier 必须静态成立——这是"声明超集、运行时路由"
|
||||
// 模式,避免切换视图时重绑描述符
|
||||
.Read(m_TemporalDiff, RG::ResourceUse::ShaderRead,
|
||||
vk::ShaderStageFlagBits::eFragment)
|
||||
.Read(m_RawHDR, RG::ResourceUse::ShaderRead,
|
||||
vk::ShaderStageFlagBits::eFragment)
|
||||
.Read(m_Velocity, RG::ResourceUse::ShaderRead,
|
||||
vk::ShaderStageFlagBits::eFragment)
|
||||
.Read(m_ShadowMaps[0], RG::ResourceUse::ShaderRead,
|
||||
vk::ShaderStageFlagBits::eFragment)
|
||||
.Read(m_ShadowMaps[1], RG::ResourceUse::ShaderRead,
|
||||
vk::ShaderStageFlagBits::eFragment)
|
||||
.Read(m_ShadowMaps[2], RG::ResourceUse::ShaderRead,
|
||||
vk::ShaderStageFlagBits::eFragment);
|
||||
}
|
||||
|
||||
@@ -50,6 +72,11 @@ namespace Engine::Passes
|
||||
m_Gpu.UpdateSetInput(m_Sets[slot], 0, rg, m_HDR, slot);
|
||||
m_Gpu.UpdateSetInput(m_Sets[slot], 1, rg, m_A, slot);
|
||||
m_Gpu.UpdateSetInput(m_Sets[slot], 2, rg, m_TemporalDiff, slot);
|
||||
m_Gpu.UpdateSetInput(m_Sets[slot], 3, rg, m_RawHDR, slot);
|
||||
m_Gpu.UpdateSetInput(m_Sets[slot], 4, rg, m_Velocity, slot);
|
||||
m_Gpu.UpdateSetInput(m_Sets[slot], 5, rg, m_ShadowMaps[0], slot);
|
||||
m_Gpu.UpdateSetInput(m_Sets[slot], 6, rg, m_ShadowMaps[1], slot);
|
||||
m_Gpu.UpdateSetInput(m_Sets[slot], 7, rg, m_ShadowMaps[2], slot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -168,8 +168,33 @@ namespace Engine
|
||||
void Renderer::SetBloomThreshold(f32 v) { m_PostParams->bloomThreshold = v; }
|
||||
f32 Renderer::GetBloomStrength() const { return m_PostParams->bloomStrength; }
|
||||
void Renderer::SetBloomStrength(f32 v) { m_PostParams->bloomStrength = v; }
|
||||
bool Renderer::GetShowTemporalDiff() const { return m_PostParams->showTemporalDiff; }
|
||||
void Renderer::SetShowTemporalDiff(bool b) { m_PostParams->showTemporalDiff = b; }
|
||||
|
||||
// ---- 特性开关 / 调试视图:转发 SceneRenderer(状态唯一持有者)----
|
||||
bool Renderer::GetShadowsEnabled() const
|
||||
{
|
||||
return m_SceneRenderer->Frame().shadowsEnabled;
|
||||
}
|
||||
void Renderer::SetShadowsEnabled(bool b) { m_SceneRenderer->SetShadowsEnabled(b); }
|
||||
bool Renderer::GetTAAEnabled() const { return m_SceneRenderer->Frame().taaEnabled; }
|
||||
void Renderer::SetTAAEnabled(bool b) { m_SceneRenderer->SetTAAEnabled(b); }
|
||||
bool Renderer::GetBloomEnabled() const
|
||||
{
|
||||
return m_SceneRenderer->Frame().bloomEnabled;
|
||||
}
|
||||
void Renderer::SetBloomEnabled(bool b) { m_SceneRenderer->SetBloomEnabled(b); }
|
||||
int Renderer::GetDebugView() const { return m_SceneRenderer->Frame().debugView; }
|
||||
void Renderer::SetDebugView(int v) { m_SceneRenderer->SetDebugView(v); }
|
||||
|
||||
const std::vector<const char*>& Renderer::GetDebugViewNames() const
|
||||
{
|
||||
static const std::vector<const char*> kNames = {
|
||||
"Final", "TemporalDiff", "HDR", "TAAColor", "Bloom",
|
||||
"Velocity", "ShadowMap0", "ShadowMap1", "ShadowMap2",
|
||||
};
|
||||
static_assert(int(Passes::kDebugViewCount) == 9,
|
||||
"DebugView 枚举与名表同步");
|
||||
return kNames;
|
||||
}
|
||||
|
||||
u32 Renderer::GetMainInstanceCount() const
|
||||
{
|
||||
@@ -252,15 +277,17 @@ namespace Engine
|
||||
m_Passes.push_back(CreateScope<Passes::ForwardPass>(
|
||||
*m_SceneGpu, frame, m_HDRColor, m_Velocity, m_Depth, m_ShadowMaps));
|
||||
m_Passes.push_back(CreateScope<Passes::TAAPass>(
|
||||
*m_FullscreenGpu, /*historyAlpha*/ 0.9f, m_HDRColor, m_Velocity,
|
||||
m_TAAColor));
|
||||
*m_FullscreenGpu, frame, /*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_TAAColor, m_BloomA, m_BloomB));
|
||||
*m_FullscreenGpu, *m_PostParams, frame, m_TAAColor, m_BloomA,
|
||||
m_BloomB));
|
||||
m_Passes.push_back(CreateScope<Passes::TonemapPass>(
|
||||
*m_FullscreenGpu, *m_PostParams, m_TAAColor, m_BloomA,
|
||||
m_TemporalDiff, m_Backbuffer));
|
||||
*m_FullscreenGpu, *m_PostParams, frame, m_TAAColor, m_BloomA,
|
||||
m_TemporalDiff, m_Backbuffer, m_HDRColor, m_Velocity,
|
||||
m_ShadowMaps[0], m_ShadowMaps[1], m_ShadowMaps[2]));
|
||||
m_Passes.push_back(CreateScope<Passes::ImGuiPass>(
|
||||
&m_ImGuiLayer, m_Backbuffer));
|
||||
m_Passes.push_back(CreateScope<Passes::PresentPass>(m_Backbuffer));
|
||||
|
||||
@@ -157,8 +157,8 @@ namespace Engine
|
||||
ubo.projNoJitter = ubo.proj;
|
||||
|
||||
// 子像素抖动(Halton×8):光栅化采样位置逐帧偏移,TAA 累积去锯齿。
|
||||
// NDC 偏移 = 像素偏移 × 2 / 尺寸
|
||||
{
|
||||
// NDC 偏移 = 像素偏移 × 2 / 尺寸。TAA 关闭时停抖(直通画面静止)
|
||||
if (m_TAAEnabled) {
|
||||
const u32 idx = static_cast<u32>(m_FrameIndex % 8);
|
||||
const f32 jx = Halton(idx + 1, 2) - 0.5f;
|
||||
const f32 jy = Halton(idx + 1, 3) - 0.5f;
|
||||
@@ -168,6 +168,13 @@ namespace Engine
|
||||
|
||||
ubo.ambientColor = scene.GetSettings().ambientColor;
|
||||
|
||||
// ---- 运行时开关/调试视图落帧(各 pass 与 frag 只读契约字段)----
|
||||
m_Frame.shadowsEnabled = m_ShadowsEnabled;
|
||||
m_Frame.taaEnabled = m_TAAEnabled;
|
||||
m_Frame.bloomEnabled = m_BloomEnabled;
|
||||
m_Frame.debugView = m_DebugView;
|
||||
ubo.cascadeSplits.w = m_ShadowsEnabled ? 1.0f : 0.0f;
|
||||
|
||||
// 天空盒:视图去平移(只留旋转)× 投影 → 逆矩阵,push 给 Skybox pass;
|
||||
// 反投影远平面点 = 相机相对世界方向,frag normalize 后采样 cube
|
||||
m_Frame.skyInvVP =
|
||||
|
||||
Reference in New Issue
Block a user