- 新增Math库: Vector2/3/4, Matrix3/4, Quaternion, Transform, Color等 - 新增测试框架: Google Test (gtest) - 新增140个单元测试,覆盖Vector, Matrix, Quaternion, Geometry - VolumeRenderer支持vcpkg的NanoVDB - 添加TESTING.md测试文档
127 KiB
127 KiB
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)
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)
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<LinearAllocator> CreateLinearAllocator(size_t size);
std::unique_ptr<PoolAllocator> CreatePoolAllocator(size_t blockSize, size_t count);
std::unique_ptr<ProxyAllocator> 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)
namespace XCEngine {
namespace Containers {
template<typename T>
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<T> 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<typename... Args>
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<typename Key, typename Value>
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<Pair> pairs;
};
Array<Bucket> 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)
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<typename T = void()>
using Func = std::function<T>;
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<uint32> m_refCount{1};
};
template<typename Func>
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<void()>;
TaskGroup();
~TaskGroup();
uint64 AddTask(std::unique_ptr<ITask> 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<ITask> 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<typename Func>
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<typename Func>
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 日志与调试系统
namespace XCEngine {
namespace Core {
template<typename... Args>
class Event {
public:
using Callback = std::function<void(Args...)>;
using Listener = std::pair<uint64_t, Callback>;
using Iterator = typename std::vector<Listener>::iterator;
uint64_t Subscribe(Callback callback) {
std::lock_guard<std::mutex> 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<std::mutex> lock(m_mutex);
m_pendingUnsubscribes.push_back(id);
}
void ProcessUnsubscribes() {
std::lock_guard<std::mutex> 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<Listener> listenersCopy;
{
std::lock_guard<std::mutex> 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<std::mutex> 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<Listener> m_listeners;
std::vector<uint64_t> 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<uint32_t> m_refCount;
};
template<typename T>
using Ref = std::shared_ptr<T>;
template<typename T>
using UniqueRef = std::unique_ptr<T>;
} // 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<ILogSink> 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 组件基类
namespace XCEngine {
class Scene;
class GameObject;
class TransformComponent;
// 组件类型注册(用于运行时类型识别)
class ComponentTypeRegistry {
public:
static ComponentTypeRegistry& Get();
template<typename T>
static uint32_t GetTypeId() {
static uint32_t id = Get().Register(typeid(T).name(), static_cast<uint32_t>(-1));
return id;
}
template<typename T>
static uint32_t GetTypeId(const char* typeName) {
static uint32_t id = Get().Register(typeName, static_cast<uint32_t>(-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<uint32_t> m_nextTypeId{0};
std::unordered_map<uint32_t, String> m_idToName;
std::unordered_map<String, uint32_t> 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<typename T>
T* GetComponent() const { return m_gameObject->GetComponent<T>(); }
template<typename T>
std::vector<T*> GetComponents() const { return m_gameObject->GetComponents<T>(); }
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组件
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<int>(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<TransformComponent*> 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
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<typename T>
T* AddComponent();
template<typename T>
void RemoveComponent();
template<typename T>
T* GetComponent() const;
template<typename T>
std::vector<T*> GetComponents() const;
template<typename T>
T* GetComponentInChildren() const;
template<typename T>
std::vector<T*> GetComponentsInChildren() const;
template<typename T>
T* GetComponentInParent() const;
GameObject* GetParent() const;
void SetParent(GameObject* parent);
void SetParent(GameObject* parent, bool worldPositionStays);
const std::vector<GameObject*>& 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<GameObject*> FindObjectsOfType();
static std::vector<GameObject*> FindGameObjectsWithTag(const String& tag);
void Destroy();
private:
void AddComponentInternal(Component* component);
void RemoveComponentInternal(Component* component);
std::vector<std::unique_ptr<Component>> m_components;
std::unordered_map<uint32_t, size_t> m_componentTypeIndex;
std::vector<GameObject*> m_children;
GameObject* m_parent = nullptr;
Scene* m_scene = nullptr;
std::unique_ptr<TransformComponent> 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<TransformComponent>();
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*> GameObject::FindObjectsOfType() {
return SceneManager::Get().GetActiveScene()->FindObjectsOfType<GameObject>();
}
inline std::vector<GameObject*> GameObject::FindGameObjectsWithTag(const String& tag) {
return SceneManager::Get().GetActiveScene()->FindGameObjectsWithTag(tag);
}
} // namespace XCEngine
第三章 场景系统
3.1 Scene
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<GameObject*> GetRootGameObjects() const {
std::vector<GameObject*> 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<GameObject*> FindGameObjectsWithTag(const String& tag) const;
template<typename T>
std::vector<T*> FindObjectsOfType() const;
template<typename T>
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<void()> 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<std::unique_ptr<GameObject>> 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<void(Scene*)> 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<Scene*> GetAllScenes() const;
void Update(float deltaTime);
void FixedUpdate(float fixedDeltaTime);
void LateUpdate(float deltaTime);
Event<Scene*> OnSceneLoaded;
Event<Scene*> OnSceneUnloaded;
Event<Scene*> OnActiveSceneChanged;
private:
SceneManager() = default;
std::vector<std::unique_ptr<Scene>> m_scenes;
Scene* m_activeScene = nullptr;
Scene* m_loadingScene = nullptr;
std::unordered_map<String, Scene*> m_sceneNameMap;
std::function<void(Scene*)> m_loadCallback;
bool m_loading = false;
};
// GameObject创建辅助类
class GameObjectBuilder {
public:
explicit GameObjectBuilder(const String& name = "GameObject");
~GameObjectBuilder() = default;
template<typename T, typename... Args>
GameObjectBuilder& AddComponent(Args&&... args);
GameObject* Build();
private:
String m_name;
std::vector<std::function<void(GameObject*)>> m_components;
};
} // namespace XCEngine
第四章 渲染系统
借鉴 Unity 渲染架构设计
4.0 公共类型定义
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<int32_t> 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<IShaderResourceView> m_srv;
std::unique_ptr<IRenderTargetView> 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<IDepthStencilView> m_dsv;
std::unique_ptr<IShaderResourceView> 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<RenderTargetIdentifier>& 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<Matrix4x4>& 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<uint8_t> m_data;
std::vector<std::string> m_sampleNames;
int m_sampleDepth = 0;
};
class Mesh : public IResource {
public:
Mesh();
~Mesh();
void SetVertices(const std::vector<Vector3>& vertices);
void SetNormals(const std::vector<Vector3>& normals);
void SetTangents(const std::vector<Vector4>& tangents);
void SetUVs(int channel, const std::vector<Vector2>& uvs);
void SetUVs(int channel, const std::vector<Vector3>& uvs);
void SetTriangles(const std::vector<uint32_t>& triangles, int submesh);
void SetIndices(const std::vector<uint16_t>& indices, int submesh);
void SetIndices(const std::vector<uint32_t>& indices, int submesh);
const std::vector<Vector3>& GetVertices() const { return m_vertices; }
const std::vector<Vector3>& GetNormals() const { return m_normals; }
const std::vector<Vector4>& 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<int>(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<Vector3> vertices;
std::vector<Vector3> normals;
std::vector<Vector4> tangents;
std::vector<Vector4> uvs[8];
std::vector<uint32_t> indices32;
std::vector<uint16_t> indices16;
};
void GetMeshData(MeshData& data) const;
private:
std::vector<Vector3> m_vertices;
std::vector<Vector3> m_normals;
std::vector<Vector4> m_tangents;
std::vector<Vector4> m_uvs[8];
struct SubmeshDescriptor {
int indexStart;
int indexCount;
int baseVertex;
MeshTopology topology;
};
std::vector<SubmeshDescriptor> 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 抽象层接口
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<ResourceStateFlag>(static_cast<uint32_t>(a) | static_cast<uint32_t>(b));
}
inline ResourceStateFlag operator&(ResourceStateFlag a, ResourceStateFlag b) {
return static_cast<ResourceStateFlag>(static_cast<uint32_t>(a) & static_cast<uint32_t>(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 实现
// ============================================
// D3D12 前向声明
// ============================================
struct ID3D12Device;
struct ID3D12CommandQueue;
struct ID3D12CommandAllocator;
struct ID3D12GraphicsCommandList;
struct ID3D12DescriptorHeap;
struct ID3D12RootSignature;
struct ID3D12PipelineState;
struct ID3D12Fence;
struct ID3D12QueryHeap;
struct IDXGISwapChain3;
template<typename T>
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<ID3D12Device> m_device;
ComPtr<ID3D12CommandQueue> m_directQueue;
ComPtr<ID3D12CommandQueue> m_computeQueue;
ComPtr<ID3D12CommandQueue> 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<ID3D12GraphicsCommandList> 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<ID3D12DescriptorHeap> 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<uint8_t>& serializedData
);
ComPtr<ID3D12RootSignature> 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<ID3D12PipelineState> 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<ID3D12Fence> 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<ID3D12QueryHeap> 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<IDXGISwapChain3> m_swapChain;
std::vector<RenderTexture*> 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<RHI::IRHIDevice> m_device;
std::unique_ptr<ICommandList> m_mainCommandList;
std::unique_ptr<RHI::ISwapChain> m_swapChain;
std::unique_ptr<GBufferPass> m_gBufferPass;
std::unique_ptr<LightingPass> m_lightingPass;
std::unique_ptr<ShadowPass> m_shadowPass;
std::unique_ptr<PostProcessPass> 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<uint64_t>{}(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<IShaderResourceView> m_srv;
std::unique_ptr<IRenderTargetView> m_rtv;
std::unique_ptr<IDepthStencilView> 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 相机组件
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 光照组件
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 渲染网格组件
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 材质系统
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<UniformDesc> uniforms;
};
class Shader : public IResource {
public:
const String& GetSource() const { return m_source; }
ShaderType GetType() const { return m_type; }
const std::vector<ShaderUniformBlock>& GetUniformBlocks() const { return m_uniformBlocks; }
const std::vector<UniformDesc>& GetResources() const { return m_resources; }
bool HasVariant(const String& variantName) const;
Shader* GetVariant(const HashMap<String, String>& 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<ShaderUniformBlock> m_uniformBlocks;
std::vector<UniformDesc> m_resources;
HashMap<String, std::unique_ptr<Shader>> 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<String, Vector4> floatProps;
HashMap<String, Vector4> intProps;
HashMap<String, Matrix4x4> matrixProps;
HashMap<String, ResourceGUID> 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<ResourceGUID, std::unique_ptr<Material>> 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<String, PropertyValue> 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 渲染管线
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<VisibleObject> 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<LightData> 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<uint64_t> m_visibleRenderers;
Frustum m_frustum;
std::vector<Plane> 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<LightData*>& 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<LightData> 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<LightData*>& 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<RenderTexture> m_texture;
int m_width = 0;
int m_height = 0;
std::vector<ShadowSlice> 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<RenderItem>& GetOpaque() const { return m_opaque; }
const std::vector<RenderItem>& GetTransparent() const { return m_transparent; }
const std::vector<RenderItem>& 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<RenderItem> m_opaque;
std::vector<RenderItem> m_transparent;
std::vector<RenderItem> 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<LightData> lights;
std::vector<LightData> 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<RenderTexture> m_colorTarget;
std::unique_ptr<RenderTexture> m_depthTarget;
std::vector<LightData> m_mainLightData;
std::vector<LightData> 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<RenderTexture> m_gBufferAlbedo;
std::unique_ptr<RenderTexture> m_gBufferNormal;
std::unique_ptr<RenderTexture> m_gBufferMetallicRoughness;
std::unique_ptr<RenderTexture> 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<RenderPipeline> pipeline);
void CreatePipeline(RenderPipelineType type);
void Resize(uint32_t width, uint32_t height);
private:
std::unique_ptr<RenderPipeline> 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/
附录:待扩展功能
以下功能将在后续迭代中添加:
- 物理系统 - RigidBodyComponent, ColliderComponent, PhysicsWorld
- 音频系统 - AudioSourceComponent, AudioListenerComponent, AudioEngine
- 动画系统 - AnimatorComponent, AnimationClip, Skeleton
- 粒子系统 - ParticleSystemComponent, GPUParticles
- UI系统 - CanvasComponent, ImageComponent, TextComponent, ButtonComponent
- 网络系统 - NetworkIdentityComponent, NetworkTransformComponent
- 完整编辑器 - HierarchyPanel, InspectorPanel, SceneViewPanel