decode 是切换耗时大头(4k ≈ 130-160ms),搬出主线程后运行时切换 只剩 GPU 段(~40ms)。IblGenerator 拆两段式:DecodeHdr(static, 纯 CPU 无线程状态,worker 可调)+ FromDecoded(GPU 生成,主线程); FromHdrEquirect 保留为同步便捷路径。Assets 层经 IAssetUploader 重载 + AssetManager 重载传递预解码产物(路径已缓存则丢弃去重)。 App 层单 in-flight 状态机:worker 只产出纯 CPU 像素数据,忙肋期 新请求记 pending 接力(只保留最终意图),OnUpdate 每帧收割 + SetEnvironment 换绑,析构 join。 实测(RTX 5060 Laptop,4 实例网格 + 运行中连切 3 环境): ~180fps 无感知尖峰;0 validation。
92 lines
3.7 KiB
C++
92 lines
3.7 KiB
C++
//
|
||
// Created by atdunbg on 2026/9/23.
|
||
//
|
||
// Cubemap:环境立方体贴图 + IBL 预积分资源(split-sum 四件套)。
|
||
//
|
||
// 纯 GPU 资源持有类(对齐 Model 的定位):只管 image/view/采样器的
|
||
// 同生共死,不做任何生成/上传。预积分由 IblGenerator(compute 链)
|
||
// 产出后注入——环境切换的入口在 Assets 层(AssetManager::LoadEnvironment)。
|
||
//
|
||
// env cube —— 重采样 6 面(Skybox 背景)
|
||
// irradiance cube —— 半球 Lambert 积分(PBR 漫反射 ambient)
|
||
// prefilter cube —— GGX 重要性采样 × mip 分级 roughness(镜面 IBL)
|
||
// BRDF LUT —— 2D 积分表(纯数学,与环境内容无关)
|
||
// 全部 fp16,运行时采样零积分开销。
|
||
//
|
||
|
||
#ifndef HELLOVULKAN_CUBEMAP_H
|
||
#define HELLOVULKAN_CUBEMAP_H
|
||
|
||
#include <Engine/Core/Types.h>
|
||
#include <Engine/Vulkan/MemoryAllocator.h>
|
||
#include <vulkan/vulkan.hpp>
|
||
#include <vector>
|
||
|
||
namespace Engine {
|
||
|
||
class Device;
|
||
|
||
// 环境的 CPU 源数据(等距柱状 HDR 解码产物,RGBA float 行优先)。
|
||
// 纯数据无线程状态:异步加载时由后台线程产出(DecodeHdr),
|
||
// 主线程消费(FromDecoded → GPU 生成)。decode 是切换耗时大头,
|
||
// 搬出主线程后运行时切换只剩 GPU 段(~40ms)。
|
||
struct DecodedEquirect {
|
||
std::vector<f32> pixels;
|
||
u32 w = 0;
|
||
u32 h = 0;
|
||
bool Valid() const { return !pixels.empty() && w > 0 && h > 0; }
|
||
};
|
||
|
||
// GPU 纹理资源三元组(RHI 惯例):image/view/显存分配同生共死,
|
||
// 析构统一释放——杜绝"建了 image 丢了 view"类半套泄漏。
|
||
// 上传 helper 直接以此为单位产出,消费端只拿引用计数语义的整单元
|
||
struct EnvTexture {
|
||
vk::Image image{};
|
||
vk::ImageView view{};
|
||
MemoryAllocator::Allocation allocation;
|
||
};
|
||
|
||
class Cubemap {
|
||
public:
|
||
~Cubemap();
|
||
|
||
Cubemap(const Cubemap&) = delete;
|
||
Cubemap& operator=(const Cubemap&) = delete;
|
||
|
||
// ---- 消费端契约(SkyboxPass:背景;SceneGpu:PBR ambient)----
|
||
vk::ImageView GetView() const { return m_Env.view; } // 环境 cube
|
||
vk::ImageView GetIrradianceView() const { return m_Irr.view; } // 漫反射
|
||
vk::ImageView GetPrefilteredView() const { return m_Pref.view; } // 镜面
|
||
vk::ImageView GetBrdfLutView() const { return m_Lut.view; } // LUT
|
||
|
||
// cube 资源共享采样器(maxLod 覆盖 pre-filter mip 链)
|
||
vk::Sampler GetSampler() const { return m_EnvSampler; }
|
||
// LUT 专用采样器(clamp-to-edge):共享的 border 白采样器会在
|
||
// uv=1.0 处混入 50% 白色 border,导致高 roughness 镜面偏大
|
||
vk::Sampler GetBrdfLutSampler() const { return m_LutSampler; }
|
||
|
||
private:
|
||
friend class IblGenerator; // 生成端唯一构造入口
|
||
|
||
Cubemap(Device& device, MemoryAllocator& allocator,
|
||
EnvTexture env, EnvTexture irr, EnvTexture pref,
|
||
EnvTexture lut, vk::Sampler envSampler, vk::Sampler lutSampler)
|
||
: m_Device(device), m_Allocator(allocator),
|
||
m_Env(env), m_Irr(irr), m_Pref(pref), m_Lut(lut),
|
||
m_EnvSampler(envSampler), m_LutSampler(lutSampler) {}
|
||
|
||
Device& m_Device;
|
||
MemoryAllocator& m_Allocator;
|
||
|
||
EnvTexture m_Env; // 环境 cube(Skybox 背景)
|
||
EnvTexture m_Irr; // 漫反射辐照度 cube
|
||
EnvTexture m_Pref; // pre-filtered cube(mip 分 roughness)
|
||
EnvTexture m_Lut; // BRDF 积分 LUT(2D)
|
||
vk::Sampler m_EnvSampler;
|
||
vk::Sampler m_LutSampler;
|
||
};
|
||
|
||
} // namespace Engine
|
||
|
||
#endif //HELLOVULKAN_CUBEMAP_H
|