-
[DirectX11] SceneManager와 MeshRenderer2024년 02월 19일
- 유니얼
-
작성자
-
2024.02.19.:46
728x90DirectX 11로 게임 엔진 아키텍처 만들기
이번 블로그 글에서는 MeshRender와 Scene 관리에 대해 알아보고자 합니다. 특히, DirectX 11을 사용하여 각 게임 오브젝트마다 리소스를 그리는 작업을 효율적으로 나누는 방법에 초점을 맞출 것입니다. 이를 위해 MeshRenderer 구현 방법과 함께, Scene과 SceneManager의 역할과 구현 방법에 대해 상세히 다루어, 게임의 구조를 보다 효율적으로 관리하는 방법을 탐구할 예정입니다.
참고강의 링크:
MeshRender
MeshRenderer는 게임 오브젝트에 부착되어 그 오브젝트의 메시를 화면에 그리는 역할을 합니다. DirectX 11에서는 이를 위해 각 메시의 정점 데이터를 GPU에 전송하고, 적절한 셰이더를 사용하여 이를 렌더링하는 과정이 필요합니다. MeshRenderer 컴포넌트는 다음과 같은 핵심 기능을 포함합니다:
- 메시 데이터 관리: 오브젝트의 메시(정점, 인덱스, 텍스처 좌표 등)를 관리합니다.
- 렌더링 설정: 사용할 셰이더 프로그램, 텍스처, 머티리얼 등 렌더링에 필요한 설정을 관리합니다.
- 드로우 콜 실행: 게임 루프 내에서 적절한 시점에 GPU로 드로우 콜을 실행하여 메시를 그립니다.
#pragma once #include "Component.h" class Mesh; class Material; #include "Material.h" #include "Shader.h" // MeshRenderer 클래스는 게임 오브젝트의 메시를 렌더링하는 컴포넌트입니다. class MeshRenderer : public Component { using Super = Component; // 부모 클래스인 Component에 대한 별칭을 설정합니다. public: // 생성자: DirectX 디바이스와 디바이스 컨텍스트를 인자로 받습니다. MeshRenderer(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext); virtual ~MeshRenderer(); // 소멸자 // 머티리얼 설정 메소드 void SetMaterial(shared_ptr<Material> material) { _material = material; } // 셰이더 설정 메소드 void SetShader(shared_ptr<Shader> shader) { _material->SetShader(shader); } // 메시 설정 메소드 void SetMesh(shared_ptr<Mesh> mesh) { _mesh = mesh; } // 텍스처 설정 메소드 void SetTexture(shared_ptr<Texture> texture) { _material->SetTexture(texture); } // 머티리얼 가져오기 메소드 shared_ptr<Material> GetMaterial() { return _material; } // 버텍스 셰이더 가져오기 메소드 shared_ptr<VertexShader> GetVertexShader() { return GetMaterial()->GetShader()->GetVertexShader(); } // 인풋 레이아웃 가져오기 메소드 shared_ptr<InputLayout> GetInputLayout() { return GetMaterial()->GetShader()->GetInputLayout(); } // 픽셀 셰이더 가져오기 메소드 shared_ptr<PixelShader> GetPixelShader() { return GetMaterial()->GetShader()->GetPixelShader(); } // 메시 가져오기 메소드 shared_ptr<Mesh> GetMesh() { return _mesh; } // 텍스처 가져오기 메소드 shared_ptr<Texture> GetTexture() { return _material->GetTexture(); } private: ComPtr<ID3D11Device> _device; // DirectX 디바이스 인스턴스 friend class RenderManager; // RenderManager 클래스에서 MeshRenderer의 private 멤버에 접근할 수 있도록 허용 // 메시와 머티리얼 정보를 저장하는 멤버 변수 shared_ptr<Mesh> _mesh; // 메시 정보 shared_ptr<Material> _material; // 머티리얼 정보 };
#include "pch.h" #include "MeshRenderer.h" #include "Camera.h" #include "GameObject.h" #include "Game.h" #include "Pipeline.h" #include "Mesh.h" // 생성자 구현: MeshRenderer 컴포넌트를 초기화합니다. MeshRenderer::MeshRenderer(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext) : Super(ComponentType::MeshRenderer), _device(device) { } // 소멸자 구현 MeshRenderer::~MeshRenderer() { }
Scene
Scene은 게임의 한 장면을 구성하는 오브젝트들의 집합입니다. 예를 들어, 메인 메뉴, 각 게임 레벨, 종료 화면 등 게임의 다양한 단계를 각각 다른 Scene으로 구성할 수 있습니다. Scene 내에서는 다음과 같은 요소들을 관리합니다:
- 게임 오브젝트: Scene에 속한 모든 게임 오브젝트들의 리스트를 관리합니다.
- 라이팅과 카메라 설정: Scene의 라이팅, 카메라 뷰와 같은 환경 설정을 관리합니다.
- 업데이트와 렌더링: Scene 내의 모든 게임 오브젝트를 업데이트하고, 렌더링 순서를 결정합니다.
#pragma once class GameObject; // Scene 클래스는 게임의 장면을 관리하는 클래스입니다. 여러 게임 오브젝트들을 포함하고 있습니다. 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>& gameObejct : _gameObjects) { gameObejct->Awake(); } } // 장면이 시작될 때 각 게임 오브젝트의 Start 메소드를 호출합니다. void Scene::Start() { for (const shared_ptr<GameObject>& gameObejct : _gameObjects) { gameObejct->Start(); } } // 매 프레임마다 각 게임 오브젝트의 Update 메소드를 호출합니다. void Scene::Update() { for (const shared_ptr<GameObject>& gameObejct : _gameObjects) { gameObejct->Update(); } } // 모든 Update 메소드 호출 후 각 게임 오브젝트의 LateUpdate 메소드를 호출합니다. void Scene::LateUpdate() { for (const shared_ptr<GameObject>& gameObejct : _gameObjects) { gameObejct->LateUpdate(); } } // 고정된 시간 간격으로 각 게임 오브젝트의 FixedUpdate 메소드를 호출합니다. void Scene::FixedUpdate() { for (const shared_ptr<GameObject>& gameObejct : _gameObjects) { gameObejct->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); } }
SceneManager
SceneManager는 게임의 전체적인 Scene 관리를 담당합니다. 이는 현재 활성화된 Scene을 추적하고, Scene 간 전환을 처리하는 역할을 합니다. SceneManager의 주요 기능은 다음과 같습니다:
- Scene 로딩과 언로딩: 새 Scene을 로딩하거나 현재 Scene을 언로딩합니다.
- Scene 전환: 사용자의 입력이나 게임 로직에 따라 다른 Scene으로의 전환을 관리합니다.
- Scene 관리: 현재 활성화된 Scene에 대한 참조를 유지하고, 필요에 따라 다른 Scene으로의 정보 전달을 처리합니다.
#pragma once class Scene; // SceneManager 클래스는 게임의 여러 장면(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" // SceneManager 클래스 헤더 포함 #include "Scene.h" // Scene 클래스 헤더 포함 #include "GameObject.h" // GameObject 클래스 헤더 포함 #include "Camera.h" // Camera 클래스 헤더 포함 #include "MeshRenderer.h" // MeshRenderer 클래스 헤더 포함 #include "ResourceManager.h" // ResourceManager 클래스 헤더 포함 #include "Game.h" // Game 클래스 헤더 포함 #include "Mesh.h" // Mesh 클래스 헤더 포함 #include "Animator.h" // Animator 클래스 헤더 포함 // SceneManager 클래스의 생성자입니다. Graphics 객체를 인자로 받아 멤버 변수를 초기화합니다. SceneManager::SceneManager(shared_ptr<Graphics> graphics) : _graphics(graphics) { } // 초기화 함수입니다. 활성화된 장면이 없으면 함수를 종료합니다. // 활성화된 장면이 있으면, 해당 장면의 Awake와 Start 함수를 호출합니다. void SceneManager::Init() { if (_activeScene == nullptr) { return; } _activeScene->Awake(); _activeScene->Start(); } // 매 프레임마다 호출되는 업데이트 함수입니다. // 활성화된 장면이 없으면 함수를 종료합니다. // 활성화된 장면이 있으면, 해당 장면의 FixedUpdate, Update, LateUpdate 함수를 차례로 호출합니다. void SceneManager::Update() { if (_activeScene == nullptr) { return; } _activeScene->FixedUpdate(); _activeScene->Update(); _activeScene->LateUpdate(); } // 새로운 장면을 로드하는 함수입니다. 장면 이름을 인자로 받습니다. // 여기서는 장면 이름을 사용하지 않고, 단순히 LoadTestScene 함수를 호출하여 테스트 장면을 로드합니다. void SceneManager::LoadScene(wstring sceneName) { // 장면 리소스 관련 로직은 여기에 구현될 수 있습니다. _activeScene = LoadTestScene(); // 테스트 장면을 로드합니다. Init(); // 로드된 장면을 초기화합니다. } // 테스트 장면을 로드하는 내부 함수입니다. // 실제 게임에서는 다양한 장면을 로드하기 위해 이 함수를 수정하거나 다른 함수를 추가할 수 있습니다. shared_ptr<Scene> SceneManager::LoadTestScene() { shared_ptr<Scene> scene = make_shared<Scene>(); // 새로운 Scene 객체를 생성합니다. // 카메라 객체를 생성하고 장면에 추가하는 코드 블록입니다. { shared_ptr<GameObject> camera = make_shared<GameObject>(_graphics->GetDevice(), _graphics->GetDeviceContext()); { camera->GetOrAddTransform(); // 카메라의 Transform 컴포넌트를 추가합니다. camera->AddComponent(make_shared<Camera>()); // 카메라 컴포넌트를 추가합니다. scene->AddGameObject(camera); // 생성된 카메라 객체를 장면에 추가합니다. } } // 몬스터 객체를 생성하고 장면에 추가하는 코드 블록입니다. // 아래에는 몬스터 객체를 두 번 생성하는 예시가 있습니다. 실제 게임에서는 다양한 종류의 객체를 생성할 수 있습니다. { shared_ptr<GameObject> monster = make_shared<GameObject>(_graphics->GetDevice(), _graphics->GetDeviceContext()); monster->GetOrAddTransform()->SetWorldPosition(Vec3{ 2.0f,2.0f,0 }); // 몬스터의 위치를 설정합니다. { monster->GetOrAddTransform(); // 몬스터의 Transform 컴포넌트를 추가합니다. auto meshRenderer = make_shared<MeshRenderer>(_graphics->GetDevice(), _graphics->GetDeviceContext()); monster->AddComponent(meshRenderer); // MeshRenderer 컴포넌트를 추가합니다. } scene->AddGameObject(monster); // 생성된 몬스터 객체를 장면에 추가합니다. } return scene; // 설정이 완료된 장면 객체를 반환합니다. }
결론
MeshRenderer와 SceneManager를 사용하여 게임 오브젝트마다 리소스를 그리는 작업을 나누고, Scene을 통해 게임의 다양한 장면을 효율적으로 관리하는 구조는 게임 개발에서 매우 중요합니다. 이러한 구조는 게임의 성능 최적화와 유지 보수성 향상에 기여하며, 개발자가 보다 복잡한 게임 로직과 장면 전환을 쉽게 구현할 수 있게 합니다.
반응형다음글이전글이전 글이 없습니다.댓글