수업


📘 주제

MeshRenderer로부터 렌더링 책임을 분리하고, 중앙 집중식으로 렌더링 처리를 담당하는 RenderManager 구현

이 강의의 핵심은 기존에 MeshRenderer 클래스 내부에 있었던 렌더링 관련 로직과 책임을 RenderManager 클래스로 이동시켜,
렌더링 과정을 중앙 집중화하고 구조를 확장성 있고 유지보수 가능한 형태로 개편하는 것입니다.

렌더링 시 필요한 CameraData, TransformData 등의 데이터를 GPU로 넘기기 위해 ConstantBuffer를 사용하는데,
이때 각 물체마다 버퍼를 만들지 않고 RenderManager에서 공용으로 하나만 생성하여 고속복사를 통해 공유하는 구조를 설계합니다.


📙 개념

개념설명
렌더링 책임 분리MeshRenderer의 렌더링 코드를 RenderManager로 이전하여 역할 분담
공용 버퍼 사용모든 오브젝트에서 공유할 Camera/Transform 버퍼를 RenderManager가 관리
Render 대상 수집현재 씬에서 렌더링이 필요한 GameObject만 필터링하여 보관
렌더링 파이프라인 설정VertexShader, PixelShader, Layout, 상태 객체들을 설정 후 렌더링 실행
Init 함수 분리생성자 내에서 리소스 생성 시 shared_from_this 충돌 가능성을 방지하기 위한 분리
friend 키워드 활용RenderManager가 MeshRenderer의 private 멤버에 접근 가능하도록 허용

🧾 용어 정리

용어설명
RenderManager모든 렌더링 로직을 전담하는 클래스
RenderHelper.h렌더링 시 GPU에 넘길 데이터를 정의한 구조체 (CameraData, TransformData) 보관
CameraDataView, Projection 행렬을 저장하는 구조체
TransformDataWorld 행렬을 저장하는 구조체
ConstantBuffer<T>CPU에서 GPU로 데이터를 복사하기 위한 버퍼 템플릿 클래스
PipelineInfo렌더링 시 파이프라인 설정 정보를 담는 구조체
RasterizerState, BlendState, SamplerStateDirectX의 파이프라인 렌더 상태 객체들
_renderObjects현재 프레임에서 렌더링 대상이 되는 GameObject 리스트

💻 코드 분석

📂 1. RenderHelper.h

struct CameraData
{
    Matrix matView = Matrix::Identity;
    Matrix matProjection = Matrix::Identity;
};

struct TransformData
{
    Matrix matWorld = Matrix::Identity;
};
  • CameraData: 뷰/투영 행렬 저장
  • TransformData: 월드 행렬 저장
  • 원래 Struct.h에 있던 정의를 RenderHelper.h로 이동시킴.
    → 렌더링에 특화된 구조체이기 때문.

📂 2. RenderManager 클래스 선언

class RenderManager
{
public:
    RenderManager(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext);
    void Init();
    void Update(shared_ptr<Graphics> graphics);

private:
    void PushCameraData();
    void PushTransformData();
    void GatherRenderableObjects();
    void RenderObjects();

private:
    ComPtr<ID3D11Device> _device;
    ComPtr<ID3D11DeviceContext> _deviceContext;
    shared_ptr<Pipeline> _pipeline;

    CameraData _cameraData;
    shared_ptr<ConstantBuffer<CameraData>> _cameraBuffer;

    TransformData _transformData;
    shared_ptr<ConstantBuffer<TransformData>> _transformBuffer;

    shared_ptr<RasterizerState> _rasterizerState;
    shared_ptr<BlendState> _blendState;
    shared_ptr<SamplerState> _samplerState;

    vector<shared_ptr<GameObject>> _renderObjects;
};
  • 디바이스, 컨텍스트 저장
  • 공용 버퍼: 카메라/트랜스폼
  • 파이프라인 상태 객체: RS, Blend, Sampler
  • 렌더 대상: _renderObjects

📂 3. RenderManager::Init()

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();
}
  • 모든 공용 리소스들을 초기화
  • 메모리 절약과 재사용을 위해 GameObject마다 만들지 않고 한 번만 생성

📂 4. RenderManager::Update()

void RenderManager::Update(shared_ptr<Graphics> graphics)
{
    graphics->RenderBegin();

    PushCameraData();
    GatherRenderableObjects();
    RenderObjects();

    graphics->RenderEnd();
}
  • 프레임별 렌더링의 전체 흐름을 담당하는 함수
  • Game에서는 RENDER->Update() 호출만으로 렌더링 전체 수행 가능

📂 5. PushCameraData()

void RenderManager::PushCameraData()
{
    _cameraData.matView = Camera::S_MatView;
    _cameraData.matProjection = Camera::S_MatProjection;
    _cameraBuffer->CopyData(_cameraData);
}
  • 카메라 정보를 전역에서 받아와 GPU로 복사
  • 현재는 하나의 카메라만 가정 (추후 다중 카메라 지원 고려 가능)

📂 6. PushTransformData()

void RenderManager::PushTransformData()
{
    _transformBuffer->CopyData(_transformData);
}
  • 물체마다 다른 월드 행렬을 GPU로 복사

📂 7. GatherRenderableObjects()

void RenderManager::GatherRenderableObjects()
{
    _renderObjects.clear();

    auto& gameObjects = SCENE->GetActiveScene()->GetGameObjects();
    for (const auto& gameObject : gameObjects)
    {
        auto meshRenderer = gameObject->GetMeshRenderer();
        if (meshRenderer)
            _renderObjects.push_back(gameObject);
    }
}
  • 현재 활성화된 Scene의 모든 GameObject 중 MeshRenderer가 있는 오브젝트만 선별하여 리스트에 저장

