refactor: 解耦重构——还清四处架构债(对齐 UE/Unity 分层)
- SceneRenderer:场景→渲染数据翻译层(UE FSceneRenderer / Unity CullingResults
模式),收口相机/灯光/光空间矩阵/双视图剔除,Renderer 只编排
- pass 对象化(Unity ScriptableRenderPass 模式):8 个 pass lambda 拆为
Passes::{Shadow,Forward,Bloom,Tonemap,ImGui,Present},BuildGraph 超级函数消失;
SceneGpu/FullscreenGpu 承接共享装配
- 中性 AssetRef(Core 层):ECS 组件不再依赖 Assets 模块(Unity InstanceID 思路)
- IAssetUploader 接口:AssetManager 不感知 Vulkan 具体类,上传服务由渲染层
VulkanAssetUploader 提供
- Renderer 公共 API 不变(App 层零改动),编译零错误 validation 零警告
This commit is contained in:
@@ -1,37 +0,0 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/22.
|
||||
//
|
||||
// AssetHandle:资产句柄 = (池内索引, 生成号),与 Entity/RG 句柄同一哲学。
|
||||
//
|
||||
// 组件、场景数据只存句柄;所有权归 AssetManager。
|
||||
// 悬空句柄(generation 不匹配)会被 Get 显式拒绝,杜绝 use-after-free。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_ASSETHANDLE_H
|
||||
#define HELLOVULKAN_ASSETHANDLE_H
|
||||
|
||||
#include <Engine/Core/Types.h>
|
||||
|
||||
// Model 前向声明(句柄不依赖完整类型)
|
||||
namespace Engine { class Model; }
|
||||
|
||||
namespace Engine::Assets {
|
||||
|
||||
inline constexpr u32 kInvalidAssetIndex = 0xFFFFFFFF;
|
||||
|
||||
template<typename T>
|
||||
struct AssetHandle {
|
||||
u32 index = kInvalidAssetIndex;
|
||||
u32 generation = 0;
|
||||
|
||||
bool Valid() const { return index != kInvalidAssetIndex; }
|
||||
explicit operator bool() const { return Valid(); }
|
||||
bool operator==(const AssetHandle& o) const = default;
|
||||
};
|
||||
|
||||
// 常用别名
|
||||
using ModelHandle = AssetHandle<Engine::Model>;
|
||||
|
||||
} // namespace Engine::Assets
|
||||
|
||||
#endif //HELLOVULKAN_ASSETHANDLE_H
|
||||
@@ -3,14 +3,9 @@
|
||||
//
|
||||
// AssetManager:引擎资产层。
|
||||
//
|
||||
// 职责划分(对照 Renderer):
|
||||
// - 资产层:路径 → 解析/加载 → 缓存去重 → 句柄分发 + 生命周期管理
|
||||
// - 渲染层:拿已解析资产创建/绑定 GPU 资源
|
||||
//
|
||||
// Model 的构造仍需要 GPU 上下文(buffer/image upload),这是现阶段的
|
||||
// 折中:资产层"使用"GPU 层的接口,但 Renderer 不再知道磁盘和缓存。
|
||||
// 后续演进:把 Model 拆成 CPU 解析数据 + GPU 上传两段,实现真正的
|
||||
// 异步加载(IO 线程解析 → 主线程/上传队列提交),本文件结构已为此留好位置。
|
||||
// 职责:路径 → 解析/加载 → 缓存去重 → 句柄分发 + 生命周期管理。
|
||||
// GPU 创建不在这里:经 IAssetUploader 接口(渲染层提供实现)完成,
|
||||
// 本类不感知 Vulkan——依赖方向 Assets → 接口,实现由组合根注入。
|
||||
//
|
||||
// 组件存句柄不存指针的理由:
|
||||
// shared_ptr 会引入共享所有权 → 原子引用计数(swap-remove 拷贝时)
|
||||
@@ -23,7 +18,8 @@
|
||||
|
||||
#include <Engine/Core/Types.h>
|
||||
#include <Engine/Core/Log.h>
|
||||
#include <Engine/Assets/AssetHandle.h>
|
||||
#include <Engine/Core/AssetRef.h>
|
||||
#include <Engine/Assets/IAssetUploader.h>
|
||||
#include <Engine/Renderer/Model.h>
|
||||
|
||||
#include <functional>
|
||||
@@ -32,11 +28,6 @@
|
||||
#include <vector>
|
||||
|
||||
namespace Engine {
|
||||
|
||||
class Device;
|
||||
class MemoryAllocator;
|
||||
class DescriptorManager;
|
||||
|
||||
namespace Assets {
|
||||
|
||||
// ---------- 通用资产缓存(不感知 Vulkan / 磁盘细节由 loader 决定) ----------
|
||||
@@ -48,7 +39,7 @@ namespace Engine {
|
||||
using LoaderFn = std::function<Scope<T>(const std::string&)>;
|
||||
|
||||
// 加载(带路径去重)。失败返回无效句柄。
|
||||
AssetHandle<T> Load(const std::string& path, const LoaderFn& loader)
|
||||
AssetRef<T> Load(const std::string& path, const LoaderFn& loader)
|
||||
{
|
||||
if (auto it = m_ByPath.find(path); it != m_ByPath.end()) {
|
||||
return it->second;
|
||||
@@ -60,7 +51,7 @@ namespace Engine {
|
||||
return {};
|
||||
}
|
||||
|
||||
AssetHandle<T> h;
|
||||
AssetRef<T> h;
|
||||
if (!m_Free.empty()) {
|
||||
h.index = m_Free.back();
|
||||
m_Free.pop_back();
|
||||
@@ -77,7 +68,7 @@ namespace Engine {
|
||||
}
|
||||
|
||||
// 句柄 → 资产指针。悬空句柄 FATAL(bug 信号);已卸载返回 nullptr。
|
||||
T* Get(AssetHandle<T> h) const
|
||||
T* Get(AssetRef<T> h) const
|
||||
{
|
||||
if (!h.Valid() || h.index >= m_Entries.size()) {
|
||||
ENGINE_FATAL("AssetCache::Get: invalid handle (index={}, gen={})",
|
||||
@@ -94,7 +85,7 @@ namespace Engine {
|
||||
// 卸载:句柄即刻失效(generation 递增),路径缓存清除。
|
||||
// 注意:GPU 侧何时安全释放由上层(Renderer fence)保证——
|
||||
// 本类只管所有权,不管 GPU 生命周期。
|
||||
void Unload(AssetHandle<T> h)
|
||||
void Unload(AssetRef<T> h)
|
||||
{
|
||||
if (!h.Valid() || h.index >= m_Entries.size()) return;
|
||||
|
||||
@@ -109,7 +100,7 @@ namespace Engine {
|
||||
m_Free.push_back(h.index);
|
||||
}
|
||||
|
||||
const std::string& Path(AssetHandle<T> h) const
|
||||
const std::string& Path(AssetRef<T> h) const
|
||||
{
|
||||
static const std::string kEmpty;
|
||||
if (!h.Valid() || h.index >= m_Entries.size()) return kEmpty;
|
||||
@@ -132,29 +123,27 @@ namespace Engine {
|
||||
|
||||
std::vector<Entry> m_Entries;
|
||||
std::vector<u32> m_Free;
|
||||
std::unordered_map<std::string, AssetHandle<T>> m_ByPath;
|
||||
std::unordered_map<std::string, AssetRef<T>> m_ByPath;
|
||||
};
|
||||
|
||||
// ---------- AssetManager:全引擎资产入口 ----------
|
||||
// (ModelHandle 别名来自 AssetHandle.h)
|
||||
|
||||
class AssetManager {
|
||||
public:
|
||||
// GPU 上下文由组合根(Application)在 Renderer 装配完成后注入
|
||||
AssetManager(Device& device, MemoryAllocator& allocator,
|
||||
DescriptorManager& descriptors,
|
||||
vk::DescriptorSetLayout textureLayout);
|
||||
// 上传服务由组合根(Application)注入:渲染层实现接口,
|
||||
// 资产层不感知 Vulkan 具体类
|
||||
explicit AssetManager(IAssetUploader& uploader);
|
||||
~AssetManager() = default;
|
||||
|
||||
AssetManager(const AssetManager&) = delete;
|
||||
AssetManager& operator=(const AssetManager&) = delete;
|
||||
|
||||
ModelHandle LoadModel(const std::string& path);
|
||||
Model* GetModel(ModelHandle h) const { return m_Models.Get(h); }
|
||||
void UnloadModel(ModelHandle h) { m_Models.Unload(h); }
|
||||
ModelRef LoadModel(const std::string& path);
|
||||
Model* GetModel(ModelRef h) const { return m_Models.Get(h); }
|
||||
void UnloadModel(ModelRef h) { m_Models.Unload(h); }
|
||||
|
||||
// 程序化平面(纯色贴图):size 为半边长。带缓存,同参数共享一份。
|
||||
ModelHandle CreatePlane(f32 halfSize, u8 r, u8 g, u8 b);
|
||||
ModelRef CreatePlane(f32 halfSize, u8 r, u8 g, u8 b);
|
||||
|
||||
AssetCache<Model>& Models() { return m_Models; }
|
||||
|
||||
@@ -162,10 +151,7 @@ namespace Engine {
|
||||
// 各自一个 AssetCache<T> + 便捷方法,模式与 Model 完全一致。
|
||||
|
||||
private:
|
||||
Device& m_Device;
|
||||
MemoryAllocator& m_Allocator;
|
||||
DescriptorManager& m_Descriptors;
|
||||
vk::DescriptorSetLayout m_TextureLayout;
|
||||
IAssetUploader& m_Uploader;
|
||||
|
||||
AssetCache<Model> m_Models;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/23.
|
||||
//
|
||||
// IAssetUploader:资产层 → GPU 的上传接口。
|
||||
//
|
||||
// 资产层(AssetManager/AssetCache)只认这个接口,不感知 Vulkan 具体类
|
||||
// (Device/Allocator/DescriptorManager)。实现由渲染层提供
|
||||
// (VulkanAssetUploader),组合根(Renderer)装配后注入。
|
||||
//
|
||||
// 对齐 UE:资产系统(AssetManager/StreamableManager)与渲染资源创建
|
||||
// (rendering thread / RHI)分离,资产层只拿到"可用的渲染资源"。
|
||||
//
|
||||
// 后续演进点:接口加返回 future / 回调即为异步加载
|
||||
// (IO 线程解析 → 上传队列提交),本接口已是正确的接缝。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_IASSETUPLOADER_H
|
||||
#define HELLOVULKAN_IASSETUPLOADER_H
|
||||
|
||||
#include <Engine/Core/Types.h>
|
||||
#include <Engine/Renderer/Model.h>
|
||||
|
||||
namespace Engine::Assets {
|
||||
|
||||
class IAssetUploader {
|
||||
public:
|
||||
virtual ~IAssetUploader() = default;
|
||||
|
||||
// 磁盘模型 → 解析 + GPU 上传(失败返回 nullptr)
|
||||
virtual Scope<Model> LoadModel(const std::string& path) = 0;
|
||||
|
||||
// 程序化纯色平面(size 为半边长)
|
||||
virtual Scope<Model> CreatePlane(f32 halfSize, u8 r, u8 g, u8 b) = 0;
|
||||
};
|
||||
|
||||
} // namespace Engine::Assets
|
||||
|
||||
#endif //HELLOVULKAN_IASSETUPLOADER_H
|
||||
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/23.
|
||||
//
|
||||
// AssetRef:中性资产引用 = (池内索引, 生成号),与 Entity/RG 句柄同一哲学。
|
||||
//
|
||||
// 放在 Core 层(不依赖 Assets/Vulkan):ECS 组件、序列化数据只存这个
|
||||
// 纯值类型。对齐 UE/Unity 的做法——组件持有"资产引用",但不感知资产
|
||||
// 系统内部:Unity 的 InstanceID、UE 的 FSoftObjectPath 本质都是中性引用
|
||||
// 值,解析归资产系统(AssetManager)。
|
||||
// 悬空引用(generation 不匹配)由 AssetCache::Get 显式拒绝。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_ASSETREF_H
|
||||
#define HELLOVULKAN_ASSETREF_H
|
||||
|
||||
#include <Engine/Core/Types.h>
|
||||
|
||||
// 资产类型前向声明(必须放全局层:namespace 内前向声明会创建
|
||||
// Engine::Assets::Engine::Model 这类错误嵌套命名空间)
|
||||
namespace Engine {
|
||||
class Model;
|
||||
class Texture;
|
||||
class Material;
|
||||
}
|
||||
|
||||
namespace Engine {
|
||||
|
||||
inline constexpr u32 kInvalidAssetIndex = 0xFFFFFFFF;
|
||||
|
||||
template<typename T>
|
||||
struct AssetRef {
|
||||
u32 index = kInvalidAssetIndex;
|
||||
u32 generation = 0;
|
||||
|
||||
bool Valid() const { return index != kInvalidAssetIndex; }
|
||||
explicit operator bool() const { return Valid(); }
|
||||
bool operator==(const AssetRef& o) const = default;
|
||||
};
|
||||
|
||||
// 常用别名(新增资产类型时在这里加一行)
|
||||
using ModelRef = AssetRef<Model>;
|
||||
|
||||
} // namespace Engine
|
||||
|
||||
#endif //HELLOVULKAN_ASSETREF_H
|
||||
@@ -10,8 +10,8 @@
|
||||
|
||||
#include <Engine/Core/Types.h>
|
||||
#include <Engine/Core/UUID.h>
|
||||
#include <Engine/Core/AssetRef.h>
|
||||
#include <Engine/Renderer/Camera.h>
|
||||
#include <Engine/Assets/AssetHandle.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
@@ -62,9 +62,10 @@ namespace Engine::ECS {
|
||||
};
|
||||
|
||||
// 网格渲染体:引用共享的 Model 资产。
|
||||
// 存句柄不存指针/Ref:所有权归 AssetManager,悬空由句柄 generation 拦截。
|
||||
// 存中性 AssetRef(Core 层纯值类型,Unity InstanceID 思路)——
|
||||
// ECS 不感知资产系统内部;解析归 AssetManager,悬空由 generation 拦截。
|
||||
struct MeshRendererComponent {
|
||||
Assets::ModelHandle model;
|
||||
ModelRef model;
|
||||
};
|
||||
|
||||
// 相机。一个场景中 primary=true 的实体是当前渲染视角。
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/23.
|
||||
//
|
||||
// BloomPass:Extract(HDR 软阈值)→ BlurH → BlurV,全部半分辨率。
|
||||
// 一个"效果"对应多个 RG pass 的例子(Unity 的一个 ScriptableRenderPass
|
||||
// 常含多个 PassEvent 阶段,同构)。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_BLOOMPASS_H
|
||||
#define HELLOVULKAN_BLOOMPASS_H
|
||||
|
||||
#include <Engine/Renderer/Passes/RenderPass.h>
|
||||
#include <Engine/Renderer/Passes/FullscreenGpu.h>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace Engine::Passes {
|
||||
|
||||
class BloomPass final : public RenderPass {
|
||||
public:
|
||||
BloomPass(FullscreenGpu& gpu, PostProcessParams& params,
|
||||
RG::TextureHandle hdrColor,
|
||||
RG::TextureHandle bloomA, RG::TextureHandle bloomB);
|
||||
~BloomPass() override = default;
|
||||
|
||||
void Register(RG::RenderGraph& rg) override;
|
||||
void OnTargetsRebuilt(RG::RenderGraph& rg) override;
|
||||
|
||||
private:
|
||||
FullscreenGpu& m_Gpu;
|
||||
PostProcessParams& m_Params;
|
||||
RG::TextureHandle m_HDR;
|
||||
RG::TextureHandle m_A; // 提取 + 垂直模糊结果
|
||||
RG::TextureHandle m_B; // 水平模糊中间结果
|
||||
|
||||
// per-slot 输入描述符
|
||||
std::vector<vk::DescriptorSet> m_ExtractSets;
|
||||
std::vector<vk::DescriptorSet> m_BlurHSets;
|
||||
std::vector<vk::DescriptorSet> m_BlurVSets;
|
||||
};
|
||||
|
||||
} // namespace Engine::Passes
|
||||
|
||||
#endif //HELLOVULKAN_BLOOMPASS_H
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/23.
|
||||
//
|
||||
// ForwardPass:相机视角渲染到 HDR 颜色图(线性光照值)。
|
||||
// 显示变换不在本 pass——HDRColor 经 Tonemap 归一后才写 Backbuffer
|
||||
// (对齐 UE/Unity:SceneColor(HDR) → tonemapper → UI)。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_FORWARDPASS_H
|
||||
#define HELLOVULKAN_FORWARDPASS_H
|
||||
|
||||
#include <Engine/Renderer/Passes/RenderPass.h>
|
||||
#include <Engine/Renderer/Passes/SceneGpu.h>
|
||||
#include <Engine/Renderer/SceneTypes.h>
|
||||
|
||||
namespace Engine::Passes {
|
||||
|
||||
class ForwardPass final : public RenderPass {
|
||||
public:
|
||||
ForwardPass(SceneGpu& gpu, FrameSceneData& frame,
|
||||
RG::TextureHandle hdrColor, RG::TextureHandle depth,
|
||||
RG::TextureHandle shadowMap)
|
||||
: m_Gpu(gpu), m_Frame(frame),
|
||||
m_HDRColor(hdrColor), m_Depth(depth), m_ShadowMap(shadowMap) {}
|
||||
|
||||
void Register(RG::RenderGraph& rg) override;
|
||||
|
||||
private:
|
||||
SceneGpu& m_Gpu;
|
||||
FrameSceneData& m_Frame;
|
||||
RG::TextureHandle m_HDRColor;
|
||||
RG::TextureHandle m_Depth;
|
||||
RG::TextureHandle m_ShadowMap;
|
||||
};
|
||||
|
||||
} // namespace Engine::Passes
|
||||
|
||||
#endif //HELLOVULKAN_FORWARDPASS_H
|
||||
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/23.
|
||||
//
|
||||
// FullscreenGpu:全屏后处理共享装配(Tonemap/Bloom 系 pass 共用)。
|
||||
//
|
||||
// 全屏 pass 的共性收口在这里:Set0 = {输入0, 输入1}、push 16B 通用结构
|
||||
// (规避 VUID-08878 的"range 定义必须一致")、无顶点输入全屏三角、
|
||||
// 公共录制函数。新增全屏效果 = 复用本类 + 新增一个 frag shader。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_FULLSCREENGPU_H
|
||||
#define HELLOVULKAN_FULLSCREENGPU_H
|
||||
|
||||
#include <Engine/Core/Types.h>
|
||||
#include <Engine/RenderGraph/RenderGraph.h>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
namespace Engine {
|
||||
|
||||
class Device;
|
||||
class DescriptorManager;
|
||||
class ShaderManager;
|
||||
|
||||
namespace Passes {
|
||||
|
||||
// 全屏 pass 通用 push(16B):所有全屏 pass 统一声明与推送
|
||||
struct FullscreenPush {
|
||||
f32 exposure;
|
||||
f32 param0; // 各 pass 自定语义(tonemap: aces 开关)
|
||||
f32 param1;
|
||||
f32 param2;
|
||||
};
|
||||
|
||||
// 后处理链参数(ImGui 可调;Renderer 持有,pass 按引用读取)
|
||||
struct PostProcessParams {
|
||||
f32 exposure = 1.0f;
|
||||
bool useACES = true;
|
||||
f32 bloomThreshold = 1.0f; // HDR 域亮度阈值
|
||||
f32 bloomStrength = 0.8f; // 叠加强度
|
||||
};
|
||||
|
||||
class FullscreenGpu {
|
||||
public:
|
||||
FullscreenGpu(Device& device, DescriptorManager& descriptors,
|
||||
ShaderManager& shaders);
|
||||
~FullscreenGpu();
|
||||
|
||||
FullscreenGpu(const FullscreenGpu&) = delete;
|
||||
FullscreenGpu& operator=(const FullscreenGpu&) = delete;
|
||||
|
||||
vk::DescriptorSetLayout setLayout; // Set0 = {输入0, 输入1}
|
||||
vk::PipelineLayout layout; // push 16B(FullscreenPush)
|
||||
vk::Sampler sampler;
|
||||
vk::ShaderEXT vert{}, extractFrag{}, blurFrag{}, tonemapFrag{};
|
||||
|
||||
// 各 pass 自己持有 per-slot set;分配统一走这里
|
||||
vk::DescriptorSet AllocateSet();
|
||||
|
||||
// 输入图片绑定(RG 重编译后重绑;物理镜像按槽位各一份)
|
||||
void UpdateSetInput(vk::DescriptorSet set, u32 binding,
|
||||
RG::RenderGraph& rg, RG::TextureHandle input,
|
||||
u32 slot);
|
||||
|
||||
// 全屏 pass 公共录制:动态状态/draw 全一致,仅附件 view、
|
||||
// 输入 set、push 值不同
|
||||
void RecordFullscreen(RG::RenderGraphContext& ctx, vk::ImageView view,
|
||||
vk::ShaderEXT frag, const vk::DescriptorSet& set,
|
||||
const FullscreenPush& push);
|
||||
|
||||
private:
|
||||
Device& m_Device;
|
||||
DescriptorManager& m_Descriptors;
|
||||
};
|
||||
|
||||
} // namespace Passes
|
||||
} // namespace Engine
|
||||
|
||||
#endif //HELLOVULKAN_FULLSCREENGPU_H
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/23.
|
||||
//
|
||||
// ImGuiPass:叠加层(loadOp=Load,不清屏)。
|
||||
// 框架只负责把 draw data 录进 cmd;UI 内容全部由派生类在
|
||||
// OnRenderOverlay() 里构建,框架自身不画任何 ImGui 控件。
|
||||
// 未启用叠加层时空转(begin/end 一次空 rendering region)。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_IMGUIPASS_H
|
||||
#define HELLOVULKAN_IMGUIPASS_H
|
||||
|
||||
#include <Engine/Renderer/Passes/RenderPass.h>
|
||||
|
||||
namespace Engine {
|
||||
|
||||
class ImGuiLayer;
|
||||
|
||||
namespace Passes {
|
||||
|
||||
class ImGuiPass final : public RenderPass {
|
||||
public:
|
||||
// 二级指针:Renderer::SetImGuiLayer 在 Register 之后才可能被调
|
||||
//(EnableImGui 时机由派生类决定),执行期解引用取最新值
|
||||
ImGuiPass(ImGuiLayer** layer, RG::TextureHandle backbuffer)
|
||||
: m_Layer(layer), m_Backbuffer(backbuffer) {}
|
||||
|
||||
void Register(RG::RenderGraph& rg) override;
|
||||
|
||||
private:
|
||||
ImGuiLayer** m_Layer;
|
||||
RG::TextureHandle m_Backbuffer;
|
||||
};
|
||||
|
||||
} // namespace Passes
|
||||
} // namespace Engine
|
||||
|
||||
#endif //HELLOVULKAN_IMGUIPASS_H
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/23.
|
||||
//
|
||||
// PresentPass:transition 到 ePresentSrcKHR。
|
||||
// layout 转换由 RG 的 barrier 完成,实际 vkQueuePresentKHR 由 Renderer 驱动。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_PRESENTPASS_H
|
||||
#define HELLOVULKAN_PRESENTPASS_H
|
||||
|
||||
#include <Engine/Renderer/Passes/RenderPass.h>
|
||||
|
||||
namespace Engine::Passes {
|
||||
|
||||
class PresentPass final : public RenderPass {
|
||||
public:
|
||||
explicit PresentPass(RG::TextureHandle backbuffer)
|
||||
: m_Backbuffer(backbuffer) {}
|
||||
|
||||
void Register(RG::RenderGraph& rg) override
|
||||
{
|
||||
rg.AddPass("Present", [](RG::RenderGraphContext&) {})
|
||||
.Read(m_Backbuffer, RG::ResourceUse::Present);
|
||||
}
|
||||
|
||||
private:
|
||||
RG::TextureHandle m_Backbuffer;
|
||||
};
|
||||
|
||||
} // namespace Engine::Passes
|
||||
|
||||
#endif //HELLOVULKAN_PRESENTPASS_H
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/23.
|
||||
//
|
||||
// RenderPass:渲染 pass 对象基类(Unity ScriptableRenderPass 思路)。
|
||||
//
|
||||
// pass 自己负责两件事,框架(Renderer)不再手写"超级函数":
|
||||
// Register —— 向 RenderGraph 声明资源使用 + 录制 lambda;
|
||||
// 执行序由 RG 拓扑排序决定(writer 必先于 reader),
|
||||
// 与注册顺序无关
|
||||
// OnTargetsRebuilt —— RG 重编译(resize / vsync 切换)后重绑描述符
|
||||
// (物理镜像按槽位可能全部换新)
|
||||
//
|
||||
// pass 之间不互相依赖:数据流只经 RG 资源句柄。新增效果 = 新增一个
|
||||
// RenderPass 子类 + Renderer::BuildGraph 里注册一行,其它代码不动。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_RENDERPASS_H
|
||||
#define HELLOVULKAN_RENDERPASS_H
|
||||
|
||||
#include <Engine/RenderGraph/RenderGraph.h>
|
||||
|
||||
namespace Engine::Passes {
|
||||
|
||||
class RenderPass {
|
||||
public:
|
||||
virtual ~RenderPass() = default;
|
||||
|
||||
virtual void Register(RG::RenderGraph& rg) = 0;
|
||||
virtual void OnTargetsRebuilt(RG::RenderGraph& rg) { (void)rg; }
|
||||
};
|
||||
|
||||
} // namespace Engine::Passes
|
||||
|
||||
#endif //HELLOVULKAN_RENDERPASS_H
|
||||
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/23.
|
||||
//
|
||||
// SceneGpu:场景级 GPU 共享装配(Shadow/Forward 及未来几何类 pass 共用)。
|
||||
//
|
||||
// 从 Renderer 拆出的装配体:set 布局 / pipeline 布局 / shader object /
|
||||
// 采样器 / per-slot 描述符集合。新增几何 pass(延迟、调试线框等)直接
|
||||
// 复用本装配,不必碰 Renderer。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_SCENEGPU_H
|
||||
#define HELLOVULKAN_SCENEGPU_H
|
||||
|
||||
#include <Engine/Core/FrameContext.h>
|
||||
#include <Engine/RenderGraph/RenderGraph.h>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace Engine {
|
||||
|
||||
class Device;
|
||||
class DescriptorManager;
|
||||
class ShaderManager;
|
||||
class UniformBuffer;
|
||||
|
||||
namespace Passes {
|
||||
|
||||
class SceneGpu {
|
||||
public:
|
||||
SceneGpu(Device& device, DescriptorManager& descriptors,
|
||||
ShaderManager& shaders,
|
||||
UniformBuffer& ubo, UniformBuffer& objectBuffer);
|
||||
~SceneGpu();
|
||||
|
||||
SceneGpu(const SceneGpu&) = delete;
|
||||
SceneGpu& operator=(const SceneGpu&) = delete;
|
||||
|
||||
// ---- set 布局(shader 契约,改绑定必须同步 shaders/)----
|
||||
vk::DescriptorSetLayout uboSetLayout; // Set0 = {UBO, ObjectBuffer}
|
||||
vk::DescriptorSetLayout textureSetLayout; // Set1 = {albedo}
|
||||
vk::DescriptorSetLayout shadowSetLayout; // Set2 = {shadow map}
|
||||
vk::PipelineLayout forwardLayout; // 3 sets,无 push(GPUDriven 经 SSBO)
|
||||
vk::PipelineLayout shadowLayout; // Set0,push = lightVP 64B
|
||||
|
||||
// per-slot 描述符:Set0(UBO+实例 SSBO)与 Set2(阴影图采样)
|
||||
std::vector<vk::DescriptorSet> uboSets;
|
||||
std::vector<vk::DescriptorSet> shadowSets;
|
||||
|
||||
// 阴影采样器:clamp-to-border 白色 = 光视锥外自动无阴影
|
||||
//(省 shader 出界分支)
|
||||
vk::Sampler shadowSampler;
|
||||
|
||||
vk::ShaderEXT forwardVert{}, forwardFrag{};
|
||||
vk::ShaderEXT shadowVert{}, shadowFrag{};
|
||||
|
||||
// RG 重编译后重绑阴影图(物理镜像按槽位各一份)
|
||||
void BindShadowMap(RG::RenderGraph& rg, RG::TextureHandle shadowMap);
|
||||
|
||||
private:
|
||||
Device& m_Device;
|
||||
DescriptorManager& m_Descriptors;
|
||||
};
|
||||
|
||||
} // namespace Passes
|
||||
} // namespace Engine
|
||||
|
||||
#endif //HELLOVULKAN_SCENEGPU_H
|
||||
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/23.
|
||||
//
|
||||
// ShadowPass:光源视角写深度。GPUDriven batch 消费光源视锥剔除结果
|
||||
// (FrameSceneData::shadowView——相机外实体仍投影子)。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_SHADOWPASS_H
|
||||
#define HELLOVULKAN_SHADOWPASS_H
|
||||
|
||||
#include <Engine/Renderer/Passes/RenderPass.h>
|
||||
#include <Engine/Renderer/Passes/SceneGpu.h>
|
||||
#include <Engine/Renderer/SceneTypes.h>
|
||||
|
||||
namespace Engine::Passes {
|
||||
|
||||
class ShadowPass final : public RenderPass {
|
||||
public:
|
||||
ShadowPass(SceneGpu& gpu, FrameSceneData& frame, RG::TextureHandle shadowMap)
|
||||
: m_Gpu(gpu), m_Frame(frame), m_ShadowMap(shadowMap) {}
|
||||
|
||||
void Register(RG::RenderGraph& rg) override;
|
||||
void OnTargetsRebuilt(RG::RenderGraph& rg) override;
|
||||
|
||||
private:
|
||||
SceneGpu& m_Gpu;
|
||||
FrameSceneData& m_Frame;
|
||||
RG::TextureHandle m_ShadowMap;
|
||||
};
|
||||
|
||||
} // namespace Engine::Passes
|
||||
|
||||
#endif //HELLOVULKAN_SHADOWPASS_H
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/23.
|
||||
//
|
||||
// TonemapPass:HDR(+bloom)→ 显示空间,全屏三角写 Backbuffer。
|
||||
// 显示变换在此显式建模(对齐 UE/Unity:HDR SceneColor → tonemapper → UI)。
|
||||
// Backbuffer 从此只接收"显示空间"颜色:tonemap 直接写、ImGui 叠加。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_TONEMAPPASS_H
|
||||
#define HELLOVULKAN_TONEMAPPASS_H
|
||||
|
||||
#include <Engine/Renderer/Passes/RenderPass.h>
|
||||
#include <Engine/Renderer/Passes/FullscreenGpu.h>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace Engine::Passes {
|
||||
|
||||
class TonemapPass final : public RenderPass {
|
||||
public:
|
||||
TonemapPass(FullscreenGpu& gpu, PostProcessParams& params,
|
||||
RG::TextureHandle hdrColor, RG::TextureHandle bloomA,
|
||||
RG::TextureHandle backbuffer);
|
||||
~TonemapPass() override = default;
|
||||
|
||||
void Register(RG::RenderGraph& rg) override;
|
||||
void OnTargetsRebuilt(RG::RenderGraph& rg) override;
|
||||
|
||||
private:
|
||||
FullscreenGpu& m_Gpu;
|
||||
PostProcessParams& m_Params;
|
||||
RG::TextureHandle m_HDR;
|
||||
RG::TextureHandle m_A;
|
||||
RG::TextureHandle m_Backbuffer;
|
||||
|
||||
std::vector<vk::DescriptorSet> m_Sets; // per-slot
|
||||
};
|
||||
|
||||
} // namespace Engine::Passes
|
||||
|
||||
#endif //HELLOVULKAN_TONEMAPPASS_H
|
||||
@@ -1,6 +1,19 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/20.
|
||||
//
|
||||
// Renderer:渲染门面 + 渲染侧组合根。
|
||||
//
|
||||
// 分工(对照 UE/Unity 的渲染架构):
|
||||
// Renderer —— 装配模块、声明 RG 资源、注册 pass 对象、
|
||||
// 每帧编排(翻译场景 → 写 buffer → 驱动 RG → 提交呈现)。
|
||||
// 不理解场景细节,不含 pass 实现。
|
||||
// SceneRenderer —— 场景 → FrameSceneData 的翻译层(相机/灯光/剔除,
|
||||
// 对应 UE FSceneRenderer / Unity CullingResults)。
|
||||
// Passes::* —— 各 pass 的声明与录制(对应 Unity ScriptableRenderPass)。
|
||||
// 新增效果 = 新增 pass 类 + BuildGraph 注册一行。
|
||||
//
|
||||
// 对外只暴露两个入口:Render(Scene&, Assets&) 和给 App 层调参的访问器。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_RENDERER_H
|
||||
#define HELLOVULKAN_RENDERER_H
|
||||
@@ -9,13 +22,11 @@
|
||||
|
||||
#include <Engine/Core/Types.h>
|
||||
#include <Engine/Core/FrameContext.h>
|
||||
#include <Engine/Renderer/SceneTypes.h>
|
||||
#include <Engine/RenderGraph/RenderGraph.h>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
namespace Engine {
|
||||
|
||||
class Window;
|
||||
@@ -27,26 +38,14 @@ namespace Engine {
|
||||
class SyncManager;
|
||||
class CommandManager;
|
||||
class UniformBuffer;
|
||||
class Model;
|
||||
class SceneRenderer;
|
||||
class VulkanAssetUploader;
|
||||
class ImGuiLayer;
|
||||
|
||||
namespace ECS { class Scene; }
|
||||
namespace Assets { class AssetManager; }
|
||||
class ImGuiLayer;
|
||||
class Mesh;
|
||||
namespace Assets { class AssetManager; class IAssetUploader; }
|
||||
namespace Passes { class RenderPass; class SceneGpu; class FullscreenGpu; class PostProcessParams; }
|
||||
|
||||
// GPUDriven:按 mesh 聚合的绘制批
|
||||
struct InstanceBatch {
|
||||
Mesh* mesh;
|
||||
u32 first; // 在实例矩阵数组中的起始下标
|
||||
u32 count; // 实例数
|
||||
};
|
||||
|
||||
// Renderer 职责(收敛后):
|
||||
// 1. 装配底层模块(Device/Swapchain/Sync/Command/Descriptor/Shader)
|
||||
// 2. 声明并驱动 RenderGraph(pass 结构在这里组装)
|
||||
// 3. Render(Scene&, AssetManager&):从 ECS 场景读取相机/灯光/渲染体,
|
||||
// 经资产层解析句柄后绘制
|
||||
// 不拥有场景,不加载资产(资产归 AssetManager,磁盘 IO 与这里无关)。
|
||||
class Renderer {
|
||||
public:
|
||||
Renderer(Window& window);
|
||||
@@ -61,69 +60,63 @@ namespace Engine {
|
||||
Device& GetDevice() const { return *m_Device; }
|
||||
MemoryAllocator& GetAllocator() const { return *m_Allocator; }
|
||||
DescriptorManager& GetDescriptorManager() const { return *m_DescriptorManager; }
|
||||
vk::DescriptorSetLayout GetTextureSetLayout() const { return m_TextureSetLayout; }
|
||||
vk::Format GetSwapchainFormat() const; // Swapchain 不完整,实现在 cpp
|
||||
vk::DescriptorSetLayout GetTextureSetLayout() const; // 实现在 cpp(SceneGpu 成员)
|
||||
vk::Format GetSwapchainFormat() const;
|
||||
u32 GetSwapchainImageCount() const;
|
||||
// 资产上传服务(渲染层对资产层提供的 IAssetUploader 实现)
|
||||
Assets::IAssetUploader& GetAssetUploader() const;
|
||||
|
||||
// 可选叠加层(ImGui):不设置则 RG 里的 ImGui pass 为空转。
|
||||
// 生命周期:层必须先于 Renderer 析构(Application 成员序保证)。
|
||||
void SetImGuiLayer(ImGuiLayer* layer) { m_ImGuiLayer = layer; }
|
||||
|
||||
// ---- 后处理参数(ImGui 可调,转发到 pass 共享的 PostProcessParams)----
|
||||
f32 GetExposure() const;
|
||||
void SetExposure(f32 e);
|
||||
bool GetUseACES() const;
|
||||
void SetUseACES(bool b);
|
||||
f32 GetBloomThreshold() const;
|
||||
void SetBloomThreshold(f32 v);
|
||||
f32 GetBloomStrength() const;
|
||||
void SetBloomStrength(f32 v);
|
||||
|
||||
// pass 级 GPU 耗时(最近完成帧,毫秒;与 GetPassGpuMs 下标对应)
|
||||
const std::vector<std::string>& GetPassNames() const { return m_PassNames; }
|
||||
const std::vector<f32>& GetPassGpuMs() const { return m_PassGpuMs; }
|
||||
|
||||
// 双视图剔除后的实例数(遥测)
|
||||
u32 GetMainInstanceCount() const;
|
||||
u32 GetShadowInstanceCount() const;
|
||||
|
||||
// 垂直同步开关(present mode 切换会重建 swapchain),
|
||||
// 只应在帧 UI 构建段调用(Render 之前)
|
||||
void SetVSync(bool vsync);
|
||||
|
||||
private:
|
||||
void BuildGraph(); // 声明 pass 结构 + 首次 Compile
|
||||
void BuildGraph(); // 声明 RG 资源 + 注册 pass 对象
|
||||
void HandleResize();
|
||||
void UpdateShadowDescriptors();
|
||||
void UpdateFullscreenDescriptors();
|
||||
void ReadGpuTimes(u32 frameSlot);
|
||||
|
||||
Window& m_Window;
|
||||
|
||||
// ---- 底层模块(析构序:后声明者先析构,RG 在 Device/Allocator 之前)----
|
||||
// ---- 底层模块(析构序:后声明者先析构;引用他人者先析构)----
|
||||
Scope<Device> m_Device;
|
||||
Scope<MemoryAllocator> m_Allocator;
|
||||
Scope<DescriptorManager> m_DescriptorManager;
|
||||
Scope<ShaderManager> m_ShaderManager;
|
||||
Scope<UniformBuffer> m_UniformBuffer; // per-slot UBO ring
|
||||
Scope<UniformBuffer> m_ObjectBuffer; // GPUDriven 实例矩阵 ring(SSBO)
|
||||
Scope<Passes::SceneGpu> m_SceneGpu; // 场景类 pass 共享装配
|
||||
Scope<Passes::FullscreenGpu> m_FullscreenGpu; // 全屏 pass 共享装配
|
||||
Scope<Swapchain> m_Swapchain;
|
||||
Scope<SyncManager> m_SyncManager;
|
||||
Scope<CommandManager> m_CommandManager;
|
||||
Scope<UniformBuffer> m_UniformBuffer;
|
||||
Scope<UniformBuffer> m_ObjectBuffer; // GPUDriven 实例矩阵 ring(SSBO)
|
||||
Scope<SceneRenderer> m_SceneRenderer; // 场景翻译层(先于 pass 构造)
|
||||
Scope<RG::RenderGraph> m_RenderGraph;
|
||||
Scope<VulkanAssetUploader> m_AssetUploader;
|
||||
|
||||
// ---- 管线装配(shader object 方案,无 vk::Pipeline)----
|
||||
// Forward layout:3 个 set(UBO/贴图/阴影图)+ 128B push(与 Shadow pass
|
||||
// 共用上限;forward 的 shader block 只有 64B,block ⊂ range 合法)
|
||||
vk::PipelineLayout m_PipelineLayout;
|
||||
vk::DescriptorSetLayout m_UBOSetLayout;
|
||||
vk::DescriptorSetLayout m_TextureSetLayout;
|
||||
vk::DescriptorSetLayout m_ShadowSetLayout;
|
||||
std::vector<vk::DescriptorSet> m_UBODescriptorSets; // 每帧槽位一个
|
||||
std::vector<vk::DescriptorSet> m_ShadowDescriptorSets; // 每帧槽位一个
|
||||
vk::Sampler m_ShadowSampler;
|
||||
vk::ShaderEXT m_VertShader{};
|
||||
vk::ShaderEXT m_FragShader{};
|
||||
|
||||
// Shadow pass 独立装配:无 set,push constant = {lightVP, model} 128B
|
||||
vk::PipelineLayout m_ShadowPipelineLayout;
|
||||
vk::ShaderEXT m_ShadowVertShader{};
|
||||
vk::ShaderEXT m_ShadowFragShader{};
|
||||
|
||||
// Tonemap pass 装配:Set0 = {HDR 颜色图, Bloom 图},push = 16B
|
||||
//(全屏 pass 通用:exposure/aces/bloomStrength/pad)
|
||||
vk::PipelineLayout m_TonemapPipelineLayout;
|
||||
vk::DescriptorSetLayout m_TonemapSetLayout;
|
||||
std::vector<vk::DescriptorSet> m_TonemapDescriptorSets; // 每帧槽位一个
|
||||
vk::Sampler m_TonemapSampler;
|
||||
vk::ShaderEXT m_TonemapVertShader{};
|
||||
vk::ShaderEXT m_TonemapFragShader{};
|
||||
|
||||
// Bloom:Extract(HDR→A) → BlurH(A→B) → BlurV(B→A),半分辨率
|
||||
// 与 Tonemap 共用 set layout/pipeline layout/vertex shader
|
||||
std::vector<vk::DescriptorSet> m_BloomExtractSets; // 每帧槽位
|
||||
std::vector<vk::DescriptorSet> m_BloomBlurHSets;
|
||||
std::vector<vk::DescriptorSet> m_BloomBlurVSets;
|
||||
vk::ShaderEXT m_BloomExtractFrag{};
|
||||
vk::ShaderEXT m_BloomBlurFrag{};
|
||||
// pass 对象(注册序;执行序由 RG 拓扑排序决定)
|
||||
std::vector<Scope<Passes::RenderPass>> m_Passes;
|
||||
|
||||
// ---- RenderGraph 资源句柄 ----
|
||||
RG::TextureHandle m_Backbuffer{};
|
||||
@@ -133,34 +126,12 @@ namespace Engine {
|
||||
RG::TextureHandle m_BloomA{}; // 半分辨率:提取 + 垂直模糊结果
|
||||
RG::TextureHandle m_BloomB{}; // 半分辨率:水平模糊中间结果
|
||||
|
||||
// ---- 当帧绑定(Render() 期间有效,供 pass 回调读取)----
|
||||
ECS::Scene* m_BoundScene = nullptr;
|
||||
Assets::AssetManager* m_BoundAssets = nullptr;
|
||||
glm::mat4 m_LightSpace{1.0f}; // 阴影光源 VP(每帧由 Render 算好)
|
||||
|
||||
// GPUDriven:当帧实例数据(Render 期收集,Forward pass 消费)
|
||||
// 双视图剔除:相机视锥与光源视锥各出一份可见列表——
|
||||
// 相机外的实体仍可能投影子进视野,所以 Shadow 用光源视锥单独剔除
|
||||
struct CullResult {
|
||||
std::vector<InstanceBatch> batches;
|
||||
u32 instanceCount = 0;
|
||||
};
|
||||
CullResult m_MainView; // 相机视锥
|
||||
CullResult m_ShadowView; // 光源视锥
|
||||
std::unordered_map<Mesh*, u32> m_MainBatchLookup;
|
||||
std::unordered_map<Mesh*, u32> m_ShadowBatchLookup;
|
||||
std::vector<glm::mat4> m_InstanceModels; // [主视图段 | 阴影视图段]
|
||||
static constexpr u32 kMaxInstances = 16384;
|
||||
// pass 共享的可调参数(Renderer 持有,App 层访问器转发)
|
||||
Scope<Passes::PostProcessParams> m_PostParams;
|
||||
|
||||
// 可选叠加层(不拥有;Application 持有)
|
||||
ImGuiLayer* m_ImGuiLayer = nullptr;
|
||||
|
||||
// ---- Tonemap/Bloom 参数(ImGui 可调)----
|
||||
f32 m_Exposure = 1.0f;
|
||||
bool m_UseACES = true;
|
||||
f32 m_BloomThreshold = 1.0f; // HDR 域亮度阈值
|
||||
f32 m_BloomStrength = 0.8f; // 叠加强度
|
||||
|
||||
// GPU timestamp(pass 级耗时,ImGui 可读)
|
||||
vk::QueryPool m_QueryPool;
|
||||
u32 m_QueriesPerFrame = 0; // 每帧槽位的查询数 = pass 数 × 2
|
||||
@@ -168,31 +139,6 @@ namespace Engine {
|
||||
std::vector<std::string> m_PassNames; // 执行序 pass 名
|
||||
std::vector<f32> m_PassGpuMs; // 最近一帧各 pass 耗时
|
||||
bool m_TimesPrimed[2] = {false, false}; // 每槽位首帧跳过读取
|
||||
f32 m_CollectMs = 0.0f; // 实例收集 CPU 耗时(遥测)
|
||||
|
||||
public:
|
||||
f32 GetExposure() const { return m_Exposure; }
|
||||
void SetExposure(f32 e) { m_Exposure = e; }
|
||||
bool GetUseACES() const { return m_UseACES; }
|
||||
void SetUseACES(bool b) { m_UseACES = b; }
|
||||
f32 GetBloomThreshold() const { return m_BloomThreshold; }
|
||||
void SetBloomThreshold(f32 v) { m_BloomThreshold = v; }
|
||||
f32 GetBloomStrength() const { return m_BloomStrength; }
|
||||
void SetBloomStrength(f32 v) { m_BloomStrength = v; }
|
||||
|
||||
// pass 级 GPU 耗时(最近完成帧,毫秒;与 GetPassGpuMs 下标对应)
|
||||
const std::vector<std::string>& GetPassNames() const { return m_PassNames; }
|
||||
const std::vector<f32>& GetPassGpuMs() const { return m_PassGpuMs; }
|
||||
|
||||
// 双视图剔除后的实例数(遥测)
|
||||
u32 GetMainInstanceCount() const { return m_MainView.instanceCount; }
|
||||
u32 GetShadowInstanceCount() const { return m_ShadowView.instanceCount; }
|
||||
|
||||
// 垂直同步开关(Mailbox ↔ Immediate):切换会重建 swapchain,
|
||||
// 只应在帧 UI 构建段调用(Render 之前)
|
||||
void SetVSync(bool vsync);
|
||||
|
||||
private:
|
||||
|
||||
vk::Extent2D m_Extent{};
|
||||
u32 m_CurrentFrame = 0;
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/23.
|
||||
//
|
||||
// SceneRenderer:场景 → 渲染数据的每帧翻译层(UE FSceneRenderer /
|
||||
// Unity CullingResults 的对应物)。
|
||||
//
|
||||
// 职责(全部是"读场景、产数据",不碰 GPU、不碰 Vulkan):
|
||||
// 1. 相机/灯光/环境色 → UniformBufferObject 语义组装(含阴影光空间矩阵)
|
||||
// 2. 单趟实例收集 + 双视图剔除(相机视锥/光源视锥各自独立可见列表——
|
||||
// 相机外实体仍可能投影子进视野,shadow popping 的教训)
|
||||
// Renderer 拿 FrameSceneData 写 buffer、驱动 pass;场景理解全部收口在此。
|
||||
//
|
||||
// 扩展性:
|
||||
// - 多光源:lights 数组已就位(kMaxLights),每灯各自 lightSpace 即 CSM 前置
|
||||
// - 级联阴影:BuildFrame 内按级联多出几份 lightSpace + shadowView,
|
||||
// pass 侧按索引消费,本类结构不变
|
||||
// - 遮挡剔除/GPU 剔除:只改本类收集逻辑,下游无感知
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_SCENERENDERER_H
|
||||
#define HELLOVULKAN_SCENERENDERER_H
|
||||
|
||||
#include <Engine/Core/Types.h>
|
||||
#include <Engine/Renderer/SceneTypes.h>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Engine {
|
||||
|
||||
namespace ECS { class Scene; }
|
||||
namespace Assets { class AssetManager; }
|
||||
|
||||
class SceneRenderer {
|
||||
public:
|
||||
// 从场景构建当帧渲染数据。无 primary 相机返回 false(渲染跳帧)。
|
||||
// aspect 由调用方传入(跟随 swapchain,本类不感知窗口)。
|
||||
bool BuildFrame(ECS::Scene& scene, Assets::AssetManager& assets, f32 aspect);
|
||||
|
||||
FrameSceneData& Frame() { return m_Frame; }
|
||||
|
||||
// ---- 遥测 ----
|
||||
u32 GetMainInstanceCount() const { return m_Frame.mainView.instanceCount; }
|
||||
u32 GetShadowInstanceCount() const { return m_Frame.shadowView.instanceCount; }
|
||||
f32 GetCollectMs() const { return m_Frame.collectMs; }
|
||||
|
||||
private:
|
||||
// 阴影光空间矩阵:光源正交投影(覆盖场景,[0,1] 深度重映射)。
|
||||
// 写入(Shadow pass push)与采样(Forward UBO)共用同一矩阵。
|
||||
void ComputeLightSpace(const glm::vec3& shadowDir);
|
||||
|
||||
FrameSceneData m_Frame;
|
||||
|
||||
// batch 聚合查找表(mesh → batch 下标),每帧 clear 复用桶
|
||||
std::unordered_map<Mesh*, u32> m_MainLookup;
|
||||
std::unordered_map<Mesh*, u32> m_ShadowLookup;
|
||||
|
||||
bool m_TruncationWarned = false; // 实例缓冲打满只告警一次
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
|
||||
#endif //HELLOVULKAN_SCENERENDERER_H
|
||||
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/23.
|
||||
//
|
||||
// SceneTypes:场景 → GPU 的数据契约(CPU 结构镜像 shader 布局)。
|
||||
//
|
||||
// SceneRenderer 生产、Renderer/各 pass 消费;改字段必须同步 shaders/。
|
||||
// 常量也集中在这里:SSBO 容量、灯数、阴影图尺寸都是"渲染预算",
|
||||
// 改任何一个都要同步评估 buffer/池容量。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_SCENETYPES_H
|
||||
#define HELLOVULKAN_SCENETYPES_H
|
||||
|
||||
#include <Engine/Core/Types.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace Engine {
|
||||
|
||||
class Mesh;
|
||||
|
||||
// GPUDriven:按 mesh 聚合的绘制批
|
||||
struct InstanceBatch {
|
||||
Mesh* mesh;
|
||||
u32 first; // 在实例矩阵数组中的起始下标
|
||||
u32 count; // 实例数
|
||||
};
|
||||
|
||||
// 一个渲染视图的剔除结果(相机视图 / 光源视图各一份)
|
||||
struct CullResult {
|
||||
std::vector<InstanceBatch> batches;
|
||||
u32 instanceCount = 0;
|
||||
};
|
||||
|
||||
constexpr u32 kMaxLights = 4;
|
||||
constexpr u32 kMaxInstances = 16384; // 实例 SSBO 容量(矩阵数)
|
||||
constexpr u32 kShadowMapSize = 2048; // 阴影图边长
|
||||
|
||||
// 镜像 shader 侧 UBO 布局的灯光项
|
||||
struct LightData {
|
||||
glm::vec4 direction; // xyz = 方向(已归一),w 未用
|
||||
glm::vec4 color; // rgb = 颜色,a = 强度
|
||||
};
|
||||
|
||||
// 镜像 simple_shader 的 UBO 布局(std140 语义由 shader 侧对齐)
|
||||
struct UniformBufferObject {
|
||||
glm::mat4 view;
|
||||
glm::mat4 proj;
|
||||
glm::mat4 lightSpace; // 阴影光源 VP(写入与采样共用同一矩阵)
|
||||
glm::vec4 ambientColor;
|
||||
LightData lights[kMaxLights];
|
||||
};
|
||||
|
||||
// 每帧从场景收集的渲染数据(SceneRenderer 生产,pass 消费)。
|
||||
// 复用成员容量:clear() 不缩容,稳态零每帧堆分配。
|
||||
struct FrameSceneData {
|
||||
UniformBufferObject ubo{};
|
||||
|
||||
// 实例矩阵数组 = [主视图段 | 阴影视图段](共享同一 per-slot SSBO)
|
||||
std::vector<glm::mat4> instanceModels;
|
||||
CullResult mainView; // 相机视锥 → Forward pass
|
||||
CullResult shadowView; // 光源视锥 → Shadow pass(相机外实体仍投影子)
|
||||
|
||||
f32 collectMs = 0.0f; // 收集+剔除 CPU 耗时(遥测)
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
|
||||
#endif //HELLOVULKAN_SCENETYPES_H
|
||||
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/23.
|
||||
//
|
||||
// VulkanAssetUploader:IAssetUploader 的渲染层实现。
|
||||
//
|
||||
// 属于渲染层对资产层提供的服务:持有 GPU 上下文,负责把解析后的
|
||||
// 资产数据创建为 Vulkan 资源。资产层(AssetManager)只看到接口,
|
||||
// 不知道 Device/Allocator 的存在——依赖方向:Assets → IAssetUploader
|
||||
// ← VulkanAssetUploader(渲染层),永远不出现 Assets → Vulkan 具体。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_VULKANASSETUPLOADER_H
|
||||
#define HELLOVULKAN_VULKANASSETUPLOADER_H
|
||||
|
||||
#include <Engine/Assets/IAssetUploader.h>
|
||||
|
||||
namespace Engine {
|
||||
|
||||
class Device;
|
||||
class MemoryAllocator;
|
||||
class DescriptorManager;
|
||||
|
||||
class VulkanAssetUploader final : public Assets::IAssetUploader {
|
||||
public:
|
||||
VulkanAssetUploader(Device& device, MemoryAllocator& allocator,
|
||||
DescriptorManager& descriptors,
|
||||
vk::DescriptorSetLayout textureLayout)
|
||||
: m_Device(device), m_Allocator(allocator),
|
||||
m_Descriptors(descriptors), m_TextureLayout(textureLayout) {}
|
||||
|
||||
Scope<Model> LoadModel(const std::string& path) override;
|
||||
Scope<Model> CreatePlane(f32 halfSize, u8 r, u8 g, u8 b) override;
|
||||
|
||||
private:
|
||||
Device& m_Device;
|
||||
MemoryAllocator& m_Allocator;
|
||||
DescriptorManager& m_Descriptors;
|
||||
vk::DescriptorSetLayout m_TextureLayout;
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
|
||||
#endif //HELLOVULKAN_VULKANASSETUPLOADER_H
|
||||
Reference in New Issue
Block a user