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
+2 -1
View File
@@ -33,7 +33,8 @@ file(GLOB_RECURSE SHADER_SOURCES
CONFIGURE_DEPENDS # 新增 shader 时自动重配
RELATIVE ${SHADER_SRC_DIR}
${SHADER_SRC_DIR}/*.vert
${SHADER_SRC_DIR}/*.frag)
${SHADER_SRC_DIR}/*.frag
${SHADER_SRC_DIR}/*.comp)
foreach (f ${SHADER_SOURCES})
auto_compile_shader(${f})
+38
View File
@@ -30,6 +30,20 @@ using namespace Engine::ECS;
namespace
{
// 可切换环境(IBL 动态切换演示):路径 → AssetManager 缓存去重,
// 重复选择同一环境零成本;首选路径触发一次 compute 预积分
constexpr const char* kEnvPaths[] = {
"assets/textures/venice_dawn_1_4k.hdr",
"assets/textures/rooitou_park_4k.hdr",
"assets/textures/pink_sunrise_4k.hdr",
"assets/textures/birchwood_4k.hdr",
};
constexpr const char* kEnvNames[] = {
"Venice Dawn", "Rooitou Park", "Pink Sunrise", "Birchwood",
};
constexpr int kEnvCount = 4;
constexpr int kDefaultEnv = 0;
class SandboxApp final : public Application
{
public:
@@ -48,6 +62,14 @@ namespace
// ImGui 叠加层(框架只做管线桥接,UI 内容全部在这里定义)
EnableImGui();
// 默认环境(IBL 四件套):经资产层加载(compute 预积分,毫秒级),
// 其余环境在 ImGui 里按需 lazy 加载后切换
const auto env = GetAssets().LoadEnvironment(
kEnvPaths[kDefaultEnv]);
if (env.Valid()) {
GetRenderer().SetEnvironment(GetAssets().GetEnvironment(env));
}
// 模型资产(PBR 验证场景:backpack 为旧式贴图资产,
// 退化为电介质因子路径——albedo+normal,metallic=0/roughness=0.5)
const auto model = GetAssets().LoadModel("assets/models/backpack/backpack.obj");
@@ -199,6 +221,21 @@ namespace
renderer.SetBloomEnabled(bloom);
}
// 动态环境切换(Assets 层加载 → Renderer 换绑;缓存去重)
ImGui::Separator();
ImGui::Text("Environment (IBL)");
int envIdx = m_EnvIndex;
if (ImGui::Combo("env", &envIdx, kEnvNames, kEnvCount))
{
const auto ref = GetAssets().LoadEnvironment(kEnvPaths[envIdx]);
if (ref.Valid())
{
renderer.SetEnvironment(GetAssets().GetEnvironment(ref));
m_EnvIndex = envIdx;
}
}
ImGui::Text("(switch = compute pre-integrate, ms-level)");
// 调试视图:单看某个 pass 的中间输出(类 UE pass debug)
const auto& viewNames = renderer.GetDebugViewNames();
int view = renderer.GetDebugView();
@@ -324,6 +361,7 @@ namespace
std::vector<EntityHandle> m_Spinners;
f32 m_Time = 0.0f;
bool m_PauseAnim = true; // 冻结动画时钟(帧历史 diff 验证用)
int m_EnvIndex = kDefaultEnv;
};
}