📘 주제

렌더링 흐름을 RenderManager로 완전히 통합하고, Game 구조 및 MeshRenderer를 리팩토링하여 전체 엔진 렌더링 구조를 정리

Part 1에서 구현된 RenderManager를 기반으로, Game 클래스의 렌더링 흐름을 RenderManager로 완전히 위임하고, MeshRenderer 클래스는 렌더링 책임을 분리하여 데이터만 보관하도록 구조를 정리한다. 또한 전역 매크로 등록을 통해 편리한 접근 방식을 도입하며, 전체 렌더링 구조의 완성형 틀을 만든다.


📙 개념

개념설명
렌더링 책임 완전 통합Game 클래스의 RenderBegin/End, MeshRenderer의 Render 함수까지 RenderManager로 이전
Game 구조 경량화Game 클래스는 오직 RenderManager를 호출만 하며 파이프라인, 버퍼 생성 책임 제거
전역 접근 매크로 도입RENDER 매크로를 통해 RenderManager에 쉽게 접근 가능
MeshRenderer 역할 최소화렌더링 로직은 제거, 파이프라인 설정용 데이터만 보관
유지보수성 향상렌더링 흐름이 RenderManager에서 일괄 처리되므로 디버깅과 확장성 확보 용이

🧾 용어정리

용어설명
RENDERRenderManager에 접근하기 위한 전역 매크로 (RENDER->Update(...))
friend class RenderManager;RenderManager가 MeshRenderer의 private 멤버에 접근 가능하도록 허용
Game::Render()이제 RenderManager의 Update를 호출하는 단순 역할만 수행
_renderObjects렌더링 대상 GameObject 배열
Graphics::RenderBegin/End()렌더링 루프의 시작/종료를 의미하며 RenderManager에서 호출됨
Init()RenderManager 내부에서 파이프라인, 버퍼, 상태 객체 등을 초기화하는 함수

💻 코드 분석


🔧 1. Game 클래스에서 RenderManager 통합

📄 Game.h

class RenderManager;

shared_ptr<RenderManager> GetRenderManager() { return _render; }

private:
shared_ptr<RenderManager> _render;
  • 기존에 있던 _pipeline 관련 멤버는 삭제
  • _render 멤버를 통해 RenderManager를 전역에서 접근 가능

📄 Game.cpp

_render = make_shared<RenderManager>(_graphics->GetDevice(), _graphics->GetDeviceContext());
_render->Init();
  • Init()에서 RenderManager 인스턴스를 생성하고 초기화
  • 이전까지 존재했던 Pipeline 관련 생성 코드는 삭제됨

🔧 2. Game 클래스 렌더링 흐름 정리

📄 Game::Update

void Game::Update()
{
    TIME->Update();
    INPUT->Update();
    SCENE->Update();
}
  • RenderBegin, RenderEnd는 삭제 (RenderManager에서 수행하므로)

📄 Game::Render

void Game::Render()
{
    RENDER->Update(_graphics);
}
  • 이제 Game은 단순히 RENDER 매크로를 통해 렌더링 호출만 수행

🔧 3. 전역 매크로 등록 (pch.h)

#define RENDER GAME->GetRenderManager()
  • 전역에서 RENDER->Update(...)와 같이 간단하게 RenderManager에 접근 가능

🔧 4. MeshRenderer의 역할 정리

📄 MeshRenderer.h

class MeshRenderer : public Component
{
    ...
    friend class RenderManager;

private:
    shared_ptr<Geometry<VertexTextureData>> _geometry;
    shared_ptr<VertexBuffer> _vertexBuffer;
    shared_ptr<IndexBuffer> _indexBuffer;
    shared_ptr<InputLayout> _inputLayout;
    shared_ptr<VertexShader> _vertexShader;
    shared_ptr<PixelShader> _pixelShader;
    shared_ptr<Texture> _texture1;
};
  • 렌더링과 관련된 정보는 그대로 보관
  • RenderManager에서 사용하기 위해 friend 선언
    • 혹은 Getter 함수로 대체 가능

📄 MeshRenderer::Update

void MeshRenderer::Update()
{
    // Render 호출 제거
}
  • RenderManager가 전체 렌더링을 처리하므로 Render() 호출은 제거

📄 MeshRenderer::Render()

  • 완전히 제거해도 무방
  • 중앙화된 RenderManager가 모든 렌더링 흐름을 책임짐

🧠 핵심

항목설명
✅ RenderManager는 렌더링 전 과정(데이터 수집, 상태 설정, 렌더 호출)을 통합 수행
✅ Game은 단순히 RENDER->Update(...)만 호출함으로써 렌더링 로직을 위임
✅ MeshRenderer는 렌더링 코드 제거, 렌더링에 필요한 데이터만 보관
✅ RenderBegin/End 호출은 RenderManager가 담당하여 Game::Update에서 제거됨
✅ RenderHelper 구조체 분리 및 공용 버퍼 구조로 리소스 최적화 실현
✅ 향후 다중 카메라, 조명, 후처리 시스템 연동을 위한 구조 기반 확보

🧩 전체 렌더링 흐름

[Game::Render()]
   └── RENDER->Update()
           ├── RenderBegin()
           ├── PushCameraData()
           ├── GatherRenderableObjects()
           ├── RenderObjects()
           └── RenderEnd()

profile
李家네_공부방

0개의 댓글