Files
HelloVulkan/Engine/include/Engine/Renderer/Renderer.h
T
atdunbg 20f0035baa feat: ImGui docking Editor + 显示链/帧同步/输入语义重构
- App/editor: Hierarchy/Inspector/Viewport/Stats 四面板 + DockBuilder 默认布局,main.cpp 瘦身为场景搭建与生命周期
- 显示链: Tonemap→PresentTarget 经 ImGui::Image 呈现(零色偏),backbuffer 仅承载 ImGui;Direct/Viewport 双显示模式 + 面板分辨率上报
- 帧首同步 BeginFrameSync: resize/vsync/尺寸/模式意图统一帧首落定(修描述符悬垂);修复 vsync 意图未落 swapchain 导致的每帧重建交换链
- 输入: Editor 每帧判定键盘/鼠标归属(打字让位、Viewport hover/focus 放行、Fullscreen 全放行)
- 材质: roughness 独立槽位 + 非 glTF 金属/粗糙贴图映射;透明队列 depthWrite=FALSE + translucent 独立 shader + scratch 清帧
- FBX: 非蒙皮网格烘焙节点链全局变换(Z-up 旋转/单位换算落顶点)
- Hierarchy 行 ImGui ID 以 UUID 作用域(重名不冲突、改名不丢选中)
2026-09-30 00:24:53 +08:00

