포스트

DirecX12 | Lecture 14. Component (인프런)

DirectX12 강의 14. Component를 정리한 글입니다.

DirecX12 | Lecture 14. Component (인프런)

강의 정보 🎓


게임 오브젝트 구조를 컴포넌트 기반(Component-based) 으로 구성하여 유연한 설계를 구현합니다.

(유니티처럼 → 컴포넌트 기반 / 언리얼은 상속 기반 + 컴포넌트)


1. GameObject, Component 구조 설계

생성된 클래스:

  • Component
  • GameObject
  • MeshRenderer
  • Transform
  • MonoBehaviour

2. Component 클래스

  • enum class ComponentType 정의, MonoBehaviour를 마지막으로 정의 해준다.
  • 주요 멤버 함수:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
      public:
      	virtual void Awake() {}
      	virtual void Start() {}
      	virtual void Update() {}
      	virtual void LateUpdate() {}
        	
      private:
      	// GameObject만 이 함수를 접근하도록
      	friend class GameObject;
      	void SetGameObject(std::shared_ptr<GameObject> gameObject) { mGameObject = gameObject; }
        
    
  • 주요 멤버 변수:

    1
    2
    3
    
      protected:
      	COMPONENT_TYPE mType;
      	std::weak_ptr<GameObject> mGameObject;
    

3. GameObject 클래스

  • 상속 (스마트 포인터 전달에 필요)

    1
    
      class GameObject : public std::enable_shared_from_this<GameObject>
    
  • 주요 멤버 함수:

    1
    2
    3
    4
    5
    6
    7
    8
    
      public:
      	void Init();
      	void Awake();
      	void Start();
      	void Update();
      	void LateUpdate();
        
      	void AddComponent(std::shared_ptr<Component> component);	// 컴포넌트를 추가
    
  • 주요 멤버 변수:

    1
    2
    3
    
      private:
      	std::array<std::shared_ptr<Component>, FIXED_COMPONENT_COUNT> mComponents;
      	std::vector<std::shared_ptr<MonoBehaviour>> mScripts;
    

4. MonoBehaviour & Transform

  • Component 상속
  • 기본적인 생성자/소멸자 구현

5. MeshRenderer

  • Component 상속
  • MeshMaterial 클래스 관리
  • 주요 멤버 함수:

    1
    2
    3
    4
    5
    6
    7
    
      	virtual void Update() override { Render(); }
      	void Render()
      	{
      		// GetTransform()->Update();
      		mMaterial->Update();
      		mMesh->Render();
      	}
    
  • 주요 멤버 변수:

    1
    2
    
      	std::shared_ptr<Mesh> mMesh;
      	std::shared_ptr<Material> mMaterial;
    

6. Mesh 수정

  • Material, Transform 멤버 변수 삭제 (Component에서 받도록 변경)
  • Render() 시 Material/Transform 관련 호출를 제거한다.

7. Game.cpp 변경

  • 전역 GameObject를 추가한다.
  • Mesh 초기화 → GameObject::Init() 내부로 이동
  • init 함수 내부:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
      	//... 버텍스, 인덱스 설정 등
        	
      	gameObject->Init();	// Transform 추가
        
      	std::shared_ptr<MeshRenderer> meshRenderer = std::make_shared<MeshRenderer>();
      	{
      		std::shared_ptr<Mesh> mesh = std::make_shared<Mesh>();
      		mesh->Init(device, commandQueueLayer, vertices, indexes);
      		meshRenderer->SetMesh(mesh);
      	}
        
      	{
      		std::shared_ptr<Shader> shader = std::make_shared<Shader>();
      		std::shared_ptr<Texture> texture = std::make_shared<Texture>();
      		shader->Init(device, rootSignature, depthStencilBuffer->GetDSVFormat(), L"..\\Resources\\Shader\\default.hlsli");
      		texture->Init(device, commandQueueLayer, L"..\\Resources\\Texture\\avatar.png");
      		std::shared_ptr<Material> material = std::make_shared<Material>();
      		material->SetShader(shader);
      		material->SetFloat(0, 0.3f);
      		material->SetFloat(1, 0.4f);
      		material->SetFloat(2, 0.3f);
      		material->SetTexture(0, texture);
      		meshRenderer->SetMaterial(material);
      	}
        
      	gameObject->AddComponent(meshRenderer);
        
      	commandQueueLayer->WaitForGpuComplete();
      };
    
  • Game Update() 내부

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
      void Game::Update()
      {
      	Engine::GetInstance().Update();
      	Engine::GetInstance().RenderBegin();
        	
      	gameObject->Update();
        
      	Engine::GetInstance().RenderEnd();
      }
    

현재 문제 & 해결

문제

  • MeshRenderer에서 Render 시 device 등 인자들이 필요하다.
  • Component Update() 에서도 동일 인자 필요 → GameObject Update 수정 필요
  • 구조상 불필요한 수정이 우려된다.

해결

GameObject에 Update() 와 Render() 를 분리하여 해결하였다.

→ Component는 필요 시 Render() 를 오버라이드해서 사용한다.


요약

항목설명
Component 기반 구조GameObject + Component
GameObject 역할Component 추가/Update/Render 관리
MeshRenderer 역할Mesh + Material 묶어서 렌더링
Mesh 구조 변경Material/Transform 제거
Game 흐름 변경GameObject 중심으로 관리
Render 구조GameObject에서 Update/Render 분리

느낀점 📝

느낀점 💡 컴포넌트 기반의 구조를 구현해보고 싶었는데 마침 강의에서 비슷한 형태로 구현하게 되어서 매우 좋았다. 이를 기반으로 나만의 미니 엔진을 구현해보고싶다는 욕구가 든다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.