# XCEngine - 渲染引擎架构设计文档 > **借鉴 Unity 渲染架构概念设计** --- ## 渲染流程图 ``` ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ 渲染流程 │ └─────────────────────────────────────────────────────────────────────────────────────┘ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Scene │────▶│ Culling │────▶│ RenderQueue │────▶│ Renderer │ │ 场景数据 │ │ System │ │ 渲染队列 │ │ 渲染器 │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ ▼ │ ▼ ┌─────────────┐ │ ┌─────────────┐ │CullingResults│◀──────────┘ │ CommandList │ │ 剔除结果 │ PrepareRender │ 命令列表 │ └─────────────┘ QueueEntries └─────────────┘ │ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Camera │────▶│ LightManager│────▶│ Pass │────▶│ GPU │ │ 相机 │ │ 光照管理 │ │ 渲染通道 │ │ GPU执行 │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ │ ▼ ▼ ┌─────────────┐ ┌─────────────┐ │ ShadowAtlas │ │ Material │ │ 阴影图集 │ │ 材质 │ └─────────────┘ └─────────────┘ 流程说明: 1. Scene 提供场景数据(GameObjects, Components) 2. CullingSystem 执行视锥剔除,产出 CullingResults 3. RenderQueue 根据 CullingResults 准备渲染项(Renderer::PrepareRenderQueueEntries) 4. Renderer 遍历 RenderQueue,通过 CommandList 提交绘制命令 5. LightManager/ShadowAtlas 处理光照和阴影 6. 最终 GPU 执行渲染命令 ``` ``` ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ RHI 抽象层架构 │ └─────────────────────────────────────────────────────────────────────────────────────┘ ┌─────────────────┐ │ RHISystem │ 渲染系统入口 └────────┬────────┘ │ ┌───────────────────────┼───────────────────────┐ │ │ │ ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ │ D3D12Device │ │ D3D11Device │ │ VulkanDevice │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ └───────────────────────┼───────────────────────┘ │ ┌────────▼────────┐ │ IRHIDevice │ 抽象设备接口 └────────┬────────┘ │ ┌──────────────────────────────────┼──────────────────────────────────┐ │ │ │ │ │ │ │ ┌────▼────┐ ┌───▼────┐ ┌────▼┐ ┌──▼────┐ ┌───▼───┐ ┌───▼────┐ ┌──▼────┐ │CommandQueue│ │Descriptor│ │Fence│ │SwapChain│ │RootSig│ │PSO │ │Texture│ │ 命令队列 │ │Heap │ │围栏 │ │交换链 │ │根签名 │ │管线状态│ │纹理 │ └──────────┘ └────────┘ └─────┘ └────────┘ └───────┘ └───────┘ └───────┘ ``` > **重要声明**:本架构借鉴 Unity 渲染系统的核心概念与设计模式,包括: > - `CullingResults` / `CullingSystem` - 剔除系统(概念来自Unity SRP API) > - `RenderPipeline` / `RenderPipelineManager` - 渲染管线 > - `RenderQueue` / `RenderQueueEntry` - 渲染队列 > - `Renderer` - 渲染器核心 > - `ScriptableRenderContext` - 渲染上下文 > - `Shader` / `Pass` / `Material` - 着色器与材质 > - `LightManager` / `ShadowAtlas` - 光照与阴影管理 > > **注**:Unity底层C++渲染架构未公开,本设计基于公开API概念与通用渲染引擎模式实现。 > > 版本: 1.0 > 日期: 2026-03-13 > 目标: 构建专业级实时体积渲染引擎 --- ## 第一章 核心基础层 ### 1.1 数学库 (Math Library) ```cpp namespace XCEngine { namespace Math { struct Vector2 { float x, y; static Vector2 Zero() { return Vector2{0, 0}; } static Vector2 One() { return Vector2{1, 1}; } static Vector2 Up() { return Vector2{0, 1}; } static Vector2 Down() { return Vector2{0, -1}; } static Vector2 Right() { return Vector2{1, 0}; } static Vector2 Left() { return Vector2{-1, 0}; } static float Dot(const Vector2& a, const Vector2& b); static float Cross(const Vector2& a, const Vector2& b); static Vector2 Normalize(const Vector2& v); static float Magnitude(const Vector2& v); static Vector2 Lerp(const Vector2& a, const Vector2& b, float t); }; struct Vector3 { float x, y, z; static Vector3 Zero() { return Vector3{0, 0, 0}; } static Vector3 One() { return Vector3{1, 1, 1}; } static Vector3 Forward() { return Vector3{0, 0, 1}; } static Vector3 Back() { return Vector3{0, 0, -1}; } static Vector3 Up() { return Vector3{0, 1, 0}; } static Vector3 Down() { return Vector3{0, -1, 0}; } static Vector3 Right() { return Vector3{1, 0, 0}; } static Vector3 Left() { return Vector3{-1, 0, 0}; } static Vector3 Cross(const Vector3& a, const Vector3& b); static float Dot(const Vector3& a, const Vector3& b); static Vector3 Normalize(const Vector3& v); static float Magnitude(const Vector3& v); static float SqrMagnitude(const Vector3& v); static Vector3 Lerp(const Vector3& a, const Vector3& b, float t); static Vector3 MoveTowards(const Vector3& current, const Vector3& target, float maxDistance); }; struct Vector4 { float x, y, z, w; }; struct Matrix3x3 { float m[3][3]; static Matrix3x3 Identity() { Matrix3x3 result{}; result.m[0][0] = 1.0f; result.m[1][1] = 1.0f; result.m[2][2] = 1.0f; return result; } static Matrix3x3 Zero() { Matrix3x3 result{}; return result; } Matrix3x3 operator*(const Matrix3x3& other) const; Vector3 operator*(const Vector3& v) const; Matrix3x3 Transpose() const; Matrix3x3 Inverse() const; float Determinant() const; }; struct Matrix4x4 { float m[4][4]; static Matrix4x4 Identity() { Matrix4x4 result{}; result.m[0][0] = 1.0f; result.m[1][1] = 1.0f; result.m[2][2] = 1.0f; result.m[3][3] = 1.0f; return result; } static Matrix4x4 Zero() { Matrix4x4 result{}; return result; } static Matrix4x4 Translation(const Vector3& v); static Matrix4x4 Rotation(const Quaternion& q); static Matrix4x4 Scale(const Vector3& v); static Matrix4x4 TRS(const Vector3& translation, const Quaternion& rotation, const Vector3& scale); static Matrix4x4 LookAt(const Vector3& eye, const Vector3& target, const Vector3& up); static Matrix4x4 Perspective(float fov, float aspect, float near, float far); static Matrix4x4 Orthographic(float left, float right, float bottom, float top, float near, float far); Matrix4x4 operator*(const Matrix4x4& other) const; Vector4 operator*(const Vector4& v) const; Vector3 MultiplyPoint(const Vector3& v) const; Vector3 MultiplyVector(const Vector3& v) const; Matrix4x4 Transpose() const; Matrix4x4 Inverse() const; float Determinant() const; Vector3 GetTranslation() const; Quaternion GetRotation() const; Vector3 GetScale() const; void Decompose(Vector3& translation, Quaternion& rotation, Vector3& scale) const; }; struct Quaternion { float x, y, z, w; static Quaternion Identity() { return Quaternion{0, 0, 0, 1}; } static Quaternion FromAxisAngle(const Vector3& axis, float radians); static Quaternion FromEulerAngles(float pitch, float yaw, float roll); static Quaternion FromRotationMatrix(const Matrix4x4& matrix); static Quaternion Slerp(const Quaternion& a, const Quaternion& b, float t); static Quaternion LookRotation(const Vector3& forward, const Vector3& up = Vector3::Up()); Vector3 ToEulerAngles() const; Matrix4x4 ToMatrix4x4() const; Vector3 operator*(const Vector3& v) const; Quaternion operator*(const Quaternion& other) const; Quaternion Inverse() const; float Dot(const Quaternion& other) const; }; struct Transform { Vector3 position = Vector3::Zero(); Quaternion rotation = Quaternion::Identity(); Vector3 scale = Vector3::One(); Matrix4x4 ToMatrix() const; Transform Inverse() const; Transform operator*(const Transform& other) const; Vector3 TransformPoint(const Vector3& point) const; Vector3 TransformDirection(const Vector3& direction) const; }; enum class Space { Self, World }; struct Color { float r, g, b, a; static Color White() { return Color{1, 1, 1, 1}; } static Color Black() { return Color{0, 0, 0, 1}; } static Color Red() { return Color{1, 0, 0, 1}; } static Color Green() { return Color{0, 1, 0, 1}; } static Color Blue() { return Color{0, 0, 1, 1}; } static Color Yellow() { return Color{1, 1, 0, 1}; } static Color Cyan() { return Color{0, 1, 1, 1}; } static Color Magenta() { return Color{1, 0, 1, 1}; } static Color Clear() { return Color{0, 0, 0, 0}; } static Color Lerp(const Color& a, const Color& b, float t); }; struct Rect { float x, y, width, height; Rect() : x(0), y(0), width(0), height(0) {} Rect(float x, float y, float w, float h) : x(x), y(y), width(w), height(h) {} float GetLeft() const { return x; } float GetRight() const { return x + width; } float GetTop() const { return y; } float GetBottom() const { return y + height; } Vector2 GetPosition() const { return Vector2{x, y}; } Vector2 GetSize() const { return Vector2{width, height}; } bool Contains(float px, float py) const { return px >= x && px < x + width && py >= y && py < y + height; } }; struct RectInt { int32_t x, y, width, height; RectInt() : x(0), y(0), width(0), height(0) {} RectInt(int32_t x, int32_t y, int32_t w, int32_t h) : x(x), y(y), width(w), height(h) {} }; struct Viewport { float x, y, width, height; float minDepth = 0.0f; float maxDepth = 1.0f; Viewport() : x(0), y(0), width(0), height(0) {} Viewport(float x, float y, float w, float h) : x(x), y(y), width(w), height(h) {} }; struct Ray { Vector3 origin; Vector3 direction; Vector3 GetPoint(float t) const; bool Intersects(const Sphere& sphere, float& t) const; bool Intersects(const Box& box, float& t) const; bool Intersects(const Plane& plane, float& t) const; }; struct Sphere { Vector3 center; float radius; }; struct Box { Vector3 center; Vector3 extents; Matrix4x4 transform; }; struct Plane { Vector3 normal; float distance; }; struct Frustum; struct OBB; struct AABB; } // namespace Math } // namespace XCEngine ``` ### 1.2 内存管理 (Memory Management) ```cpp namespace XCEngine { namespace Memory { class IAllocator { public: virtual ~IAllocator() = default; virtual void* Allocate(size_t size, size_t alignment = 0) = 0; virtual void Free(void* ptr) = 0; virtual void* Reallocate(void* ptr, size_t newSize) = 0; virtual size_t GetTotalAllocated() const = 0; virtual size_t GetTotalFreed() const = 0; virtual size_t GetPeakAllocated() const = 0; virtual size_t GetAllocationCount() const = 0; virtual const char* GetName() const = 0; }; class LinearAllocator : public IAllocator { public: explicit LinearAllocator(size_t size, IAllocator* parent = nullptr); ~LinearAllocator(); void* Allocate(size_t size, size_t alignment = 8) override; void Free(void* ptr) override; void Clear(); void* GetMarker() const; void SetMarker(void* marker); private: byte* m_buffer = nullptr; size_t m_capacity = 0; size_t m_offset = 0; IAllocator* m_parent = nullptr; }; class PoolAllocator : public IAllocator { public: PoolAllocator(size_t blockSize, size_t poolSize, size_t alignment = 8); ~PoolAllocator(); void* Allocate(size_t size, size_t alignment = 0) override; void Free(void* ptr) override; bool Contains(void* ptr) const; size_t GetBlockSize() const { return m_blockSize; } size_t GetFreeBlockCount() const; private: struct FreeNode { FreeNode* next; }; size_t m_blockSize = 0; size_t m_alignment = 0; void* m_memory = nullptr; FreeNode* m_freeList = nullptr; size_t m_totalBlocks = 0; size_t m_freeBlocks = 0; }; class ProxyAllocator : public IAllocator { public: ProxyAllocator(IAllocator* underlying, const char* name); void* Allocate(size_t size, size_t alignment = 0) override; void Free(void* ptr) override; void* Reallocate(void* ptr, size_t newSize) override; struct Stats { size_t totalAllocated; size_t totalFreed; size_t peakAllocated; size_t allocationCount; size_t memoryOverhead; }; const Stats& GetStats() const; private: IAllocator* m_underlying; const char* m_name; Stats m_stats; Mutex m_mutex; }; class MemoryManager { public: static MemoryManager& Get(); void Initialize(); void Shutdown(); IAllocator* GetSystemAllocator(); std::unique_ptr CreateLinearAllocator(size_t size); std::unique_ptr CreatePoolAllocator(size_t blockSize, size_t count); std::unique_ptr CreateProxyAllocator(const char* name); void SetTrackAllocations(bool track); void DumpMemoryLeaks(); void GenerateMemoryReport(); }; #define XE_ALLOC(allocator, size, ...) allocator->Allocate(size, ##__VA_ARGS__) #define XE_FREE(allocator, ptr) allocator->Free(ptr) } // namespace Memory } // namespace XCEngine ``` ### 1.3 容器库 (Containers) ```cpp namespace XCEngine { namespace Containers { template class Array { public: using Iterator = T*; using ConstIterator = const T*; Array() = default; explicit Array(size_t capacity); Array(size_t count, const T& value); Array(std::initializer_list init); ~Array(); Array(const Array& other); Array(Array&& other) noexcept; Array& operator=(const Array& other); Array& operator=(Array&& other) noexcept; T& operator[](size_t index); const T& operator[](size_t index) const; T* Data() { return m_data; } const T* Data() const { return m_data; } size_t Size() const { return m_size; } size_t Capacity() const { return m_capacity; } void Clear(); void PushBack(const T& value); void PushBack(T&& value); template T& EmplaceBack(Args&&... args); void PopBack(); private: T* m_data = nullptr; size_t m_size = 0; size_t m_capacity = 0; IAllocator* m_allocator = nullptr; }; class String { public: String(); String(const char* str); String(const char* str, size_t len); ~String(); String& operator+=(const String& other); String& operator+=(const char* str); String Substring(size_t pos, size_t len = npos) const; String Trim() const; String ToLower() const; String ToUpper() const; size_t Find(const char* str, size_t pos = 0) const; bool StartsWith(const String& prefix) const; bool EndsWith(const String& suffix) const; const char* CStr() const { return m_data; } size_t Length() const { return m_length; } private: char* m_data = nullptr; size_t m_length = 0; size_t m_capacity = 0; }; template class HashMap { public: struct Pair { Key first; Value second; }; HashMap() = default; explicit HashMap(size_t bucketCount, IAllocator* allocator = nullptr); Value& operator[](const Key& key); Value* Find(const Key& key); const Value* Find(const Key& key) const; bool Contains(const Key& key) const; bool Insert(const Key& key, const Value& value); bool Erase(const Key& key); void Clear(); size_t Size() const { return m_size; } private: size_t GetBucketIndex(const Key& key) const; void Resize(); struct Bucket { Array pairs; }; Array m_buckets; size_t m_bucketCount = 0; size_t m_size = 0; float m_loadFactor = 0.75f; IAllocator* m_allocator = nullptr; }; } // namespace Containers } // namespace XCEngine ``` ### 1.4 线程系统 (Threading) ```cpp namespace XCEngine { namespace Threading { enum class TaskPriority : uint8_t { Critical = 0, High = 1, Normal = 2, Low = 3, Idle = 4 }; enum class TaskStatus : uint8_t { Pending, Scheduled, Running, Completed, Failed, Canceled }; template using Func = std::function; class ITask { public: virtual ~ITask() = default; virtual void Execute() = 0; virtual void OnComplete() {} virtual void OnCancel() {} TaskPriority GetPriority() const { return m_priority; } TaskStatus GetStatus() const { return m_status; } uint64 GetId() const { return m_id; } protected: TaskPriority m_priority = TaskPriority::Normal; TaskStatus m_status = TaskStatus::Pending; uint64 m_id = 0; std::atomic m_refCount{1}; }; template class LambdaTask : public ITask { public: explicit LambdaTask(Func&& func, TaskPriority priority = TaskPriority::Normal) : m_func(std::move(func)), m_priority(priority) {} void Execute() override { m_func(); } private: Func m_func; }; class TaskGroup { public: using Callback = std::function; TaskGroup(); ~TaskGroup(); uint64 AddTask(std::unique_ptr task); uint64 AddTask(Func&& func, TaskPriority priority = TaskPriority::Normal); void AddDependency(uint64 taskId, uint64 dependsOn); void Wait(); bool WaitFor(std::chrono::milliseconds timeout); void SetCompleteCallback(Callback&& callback); bool IsComplete() const; float GetProgress() const; }; class TaskSystem { public: static TaskSystem& Get(); void Initialize(const TaskSystemConfig& config); void Shutdown(); uint64 Submit(std::unique_ptr task); uint64 Submit(Func&& func, TaskPriority priority = TaskPriority::Normal); TaskGroup* CreateTaskGroup(); void DestroyTaskGroup(TaskGroup* group); void Wait(uint64 taskId); uint32 GetWorkerThreadCount() const; void Update(); template void ParallelFor(int32 start, int32 end, Func&& func); void RunOnMainThread(Func&& func); }; class Mutex { public: Mutex() = default; ~Mutex() = default; void Lock(); void Unlock(); bool TryLock(); private: std::mutex m_mutex; }; class SpinLock { public: void Lock(); void Unlock(); bool TryLock(); private: std::atomic_flag m_flag = ATOMIC_FLAG_INIT; }; class ReadWriteLock { public: void ReadLock(); void ReadUnlock(); void WriteLock(); void WriteUnlock(); private: std::mutex m_mutex; std::condition_variable m_readCondition; std::condition_variable m_writeCondition; int32_t m_readers = 0; int32_t m_writersWaiting = 0; bool m_writerActive = false; }; class Thread { public: using Id = uint64_t; Thread(); ~Thread(); template void Start(Func&& func, const String& name = "Thread"); void Join(); void Detach(); Id GetId() const { return m_id; } const String& GetName() const { return m_name; } static Id GetCurrentId(); static void Sleep(uint32_t milliseconds); static void Yield(); private: Id m_id = 0; String m_name; std::thread m_thread; }; } // namespace Threading } // namespace XCEngine ``` ### 1.5 日志与调试系统 ```cpp namespace XCEngine { namespace Core { template class Event { public: using Callback = std::function; using Listener = std::pair; using Iterator = typename std::vector::iterator; uint64_t Subscribe(Callback callback) { std::lock_guard lock(m_mutex); uint64_t id = ++m_nextId; m_listeners.emplace_back(id, std::move(callback)); return id; } void Unsubscribe(uint64_t id) { std::lock_guard lock(m_mutex); m_pendingUnsubscribes.push_back(id); } void ProcessUnsubscribes() { std::lock_guard lock(m_mutex); for (uint64_t id : m_pendingUnsubscribes) { m_listeners.erase( std::remove_if(m_listeners.begin(), m_listeners.end(), [id](const auto& pair) { return pair.first == id; }), m_listeners.end() ); } m_pendingUnsubscribes.clear(); } void Invoke(Args... args) const { std::vector listenersCopy; { std::lock_guard lock(m_mutex); if (!m_pendingUnsubscribes.empty()) { for (uint64_t id : m_pendingUnsubscribes) { m_listeners.erase( std::remove_if(m_listeners.begin(), m_listeners.end(), [id](const auto& pair) { return pair.first == id; }), m_listeners.end() ); } m_pendingUnsubscribes.clear(); } listenersCopy = m_listeners; } for (const auto& [id, callback] : listenersCopy) { callback(args...); } } void Clear() { std::lock_guard lock(m_mutex); m_listeners.clear(); } Iterator begin() { return m_listeners.begin(); } Iterator end() { return m_listeners.end(); } private: mutable std::mutex m_mutex; std::vector m_listeners; std::vector m_pendingUnsubscribes; uint64_t m_nextId = 0; }; using int8 = int8_t; using int16 = int16_t; using int32 = int32_t; using int64 = int64_t; using uint8 = uint8_t; using uint16 = uint16_t; using uint32 = uint32_t; using uint64 = uint64_t; using byte = uint8_t; class RefCounted { public: RefCounted() : m_refCount(1) {} virtual ~RefCounted() = default; void AddRef() { ++m_refCount; } void Release() { if (--m_refCount == 0) { delete this; } } uint32_t GetRefCount() const { return m_refCount.load(); } protected: std::atomic m_refCount; }; template using Ref = std::shared_ptr; template using UniqueRef = std::unique_ptr; } // namespace Core } // namespace XCEngine namespace XCEngine { namespace Debug { enum class LogLevel : uint8_t { Verbose = 0, Debug = 1, Info = 2, Warning = 3, Error = 4, Fatal = 5 }; enum class LogCategory { General, Rendering, Physics, Audio, Scripting, Network, Memory, Threading, FileSystem, Custom }; struct LogEntry { LogLevel level; LogCategory category; String message; String file; int32 line; String function; uint64 timestamp; uint32 threadId; }; class ILogSink { public: virtual ~ILogSink() = default; virtual void Log(const LogEntry& entry) = 0; virtual void Flush() = 0; }; class ConsoleLogSink : public ILogSink { public: void Log(const LogEntry& entry) override; void Flush() override; void SetColorOutput(bool enable); void SetMinimumLevel(LogLevel level); }; class FileLogSink : public ILogSink { public: explicit FileLogSink(const String& filePath); ~FileLogSink(); void Log(const LogEntry& entry) override; void Flush() override; private: String m_filePath; FileWriter m_writer; }; class Logger { public: static Logger& Get(); void Initialize(); void Shutdown(); void AddSink(std::unique_ptr sink); void RemoveSink(ILogSink* sink); void Log(LogLevel level, LogCategory category, const String& message, const char* file = nullptr, int32 line = 0, const char* function = nullptr); void Verbose(LogCategory category, const String& message); void Debug(LogCategory category, const String& message); void Info(LogCategory category, const String& message); void Warning(LogCategory category, const String& message); void Error(LogCategory category, const String& message); void Fatal(LogCategory category, const String& message); void SetMinimumLevel(LogLevel level); void SetCategoryEnabled(LogCategory category, bool enabled); }; #define XE_LOG(category, level, message) \ XCEngine::Debug::Logger::Get().Log(level, category, message, __FILE__, __LINE__, __FUNCTION__) #define XE_ASSERT(condition, message) \ if (!(condition)) { \ XCEngine::Debug::Logger::Get().Fatal(XCEngine::Debug::LogCategory::General, message); \ __debugbreak(); \ } class Profiler { public: static Profiler& Get(); void Initialize(); void Shutdown(); void BeginProfile(const char* name); void EndProfile(); void BeginFrame(); void EndFrame(); void MarkEvent(const char* name, uint64_t timestamp, uint32_t threadId); void SetMarker(const char* name, uint32_t color); void ExportChromeTracing(const String& filePath); }; #define XE_PROFILE_BEGIN(name) XCEngine::Debug::Profiler::Get().BeginProfile(name) #define XE_PROFILE_END() XCEngine::Debug::Profiler::Get().EndProfile() #define XE_PROFILE_FUNCTION() XE_PROFILE_BEGIN(__FUNCTION__) } // namespace Debug } // namespace XCEngine ``` --- ## 第二章 组件系统 ### 2.1 组件基类 ```cpp namespace XCEngine { class Scene; class GameObject; class TransformComponent; // 组件类型注册(用于运行时类型识别) class ComponentTypeRegistry { public: static ComponentTypeRegistry& Get(); template static uint32_t GetTypeId() { static uint32_t id = Get().Register(typeid(T).name(), static_cast(-1)); return id; } template static uint32_t GetTypeId(const char* typeName) { static uint32_t id = Get().Register(typeName, static_cast(-1)); return id; } static uint32_t GetTypeIdFromName(const char* typeName) { return Get().GetIdByName(typeName); } static const char* GetTypeName(uint32_t typeId) { return Get().GetNameById(typeId); } private: uint32_t Register(const char* typeName, uint32_t suggestedId); uint32_t GetIdByName(const char* typeName) const; const char* GetNameById(uint32_t typeId) const; std::atomic m_nextTypeId{0}; std::unordered_map m_idToName; std::unordered_map m_nameToId; Mutex m_mutex; }; // 组件基类(类Unity MonoBehaviour) class Component { public: Component(); virtual ~Component(); GameObject* gameObject() const { return m_gameObject; } TransformComponent& transform() const { return m_gameObject->GetTransform(); } bool IsEnabled() const { return m_enabled; } void SetEnabled(bool enabled) { m_enabled = enabled; } Scene* GetScene() const; template T* GetComponent() const { return m_gameObject->GetComponent(); } template std::vector GetComponents() const { return m_gameObject->GetComponents(); } virtual void Awake() {} virtual void Start() {} virtual void Update(float deltaTime) {} virtual void FixedUpdate() {} virtual void LateUpdate(float deltaTime) {} virtual void OnDestroy() {} virtual void OnEnable() {} virtual void OnDisable() {} protected: GameObject* m_gameObject = nullptr; bool m_enabled = true; friend class GameObject; }; } // namespace XCEngine ``` ### 2.2 Transform组件 ```cpp namespace XCEngine { class TransformComponent : public Component { public: Vector3 GetLocalPosition() const { return m_localPosition; } void SetLocalPosition(const Vector3& position) { m_localPosition = position; SetDirty(); } Quaternion GetLocalRotation() const { return m_localRotation; } void SetLocalRotation(const Quaternion& rotation) { m_localRotation = rotation; SetDirty(); } Vector3 GetLocalScale() const { return m_localScale; } void SetLocalScale(const Vector3& scale) { m_localScale = scale; SetDirty(); } Vector3 GetPosition() const; void SetPosition(const Vector3& position); Quaternion GetRotation() const; void SetRotation(const Quaternion& rotation); Vector3 GetScale() const; void SetScale(const Vector3& scale); Vector3 GetForward() const { return GetRotation() * Vector3::Forward(); } Vector3 GetRight() const { return GetRotation() * Vector3::Right(); } Vector3 GetUp() const { return GetRotation() * Vector3::Up(); } const Matrix4x4& GetLocalToWorldMatrix() const; Matrix4x4 GetWorldToLocalMatrix() const; TransformComponent* GetParent() const { return m_parent; } void SetParent(TransformComponent* parent, bool worldPositionStays = true); int GetChildCount() const { return static_cast(m_children.size()); } TransformComponent* GetChild(int index) const; TransformComponent* Find(const String& name) const; void DetachChildren(); void SetAsFirstSibling(); void SetAsLastSibling(); void SetSiblingIndex(int index); int GetSiblingIndex() const; void LookAt(const Vector3& target); void LookAt(const Vector3& target, const Vector3& up); void Rotate(const Vector3& eulers); void Rotate(const Vector3& axis, float angle); void Translate(const Vector3& translation); void Translate(const Vector3& translation, Math::Space relativeTo); Vector3 TransformPoint(const Vector3& point) const; Vector3 InverseTransformPoint(const Vector3& point) const; Vector3 TransformDirection(const Vector3& direction) const; Vector3 InverseTransformDirection(const Vector3& direction) const; void SetDirty() { m_dirty = true; } private: Vector3 m_localPosition = Vector3::Zero(); Quaternion m_localRotation = Quaternion::Identity(); Vector3 m_localScale = Vector3::One(); TransformComponent* m_parent = nullptr; std::vector m_children; mutable Matrix4x4 m_localToWorldMatrix; mutable Matrix4x4 m_worldToLocalMatrix; mutable Vector3 m_worldPosition; mutable Quaternion m_worldRotation; mutable Vector3 m_worldScale; mutable bool m_dirty = true; void UpdateWorldTransform() const; friend class GameObject; }; } // namespace XCEngine ``` ### 2.3 GameObject ```cpp namespace XCEngine { class Scene; class GameObject { public: GameObject(); ~GameObject(); struct ConstructParams { String name = "GameObject"; GameObject* parent = nullptr; bool active = true; }; static GameObject* Create(const ConstructParams& params = {}); static void Destroy(GameObject* obj); String name; bool active = true; TransformComponent& GetTransform() { return *m_transform; } const TransformComponent& GetTransform() const { return *m_transform; } Scene* GetScene() const { return m_scene; } template T* AddComponent(); template void RemoveComponent(); template T* GetComponent() const; template std::vector GetComponents() const; template T* GetComponentInChildren() const; template std::vector GetComponentsInChildren() const; template T* GetComponentInParent() const; GameObject* GetParent() const; void SetParent(GameObject* parent); void SetParent(GameObject* parent, bool worldPositionStays); const std::vector& GetChildren() const; GameObject* GetChild(int index) const; int GetChildCount() const; int GetSiblingIndex() const; void SetSiblingIndex(int index); void SetActive(bool active); bool IsActive() const; bool IsActiveInHierarchy() const; static GameObject* Find(const String& name); static std::vector FindObjectsOfType(); static std::vector FindGameObjectsWithTag(const String& tag); void Destroy(); private: void AddComponentInternal(Component* component); void RemoveComponentInternal(Component* component); std::vector> m_components; std::unordered_map m_componentTypeIndex; std::vector m_children; GameObject* m_parent = nullptr; Scene* m_scene = nullptr; std::unique_ptr m_transform; void Initialize(const ConstructParams& params); friend class Scene; friend class TransformComponent; }; inline GameObject::GameObject() { } inline GameObject::~GameObject() { for (auto* child : m_children) { delete child; } } inline GameObject* GameObject::Create(const ConstructParams& params) { GameObject* obj = new GameObject(); obj->Initialize(params); return obj; } inline void GameObject::Destroy(GameObject* obj) { delete obj; } inline void GameObject::Initialize(const ConstructParams& params) { name = params.name; active = params.active; m_transform = std::make_unique(); m_transform->m_gameObject = this; if (params.parent) { params.parent->m_children.push_back(this); m_parent = params.parent; } } inline void GameObject::Destroy() { if (m_scene) { m_scene->DestroyGameObject(this); } else { delete this; } } inline GameObject* GameObject::Find(const String& name) { return SceneManager::Get().GetActiveScene()->Find(name); } inline std::vector GameObject::FindObjectsOfType() { return SceneManager::Get().GetActiveScene()->FindObjectsOfType(); } inline std::vector GameObject::FindGameObjectsWithTag(const String& tag) { return SceneManager::Get().GetActiveScene()->FindGameObjectsWithTag(tag); } } // namespace XCEngine ``` --- ## 第三章 场景系统 ### 3.1 Scene ```cpp namespace XCEngine { class Scene { public: Scene(); ~Scene(); const String& GetName() const { return m_name; } void SetName(const String& name) { m_name = name; } GameObject* CreateGameObject(const String& name = "GameObject") { GameObject::ConstructParams params; params.name = name; params.parent = nullptr; params.active = true; GameObject* obj = GameObject::Create(params); obj->m_scene = this; AddGameObject(obj); return obj; } GameObject* CreateGameObject(const String& name, GameObject* parent) { GameObject::ConstructParams params; params.name = name; params.parent = parent; params.active = true; GameObject* obj = GameObject::Create(params); obj->m_scene = this; AddGameObject(obj); return obj; } void DestroyGameObject(GameObject* obj); std::vector GetRootGameObjects() const { std::vector roots; roots.reserve(m_gameObjects.size() / 2); for (auto& obj : m_gameObjects) { if (obj->GetParent() == nullptr) { roots.push_back(obj.get()); } } return roots; } GameObject* Find(const String& name) const; GameObject* FindGameObjectWithTag(const String& tag) const; std::vector FindGameObjectsWithTag(const String& tag) const; template std::vector FindObjectsOfType() const; template T* FindObjectOfType() const; bool IsActive() const { return m_isActive; } void SetActive(bool active); void Load(const String& filePath); void LoadAsync(const String& filePath, std::function callback); void Save(const String& filePath); void Update(float deltaTime); void FixedUpdate(float fixedDeltaTime); void LateUpdate(float deltaTime); void DebugDraw(); int GetObjectCount() const { return m_gameObjects.size(); } private: void AddGameObject(GameObject* obj); void RemoveGameObject(GameObject* obj); String m_name; std::vector> m_gameObjects; bool m_isActive = true; friend class GameObject; friend class SceneManager; }; class SceneManager { public: static SceneManager& Get(); void Initialize(); void Shutdown(); Scene* CreateScene(const String& name); void LoadScene(const String& filePath); void LoadSceneAsync(const String& filePath, std::function callback); void UnloadScene(Scene* scene); void UnloadScene(const String& sceneName); void SetActiveScene(Scene* scene); void SetActiveScene(const String& sceneName); Scene* GetActiveScene() const; Scene* GetScene(const String& name) const; std::vector GetAllScenes() const; void Update(float deltaTime); void FixedUpdate(float fixedDeltaTime); void LateUpdate(float deltaTime); Event OnSceneLoaded; Event OnSceneUnloaded; Event OnActiveSceneChanged; private: SceneManager() = default; std::vector> m_scenes; Scene* m_activeScene = nullptr; Scene* m_loadingScene = nullptr; std::unordered_map m_sceneNameMap; std::function m_loadCallback; bool m_loading = false; }; // GameObject创建辅助类 class GameObjectBuilder { public: explicit GameObjectBuilder(const String& name = "GameObject"); ~GameObjectBuilder() = default; template GameObjectBuilder& AddComponent(Args&&... args); GameObject* Build(); private: String m_name; std::vector> m_components; }; } // namespace XCEngine ``` --- ## 第四章 渲染系统 > **借鉴 Unity 渲染架构设计** ### 4.0 公共类型定义 ```cpp namespace XCEngine { namespace Rendering { // ============================================ // 前置类型定义 - 资源基类 // ============================================ enum class ResourceLoadState { Undefined, Unloaded, Loading, Loaded, Unloading, Failed }; enum class ResourceType { Mesh, Texture, Shader, Material, ComputeBuffer, GraphicsBuffer, Sampler, RenderTarget, DepthStencil, VertexBuffer, IndexBuffer, Unknown }; class IResource { public: virtual ~IResource() = default; virtual void SetName(const std::string& name) { m_name = name; } virtual const std::string& GetName() const { return m_name; } virtual ResourceType GetType() const = 0; virtual ResourceLoadState GetLoadState() const { return m_loadState; } virtual bool IsValid() const { return m_loadState == ResourceLoadState::Loaded; } virtual void Load() = 0; virtual void Unload() = 0; virtual int GetRefCount() const { return m_refCount.load(); } virtual void AddRef() { m_refCount.fetch_add(1); } virtual void Release() { if (m_refCount.fetch_sub(1) == 1) { delete this; } } protected: IResource() : m_loadState(ResourceLoadState::Unloaded), m_memoryUsage(0) {} std::string m_name; ResourceLoadState m_loadState; uint64_t m_memoryUsage; std::atomic m_refCount{1}; }; // ============================================ // 缓冲区类型定义 // ============================================ class VertexBuffer : public IResource { public: ResourceType GetType() const override { return ResourceType::VertexBuffer; } void Load() override {} void Unload() override {} uint32_t GetVertexCount() const { return m_vertexCount; } uint32_t GetStride() const { return m_stride; } uint64_t GetSize() const { return m_size; } void SetData(const void* data, uint64_t size); void* Map(); void Unmap(); private: uint32_t m_vertexCount = 0; uint32_t m_stride = 0; uint64_t m_size = 0; void* m_nativeHandle = nullptr; }; class IndexBuffer : public IResource { public: ResourceType GetType() const override { return ResourceType::IndexBuffer; } void Load() override {} void Unload() override {} uint32_t GetIndexCount() const { return m_indexCount; } bool Is32Bit() const { return m_is32Bit; } uint64_t GetSize() const { return m_size; } void SetData(const void* data, uint64_t size); void* Map(); void Unmap(); private: uint32_t m_indexCount = 0; bool m_is32Bit = false; uint64_t m_size = 0; void* m_nativeHandle = nullptr; }; // ============================================ // 渲染目标类型定义 // ============================================ struct RenderTargetDesc { uint32_t width = 0; uint32_t height = 0; Format format = Format::R8G8B8A8_UNorm; SampleCount sampleCount = SampleCount::Count1; uint32_t mipLevels = 1; uint32_t arraySize = 1; bool enableUAV = false; String name; }; class RenderTarget : public IResource { public: ResourceType GetType() const override { return ResourceType::RenderTarget; } void Load() override {} void Unload() override {} uint32_t GetWidth() const { return m_width; } uint32_t GetHeight() const { return m_height; } Format GetFormat() const { return m_format; } void* GetNativeHandle() const { return m_nativeHandle; } IShaderResourceView* GetSRV() { return m_srv.get(); } IRenderTargetView* GetRTV() { return m_rtv.get(); } private: uint32_t m_width = 0; uint32_t m_height = 0; Format m_format; void* m_nativeHandle = nullptr; std::unique_ptr m_srv; std::unique_ptr m_rtv; }; struct DepthStencilDesc { uint32_t width = 0; uint32_t height = 0; Format format = Format::D24_UNorm_S8_UInt; SampleCount sampleCount = SampleCount::Count1; bool bindAsShaderResource = false; String name; }; class DepthStencil : public IResource { public: ResourceType GetType() const override { return ResourceType::DepthStencil; } void Load() override {} void Unload() override {} uint32_t GetWidth() const { return m_width; } uint32_t GetHeight() const { return m_height; } Format GetFormat() const { return m_format; } void* GetNativeHandle() const { return m_nativeHandle; } IDepthStencilView* GetDSV() { return m_dsv.get(); } IShaderResourceView* GetSRV() { return m_srv.get(); } private: uint32_t m_width = 0; uint32_t m_height = 0; Format m_format; void* m_nativeHandle = nullptr; std::unique_ptr m_dsv; std::unique_ptr m_srv; }; // ============================================ // 渲染通道描述 // ============================================ struct RenderPassAttachmentDesc { RenderTarget* renderTarget = nullptr; DepthStencil* depthStencil = nullptr; LoadAction loadAction = LoadAction::Clear; StoreAction storeAction = StoreAction::Store; Color clearColor = Color::Black(); float clearDepth = 1.0f; uint8_t clearStencil = 0; }; struct RenderPassDesc { RenderPassAttachmentDesc* colorAttachments = nullptr; uint32_t colorAttachmentCount = 0; RenderPassAttachmentDesc* depthStencilAttachment = nullptr; Rect viewport; Rect scissor; }; // ============================================ // 基础枚举类型 // ============================================ enum class Format { Unknown = 0, R8_UNorm = 61, R8G8_UNorm = 49, R8G8B8A8_UNorm = 28, R16G16B16A16_Float = 10, R32G32B32A32_Float = 2, R16_Float = 54, R32_Float = 41, D16_UNorm = 55, D24_UNorm_S8_UInt = 45, D32_Float = 40, BC1_UNorm = 71, BC2_UNorm = 74, BC3_UNorm = 77, BC4_UNorm = 80, BC5_UNorm = 83, BC6H_UF16 = 95, BC7_UNorm = 98 }; enum class SampleCount : uint32_t { Count1 = 1, Count2 = 2, Count4 = 4, Count8 = 8 }; enum class CubemapFace : uint8_t { PositiveX = 0, NegativeX = 1, PositiveY = 2, NegativeY = 3, PositiveZ = 4, NegativeZ = 5 }; struct Frustum { Plane planes[6]; bool Contains(const Vector3& point) const; bool Contains(const Sphere& sphere) const; bool Contains(const Bounds& bounds) const; bool Intersects(const Bounds& bounds) const; }; enum class FilterMode { Point = 0, Bilinear = 1, Trilinear = 2 }; enum class TextureWrapMode { Repeat = 0, Clamp = 1, Mirror = 2, MirrorOnce = 3 }; enum class MeshTopology { Points, Lines, LineStrip, Triangles, TriangleStrip, Quads }; struct Bounds { Vector3 center; Vector3 extents; Vector3 min; Vector3 max; Bounds() : center(Vector3::Zero()), extents(Vector3::Zero()) {} Bounds(const Vector3& center, const Vector3& size) : center(center), extents(size * 0.5f) { min = center - extents; max = center + extents; } void SetMinMax(const Vector3& min, const Vector3& max) { this->min = min; this->max = max; center = (min + max) * 0.5f; extents = (max - min) * 0.5f; } bool Intersects(const Bounds& other) const; bool Contains(const Vector3& point) const; void Encapsulate(const Vector3& point); void Encapsulate(const Bounds& bounds); void Expand(float amount); void Expand(const Vector3& amount); Vector3 GetClosestPoint(const Vector3& point) const; }; struct QualityLevel { enum { Fastest = 0, Fast = 1, Simple = 2, Good = 3, High = 4, Ultra = 5 }; }; class StringView { public: StringView() : m_data(nullptr), m_length(0) {} StringView(const char* str); StringView(const char* str, size_t len); StringView(const String& str); const char* Data() const { return m_data; } size_t Length() const { return m_length; } bool Empty() const { return m_length == 0; } char operator[](size_t index) const { return m_data[index]; } int Compare(const StringView& other) const; bool operator==(const StringView& other) const; bool operator!=(const StringView& other) const; private: const char* m_data; size_t m_length; }; class Texture { public: virtual ~Texture() = default; uint32_t GetWidth() const { return m_width; } uint32_t GetHeight() const { return m_height; } uint32_t GetDepth() const { return m_depth; } uint32_t GetMipLevels() const { return m_mipLevels; } Format GetFormat() const { return m_format; } FilterMode GetFilterMode() const { return m_filterMode; } void SetFilterMode(FilterMode mode) { m_filterMode = mode; } TextureWrapMode GetWrapMode() const { return m_wrapMode; } void SetWrapMode(TextureWrapMode mode) { m_wrapMode = mode; } void* GetNativeHandle() const { return m_nativeHandle; } protected: uint32_t m_width = 0; uint32_t m_height = 0; uint32_t m_depth = 1; uint32_t m_mipLevels = 1; Format m_format = Format::R8G8B8A8_UNorm; FilterMode m_filterMode = FilterMode::Bilinear; TextureWrapMode m_wrapMode = TextureWrapMode::Clamp; void* m_nativeHandle = nullptr; }; class RenderTargetIdentifier { public: RenderTargetIdentifier(); RenderTargetIdentifier(int nameID); RenderTargetIdentifier(const String& name); RenderTargetIdentifier(Texture* texture); bool IsValid() const { return m_type != Buffer || m_nameID != -1; } bool operator==(const RenderTargetIdentifier& other) const; bool operator!=(const RenderTargetIdentifier& other) const { return !(*this == other); } int GetType() const { return m_type; } int GetNameID() const { return m_nameID; } Texture* GetTexture() const { return m_texture; } private: int m_type = Buffer; int m_nameID = -1; Texture* m_texture = nullptr; enum { Buffer, Texture2D, RenderTarget }; }; class CommandBuffer { public: CommandBuffer(); ~CommandBuffer(); void Clear(); void BeginSample(const char* name); void EndSample(const char* name); void BeginDebugGroup(const char* name); void EndDebugGroup(); void SetRenderTarget( RenderTargetIdentifier colorTarget, RenderTargetIdentifier depthTarget, int mipLevel = 0, CubemapFace cubemapFace = CubemapFace::PositiveX, bool depthIsWritable = true ); void SetRenderTarget( const std::vector& colorTargets, RenderTargetIdentifier depthTarget, int mipLevel = 0, CubemapFace cubemapFace = CubemapFace::PositiveX, bool depthIsWritable = true ); void SetViewport(const Rect& rect); void SetScissor(const Rect& rect); void SetViewMatrix(const Matrix4x4& matrix); void SetProjectionMatrix(const Matrix4x4& matrix); void DrawMeshInstanced( const Mesh& mesh, int submeshIndex, Material* material, int shaderPass, const std::vector& matrices ); void DrawMeshInstancedIndirect( const Mesh& mesh, int submeshIndex, Material* material, int shaderPass, const ComputeBuffer& argsBuffer, int argsOffset ); void DrawProcedural( Material* material, int shaderPass, MeshTopology topology, int vertexCount, int instanceCount ); void Blit( Material* material, int pass, RenderTargetIdentifier source, RenderTargetIdentifier dest ); void CopyTexture( RenderTargetIdentifier source, RenderTargetIdentifier dest ); void GetTemporaryRT( const String& name, int width, int height, Format format = Format::R8G8B8A8_UNorm, FilterMode filter = FilterMode::Bilinear, TextureWrapMode wrap = TextureWrapMode::Clamp, int depthBufferBits = 0 ); void ReleaseTemporaryRT(const String& name); void GetCommandBufferPtr(void** ptr); private: std::vector m_data; std::vector m_sampleNames; int m_sampleDepth = 0; }; class Mesh : public IResource { public: Mesh(); ~Mesh(); void SetVertices(const std::vector& vertices); void SetNormals(const std::vector& normals); void SetTangents(const std::vector& tangents); void SetUVs(int channel, const std::vector& uvs); void SetUVs(int channel, const std::vector& uvs); void SetTriangles(const std::vector& triangles, int submesh); void SetIndices(const std::vector& indices, int submesh); void SetIndices(const std::vector& indices, int submesh); const std::vector& GetVertices() const { return m_vertices; } const std::vector& GetNormals() const { return m_normals; } const std::vector& GetTangents() const { return m_tangents; } int GetSubmeshCount() const { return m_submeshes.size(); } const struct SubmeshDescriptor& GetSubmesh(int index) const; int GetVertexCount() const { return static_cast(m_vertices.size()); } int GetIndexCount(int submesh) const; MeshTopology GetTopology(int submesh) const; void SetTopology(MeshTopology topology, int submesh); void RecalculateNormals(); void RecalculateTangents(); void RecalculateBounds(); void Optimize(); bool IsUse32BitIndexBuffer() const { return m_use32BitIndex; } struct MeshData { std::vector vertices; std::vector normals; std::vector tangents; std::vector uvs[8]; std::vector indices32; std::vector indices16; }; void GetMeshData(MeshData& data) const; private: std::vector m_vertices; std::vector m_normals; std::vector m_tangents; std::vector m_uvs[8]; struct SubmeshDescriptor { int indexStart; int indexCount; int baseVertex; MeshTopology topology; }; std::vector m_submeshes; Bounds m_bounds; bool m_use32BitIndex = false; bool m_hasVertices = false; bool m_hasNormals = false; bool m_hasTangents = false; friend class MeshCollider; friend class SkinnedMeshRenderer; }; class ComputeBuffer : public IResource { public: enum class Type { Default, Raw, Append, Counter, Structured, ByteAddress }; ComputeBuffer(Type type, int count, int stride); ~ComputeBuffer(); int GetCount() const { return m_count; } int GetStride() const { return m_stride; } Type GetType() const { return m_type; } void SetData(const void* data); void GetData(void* data) const; void SetCounterValue(uint32_t value); uint32_t GetCounterValue() const; private: Type m_type; int m_count; int m_stride; void* m_buffer; }; class GraphicsBuffer : public IResource { public: enum class Target { Constant, IndexBuffer, VertexBuffer, Structured, Append, Counter, ReadWrite }; GraphicsBuffer(Target target, uint32_t count, uint32_t stride); virtual ~GraphicsBuffer(); Target GetTarget() const { return m_target; } uint32_t GetCount() const { return m_count; } uint32_t GetStride() const { return m_stride; } uint64_t GetSize() const { return m_size; } void SetData(const void* data); void GetData(void* data) const; void* Map(); void Unmap(); void SetCounterValue(uint32_t value); uint32_t GetCounterValue() const; private: Target m_target; uint32_t m_count = 0; uint32_t m_stride = 0; uint64_t m_size = 0; void* m_buffer; }; struct ShaderProgramDesc { enum class Stage { Vertex, Fragment, Compute, Geometry, Hull, Domain }; Stage stage; String source; String entryPoint; bool debug = false; bool optimize = true; }; } // namespace Rendering } // namespace XCEngine ``` ### 4.1 RHI 抽象层接口 ```cpp namespace XCEngine { namespace RHI { // ============================================ // 跨平台枚举类型 - 不暴露平台特定类型 // ============================================ enum class GraphicsAPI { Unknown, Direct3D11, Direct3D12, Vulkan, Metal, OpenGL }; enum class CommandListType { Direct, Compute, Copy, Bundle }; enum class ShaderVisibility { All = 0, Vertex = 1, Hull = 2, Domain = 3, Geometry = 4, Pixel = 5, Amplification = 6, Mesh = 7 }; enum class ResourceStateFlag : uint32_t { Common = 0, VertexBuffer = 1 << 0, ConstantBuffer = 1 << 1, IndexBuffer = 1 << 2, RenderTarget = 1 << 3, UnorderedAccess = 1 << 4, DepthWrite = 1 << 5, DepthRead = 1 << 6, ShaderResource = 1 << 7, IndirectArgument = 1 << 8, CopyDest = 1 << 9, CopySource = 1 << 10, ResolveDest = 1 << 11, ResolveSource = 1 << 12, Present = 1 << 13, RaytracingAccelerationStructure = 1 << 14, ShadingRateSource = 1 << 15 }; inline ResourceStateFlag operator|(ResourceStateFlag a, ResourceStateFlag b) { return static_cast(static_cast(a) | static_cast(b)); } inline ResourceStateFlag operator&(ResourceStateFlag a, ResourceStateFlag b) { return static_cast(static_cast(a) & static_cast(b)); } enum class DescriptorHeapType { CBV_SRV_UAV, Sampler, RTV, DSV }; enum class QueryType { Occlusion, Timestamp, PipelineStatistics }; // ============================================ // 描述结构体 // ============================================ struct CommandQueueDesc { CommandListType type = CommandListType::Direct; int priority = 0; const char* name = nullptr; }; struct DescriptorHeapDesc { DescriptorHeapType type; uint32_t count; bool shaderVisible; const char* name; }; struct QueryHeapDesc { QueryType type; uint32_t count; const char* name; }; struct SwapChainDesc { uint32_t width; uint32_t height; Format format; uint32_t bufferCount; bool vsync; bool fullscreen; }; class ICommandQueue { public: virtual ~ICommandQueue() = default; virtual void ExecuteCommandLists(ICommandList** lists, uint32_t count) = 0; virtual void Signal(IFence* fence, uint64_t value) = 0; virtual void Wait(IFence* fence, uint64_t value) = 0; virtual uint64_t GetTimestampFrequency() const = 0; }; class ICommandAllocator { public: virtual ~ICommandAllocator() = default; virtual void Reset() = 0; }; class IFence { public: virtual ~IFence() = default; virtual uint64_t GetCompletedValue() const = 0; virtual void Signal(uint64_t value) = 0; virtual void Wait(uint64_t value) = 0; virtual void Wait(uint64_t value, uint64_t timeoutMs) = 0; }; class IDescriptorHeap { public: virtual ~IDescriptorHeap() = default; virtual DescriptorHeapType GetType() const = 0; virtual uint32_t GetDescriptorCount() const = 0; virtual void* GetCPUDescriptorHandle(uint32_t index) const = 0; virtual uint64_t GetGPUDescriptorHandle(uint32_t index) const = 0; virtual void SetName(const String& name) = 0; }; class IQueryHeap { public: virtual ~IQueryHeap() = default; virtual QueryType GetType() const = 0; virtual uint32_t GetCount() const = 0; virtual void Begin(ICommandList* cmdList, uint32_t index) = 0; virtual void End(ICommandList* cmdList, uint32_t index) = 0; virtual void GetData(uint32_t index, void* data, uint32_t dataSize) = 0; }; class ISwapChain { public: virtual ~ISwapChain() = default; virtual bool Initialize(const SwapChainDesc& desc, void* windowHandle) = 0; virtual void Shutdown() = 0; virtual bool Present() = 0; virtual bool Resize(uint32_t width, uint32_t height) = 0; virtual uint32_t GetCurrentBufferIndex() const = 0; virtual RenderTexture* GetBuffer(uint32_t index) = 0; virtual void SetFullscreen(bool fullscreen) = 0; virtual bool IsFullscreen() const = 0; }; struct RootParameter { enum class Type { DescriptorTable, Constants, CBV, SRV, UAV, Sampler }; Type type; uint32_t shaderRegister; uint32_t registerSpace; ShaderVisibility visibility = ShaderVisibility::All; }; struct RootSignatureDesc { RootParameter* parameters; uint32_t parameterCount; uint32_t flags; }; class RootSignature { public: virtual ~RootSignature() = default; virtual bool Initialize(const RootSignatureDesc& desc) = 0; virtual void SetName(const String& name) = 0; }; struct PipelineDesc { RootSignature* rootSignature; Shader* vertexShader; Shader* pixelShader; Shader* computeShader; RenderState renderState; uint32_t numRenderTargets; Format rtvFormats[8]; Format dsvFormat; }; class PipelineStateObject { public: virtual ~PipelineStateObject() = default; virtual void SetName(const String& name) = 0; }; class ICommandList { public: virtual ~ICommandList() = default; virtual void Reset(ICommandAllocator* allocator) = 0; virtual void Close() = 0; virtual void BeginRenderPass(const RenderPassDesc& desc) = 0; virtual void EndRenderPass() = 0; virtual void SetPipelineState(PipelineStateObject* pso) = 0; virtual void SetRootSignature(RootSignature* signature) = 0; virtual void SetVertexBuffer(uint32_t slot, VertexBuffer* buffer, uint32_t offset = 0) = 0; virtual void SetIndexBuffer(IndexBuffer* buffer, uint32_t offset = 0) = 0; virtual void SetDescriptorHeap(IDescriptorHeap* heap) = 0; virtual void SetGraphicsDescriptorTable(uint32_t rootParameterIndex, uint64_t baseDescriptor) = 0; virtual void SetComputeDescriptorTable(uint32_t rootParameterIndex, uint64_t baseDescriptor) = 0; virtual void DrawInstanced(uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertex, uint32_t startInstance) = 0; virtual void DrawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndex, int32_t baseVertex, uint32_t startInstance) = 0; virtual void Dispatch(uint32_t x, uint32_t y, uint32_t z) = 0; virtual void SetViewports(const Viewport* viewports, uint32_t count) = 0; virtual void SetScissorRects(const Rect* rects, uint32_t count) = 0; virtual void SetRenderTargets(const RenderTarget* const* targets, uint32_t count, const DepthStencil* depthStencil) = 0; virtual void ClearRenderTargetView(const RenderTarget* target, const float color[4]) = 0; virtual void ClearDepthStencilView(const DepthStencil* depth, float depthValue, uint8_t stencil) = 0; virtual void CopyResource(IResource* dst, const IResource* src) = 0; virtual void CopyBuffer(IResource* dst, uint64_t dstOffset, const IResource* src, uint64_t srcOffset, uint64_t size) = 0; virtual void ResourceBarrier(IResource* resource, ResourceStateFlag before, ResourceStateFlag after) = 0; }; class IShaderResourceView { public: virtual ~IShaderResourceView() = default; }; class IRenderTargetView { public: virtual ~IRenderTargetView() = default; }; class IDepthStencilView { public: virtual ~IDepthStencilView() = default; }; class IRHIDevice { public: virtual ~IRHIDevice() = default; virtual GraphicsAPI GetAPI() const = 0; virtual const char* GetAPIName() const = 0; virtual bool Initialize() = 0; virtual void Shutdown() = 0; virtual bool CreateCommandQueue(ICommandQueue** queue, const CommandQueueDesc& desc) = 0; virtual bool CreateCommandAllocator(ICommandAllocator** allocator) = 0; virtual bool CreateCommandList(ICommandList** list, ICommandAllocator* allocator) = 0; virtual bool CreateFence(IFence** fence) = 0; virtual bool CreateDescriptorHeap(IDescriptorHeap** heap, const DescriptorHeapDesc& desc) = 0; virtual bool CreateQueryHeap(IQueryHeap** heap, const QueryHeapDesc& desc) = 0; virtual bool CreateRootSignature(RootSignature** signature, const RootSignatureDesc& desc) = 0; virtual bool CreatePipelineState(PipelineStateObject** pso, const PipelineDesc& desc) = 0; virtual bool CreateSwapChain(ISwapChain** swapChain, const SwapChainDesc& desc, void* windowHandle) = 0; virtual bool CreateRenderTarget(RenderTarget** target, const RenderTargetDesc& desc) = 0; virtual bool CreateDepthStencil(DepthStencil** depthStencil, const DepthStencilDesc& desc) = 0; virtual void* GetNativeDevice() const = 0; }; } // namespace RHI } // namespace XCEngine ``` ### 4.3 Direct3D 12 特有的 RHI 实现 ```cpp // ============================================ // D3D12 前向声明 // ============================================ struct ID3D12Device; struct ID3D12CommandQueue; struct ID3D12CommandAllocator; struct ID3D12GraphicsCommandList; struct ID3D12DescriptorHeap; struct ID3D12RootSignature; struct ID3D12PipelineState; struct ID3D12Fence; struct ID3D12QueryHeap; struct IDXGISwapChain3; template class ComPtr; namespace XCEngine { namespace RHI { namespace D3D12 { enum class D3D12_COMMAND_LIST_TYPE { DIRECT = 0, BUNDLE = 1, COMPUTE = 2, COPY = 3 }; enum class D3D12_DESCRIPTOR_HEAP_TYPE { CBV_SRV_UAV = 0, SAMPLER = 1, RTV = 2, DSV = 3, NUM_TYPES = 4 }; enum class D3D12_DESCRIPTOR_HEAP_FLAGS { NONE = 0, SHADER_VISIBLE = 1 }; enum class D3D12_RESOURCE_STATES { COMMON = 0, VERTEX_AND_CONSTANT_BUFFER = 0x1, INDEX_BUFFER = 0x2, RENDER_TARGET = 0x4, UNORDERED_ACCESS = 0x8, DEPTH_WRITE = 0x10, DEPTH_READ = 0x20, NON_PIXEL_SHADER_RESOURCE = 0x40, PIXEL_SHADER_RESOURCE = 0x80, STREAM_OUT = 0x100, INDIRECT_ARGUMENT = 0x200, COPY_DEST = 0x400, COPY_SOURCE = 0x800, RESOLVE_DEST = 0x1000, RESOLVE_SOURCE = 0x2000, RAYTRACING_ACCELERATION_STRUCTURE = 0x4000, SHADING_RATE_COARSE = 0x8000, SHADING_RATE_FINE = 0x10000, PRESENT = 0x0 }; enum class D3D12_SRV_DIMENSION { UNKNOWN = 0, BUFFER = 1, TEXTURE1D = 2, TEXTURE1DARRAY = 3, TEXTURE2D = 4, TEXTURE2DARRAY = 5, TEXTURE2DMS = 6, TEXTURE2DMSARRAY = 7, TEXTURE3D = 8, TEXTURECUBE = 9, TEXTURECUBEARRAY = 10 }; enum class D3D12_UAV_DIMENSION { UNKNOWN = 0, BUFFER = 1, TEXTURE1D = 2, TEXTURE1DARRAY = 3, TEXTURE2D = 4, TEXTURE2DARRAY = 5, TEXTURE3D = 8 }; enum class D3D12_RTV_DIMENSION { UNKNOWN = 0, BUFFER = 1, TEXTURE1D = 2, TEXTURE1DARRAY = 3, TEXTURE2D = 4, TEXTURE2DARRAY = 5, TEXTURE2DMS = 6, TEXTURE2DMSARRAY = 7, TEXTURE3D = 8 }; enum class D3D12_DSV_DIMENSION { UNKNOWN = 0, TEXTURE1D = 1, TEXTURE1DARRAY = 2, TEXTURE2D = 3, TEXTURE2DARRAY = 4, TEXTURE2DMS = 5, TEXTURE2DMSARRAY = 6 }; enum class D3D12_ROOT_SIGNATURE_FLAGS { NONE = 0, ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT = 0x1, DENY_VERTEX_SHADER_ROOT_ACCESS = 0x2, DENY_HULL_SHADER_ROOT_ACCESS = 0x4, DENY_DOMAIN_SHADER_ROOT_ACCESS = 0x8, DENY_GEOMETRY_SHADER_ROOT_ACCESS = 0x10, DENY_PIXEL_SHADER_ROOT_ACCESS = 0x20, ALLOW_STREAM_PIPELINE = 0x40, LOCAL_ROOT_SIGNATURE = 0x80 }; enum class D3D12_ROOT_PARAMETER_TYPE { DESCRIPTOR_TABLE = 0, _32BIT_CONSTANTS = 1, CBV = 2, SRV = 3, UAV = 4, SAMPLER = 5 }; enum class D3D12_SHADER_VISIBILITY { ALL = 0, VERTEX = 1, HULL = 2, DOMAIN = 3, GEOMETRY = 4, PIXEL = 5 }; enum class D3D12_FILTER { MIN_MAG_MIP_POINT = 0, MIN_MAG_POINT_MIP_LINEAR = 0x1, MIN_POINT_MAG_LINEAR_MIP_POINT = 0x2, MIN_POINT_MAG_MIP_LINEAR = 0x3, MIN_LINEAR_MAG_MIP_POINT = 0x4, MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x5, MIN_MAG_LINEAR_MIP_POINT = 0x6, MIN_MAG_MIP_LINEAR = 0x7, ANISOTROPIC = 0x15, COMPARISON_MIN_MAG_MIP_POINT = 0x80, COMPARISON_MIN_MAG_POINT_MIP_LINEAR = 0x81, COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x82, COMPARISON_MIN_POINT_MAG_MIP_LINEAR = 0x83, COMPARISON_MIN_LINEAR_MAG_MIP_POINT = 0x84, COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x85, COMPARISON_MIN_MAG_LINEAR_MIP_POINT = 0x86, COMPARISON_MIN_MAG_MIP_LINEAR = 0x87, COMPARISON_ANISOTROPIC = 0x95 }; enum class D3D12_TEXTURE_ADDRESS_MODE { WRAP = 1, MIRROR = 2, CLAMP = 3, BORDER = 4, MIRROR_ONCE = 5 }; enum class D3D12_COMPARISON_FUNC { NEVER = 1, LESS = 2, EQUAL = 3, LESS_EQUAL = 4, GREATER = 5, NOT_EQUAL = 6, GREATER_EQUAL = 7, ALWAYS = 8 }; enum class D3D12_BLEND { ZERO = 1, ONE = 2, SRC_COLOR = 3, INV_SRC_COLOR = 4, SRC_ALPHA = 5, INV_SRC_ALPHA = 6, DST_ALPHA = 7, INV_DST_ALPHA = 8, DST_COLOR = 9, INV_DST_COLOR = 10, SRC_ALPHA_SAT = 11, BLEND_FACTOR = 14, INV_BLEND_FACTOR = 15, SRC1_COLOR = 16, INV_SRC1_COLOR = 17, SRC1_ALPHA = 18, INV_SRC1_ALPHA = 19 }; enum class D3D12_BLEND_OP { ADD = 1, SUBTRACT = 2, REV_SUBTRACT = 3, MIN = 4, MAX = 5 }; enum class D3D12_COLOR_WRITE_ENABLE { RED = 1, GREEN = 2, BLUE = 4, ALPHA = 8, ALL = 15 }; enum class D3D12_CULL_MODE { NONE = 1, FRONT = 2, BACK = 3 }; enum class D3D12_FILL_MODE { WIREFRAME = 2, SOLID = 3 }; enum class D3D12_PRIMITIVE_TOPOLOGY_TYPE { UNDEFINED = 0, POINT = 1, LINE = 2, TRIANGLE = 3, PATCH = 4 }; enum class D3D12_PRIMITIVE_TOPOLOGY { UNDEFINED = 0, POINTLIST = 1, LINELIST = 2, LINESTRIP = 3, TRIANGLELIST = 4, TRIANGLESTRIP = 5, TRIANGLEFAN = 6, LINELIST_ADJ = 10, LINESTRIP_ADJ = 11, TRIANGLELIST_ADJ = 12, TRIANGLESTRIP_ADJ = 13, PATCHLIST_1 = 33, PATCHLIST_2 = 34, PATCHLIST_3 = 35, PATCHLIST_4 = 36, PATCHLIST_5 = 37, PATCHLIST_6 = 38, PATCHLIST_7 = 39, PATCHLIST_8 = 40, PATCHLIST_9 = 41, PATCHLIST_10 = 42, PATCHLIST_11 = 43, PATCHLIST_12 = 44, PATCHLIST_13 = 45, PATCHLIST_14 = 46, PATCHLIST_15 = 47, PATCHLIST_16 = 48, PATCHLIST_17 = 49, PATCHLIST_18 = 50, PATCHLIST_19 = 51, PATCHLIST_20 = 52, PATCHLIST_21 = 53, PATCHLIST_22 = 54, PATCHLIST_23 = 55, PATCHLIST_24 = 56, PATCHLIST_25 = 57, PATCHLIST_26 = 58, PATCHLIST_27 = 59, PATCHLIST_28 = 60, PATCHLIST_29 = 61, PATCHLIST_30 = 62, PATCHLIST_31 = 63, PATCHLIST_32 = 64 }; enum class D3D12_QUERY_TYPE { OCCLUSION = 0, TIMESTAMP = 1, PIPELINE_STATISTICS = 2, DEPTH_STENCIL_CLIP_CUT = 3 }; enum class D3D12_QUERY_HEAP_TYPE { OCCLUSION = 0, TIMESTAMP = 1, PIPELINE_STATISTICS = 2, SO_STATISTICS = 3, VIDEO_DECODE_STATISTICS = 4, COPY_QUEUE_TIMESTAMP = 5, TIME_STAMP = 6 }; struct D3D12_CPU_DESCRIPTOR_HANDLE { void* ptr; }; struct D3D12_GPU_DESCRIPTOR_HANDLE { uint64_t ptr; }; struct D3D12_RESOURCE_BARRIER { enum class Type { TRANSITION, ALIASING, UDV }; Type Type; union { struct { IResource* pResource; int32_t Subresource; D3D12_RESOURCE_STATES StateBefore; D3D12_RESOURCE_STATES StateAfter; } Transition; struct { IResource* pResourceBefore; IResource* pResourceAfter; } Aliasing; struct { IResource* pResource; uint32_t NumRoadmapEntries; uint32_t* pRoadmap; D3D12_RESOURCE_STATES StateBefore; D3D12_RESOURCE_STATES StateAfter; } UAV; }; }; struct D3D12_VIEWPORT { float TopLeftX; float TopLeftY; float Width; float Height; float MinDepth; float MaxDepth; }; struct D3D12_RECT { int32_t left; int32_t top; int32_t right; int32_t bottom; }; struct D3D12_INPUT_ELEMENT_DESC { const char* SemanticName; uint32_t SemanticIndex; Format Format; uint32_t InputSlot; uint32_t AlignedByteOffset; D3D12_INPUT_CLASSIFICATION InputSlotClass; uint32_t InstanceDataStepRate; }; enum class D3D12_INPUT_CLASSIFICATION { PER_VERTEX_DATA = 0, PER_INSTANCE_DATA = 1 }; struct D3D12_SO_DECLARATION_ENTRY { const char* SemanticName; uint32_t SemanticIndex; uint8_t StartComponent; uint8_t ComponentCount; uint8_t OutputSlot; }; struct D3D12_SHADER_RESOURCE_VIEW_DESC { D3D12_SRV_DIMENSION ViewDimension; Format Format; uint32_t Shader4ComponentMapping; union { struct { uint32_t MostDetailedMip; uint32_t MipLevels; uint32_t PlaneSlice; float ResourceMinLODClamp; } Texture2D; struct { uint32_t MostDetailedMip; uint32_t MipLevels; uint32_t FirstArraySlice; uint32_t ArraySize; uint32_t PlaneSlice; float ResourceMinLODClamp; } Texture2DArray; struct { uint32_t FirstWSlice; uint32_t WSize; uint32_t MostDetailedMip; uint32_t MipLevels; float ResourceMinLODClamp; } Texture3D; struct { uint32_t MostDetailedMip; uint32_t MipLevels; uint32_t FirstArraySlice; uint32_t ArraySize; uint32_t PlaneSlice; float ResourceMinLODClamp; } TextureCube; }; }; struct D3D12_UNORDERED_ACCESS_VIEW_DESC { D3D12_UAV_DIMENSION ViewDimension; Format Format; uint32_t Shader4ComponentMapping; union { struct { uint32_t MipSlice; } Buffer; struct { uint32_t MipSlice; uint32_t FirstArraySlice; uint32_t ArraySize; uint32_t PlaneSlice; } Texture2D; struct { uint32_t MipSlice; uint32_t FirstWSlice; uint32_t WSize; } Texture3D; }; }; struct D3D12_RENDER_TARGET_VIEW_DESC { D3D12_RTV_DIMENSION ViewDimension; Format Format; union { struct { uint32_t MipSlice; uint32_t FirstArraySlice; uint32_t ArraySize; } Texture2D; struct { uint32_t MipSlice; uint32_t FirstArraySlice; uint32_t ArraySize; uint32_t PlaneSlice; } Texture2DMS; }; }; struct D3D12_DEPTH_STENCIL_VIEW_DESC { D3D12_DSV_DIMENSION ViewDimension; Format Format; uint32_t MipSlice; uint32_t FirstArraySlice; uint32_t ArraySize; uint32_t PlaneSlice; }; struct D3D12_CONSTANT_BUFFER_VIEW_DESC { uint64_t BufferLocation; uint32_t SizeInBytes; }; struct D3D12_SAMPLER_DESC { D3D12_FILTER Filter; D3D12_TEXTURE_ADDRESS_MODE AddressU; D3D12_TEXTURE_ADDRESS_MODE AddressV; D3D12_TEXTURE_ADDRESS_MODE AddressW; float MipLODBias; uint32_t MaxAnisotropy; D3D12_COMPARISON_FUNC ComparisonFunc; float BorderColor[4]; float MinLOD; float MaxLOD; }; struct InputLayout { D3D12_INPUT_ELEMENT_DESC* pInputElementDescs = nullptr; uint32_t NumInputElementDescs = 0; }; struct StreamOutput { D3D12_SO_DECLARATION_ENTRY* pSODeclaration = nullptr; uint32_t NumSODeclarationEntries = 0; uint64_t* pBufferStrides = nullptr; uint32_t NumBufferStrides = 0; uint32_t RasterizedStream = 0; }; struct BlendState { bool AlphaToCoverageEnable = false; bool IndependentBlendEnable = false; struct RenderTargetBlendDesc { bool BlendEnable = false; D3D12_BLEND SrcBlend = D3D12_BLEND::ONE; D3D12_BLEND DestBlend = D3D12_BLEND::ZERO; D3D12_BLEND_OP BlendOp = D3D12_BLEND_OP::ADD; D3D12_BLEND SrcBlendAlpha = D3D12_BLEND::ONE; D3D12_BLEND DestBlendAlpha = D3D12_BLEND::ZERO; D3D12_BLEND_OP BlendOpAlpha = D3D12_BLEND_OP::ADD; D3D12_COLOR_WRITE_ENABLE RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE::ALL; }; RenderTargetBlendDesc RenderTarget[8]; }; struct RasterizerState { D3D12_FILL_MODE FillMode = D3D12_FILL_MODE::SOLID; D3D12_CULL_MODE CullMode = D3D12_CULL_MODE::BACK; bool FrontCounterClockwise = false; int32_t DepthBias = 0; float DepthBiasClamp = 0.0f; float SlopeScaledDepthBias = 0.0f; bool DepthClipEnable = true; bool MultisampleEnable = false; bool AntialiasedLineEnable = false; uint32_t ForcedSampleCount = 0; bool ConservativeRaster = false; }; struct DepthStencilState { bool DepthEnable = true; D3D12_DEPTH_WRITE_MASK DepthWriteMask = D3D12_DEPTH_WRITE_MASK::ALL; D3D12_COMPARISON_FUNC DepthFunc = D3D12_COMPARISON_FUNC::LESS; bool StencilEnable = false; uint8_t StencilReadMask = 0xFF; uint8_t StencilWriteMask = 0xFF; struct DepthStencilOpDesc { D3D12_STENCIL_OP StencilFailOp = D3D12_STENCIL_OP::KEEP; D3D12_STENCIL_OP StencilDepthFailOp = D3D12_STENCIL_OP::KEEP; D3D12_STENCIL_OP StencilPassOp = D3D12_STENCIL_OP::KEEP; D3D12_COMPARISON_FUNC StencilFunc = D3D12_COMPARISON_FUNC::ALWAYS; }; DepthStencilOpDesc FrontFace; DepthStencilOpDesc BackFace; }; enum class D3D12_DEPTH_WRITE_MASK { ZERO = 0, ALL = 1 }; enum class D3D12_STENCIL_OP { KEEP = 1, ZERO = 2, REPLACE = 3, INCR_SAT = 4, DECR_SAT = 5, INVERT = 6, INCR = 7, DECR = 8 }; struct DXGI_SAMPLE_DESC { uint32_t Count = 1; uint32_t Quality = 0; }; struct CachedPSO { void* pCachedBlob = nullptr; size_t CachedBlobSizeInBytes = 0; }; enum class D3D12_PIPELINE_STATE_FLAGS { NONE = 0, TOOL_DEBUG = 1 }; struct D3D12_GRAPHICS_PIPELINE_STATE_DESC { InputLayout* InputLayout; RootSignature* pRootSignature; Shader* VS; Shader* HS; Shader* DS; Shader* GS; Shader* PS; StreamOutput* StreamOutput; BlendState* BlendState; uint32_t SampleMask; RasterizerState* RasterizerState; DepthStencilState* DepthStencilState; D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType; uint32_t NumRenderTargets; Format RTVFormats[8]; Format DSVFormat; DXGI_SAMPLE_DESC SampleDesc; uint32_t NodeMask; CachedPSO* cachedPSO; D3D12_PIPELINE_STATE_FLAGS Flags; }; struct D3D12_COMPUTE_PIPELINE_STATE_DESC { RootSignature* pRootSignature; Shader* CS; uint32_t NodeMask; CachedPSO* cachedPSO; D3D12_PIPELINE_STATE_FLAGS Flags; }; class D3D12Device : public IRHIDevice { public: D3D12Device(); virtual ~D3D12Device(); GraphicsAPI GetAPI() const override { return GraphicsAPI::Direct3D12; } const char* GetAPIName() const override { return "Direct3D 12"; } bool Initialize() override; void Shutdown() override; ID3D12Device* GetD3D12Device() { return m_device.Get(); } ID3D12CommandQueue* GetCommandQueue(D3D12_COMMAND_LIST_TYPE type); bool CreateCommandQueue(ICommandQueue** queue, const CommandQueueDesc& desc) override; bool CreateCommandAllocator(ICommandAllocator** allocator) override; bool CreateCommandList(ICommandList** list, ICommandAllocator* allocator) override; bool CreateFence(IFence** fence) override; bool CreateDescriptorHeap(IDescriptorHeap** heap, const DescriptorHeapDesc& desc) override; bool CreateQueryHeap(IQueryHeap** heap, const QueryHeapDesc& desc) override; bool CreateRootSignature(RootSignature** signature, const RootSignatureDesc& desc) override; bool CreatePipelineState(PipelineStateObject** pso, const PipelineDesc& desc) override; bool CreateSwapChain(ISwapChain** swapChain, const SwapChainDesc& desc, void* windowHandle) override; bool CreateRenderTarget(RenderTarget** target, const RenderTargetDesc& desc) override; bool CreateDepthStencil(DepthStencil** depthStencil, const DepthStencilDesc& desc) override; void* GetNativeDevice() const override { return m_device.Get(); } private: ComPtr m_device; ComPtr m_directQueue; ComPtr m_computeQueue; ComPtr m_copyQueue; D3D_FEATURE_LEVEL m_featureLevel; bool m_raytracingSupported; bool m_meshShadersSupported; }; class D3D12CommandList : public ICommandList { public: D3D12CommandList(ID3D12CommandAllocator* allocator); virtual ~D3D12CommandList(); void Reset(ICommandAllocator* allocator) override; void Close() override; void BeginRenderPass(const RenderPassDesc& desc) override; void EndRenderPass() override; void SetPipelineState(PipelineStateObject* pso) override; void SetRootSignature(RootSignature* signature) override; void SetVertexBuffer(uint32_t slot, VertexBuffer* buffer, uint32_t offset = 0) override; void SetIndexBuffer(IndexBuffer* buffer, uint32_t offset = 0) override; void SetDescriptorHeap(IDescriptorHeap* heap) override; void SetGraphicsDescriptorTable(uint32_t rootParameterIndex, uint64_t baseDescriptor) override; void SetComputeDescriptorTable(uint32_t rootParameterIndex, uint64_t baseDescriptor) override; void DrawInstanced( uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertex, uint32_t startInstance ) override; void DrawIndexedInstanced( uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndex, int32_t baseVertex, uint32_t startInstance ) override; void Dispatch(uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ) override; void SetViewports(const Viewport* viewports, uint32_t count) override; void SetScissorRects(const Rect* rects, uint32_t count) override; void SetRenderTargets( const RenderTarget* const* renderTargets, uint32_t renderTargetCount, const DepthStencil* depthStencil ) override; void ClearRenderTargetView(const RenderTarget* target, const float color[4]) override; void ClearDepthStencilView(const DepthStencil* depthStencil, float depth, uint8_t stencil) override; void CopyResource(IResource* dst, const IResource* src) override; void CopyBuffer(IResource* dst, uint64_t dstOffset, const IResource* src, uint64_t srcOffset, uint64_t size) override; void ResourceBarrier( IResource* resource, ResourceStateFlag stateBefore, ResourceStateFlag stateAfter ); ID3D12GraphicsCommandList* GetD3D12CommandList() { return m_commandList.Get(); } private: ComPtr m_commandList; D3D12_PRIMITIVE_TOPOLOGY m_topology = D3D12_PRIMITIVE_TOPOLOGY::UNDEFINED; }; class D3D12DescriptorHeap : public IDescriptorHeap { public: D3D12DescriptorHeap(ID3D12DescriptorHeap* heap, DescriptorHeapType type, uint32_t count); virtual ~D3D12DescriptorHeap(); DescriptorHeapType GetType() const override { return m_type; } uint32_t GetDescriptorCount() const override { return m_descriptorCount; } void* GetCPUDescriptorHandle(uint32_t index) const override; uint64_t GetGPUDescriptorHandle(uint32_t index) const override; void SetName(const String& name) override; ID3D12DescriptorHeap* GetD3D12DescriptorHeap() { return m_heap.Get(); } private: ComPtr m_heap; DescriptorHeapType m_type; uint32_t m_descriptorCount; uint32_t m_descriptorSize; }; class D3D12RootSignature : public RootSignature { public: D3D12RootSignature(); virtual ~D3D12RootSignature(); bool Initialize(const RootSignatureDesc& desc) override; void SetName(const String& name) override; ID3D12RootSignature* GetD3D12RootSignature() { return m_rootSignature.Get(); } private: bool SerializeRootSignature( const RootSignatureDesc& desc, std::vector& serializedData ); ComPtr m_rootSignature; }; class D3D12PipelineState : public PipelineStateObject { public: D3D12PipelineState(); virtual ~D3D12PipelineState(); bool Initialize(const PipelineDesc& desc); void SetName(const String& name); ID3D12PipelineState* GetD3D12PipelineState() { return m_pipelineState.Get(); } private: ComPtr m_pipelineState; }; class D3D12Fence : public IFence { public: D3D12Fence(ID3D12Fence* fence); virtual ~D3D12Fence(); uint64_t GetCompletedValue() const override; void Signal(uint64_t value) override; void Wait(uint64_t value) override; void Wait(uint64_t value, uint64_t timeout) override; ID3D12Fence* GetD3D12Fence() { return m_fence.Get(); } HANDLE GetEventHandle() { return m_event; } private: ComPtr m_fence; HANDLE m_event; }; class D3D12QueryHeap : public IQueryHeap { public: D3D12QueryHeap(ID3D12QueryHeap* heap, QueryType type, uint32_t count); virtual ~D3D12QueryHeap(); QueryType GetType() const override { return m_type; } uint32_t GetCount() const override { return m_count; } void Begin(ICommandList* cmdList, uint32_t index) override; void End(ICommandList* cmdList, uint32_t index) override; void GetData(uint32_t index, void* data, uint32_t dataSize) override; ID3D12QueryHeap* GetD3D12QueryHeap() { return m_queryHeap.Get(); } private: ComPtr m_queryHeap; QueryType m_type; uint32_t m_count; }; class D3D12SwapChain : public ISwapChain { public: D3D12SwapChain(IDXGISwapChain3* swapChain); virtual ~D3D12SwapChain(); bool Initialize(const SwapChainDesc& desc, void* windowHandle) override; void Shutdown() override; bool Present() override; bool Resize(uint32_t width, uint32_t height) override; uint32_t GetCurrentBufferIndex() const override; RenderTexture* GetBuffer(uint32_t index) override; void SetFullscreen(bool fullscreen) override; bool IsFullscreen() const override; IDXGISwapChain3* GetD3D12SwapChain() { return m_swapChain.Get(); } private: ComPtr m_swapChain; std::vector m_buffers; uint32_t m_bufferCount; bool m_fullscreen; }; } // namespace D3D12 } // namespace RHI } // namespace XCEngine namespace XCEngine { namespace Rendering { using ICommandList = RHI::ICommandList; using IBuffer = RHI::IResource; enum class BufferUsage { Default, Immutable, Dynamic, Staging }; enum class MemoryUsage { Default, GPU_Only, CPU_Only, CPU_GPU }; enum class PassType { Graphics, Compute, Copy, Raytracing }; enum class LoadAction { Load, Clear, DontCare }; enum class StoreAction { Store, Resolve, StoreAndResolve, DontCare }; enum class ResolveMode { None, Min, Average, Sample0, Sample1, Sample2, Sample3, Sample4, Sample5, Sample6, Sample7 }; enum class ComparisonFunc { Never, Less, Equal, LessEqual, Greater, NotEqual, GreaterEqual, Always }; enum class BorderColor { TransparentBlack, OpaqueBlack, OpaqueWhite }; struct IndexType { static constexpr uint8_t Uint16 = 0; static constexpr uint8_t Uint32 = 1; }; enum class ResourceState { Undefined = 0, Common = 1, VertexBuffer = 2, ConstantBuffer = 3, IndexBuffer = 4, RenderTarget = 5, UnorderedAccess = 6, DepthWrite = 7, DepthRead = 8, ShaderResource = 9, IndirectArgument = 10, CopyDest = 11, CopySource = 12, ResolveDest = 13, ResolveSource = 14, Present = 15, GenericRead = 16 }; struct ResourceDesc { ResourceType type; uint32_t width = 1; uint32_t height = 1; uint32_t depth = 1; uint32_t mipLevels = 1; uint32_t arraySize = 1; Format format = Format::Unknown; SampleCount sampleCount = SampleCount::Count1; ResourceState initialState = ResourceState::Undefined; bool cpuAccessible = false; bool randomAccess = false; MemoryUsage memoryUsage = MemoryUsage::Default; String name; }; class RenderContext { public: class GBufferPass; class LightingPass; class ShadowPass; class PostProcessPass; static RenderContext* Create(const RenderContextDesc& desc); static void Destroy(RenderContext* context); static RenderContext* GetMain(); void Initialize(const RenderContextDesc& desc); void Shutdown(); RHI::IRHIDevice* GetDevice() { return m_device.get(); } void BeginFrame(); void EndFrame(); ICommandList* GetMainCommandList() { return m_mainCommandList.get(); } void SetRenderTarget(const RenderTarget& target); void SetViewport(const Viewport& viewport); void SetScissorRect(const Rect& rect); void RenderScene(const SceneRenderDesc& desc); void ApplyPostProcessing(const PostProcessDesc& desc); void CaptureFrame(const String& filePath); void ToggleDebugView(); private: std::unique_ptr m_device; std::unique_ptr m_mainCommandList; std::unique_ptr m_swapChain; std::unique_ptr m_gBufferPass; std::unique_ptr m_lightingPass; std::unique_ptr m_shadowPass; std::unique_ptr m_postProcessPass; uint32_t m_frameIndex = 0; uint64_t m_frameCount = 0; static RenderContext* s_mainContext; }; struct ResourceGUID { static constexpr uint64_t INVALID = 0; uint64_t value = INVALID; bool IsValid() const { return value != INVALID; } bool operator==(const ResourceGUID& other) const { return value == other.value; } bool operator!=(const ResourceGUID& other) const { return value != other.value; } String ToString() const; static ResourceGUID FromString(const String& str); struct Hash { size_t operator()(const ResourceGUID& guid) const { return std::hash{}(guid.value); } }; }; class RenderTexture { public: uint32_t GetWidth() const { return m_width; } uint32_t GetHeight() const { return m_height; } uint32_t GetMipLevels() const { return m_mipLevels; } Format GetFormat() const { return m_format; } void* GetNativeHandle() const { return m_nativeHandle; } IShaderResourceView* GetSRV() { return m_srv.get(); } IRenderTargetView* GetRTV() { return m_rtv.get(); } IDepthStencilView* GetDSV() { return m_dsv.get(); } void* Map(); void Unmap(); private: uint32_t m_width, m_height; uint32_t m_mipLevels; Format m_format; void* m_nativeHandle = nullptr; std::unique_ptr m_srv; std::unique_ptr m_rtv; std::unique_ptr m_dsv; }; class RenderBuffer { public: uint64_t GetSize() const { return m_size; } BufferUsage GetUsage() const { return m_usage; } void* GetNativeHandle() const { return m_nativeHandle; } void SetData(const void* data, uint64_t size, uint64_t offset = 0); void* Map(); void Unmap(); private: uint64_t m_size; BufferUsage m_usage; void* m_nativeHandle = nullptr; }; } // namespace Rendering } // namespace XCEngine ``` ### 4.4 相机组件 ```cpp namespace XCEngine { class CameraComponent : public Component { public: void Awake() override; void Start() override; void Update(float deltaTime) override; enum class ProjectionType : uint8_t { Perspective, Orthographic }; void SetProjectionType(ProjectionType type) { m_projectionType = type; } ProjectionType GetProjectionType() const { return m_projectionType; } void SetFieldOfView(float fov) { m_fieldOfView = fov; } float GetFieldOfView() const { return m_fieldOfView; } void SetOrthographicSize(float size) { m_orthographicSize = size; } float GetOrthographicSize() const { return m_orthographicSize; } void SetNearClipPlane(float near) { m_nearPlane = near; } float GetNearClipPlane() const { return m_nearPlane; } void SetFarClipPlane(float far) { m_farPlane = far; } float GetFarClipPlane() const { return m_farPlane; } void SetViewport(const Rect& rect) { m_viewportRect = rect; } const Rect& GetViewport() const { return m_viewportRect; } void SetCullingMask(int32_t mask) { m_cullingMask = mask; } int32_t GetCullingMask() const { return m_cullingMask; } void SetDepth(float depth) { m_depth = depth; } float GetDepth() const { return m_depth; } Matrix4x4 GetViewMatrix() const; Matrix4x4 GetProjectionMatrix() const; Matrix4x4 GetViewProjectionMatrix() const; Vector3 ScreenToWorldPoint(const Vector3& screenPoint) const; Vector3 WorldToScreenPoint(const Vector3& worldPoint) const; Ray ScreenPointToRay(const Vector2& screenPoint) const; Frustum& GetFrustum() { return m_frustum; } private: ProjectionType m_projectionType = ProjectionType::Perspective; float m_fieldOfView = 60.0f; float m_orthographicSize = 5.0f; float m_nearPlane = 0.1f; float m_farPlane = 1000.0f; float m_aspectRatio = 16.0f / 9.0f; Rect m_viewportRect = Rect(0, 0, 1, 1); float m_depth = 0.0f; int32_t m_cullingMask = -1; Frustum m_frustum; }; } // namespace XCEngine ``` ### 4.5 光照组件 ```cpp namespace XCEngine { class LightComponent : public Component { public: void Awake() override; void Update(float deltaTime) override; enum class LightType : uint8_t { Directional, Point, Spot, Area }; void SetLightType(LightType type) { m_type = type; } LightType GetLightType() const { return m_type; } void SetColor(const Vector3& color) { m_color = color; } Vector3 GetColor() const { return m_color; } void SetIntensity(float intensity) { m_intensity = intensity; } float GetIntensity() const { return m_intensity; } void SetRange(float range) { m_range = range; } float GetRange() const { return m_range; } void SetSpotAngle(float angle) { m_spotAngle = angle; } float GetSpotAngle() const { return m_spotAngle; } void SetCastShadows(bool cast) { m_castShadows = cast; } bool GetCastShadows() const { return m_castShadows; } void SetShadowResolution(uint32_t resolution) { m_shadowResolution = resolution; } uint32_t GetShadowResolution() const { return m_shadowResolution; } void SetCullingMask(int32_t mask) { m_cullingMask = mask; } int32_t GetCullingMask() const { return m_cullingMask; } private: LightType m_type = LightType::Point; Vector3 m_color = Vector3::One(); float m_intensity = 1.0f; float m_range = 10.0f; float m_spotAngle = 30.0f; float m_penumbraAngle = 5.0f; bool m_castShadows = true; uint32_t m_shadowResolution = 1024; float m_shadowBias = 0.005f; float m_normalOffsetBias = 0.001f; float m_nearPlane = 0.1f; int32_t m_cullingMask = -1; float m_intensityVariation = 0.0f; ResourceGUID m_cookieTextureGuid; float m_cookieSize = 5.0f; }; } // namespace XCEngine ``` ### 4.6 渲染网格组件 ```cpp namespace XCEngine { class RenderMeshComponent : public Component { public: void Awake() override; void Start() override; void Update(float deltaTime) override; ResourceGUID GetMesh() const { return m_meshGuid; } void SetMesh(const ResourceGUID& guid); ResourceGUID GetMaterial() const { return m_materialGuid; } void SetMaterial(const ResourceGUID& guid); bool GetCastShadows() const { return m_castShadows; } void SetCastShadows(bool cast) { m_castShadows = cast; } bool GetReceiveShadows() const { return m_receiveShadows; } void SetReceiveShadows(bool receive) { m_receiveShadows = receive; } private: ResourceGUID m_meshGuid; ResourceGUID m_materialGuid; bool m_castShadows = true; bool m_receiveShadows = true; }; } // namespace XCEngine ``` ### 4.7 材质系统 ```cpp namespace XCEngine { namespace Rendering { enum class ShaderType { Vertex, Fragment, Compute, Geometry, Hull, Domain }; enum class UniformType { None, Float, Float2, Float3, Float4, Int, Int2, Int3, Int4, Bool, Sampler2D, Sampler3D, SamplerCube, Sampler2DArray, Matrix3x3, Matrix4x4 }; struct UniformDesc { String name; UniformType type; uint32_t arraySize = 1; uint32_t offset = 0; }; struct ShaderUniformBlock { String name; uint32_t bindingSlot = 0; uint32_t size = 0; std::vector uniforms; }; class Shader : public IResource { public: const String& GetSource() const { return m_source; } ShaderType GetType() const { return m_type; } const std::vector& GetUniformBlocks() const { return m_uniformBlocks; } const std::vector& GetResources() const { return m_resources; } bool HasVariant(const String& variantName) const; Shader* GetVariant(const HashMap& defines); bool IsCompiled() const { return m_compiled; } const String& GetCompileErrors() const { return m_compileErrors; } private: String m_source; ShaderType m_type; bool m_compiled = false; String m_compileErrors; std::vector m_uniformBlocks; std::vector m_resources; HashMap> m_variants; }; enum class BlendMode { Opaque, Transparent, Additive, Multiply, AlphaTest }; enum class CullMode { None, Front, Back }; enum class ZWriteMode { On, Off }; enum class DepthTest { Never, Less, Equal, LessEqual, Greater, NotEqual, GreaterEqual, Always }; struct RenderState { BlendMode blendMode = BlendMode::Opaque; CullMode cullMode = CullMode::Back; ZWriteMode zWriteMode = ZWriteMode::On; DepthTest depthTest = DepthTest::LessEqual; bool depthClip = true; bool scissorTest = false; bool stencilTest = false; uint8_t stencilReadMask = 0xFF; uint8_t stencilWriteMask = 0xFF; int32_t stencilRef = 0; uint32_t colorWriteMask = 0xF; bool operator==(const RenderState& other) const; }; struct MaterialPropBlock { HashMap floatProps; HashMap intProps; HashMap matrixProps; HashMap textureProps; void SetFloat(const String& name, float value); void SetFloat(const String& name, const Vector4& value); void SetInt(const String& name, int32_t value); void SetMatrix(const String& name, const Matrix4x4& value); void SetTexture(const String& name, const ResourceGUID& guid); float GetFloat(const String& name, float defaultValue = 0.0f) const; Vector4 GetFloat4(const String& name, const Vector4& defaultValue = Vector4::Zero()) const; int32_t GetInt(const String& name, int32_t defaultValue = 0) const; Matrix4x4 GetMatrix(const String& name, const Matrix4x4& defaultValue = Matrix4x4::Identity()) const; ResourceGUID GetTexture(const String& name, ResourceGUID defaultValue = ResourceGUID::INVALID) const; }; class Material : public IResource { public: Material(); explicit Material(Shader* shader); Shader* GetShader() const { return m_shader; } void SetShader(Shader* shader); const RenderState& GetRenderState() const { return m_renderState; } void SetRenderState(const RenderState& state) { m_renderState = state; } MaterialPropBlock& GetPropBlock() { return m_props; } const MaterialPropBlock& GetPropBlock() const { return m_props; } int32_t GetRenderQueue() const { return m_renderQueue; } void SetRenderQueue(int32_t queue) { m_renderQueue = queue; } void SetFloat(const String& name, float value); void SetFloat(const String& name, const Vector4& value); void SetInt(const String& name, int32_t value); void SetTexture(const String& name, const ResourceGUID& guid); float GetFloat(const String& name, float defaultValue = 0.0f) const; int32_t GetInt(const String& name, int32_t defaultValue = 0) const; ResourceGUID GetTexture(const String& name) const; bool IsInstanced() const { return m_instanced; } void SetInstanced(bool instanced) { m_instanced = instanced; } private: Shader* m_shader = nullptr; RenderState m_renderState; MaterialPropBlock m_props; int32_t m_renderQueue = 0; bool m_instanced = false; }; class MaterialManager { public: static MaterialManager& Get(); void Initialize(); void Shutdown(); Material* CreateMaterial(Shader* shader); Material* GetMaterial(const ResourceGUID& guid) const; void DestroyMaterial(Material* material); Material* FindMaterialByName(const String& name) const; private: HashMap> m_materials; uint64_t m_nextId = 1; }; class MaterialPropertyBlock { public: MaterialPropertyBlock(); ~MaterialPropertyBlock(); void Clear(); void SetFloat(const String& name, float value); void SetVector(const String& name, const Vector4& value); void SetColor(const String& name, const Color& value); void SetMatrix(const String& name, const Matrix4x4& matrix); void SetTexture(const String& name, Texture* texture); bool HasProperty(const String& name) const; float GetFloat(const String& name, float defaultValue = 0.0f) const; Vector4 GetVector(const String& name, const Vector4& defaultValue = Vector4::Zero()) const; Color GetColor(const String& name, const Color& defaultValue = Color::White()) const; Matrix4x4 GetMatrix(const String& name, const Matrix4x4& defaultValue = Matrix4x4::Identity()) const; Texture* GetTexture(const String& name) const; bool IsEmpty() const { return m_properties.empty(); } size_t GetPropertyCount() const { return m_properties.size(); } void ApplyToMaterial(Material* material) const; void CopyFrom(const MaterialPropertyBlock& other); private: struct PropertyValue { enum class Type { Float, Vector, Matrix, Texture }; Type type; union { float floatValue; Vector4 vectorValue; Matrix4x4 matrixValue; Texture* textureValue; }; }; HashMap m_properties; }; class RenderSettings { public: static RenderSettings& Get(); void Load(); void Save(); enum class AmbientMode { Skybox, Trilight, Flat, Custom }; AmbientMode GetAmbientMode() const { return m_ambientMode; } void SetAmbientMode(AmbientMode mode) { m_ambientMode = mode; } Color GetAmbientSkyColor() const { return m_ambientSkyColor; } void SetAmbientSkyColor(const Color& color) { m_ambientSkyColor = color; } Color GetAmbientEquatorColor() const { return m_ambientEquatorColor; } void SetAmbientEquatorColor(const Color& color) { m_ambientEquatorColor = color; } Color GetAmbientGroundColor() const { return m_ambientGroundColor; } void SetAmbientGroundColor(const Color& color) { m_ambientGroundColor = color; } float GetAmbientIntensity() const { return m_ambientIntensity; } void SetAmbientIntensity(float intensity) { m_ambientIntensity = intensity; } bool GetFogEnabled() const { return m_fogEnabled; } void SetFogEnabled(bool enabled) { m_fogEnabled = enabled; } enum class FogMode { Linear, Exponential, ExponentialSquared }; FogMode GetFogMode() const { return m_fogMode; } void SetFogMode(FogMode mode) { m_fogMode = mode; } Color GetFogColor() const { return m_fogColor; } void SetFogColor(const Color& color) { m_fogColor = color; } float GetFogDensity() const { return m_fogDensity; } void SetFogDensity(float density) { m_fogDensity = density; } float GetFogStartDistance() const { return m_fogStartDistance; } void SetFogStartDistance(float distance) { m_fogStartDistance = distance; } float GetFogEndDistance() const { return m_fogEndDistance; } void SetFogEndDistance(float distance) { m_fogEndDistance = distance; } float GetShadowDistance() const { return m_shadowDistance; } void SetShadowDistance(float distance) { m_shadowDistance = distance; } uint32_t GetShadowCascadeCount() const { return m_shadowCascadeCount; } void SetShadowCascadeCount(uint32_t count) { m_shadowCascadeCount = count; } float GetShadowResolution() const { return m_shadowResolution; } void SetShadowResolution(float resolution) { m_shadowResolution = resolution; } Texture* GetSkybox() const { return m_skybox; } void SetSkybox(Texture* skybox) { m_skybox = skybox; } private: RenderSettings() = default; AmbientMode m_ambientMode = AmbientMode::Skybox; Color m_ambientSkyColor = Color{0.5f, 0.5f, 0.5f, 1.0f}; Color m_ambientEquatorColor = Color{0.2f, 0.2f, 0.2f, 1.0f}; Color m_ambientGroundColor = Color{0.1f, 0.1f, 0.1f, 1.0f}; float m_ambientIntensity = 1.0f; bool m_fogEnabled = false; FogMode m_fogMode = FogMode::Linear; Color m_fogColor = Color{0.5f, 0.5f, 0.5f, 1.0f}; float m_fogDensity = 0.01f; float m_fogStartDistance = 10.0f; float m_fogEndDistance = 100.0f; float m_shadowDistance = 150.0f; uint32_t m_shadowCascadeCount = 4; float m_shadowResolution = 1024.0f; Texture* m_skybox = nullptr; }; class GraphicsSettings { public: static GraphicsSettings& Get(); void Load(); void Save(); enum class ColorSpace { Gamma, Linear }; ColorSpace GetColorSpace() const { return m_colorSpace; } void SetColorSpace(ColorSpace space) { m_colorSpace = space; } enum class HDRSetting { Off, On, Auto }; HDRSetting GetHDR() const { return m_hdr; } void SetHDR(HDRSetting hdr) { m_hdr = hdr; } uint32_t GetMSAASamples() const { return m_msaaSamples; } void SetMSAASamples(uint32_t samples) { m_msaaSamples = samples; } bool GetRealtimeReflectionProbes() const { return m_realtimeReflectionProbes; } void SetRealtimeReflectionProbes(bool enabled) { m_realtimeReflectionProbes = enabled; } float GetLODBias() const { return m_lodBias; } void SetLODBias(float bias) { m_lodBias = bias; } int GetMaximumLODLevel() const { return m_maximumLODLevel; } void SetMaximumLODLevel(int level) { m_maximumLODLevel = level; } enum class ShaderQuality { Low, Medium, High }; ShaderQuality GetShaderQuality() const { return m_shaderQuality; } void SetShaderQuality(ShaderQuality quality) { m_shaderQuality = quality; } private: GraphicsSettings() = default; ColorSpace m_colorSpace = ColorSpace::Linear; HDRSetting m_hdr = HDRSetting::Auto; uint32_t m_msaaSamples = 4; bool m_realtimeReflectionProbes = true; float m_lodBias = 1.0f; int m_maximumLODLevel = -1; ShaderQuality m_shaderQuality = ShaderQuality::High; }; } // namespace Rendering } // namespace XCEngine ``` ### 4.8 渲染管线 ```cpp namespace XCEngine { namespace Rendering { enum class RenderPipelineType { Forward, Deferred, Hybrid, Custom }; struct RenderPipelineDesc { RenderPipelineType type = RenderPipelineType::Forward; uint32_t maxLights = 16; bool shadowEnabled = true; uint32_t shadowMapSize = 2048; bool ssaoEnabled = false; bool bloomEnabled = false; bool toneMappingEnabled = true; String toneMappingCurve = "ACES"; }; struct RenderItem { ResourceGUID meshGuid; Material* material = nullptr; Matrix4x4 worldMatrix; uint32_t instanceId = 0; int32_t renderQueue = 0; uint32_t subMeshIndex = 0; uint32_t lightingHash = 0; float GetDistanceSq(const Vector3& cameraPos) const; bool operator<(const RenderItem& other) const; }; struct CullingParams { Vector3 position; float sphereCulling; Matrix4x4 viewMatrix; Matrix4x4 projectionMatrix; float nearClipPlane; float farClipPlane; Rect viewport; int32_t cullingPlaneFlags; int32_t cullingMask; int32_t ortho; float shadowDistance; float shadowNearPlaneDistance; bool isOrthographic; bool cullDynamicObjects; int32_t LODStripping; int32_t forceCullingMode; int32_t maximumLODLevel; int32_t minimumLODLevel; }; struct CullingResults { struct VisibleObject { uint64_t instanceID; int32_t referenceID; Matrix4x4 localToWorldMatrix; Matrix4x4 localToWorldMatrixPrevious; uint64_t staticBatchRootID; uint32_t subMeshIndex; Vector4 lightmapScaleOffset; uint32_t lightmapIndex; bool staticShadowCaster; bool motionVectors; }; std::vector visibleRenderers; struct LightData { uint64_t lightID; int32_t uniqueID; Vector3 position; Vector3 color; Vector3 forward; float range; float intensity; float spotAngle; int32_t lightType; int32_t renderMode; bool enabled; bool shadowsEnabled; int32_t cullingMask; Matrix4x4 viewMatrix; Matrix4x4 projectionMatrix; }; std::vector visibleLights; Frustum frustumPlanes[2]; }; class CullingSystem { public: static CullingSystem& Get(); void Initialize(); void Shutdown(); bool PerformCulling( const CullingParams& params, CullingResults& results, Scene* scene ); void ComputeFrustumPlanes( const Matrix4x4& viewMatrix, const Matrix4x4& projectionMatrix, Frustum& frustum ); private: std::vector m_visibleRenderers; Frustum m_frustum; std::vector m_cullingPlanes; }; class ScriptableRenderContext { public: ScriptableRenderContext(); ~ScriptableRenderContext(); void SetRenderTarget( RenderTargetIdentifier colorTarget, RenderTargetIdentifier depthTarget ); void PushDebugGroup(const char* name); void PopDebugGroup(); void BeginSample(const char* name); void EndSample(const char* name); void DrawRenderer( RenderItem* renderers, size_t count, Material* material, int passIndex ); void ExecuteAndPresent(); void Submit(); private: CommandBuffer* m_commandBuffer; RenderTargetIdentifier m_activeColorTarget; RenderTargetIdentifier m_activeDepthTarget; }; class LightManager { public: static LightManager& Get(); void Initialize(); void Shutdown(); void UpdateLights( Scene* scene, CameraComponent* camera, CullingResults& cullingResults ); void GetMainLight(LightData& light); void GetVisibleLights(std::vector& lights); int GetVisibleLightCount() const { return m_visibleLights.size(); } bool HasShadows() const { return m_shadowsEnabled; } void SetShadowDistance(float distance) { m_shadowDistance = distance; } float GetShadowDistance() const { return m_shadowDistance; } private: std::vector m_visibleLights; int m_mainLightIndex = -1; float m_shadowDistance = 50.0f; bool m_shadowsEnabled = true; }; class ShadowAtlas { public: ShadowAtlas(); ~ShadowAtlas(); void Initialize(int width, int height); void Shutdown(); void Update( const std::vector& lights, CullingResults& cullingResults ); RenderTexture* GetTexture() const { return m_texture.get(); } private: struct ShadowSlice { int x, y; int width, height; bool allocated; LightData* light; }; std::unique_ptr m_texture; int m_width = 0; int m_height = 0; std::vector m_slices; }; class Renderer { public: Renderer(); ~Renderer(); void Initialize(); void Shutdown(); void Render( ScriptableRenderContext& context, CameraComponent* camera, CullingResults& cullingResults, RenderQueue& renderQueue ); void RenderOpaque( ScriptableRenderContext& context, CullingResults& cullingResults, RenderQueue& renderQueue ); void RenderTransparent( ScriptableRenderContext& context, CullingResults& cullingResults, RenderQueue& renderQueue ); void RenderShadowCasters( ScriptableRenderContext& context, CullingResults& cullingResults ); void SortRenderers(RenderQueue& renderQueue); private: void PrepareRenderQueueEntries( RenderQueue& renderQueue, CullingResults& cullingResults ); Material* m_defaultMaterial = nullptr; }; class RenderQueue { public: void Clear(); void Sort(); void Add(const RenderItem& item); void AddRange(const RenderItem* items, size_t count); const std::vector& GetOpaque() const { return m_opaque; } const std::vector& GetTransparent() const { return m_transparent; } const std::vector& GetAlphaTest() const { return m_alphaTest; } size_t GetOpaqueCount() const { return m_opaque.size(); } size_t GetTransparentCount() const { return m_transparent.size(); } size_t GetAlphaTestCount() const { return m_alphaTest.size(); } private: std::vector m_opaque; std::vector m_transparent; std::vector m_alphaTest; }; struct CameraData { Matrix4x4 viewMatrix; Matrix4x4 projectionMatrix; Matrix4x4 viewProjectionMatrix; Vector3 position; Vector3 forward; Vector3 up; Vector3 right; float nearPlane; float farPlane; float fov; float aspectRatio; Rect viewport; bool isOrthographic; }; struct RenderContextData { CameraData camera; std::vector lights; std::vector visibleLights; float deltaTime; float time; uint32_t frameIndex; uint64_t frameCount; }; class RenderPipeline { public: virtual ~RenderPipeline() = default; virtual void Initialize(const RenderPipelineDesc& desc); virtual void Shutdown(); virtual void Prepare(RenderContextData& context); virtual void Execute(RHI::ICommandList* cmdList, RenderContextData& context); virtual void Present(); RenderQueue& GetRenderQueue() { return m_renderQueue; } const RenderQueue& GetRenderQueue() const { return m_renderQueue; } RenderTexture* GetColorTarget() const { return m_colorTarget.get(); } RenderTexture* GetDepthTarget() const { return m_depthTarget.get(); } virtual void Resize(uint32_t width, uint32_t height); protected: virtual void CollectRenderItems(Scene* scene, CameraComponent* camera); virtual void SortRenderItems(); virtual void SetupLights(Scene* scene, CameraComponent* camera); RenderPipelineDesc m_desc; RenderQueue m_renderQueue; std::unique_ptr m_colorTarget; std::unique_ptr m_depthTarget; std::vector m_mainLightData; std::vector m_additionalLightData; }; class ForwardPipeline : public RenderPipeline { public: void Initialize(const RenderPipelineDesc& desc) override; void Execute(RHI::ICommandList* cmdList, RenderContextData& context) override; private: void RenderOpaque(RHI::ICommandList* cmdList, RenderContextData& context); void RenderTransparent(RHI::ICommandList* cmdList, RenderContextData& context); void RenderAlphaTest(RHI::ICommandList* cmdList, RenderContextData& context); void RenderShadowMaps(RHI::ICommandList* cmdList); void RenderLighting(RHI::ICommandList* cmdList, RenderContextData& context); }; class DeferredPipeline : public RenderPipeline { public: void Initialize(const RenderPipelineDesc& desc) override; void Execute(RHI::ICommandList* cmdList, RenderContextData& context) override; private: void RenderGBuffer(RHI::ICommandList* cmdList); void RenderDeferredLighting(RHI::ICommandList* cmdList); void RenderDeferredShading(RHI::ICommandList* cmdList); std::unique_ptr m_gBufferAlbedo; std::unique_ptr m_gBufferNormal; std::unique_ptr m_gBufferMetallicRoughness; std::unique_ptr m_gBufferDepth; }; class RenderPipelineManager { public: static RenderPipelineManager& Get(); void Initialize(const RenderPipelineDesc& desc); void Shutdown(); RenderPipeline* GetPipeline() const { return m_pipeline.get(); } void SetPipeline(std::unique_ptr pipeline); void CreatePipeline(RenderPipelineType type); void Resize(uint32_t width, uint32_t height); private: std::unique_ptr m_pipeline; RenderPipelineDesc m_desc; }; } // namespace Rendering } // namespace XCEngine ``` --- ## 第五章 目录结构(与 Unity 引擎目录结构一致) ``` XCVolumeRenderer/ ├── engine/ # 引擎核心库(静态库) │ ├── CMakeLists.txt │ ├── include/ │ │ └── XCEngine/ │ │ ├── Core/ # 核心基础 │ │ │ ├── Assert.h │ │ │ ├── Event.h │ │ │ ├── TypeTraits.h │ │ │ └── UniquePtr.h │ │ ├── Math/ # 数学库(与 Unity Mathf 对应) │ │ │ ├── Vector2.h │ │ │ ├── Vector3.h │ │ │ ├── Vector4.h │ │ │ ├── Matrix3.h │ │ │ ├── Matrix4.h │ │ │ ├── Quaternion.h │ │ │ ├── Transform.h │ │ │ ├── Color.h │ │ │ ├── Ray.h │ │ │ ├── Plane.h │ │ │ ├── Sphere.h │ │ │ ├── Box.h │ │ │ ├── Bounds.h │ │ │ └── Frustum.h │ │ ├── Containers/ # 容器(与 Unity Collections 对应) │ │ │ ├── Array.h │ │ │ ├── String.h │ │ │ ├── StringView.h │ │ │ └── HashMap.h │ │ ├── Memory/ # 内存管理 │ │ │ ├── Allocator.h │ │ │ ├── LinearAllocator.h │ │ │ ├── PoolAllocator.h │ │ │ └── ProxyAllocator.h │ │ ├── Threading/ # 线程系统 │ │ │ ├── Thread.h │ │ │ ├── Mutex.h │ │ │ ├── SpinLock.h │ │ │ ├── ReadWriteLock.h │ │ │ ├── TaskSystem.h │ │ │ └── Atomic.h │ │ ├── Debug/ # 调试系统 │ │ │ ├── Logger.h │ │ │ ├── Profiler.h │ │ │ └── LogSink.h │ │ ├── Components/ # 组件系统(与 Unity Component 对应) │ │ │ ├── GameObject.h │ │ │ ├── Component.h │ │ │ ├── ComponentTypeRegistry.h │ │ │ ├── TransformComponent.h │ │ │ ├── RenderMeshComponent.h │ │ │ ├── LightComponent.h │ │ │ └── CameraComponent.h │ │ ├── Scene/ # 场景系统(与 Unity SceneManager 对应) │ │ │ ├── Scene.h │ │ │ ├── SceneManager.h │ │ │ └── GameObjectBuilder.h │ │ ├── Renderer/ # 渲染系统(核心,与 Unity Graphics/Shader 对应) │ │ │ ├── Device.h # 设备抽象 │ │ │ ├── Context.h # 渲染上下文 │ │ │ ├── SwapChain.h # 交换链 │ │ │ ├── Buffer.h # 缓冲区 │ │ │ ├── Texture.h # 纹理 │ │ │ ├── Shader.h # Shader │ │ │ ├── Material.h # 材质 │ │ │ ├── Pipeline.h # 渲染管线 │ │ │ ├── RenderPass.h # 渲染通道 │ │ │ ├── CommandList.h # 命令列表 │ │ │ ├── RenderQueue.h # 渲染队列 │ │ │ ├── RenderPipeline.h # 渲染管线基类 │ │ │ ├── CullingSystem.h # 剔除系统 │ │ │ ├── Renderer.h # 渲染器 │ │ │ ├── LightManager.h # 光照管理器 │ │ │ ├── ShadowAtlas.h # 阴影图集 │ │ │ └── RenderModule.h # 渲染模块 │ │ ├── RHI/ # 渲染硬件抽象层(与 Unity GraphicsDevice 对应) │ │ │ ├── RHISystem.h # RHI 系统入口 │ │ │ ├── RHIDevice.h # 抽象设备接口 │ │ │ ├── CommandQueue.h # 命令队列 │ │ │ ├── CommandList.h # 命令列表 │ │ │ ├── CommandAllocator.h # 命令分配器 │ │ │ ├── Fence.h # 同步围栏 │ │ │ ├── DescriptorHeap.h # 描述符堆 │ │ │ ├── QueryHeap.h # 查询堆 │ │ │ ├── RootSignature.h # 根签名 │ │ │ ├── PipelineState.h # 管线状态 │ │ │ ├── Sampler.h # 采样器 │ │ │ └── SwapChain.h # 交换链 │ │ ├── RHI/D3D12/ # D3D12 后端实现 │ │ │ ├── D3D12Device.h │ │ │ ├── D3D12CommandList.h │ │ │ ├── D3D12CommandQueue.h │ │ │ ├── D3D12DescriptorHeap.h │ │ │ ├── D3D12RootSignature.h │ │ │ ├── D3D12PipelineState.h │ │ │ ├── D3D12Fence.h │ │ │ ├── D3D12QueryHeap.h │ │ │ ├── D3D12SwapChain.h │ │ │ ├── D3D12Texture.h │ │ │ └── D3D12Buffer.h │ │ └── XCEngine.h # 主头文件 │ ├── src/ │ │ ├── Core/ │ │ ├── Math/ │ │ ├── Components/ │ │ ├── Scene/ │ │ ├── Renderer/ │ │ ├── RHI/ │ │ │ ├── CMakeLists.txt │ │ │ └── D3D12/ │ │ └── ... │ └── third_party/ │ ├── DirectX/ # DirectX SDK │ ├── stb/ # stb 图像库 │ ├── json/ # json 解析库 │ └── NanoVDB/ # NanoVDB 体积渲染库 │ ├── runtime/ # 游戏运行时(独立可执行文件) │ ├── CMakeLists.txt │ ├── src/ │ │ ├── GameMain.cpp │ │ ├── EntryPoint.cpp │ │ └── Application.cpp │ └── resources/ │ ├── Shaders/ │ ├── Models/ │ ├── Textures/ │ └── Volumes/ │ ├── tools/ # 工具链 │ ├── ShaderCompiler/ # 着色器编译器 │ │ ├── ShaderCompiler.h │ │ └── ShaderCompileOptions.h │ ├── BuildTool/ # 构建打包工具 │ └── AssetProcessor/ # 资源处理工具 │ ├── content/ # 资源内容 │ ├── Assets/ # 资源文件夹 │ ├── Scenes/ # 场景文件 │ └── Packages/ # 资源包 │ └── projects/ # 项目文件夹 └── .. # Unity 引擎目录结构对照 # Unity/Editor/Data/Resources/ # Unity/Editor/Data/Modules/ # Unity/Editor/Data/Tools/ ``` --- ## 附录:待扩展功能 以下功能将在后续迭代中添加: 1. **物理系统** - RigidBodyComponent, ColliderComponent, PhysicsWorld 2. **音频系统** - AudioSourceComponent, AudioListenerComponent, AudioEngine 3. **动画系统** - AnimatorComponent, AnimationClip, Skeleton 4. **粒子系统** - ParticleSystemComponent, GPUParticles 5. **UI系统** - CanvasComponent, ImageComponent, TextComponent, ButtonComponent 6. **网络系统** - NetworkIdentityComponent, NetworkTransformComponent 7. **完整编辑器** - HierarchyPanel, InspectorPanel, SceneViewPanel