Game Engine & Graphic Engine
- 프로젝트를 시작한지는 좀 됬지만 어느정도 구조가 확립이 되어 정리해보려고 한다. 일단 Engine 구조를 Client Programmer와 생각하면서 중요하게 생각한 부분이 몇가지 있다.
1) Game Engine은 어떤 Graphic Engine이건 상관없이 동작을 해야한다.
2) Game Engine과 Graphic Engine은 독립적이여야 한다.
3) 데이터 전달 과정에서 어느 한 부분에 종속적인 데이터가 있으면 안된다.
4) 공유 데이터를 통해 Game Engine과 Graphic Engine은 각자 필요한 동작을 실행한다.
Game Engine과 Graphic Engine이 독립적이여야 하는 이유
- 현재 프로젝트에선 DirectX 11을 기반으로 Graphic Engine을 적용하고 있지만 추후 최신 버전의 Graphic API가 나올 수도 있으며, 현재로써도 DirectX 12, Vulkan, OpenGL 등 여러 Graphic API가 존재하기 때문에 하나의 Graphic API에 종속적이게 만들게 되면 추후 수정 및 적용에 어려움이 있을 수 있다.
Game Engine과 Graphic Engine을 어떻게 독립적으로 만들 것인가
- 어떻게 서로 모르는 상태에서 같은 데이터를 공유할 수 있을까 고민하던 도중, Client 담당 프로그래머가 게임 엔진 측에 PhysX Library를 적용하면서 해당 PhysX Data를 생성할때 User 측에서 정의한 구조체를 void* 형태로 보관하여 추후 필요할때 해당 형태로 형변환하여 사용하는 것을 참고하여 우리도 각자의 데이터를 void* 형태로 보관하되 서로 필요한 시점에 형변환해서 사용하면 되지 않을까? 라는 생각을 시작으로 구조를 짜기 시작하였다.
// Index Buffer
// 해당 Pointer는 Graphic 측에서 생성한 Resource
class IndexBuffer : public Resources
{
public:
virtual ~IndexBuffer()
{
pIndexBuf = nullptr;
};
UINT Count = 0; //인덱스 개수
void* pIndexBuf = nullptr;
};
// Vertex Buffer
// 해당 Pointer는 Graphic 측에서 생성한 Resource
class VertexBuffer : public Resources
{
public:
virtual ~VertexBuffer()
{
pVertexBuf = nullptr;
};
UINT Stride = 0; //stride값 버텍스버퍼를 만든 자료형의 크기
UINT Offset = 0;
void* pVertexBuf = nullptr;
};
// Mesh Buffer
class MeshBuffer : public Resources
{
public:
virtual ~MeshBuffer()
{
delete Mesh_Property;
delete IndexBuf;
delete VertexBuf;
}
public:
UINT BufferIndex = 0; // Mesh Buffer Index
MeshProperty* Mesh_Property; // Mesh Sub Data
IndexBuffer* IndexBuf; // Index Buffer
VertexBuffer* VertexBuf; // Vertex Buffer
};
...
/// <summary>
/// Game Engine -> Graphic Engine
/// Object 생성시 최초 한번만 변환하여 Renderer 측 List에서 관리한다
/// </summary>
class MeshData
{
public:
~MeshData()
{
}
public:
void* Render_Data; // 변환된 Render Data
ObjectData* Object_Data = nullptr; // Object Data
MeshBuffer* Mesh_Buffer = nullptr; // Mesh Buffer
MaterialBuffer* Material_Buffer = nullptr; // Material Buffer
AnimationBuffer* Animation_Buffer = nullptr; // Animation Buffer
// 추가 데이터
AnimationData* Animation_Data = nullptr; // Animation Data
TerrainData* Terrain_Data = nullptr; // Terrain Data
ParticleData* Particle_Data = nullptr; // Particle Data
MaterialPropertyBlock* Material_Block = nullptr;
};
- Game Engine과 Graphic Engine이 공유하는 구조체 정의부.
- 해당 Resource는 Game Engine측에서 요청을하여 Graphic Engine에서 생성하여 채워준다.
void* 형태로 변환하여 보관할 시 해당 형태는 보장이 되는데 매번 Casting을 해주는 것이 바람직한가
- Renderer 측에 Rendering을 위해 필요로하는 Texture Buffer, Vertex Buffer, Index Buffer 등 Graphic Resource를 Game Engine 측에서 Graphic Engine 측으로 생성 요청을 하여 해당 Resource를 생성한 후 void* 형태로 보관한 뒤 해당 Resource를 필요로 하는 Object가 생성되고 해당 Object를 Rendering 할 경우 보관하고 있는 Resource를 Graphic API에 맞는 구조체로 형변환을 하여 그리는 도중 어떤 형태인지 보장이 되는데 굳이 매 프레임 Casting을 할 필요가 있을까? 라는 생각이 들게 되었다.
- 이런 Casting 비용 조차 줄이기 위해 Graphic Engine 측에서 해당 공유 데이터와 1:1 대응하는 Resource의 구조체를 정의하여 해당 Resource가 Load 되는 시점에 Graphic Engine 측에서도 동일하게 해당 Resource를 Casting 해두어 Object 생성시 Resource를 미리 Casting 해둔 Resource를 기반으로 Rendering을 실행하는 방식으로 수정하였다.
// Game Engine 측 MeshBuffer와 대응하는 DirectX 11 전용 Mesh Data Class
class MeshRenderBuffer : public RenderResource
{
public:
UINT m_BufferIndex;
UINT m_IndexCount;
UINT m_Stride;
UINT m_Offset;
ID3D11Buffer* m_VertexBuf;
ID3D11Buffer* m_IndexBuf;
MeshProperty* m_MeshProperty;
};
...
// Game Engine 측 MeshData와 대응하는 DirectX 11 전용 Render Data Class
class RenderData
{
public:
bool m_Draw = true; // Culling 여부..
int m_InstanceLayerIndex = -1; // Instance Layer Index..
int m_InstanceIndex = -1; // Instance Index..
MeshRenderBuffer* m_Mesh; // 변환된 Mesh Data..
MaterialRenderBuffer* m_Material; // 변환된 Material Data..
TerrainRenderBuffer* m_Terrain; // 변환된 Terrain Data..
AnimationRenderBuffer* m_Animation; // 변환된 Animation Data..
ObjectData* m_ObjectData;
AnimationData* m_AnimationData;
ParticleData* m_ParticleData;
};
- 위와 같이 공유 데이터와 1:1 대응하는 해당 Graphic API 전용 구조체를 정의하여 Game Engine 측에서 Resource를 Load 할 경우 미리 Casting을 통해 Resource를 보관하고 있다가 Object가 추가 될때마다 해당 Resource를 부여하여 Rendering을 실행한다.
Render Data 전달 방식
'DirectX 11' 카테고리의 다른 글
[DirectX 11] Fast Picking (Object ID Picking) (6) | 2022.03.29 |
---|---|
[DirectX 11] Game Engine Render Resource 동기화 방식 및 Resource 관리 방식 (0) | 2022.03.16 |
[DirectX 11] Hardware Instancing (0) | 2022.03.02 |
[DirectX 11] Deferred Fog (2) | 2022.02.21 |
[DirectX 11] Bloom (1) | 2022.02.17 |