공용으로 관리될 부분은 Manager로 빼서 관리를 해보자.
SceneManager
지금까지 짠 코드를 보면 GameObject들을 그냥 Main 프로그램이 전부 다 가지고 있고 Update를 요청했다.
우리가 생각해보면 유니티에서는 Scene이라고 하는 객체가 모든 GameObject를 가지고 있고 이를 관리하고 있다.
그렇기에 SceneManager를 만들어서 관리해보자.
여기서 Scene은 위에서 말한 대로 각종 오브젝트들을 보관하고 있는 클래스이다.
SceneManager는 이러한 여러개의 Scene들을 하나로 묶어서 관리하기 위한 클래스이다.
#pragma once
class GameObject;
class Scene
{
public:
void Awake();
void Start();
void Update();
void LateUpdate();
void FixedUpdate();
public:
void AddGameObject(shared_ptr<GameObject> gameObject);
void RemoveGameObject(shared_ptr<GameObject> gameObject);
const vector<shared_ptr<GameObject>>& GetGameObjects() { return _gameObjects; }
private:
vector<shared_ptr<GameObject>> _gameObjects;
};
#include "pch.h"
#include "Scene.h"
#include "GameObject.h"
void Scene::Awake()
{
for (const shared_ptr<GameObject>& gameObject : _gameObjects)
{
gameObject->Awake();
}
}
void Scene::Start()
{
for (const shared_ptr<GameObject>& gameObject : _gameObjects)
{
gameObject->Start();
}
}
void Scene::Update()
{
for (const shared_ptr<GameObject>& gameObject : _gameObjects)
{
gameObject->Update();
}
}
void Scene::LateUpdate()
{
for (const shared_ptr<GameObject>& gameObject : _gameObjects)
{
gameObject->LateUpdate();
}
}
void Scene::FixedUpdate()
{
for (const shared_ptr<GameObject>& gameObject : _gameObjects)
{
gameObject->FixedUpdate();
}
}
void Scene::AddGameObject(shared_ptr<GameObject> gameObject)
{
_gameObjects.push_back(gameObject);
}
void Scene::RemoveGameObject(shared_ptr<GameObject> gameObject)
{
auto findIt = std::find(_gameObjects.begin(), _gameObjects.end(), gameObject);
if (findIt != _gameObjects.end())
_gameObjects.erase(findIt);
}
#pragma once
class Scene;
class SceneManager
{
public:
SceneManager(shared_ptr<Graphics> graphics);
void Init();
void Update();
void LoadScene(wstring sceneName);
public:
shared_ptr<Scene> GetActiveScene() { return _activeScene; }
private:
shared_ptr<Scene> LoadTestScene();
private:
shared_ptr<Graphics> _graphics;
private:
shared_ptr<Scene> _activeScene;
};
#include "pch.h"
#include "SceneManager.h"
#include "Scene.h"
#include "GameObject.h"
#include "Camera.h"
#include "Transform.h"
#include "MeshRenderer.h"
SceneManager::SceneManager(shared_ptr<Graphics> graphics)
: _graphics(graphics)
{
}
void SceneManager::Init()
{
if (_activeScene == nullptr)
return;
_activeScene->Awake();
_activeScene->Start();
}
void SceneManager::Update()
{
if (_activeScene == nullptr)
return;
_activeScene->Update();
_activeScene->LateUpdate();
_activeScene->FixedUpdate();
}
void SceneManager::LoadScene(wstring sceneName)
{
// Resource
_activeScene = LoadTestScene();
Init();
}
std::shared_ptr<Scene> SceneManager::LoadTestScene()
{
shared_ptr<Scene> scene = make_shared<Scene>();
// Camera
{
shared_ptr<GameObject> camera = make_shared<GameObject>(_graphics->GetDevice(), _graphics->GetDeviceContext());
{
camera->GetOrAddTransform();
camera->AddComponent(make_shared<Camera>());
scene->AddGameObject(camera);
}
}
// Monster
{
shared_ptr<GameObject> monster = make_shared<GameObject>(_graphics->GetDevice(), _graphics->GetDeviceContext());
{
monster->GetOrAddTransform();
monster->AddComponent(make_shared<MeshRenderer>(_graphics->GetDevice(), _graphics->GetDeviceContext()));
//_monster->GetTransform()->SetScale(Vec3(100.f, 100.f, 1.f));
// ..
scene->AddGameObject(monster);
}
}
return scene;
}
Resource Manager
이제 MeshRenderer에 있는 공통적인 부분을 빼 보자. 가령 예를 들어 vertexBuffer나 inputLayout 등 같은 물체라면 한번만 만들면 되는 것인 경우 같은 것을 관리하는 클래스를 만들자.
리소스 라고 하면 게임에서 한번만 로드한 후 공용으로 계속 사용하는 것이라고 말할 수 있다.
#pragma once
enum class ResourceType : uint8
{
None = -1,
Mesh,
Shader,
Texture,
Material,
Animation,
End
};
enum
{
RESOURCE_TYPE_COUNT = static_cast<uint8>(ResourceType::End)
};
class ResourceBase : public enable_shared_from_this<ResourceBase>
{
public:
ResourceBase(ResourceType type);
virtual ~ResourceBase();
ResourceType GetType() { return _type; }
void SetName(const wstring& name) { _name = name; }
const wstring& GetName() { return _name; }
uint32 GetId() { return _id; }
protected:
virtual void Load(const wstring& path) { }
virtual void Save(const wstring& path) { }
protected:
ResourceType _type = ResourceType::None;
wstring _name;
wstring _path;
uint32 _id = 0;
};
#pragma once
#include "ResourceBase.h"
class ResourceManaer
{
public:
ResourceManaer(ComPtr<ID3D11Device> device);
void Init();
template<typename T>
shared_ptr<T> Load(const wstring& key, const wstring& path);
template<typename T>
bool Add(const wstring& key, shared_ptr<T> obj);
template<typename T>
shared_ptr<T> Get(const wstring& key);
template<typename T>
ResourceType GetResourceType();
private:
void CreateDefaultTexture();
void CreateDefaultMesh();
void CreateDefaultShader();
void CreateDefaultMaterial();
void CreateDefaultAnimation();
private:
ComPtr<ID3D11Device> _device;
using KeyObjMap = map<wstring/*key*/, shared_ptr<ResourceBase>>;
// [map map map map map]
array<KeyObjMap, RESOURCE_TYPE_COUNT> _resources;
};
template<typename T>
shared_ptr<T> ResourceManaer::Load(const wstring& key, const wstring& path)
{
auto objectType = GetResourceType<T>();
KeyObjMap& keyObjMap = _resources[static_cast<uint8>(objectType)];
auto findIt = keyObjMap.find(key);
if (findIt != keyObjMap.end())
return static_pointer_cast<T>(findIt->second);
shared_ptr<T> object = make_shared<T>();
object->load(path);
keyObjMap[key] = object;
return object;
;}
template<typename T>
bool ResourceManaer::Add(const wstring& key, shared_ptr<T> object)
{
ResourceType resourceType = GetResourceType<T>();
KeyObjMap& keyObjMap = _resources[static_cast<uint8>(resourceType)];
auto findIt = keyObjMap.find(key);
if (findIt != keyObjMap.end())
return false;
keyObjMap[key] = object;
return true;
}
template<typename T>
shared_ptr<T> ResourceManaer::Get(const wstring& key)
{
ResourceType resourceType = GetResourceType<T>();
KeyObjMap& keyObjMap = _resources[static_cast<uint8>(resourceType)];
auto findIt = keyObjMap.find(key);
if (findIt != keyObjMap.end())
return static_pointer_cast<T>(findIt->second);
return nullptr;
}
template<typename T>
ResourceType ResourceManaer::GetResourceType()
{
if (std::is_same_v<T, Texture>)
return ResourceType::Texture;
assert(false);
return ResourceType::None;
}
이제 기본적인 mesh material animation shader texture을 받을 수 있게 만들어 주면 된다. 그 작업을 이어서 해볼 것이다.
RendererManager
#pragma once
#include "RenderHelper.h"
class RenderManager
{
public:
RenderManager(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext);
void Init();
void Update(shared_ptr<Graphics> graphics);
private:
void PushCameraData();
void PushTransformData();
void GatherRenderableObject();
void RenderObjects();
private:
ComPtr<ID3D11Device> _device;
ComPtr<ID3D11DeviceContext> _deviceContext;
shared_ptr<Pipeline> _pipeline;
private:
// Camera
CameraData _cameraData;
shared_ptr<ConstantBuffer<CameraData>> _cameraBuffer;
// SRT
TransformData _transformData;
shared_ptr<ConstantBuffer<TransformData>> _transformBuffer;
// Animation
private:
shared_ptr<SamplerState> _samplerState;
shared_ptr<BlendState> _blendState;
shared_ptr<RasterizerState> _rasterizerState;
vector<shared_ptr<GameObject>> _renderObjects;
};
#include "pch.h"
#include "RenderManager.h"
#include "Pipeline.h"
#include "MeshRenderer.h"
#include "Camera.h"
#include "Game.h"
#include "SceneManager.h"
#include "Scene.h"
RenderManager::RenderManager(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext)
: _device(device), _deviceContext(deviceContext)
{
}
void RenderManager::Init()
{
_pipeline = make_shared<Pipeline>(_deviceContext);
_cameraBuffer = make_shared<ConstantBuffer<CameraData>>(_device, _deviceContext);
_cameraBuffer->Create();
_transformBuffer = make_shared<ConstantBuffer<TransformData>>(_device, _deviceContext);
_transformBuffer->Create();
_rasterizerState = make_shared<RasterizerState>(_device);
_rasterizerState->Create();
_blendState = make_shared<BlendState>(_device);
_blendState->Create();
_samplerState = make_shared<SamplerState>(_device);
_samplerState->Create();
}
void RenderManager::Update(shared_ptr<Graphics> graphics)
{
graphics->RenderBegin();
PushCameraData();
GatherRenderableObject();
RenderObjects();
graphics->RenderEnd();
}
void RenderManager::PushCameraData()
{
_cameraData.matView = Camera::S_MatView;
_cameraData.matProjection = Camera::S_MatProjection;
_cameraBuffer->CopyData(_cameraData);
}
void RenderManager::PushTransformData()
{
_transformBuffer->CopyData(_transformData);
}
void RenderManager::GatherRenderableObject()
{
_renderObjects.clear();
auto& gameObjects = SCENE->GetActiveScene()->GetGameObjects();
for (const shared_ptr<GameObject> gameObject : gameObjects)
{
shared_ptr<MeshRenderer> meshRenderer = gameObject->GetMeshRenderer();
if (meshRenderer)
_renderObjects.push_back(gameObject);
}
}
void RenderManager::RenderObjects()
{
for (const shared_ptr<GameObject> gameObject : _renderObjects)
{
shared_ptr<MeshRenderer> meshRenderer = gameObject->GetMeshRenderer();
if (meshRenderer == nullptr)
continue;
shared_ptr<Transform> transform = gameObject->GetTransform();
if (transform == nullptr)
continue;
// SRT
_transformData.matWorld = transform->GetWorldMatrix();
PushTransformData();
PipelineInfo info;
info.inputLayout = meshRenderer->_inputLayout;
info.vertexShader = meshRenderer->_vertexShader;
info.pixelShader = meshRenderer->_pixelShader;
info.rasterizerState = _rasterizerState;
info.blendState = _blendState;
_pipeline->UpdatePipeline(info);
_pipeline->SetVertexBuffer(meshRenderer->_vertexBuffer);
_pipeline->SetIndexBuffer(meshRenderer->_indexBuffer);
_pipeline->SetConstantBuffer(0, SS_VertexShader, _cameraBuffer);
_pipeline->SetConstantBuffer(1, SS_VertexShader, _transformBuffer);
_pipeline->SetTexture(0, SS_PixelShader, meshRenderer->_texture1);
_pipeline->SetSamplerState(0, SS_PixelShader, _samplerState);
_pipeline->DrawIndexed(meshRenderer->_geometry->GetIndexCount(), 0, 0);
}
}
'C++ > DirectX 11' 카테고리의 다른 글
[DirectX] DirectX 11 3D 입문 - 프로젝트 설정 및 간단한 실습 (0) | 2024.09.11 |
---|---|
[DirectX] 엔진 구조로 제작하기 - Material, Animation, Data (0) | 2024.09.10 |
[DirectX] 엔진 구조로 제작하기 - Component, MeshRenderer (2) | 2024.09.05 |
[DirectX] 프레임워크 제작기 - Transform (0) | 2024.09.04 |
[DirectX] 프레임워크 제작기 - Shader, Pipeline, GameObject (1) | 2024.09.03 |