226 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// 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
#pragma once
#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 <array>
#include <vector>
namespace Engine {
class Window;
class Device;
class MemoryAllocator;
class DescriptorManager;
class ShaderManager;
class Swapchain;
class SyncManager;
class CommandManager;
class UniformBuffer;
class SceneRenderer;
class VulkanAssetUploader;
class Cubemap;
class IblGenerator;
class ImGuiLayer;
class TracyGpuProfiler;
namespace ECS { class Scene; }
namespace Assets { class AssetManager; class IAssetUploader; }
namespace Passes { class RenderPass; class SceneGpu; class FullscreenGpu; class PostProcessParams; }
class Renderer {
public:
explicit Renderer(Window& window);
~Renderer();
Renderer(const Renderer&) = delete;
Renderer& operator=(const Renderer&) = delete;
void Render(ECS::Scene& scene, Assets::AssetManager& assets, f32 dt);
// ---- 组合根(Application)装配其他模块时需要的访问器 ----
Device& GetDevice() const { return *m_Device; }
MemoryAllocator& GetAllocator() const { return *m_Allocator; }
DescriptorManager& GetDescriptorManager() const { return *m_DescriptorManager; }
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;
if (layer) RefreshSceneTextures(); // 后端就绪:注册场景纹理
}
// ---- 场景显示纹理(tonemap 输出,ImGui::Image 可采样显示)----
// 按 m_CurrentFrame 取当帧槽位的描述符(UI 构建段与紧随的
// Render 同槽位)。无 ImGui 层时返回 nullptr
void* GetSceneTexture() const;
// 渲染分辨率(PresentTarget 尺寸,等比适配用)
vk::Extent2D GetRenderExtent() const { return m_Extent; }
// ---- 后处理参数(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);
// ---- 特性开关 / 调试视图(转发到 SceneRenderer,每帧落
// FrameSceneData 契约,pass 只读;ImGui 直接对接)----
bool GetShadowsEnabled() const;
void SetShadowsEnabled(bool b);
bool GetTAAEnabled() const;
void SetTAAEnabled(bool b);
bool GetBloomEnabled() const;
void SetBloomEnabled(bool b);
bool GetLodEnabled() const;
void SetLodEnabled(bool b); // 关 = 全部强制 LOD0
int GetDebugView() const;
void SetDebugView(int v); // Passes::DebugView 枚举值
// 调试视图名表(下标 = DebugView 枚举值,ImGui combo 直接枚举)
const std::vector<const char*>& GetDebugViewNames() const;
// ---- 动态环境切换(资产归 Assets 层,Renderer 只消费)----
// env 传 AssetManager::GetEnvironment(ref) 的指针;nullptr 回中性兜底。
// 内部 waitIdle 后统一换绑(引用环境描述符的 pass 全部同步);
// compute 预积分已把生成成本压到毫秒级,waitIdle 尾巴 ≈ 单帧
void SetEnvironment(const Cubemap* env);
// 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;
bool GetInstancesTruncated() const; // 实例预算溢出(遥测红字)
f32 GetCollectMs() const; // CPU 收集+剔除段耗时
// ---- 显示模式(Editor 视口 ↔ 全屏直出;帧首同步生效)----
int GetDisplayMode() const { return m_DesiredDisplayMode; }
void SetDisplayMode(int mode); // cpp 内定义(SceneRenderer 前置声明)
// Editor 视口的期望渲染尺寸(像素;UI 面板每帧上报,帧首统一生效)
void SetViewportSize(u32 w, u32 h)
{
m_DesiredViewport = vk::Extent2D{w, h};
}
// 垂直同步开关(present mode 切换会重建 swapchain),
// 只应在帧 UI 构建段调用(Render 之前)
void SetVSync(bool vsync) { m_DesiredVSync = vsync; } // 帧首同步生效
// 帧首同步:窗口 resize / 视口尺寸 / 显示模式 / vsync 意图统一在
// UI 构建之前落定(waitIdle → 重编译 → 重绑描述符)。必须先于
// UI 构建段调用:本帧 draw data 引用的描述符与物理资源由此保证
// 全程新鲜(resize 中途换描述符会绑出已销毁句柄)
void BeginFrameSync();
private:
void BuildGraph(); // 声明 RG 资源 + 注册 pass 对象
void HandleResize(bool recreateSwapchain);
void ReadGpuTimes(u32 frameSlot);
void RefreshSceneTextures(); // 物理 view → ImGui 描述符(重建后刷新)
// 期望渲染分辨率:Editor 视口 = 面板尺寸(未上报时回退 swapchain);
// Direct = swapchain 尺寸
vk::Extent2D DesiredRenderExtent() const;
Window& m_Window;
// ---- 底层模块(析构序:后声明者先析构;引用他人者先析构)----
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<UniformBuffer> m_PrevObjectBuffer; // 上一帧实例矩阵 ring(TAA velocity)
Scope<UniformBuffer> m_SkinOffsetBuffer; // 实例→palette 基址 ring(SSBO,与实例序平行)
Scope<UniformBuffer> m_SkinPaletteBuffer; // 骨骼蒙皮矩阵 palette ring(SSBO,帧首 bump)
Scope<Passes::SceneGpu> m_SceneGpu; // 场景类 pass 共享装配
Scope<Passes::FullscreenGpu> m_FullscreenGpu; // 全屏 pass 共享装配
// 环境预积分生成端(compute 链),先于 m_Environment/m_Passes 构造
Scope<IblGenerator> m_Ibl;
// 中性兜底环境(IBL 四件套):Application 未加载/加载失败时保底;
// 声明在 m_Passes 之前 → 析构晚于 pass(引用安全)
Scope<Cubemap> m_Environment;
Scope<Swapchain> m_Swapchain;
Scope<SyncManager> m_SyncManager;
Scope<CommandManager> m_CommandManager;
Scope<SceneRenderer> m_SceneRenderer; // 场景翻译层(先于 pass 构造)
Scope<RG::RenderGraph> m_RenderGraph;
Scope<VulkanAssetUploader> m_AssetUploader;
// pass 对象(注册序;执行序由 RG 拓扑排序决定)
std::vector<Scope<Passes::RenderPass>> m_Passes;
// ---- RenderGraph 资源句柄 ----
RG::TextureHandle m_Backbuffer{};
RG::TextureHandle m_PresentTarget{}; // tonemap 输出(offscreen,ImGui 采样)
RG::TextureHandle m_Depth{};
std::array<RG::TextureHandle, kMaxCascades> m_ShadowMaps{}; // CSM 级联
RG::TextureHandle m_HDRColor{}; // Forward 输出(线性 HDR),TAA 归一
RG::TextureHandle m_Velocity{}; // Forward 输出(clip 空间运动向量)
RG::TextureHandle m_TAAColor{}; // TAA 累积输出(自引用历史),后处理源
RG::TextureHandle m_BloomA{}; // 半分辨率:提取 + 垂直模糊结果
RG::TextureHandle m_BloomB{}; // 半分辨率:水平模糊中间结果
RG::TextureHandle m_TemporalDiff{}; // 半分辨率:帧历史差异(调试)
// pass 共享的可调参数(Renderer 持有,App 层访问器转发)
Scope<Passes::PostProcessParams> m_PostParams;
// 可选叠加层(不拥有;Application 持有)
ImGuiLayer* m_ImGuiLayer = nullptr;
// GPU timestamp(pass 级耗时,ImGui 可读)
vk::QueryPool m_QueryPool;
u32 m_QueriesPerFrame = 0; // 每帧槽位的查询数 = pass 数 × 2
f32 m_TimestampPeriod = 1.0f; // ns/tick(设备属性缓存)
std::vector<std::string> m_PassNames; // 执行序 pass 名
std::vector<f32> m_PassGpuMs; // 最近一帧各 pass 耗时
bool m_TimesPrimed[2] = {false, false}; // 每槽位首帧跳过读取
// Tracy GPU 时间线(pass zone;TRACY_ENABLE 关闭时空实现)
Scope<TracyGpuProfiler> m_TracyProfiler;
vk::Extent2D m_Extent{};
u32 m_CurrentFrame = 0;
// ---- 帧首同步的意图缓冲(UI 段写入,下一帧帧首落定)----
int m_DesiredDisplayMode = kDisplayDirect; // 默认直接渲染, 视口渲染需要手动指定一下
vk::Extent2D m_DesiredViewport{}; // Editor 视口渲染分辨率(面板上报)
bool m_DesiredVSync = true;
};
} // namespace Engine
#endif //HELLOVULKAN_RENDERER_H