feat: IBL 预积分 GPU compute 化 + 环境资产入 Assets 层(动态切换)

CPU 逐像素卷积(venice 4k 阻塞 7.36s)→ 4 个 compute shader 一次性
提交:equirect→cube / irradiance / prefilter×5mip / BRDF LUT。
Cubemap 瘦身为纯资源持有类,生成职责移交 IblGenerator;
环境经 AssetManager 缓存(EnvRef),Renderer::SetEnvironment
动态换绑(RenderPass::OnEnvironmentChanged 广播)。
调试视图 +4:EnvCube / Irradiance / Prefilter / BRDF LUT。

性能前后对比(RTX 5060 Laptop,venice_dawn_1_4k.hdr):
- 改造前 CPU:7.36 s(主线程阻塞)
- 改造后 GPU:HDR decode 127-134ms + 资源 22-35ms + compute 17-19ms
  ≈ 165-190ms(约 40×);Neutral 兜底 ~6ms
- 运行中动态切换环境同量级(ms 级 GPU,decode 占大头)

冒烟:两构建目录 0 警告;运行期 0 validation(含两次环境切换 +
调试视图 9-12 轮播自动化验证)。
This commit is contained in:
2026-09-24 13:23:59 +08:00
parent 705250df76
commit 1d690067bd
30 changed files with 1162 additions and 824 deletions
@@ -52,6 +52,10 @@ namespace Engine {
kDebugShadowMap0, // CSM 级联 0 深度(近=白)
kDebugShadowMap1, // 级联 1
kDebugShadowMap2, // 级联 2
kDebugEnvCube, // IBL 环境 cube(经纬展开)
kDebugIrradiance, // IBL 漫反射辐照度(32² 低频)
kDebugPrefilter, // IBL pre-filter(纵向 = mip/roughness 分级)
kDebugBrdfLut, // BRDF 积分 LUT(RG 双通道)
kDebugViewCount
};
@@ -19,6 +19,10 @@
#include <Engine/RenderGraph/RenderGraph.h>
namespace Engine {
class Cubemap;
}
namespace Engine::Passes {
class RenderPass {
@@ -27,6 +31,10 @@ namespace Engine::Passes {
virtual void Register(RG::RenderGraph& rg) = 0;
virtual void OnTargetsRebuilt(RG::RenderGraph& rg) { (void)rg; }
// 环境资产换绑(动态切换):引用环境描述符的 pass 重绑自己的 set。
// 默认无环境影响;env 恒非空(Renderer 有中性兜底)
virtual void OnEnvironmentChanged(const Cubemap* /*env*/) {}
};
} // namespace Engine::Passes
@@ -41,6 +41,7 @@ namespace Engine {
SkyboxPass& operator=(const SkyboxPass&) = delete;
void Register(RG::RenderGraph& rg) override;
void OnEnvironmentChanged(const Cubemap* env) override;
private:
Device& m_Device;
@@ -15,39 +15,50 @@
#include <vulkan/vulkan.hpp>
#include <vector>
namespace Engine::Passes {
namespace Engine {
class TonemapPass final : public RenderPass {
public:
TonemapPass(FullscreenGpu& gpu, PostProcessParams& params,
FrameSceneData& frame,
RG::TextureHandle hdrColor, RG::TextureHandle bloomA,
RG::TextureHandle temporalDiff, RG::TextureHandle backbuffer,
RG::TextureHandle rawHdr, RG::TextureHandle velocity,
RG::TextureHandle shadowMap0, RG::TextureHandle shadowMap1,
RG::TextureHandle shadowMap2);
~TonemapPass() override = default;
class Cubemap;
class DescriptorManager;
void Register(RG::RenderGraph& rg) override;
void OnTargetsRebuilt(RG::RenderGraph& rg) override;
namespace Passes {
private:
FullscreenGpu& m_Gpu;
PostProcessParams& m_Params;
FrameSceneData& m_Frame; // debugView / bloomEnabled(帧契约)
RG::TextureHandle m_HDR;
RG::TextureHandle m_A;
RG::TextureHandle m_TemporalDiff;
RG::TextureHandle m_Backbuffer;
// ---- 调试视图源(binding 3-7,Register 时声明读防止剔除)----
// 注:TAAColor 视图直接用 binding0(主输入即 TAA 输出),无需重复绑
RG::TextureHandle m_RawHDR; // Forward 直出(TAA 前)
RG::TextureHandle m_Velocity;
RG::TextureHandle m_ShadowMaps[3];
class TonemapPass final : public RenderPass {
public:
TonemapPass(FullscreenGpu& gpu, DescriptorManager& descriptors,
PostProcessParams& params,
FrameSceneData& frame,
RG::TextureHandle hdrColor, RG::TextureHandle bloomA,
RG::TextureHandle temporalDiff, RG::TextureHandle backbuffer,
RG::TextureHandle rawHdr, RG::TextureHandle velocity,
RG::TextureHandle shadowMap0, RG::TextureHandle shadowMap1,
RG::TextureHandle shadowMap2);
~TonemapPass() override = default;
std::vector<vk::DescriptorSet> m_Sets; // per-slot
};
void Register(RG::RenderGraph& rg) override;
void OnTargetsRebuilt(RG::RenderGraph& rg) override;
void OnEnvironmentChanged(const Cubemap* env) override;
} // namespace Engine::Passes
private:
FullscreenGpu& m_Gpu;
DescriptorManager& m_Descriptors;
PostProcessParams& m_Params;
FrameSceneData& m_Frame; // debugView / bloomEnabled(帧契约)
RG::TextureHandle m_HDR;
RG::TextureHandle m_A;
RG::TextureHandle m_TemporalDiff;
RG::TextureHandle m_Backbuffer;
// ---- 调试视图源(binding 3-7,Register 时声明读防止剔除)----
// 注:TAAColor 视图直接用 binding0(主输入即 TAA 输出),无需重复绑
RG::TextureHandle m_RawHDR; // Forward 直出(TAA 前)
RG::TextureHandle m_Velocity;
RG::TextureHandle m_ShadowMaps[3];
// ---- 环境调试视图源(binding 8-11;随环境切换重绑)----
const Cubemap* m_Env = nullptr;
std::vector<vk::DescriptorSet> m_Sets; // per-slot
};
} // namespace Passes
} // namespace Engine
#endif //HELLOVULKAN_TONEMAPPASS_H