요약: Device, DeviceContext, SwapChain을 선언하고, CreateDeviceAndSwapChain을 이용해 생성해 채워주고, CreateRenderTargetView로 SwapChain의 후면버퍼를 GPU에게 전달할 수 있는 RenderTargetView 형태로 만들었다. 그리고 SetViewport로 출력할 화면을 설정하고, RenderBegin에서 RenderTargetView와 Viewport를 GPU에 세팅하고, RenderEnd에서 SwapChain의 버퍼에 그린 것을 제출해 회색 화면을 출력했다.
1. ComPtr을 이용한 Device, DeviceContext 선언
2. SwapChain
3. CreateDeviceAndSwapChain
4. RenderBegin, RenderEnd, CreateRenderTargetView
1. ComPtr을 이용한 Device, DeviceContext 선언
일단 Game.h에 두 변수를 선언 할 것이다.
private:
ID3D11Device* _device;
ID3D11DeviceContext* _deviceContext;
I는 인터페이스의 약자다.
addReference를 하고 나중에 Release를 안했거나, Release를 addReference한 수보다 많이 하면 메모리 누수 문제가 발생한다. 그래서 수동적으로 new, delete, AddRef, Release를 관리하면 바람직하지 않다.
그래서 스마트 포인터 방식으로 작동되게 래핑하는게 준비되어 있다.
ComPtr<ID3D11Device> _device = nullptr;
ComPtr<ID3D11DeviceContext> _deviceContext = nullptr;
ComPtr은 내부에서 RefCount를 증감시키고 관리해준다.
Com객체를 관리하는 포인터가 이름의 유래다. COM은 Component Object Model의 약자다.
#include <wrl.h>
...
using namespace Microsoft::WRL;
Windows Runtime Library
pch.h에서 이걸 추가해 해놨기 때문에 쓸 수 있는 것이다.
Com 객체의 역할은 무엇일까?
GPU와 대화를 하며 일을 시키는게 목적인데 GPU는 모델들 마다 스펙이 다른데 마이크로소프트사에서 만든 라이브러리로 몇 작업만 해주면 GPU제품들이랑 알아서 하드웨어적으로 연결이 된다. 이게 Com 객체의 핵심이다.
개념적으로는 _device와 _deviceContext 둘 다 총 사령관 느낌이다.
_device를 통해서 리소스를 만들어 만들어 준다. 스타에서 커맨드 센터 느낌. SCV뿐만 아니라 온갖 유닛을 생성할 수 있는 만능 커멘드 센터다.
_deviceContext를 통해서 이미 만들어진 리소스를 렌더링 파이프라인에 연결을 해준다. 렌더링 파이프라인 단계별로 함수가 있다. 예를 들어 RS단계에서 뭘 한다면 RSSet~이런식으로 되어 있다.
결국 유닛 생성은 _device로, 유닛에게 명령 내릴 때는 _deviceContext로 하면 된다.
2. SwapChain
DirectX를 공부할 때 구글링을 잘해야 한다. 예를 들어 directX11 device 에 대해 궁금하다면 검색을 해서 microsoft 페이지에서 보면 된다. 단점은 딱딱한 설명인 경우가 많아. 그런 경우에는 블로그에서 친절하게 설명해 놓은 것을 보면 된다.
https://learn.microsoft.com/ko-kr/windows/win32/direct3d11/overviews-direct3d-11-devices-intro
에 D3D11CreateDevice 또는 D3D11CreateDeviceAndSwapChain을호출하여 컴퓨터에 설치된 하드웨어 드라이버 중 하나에 대한 디바이스를 만들고 D3D_DRIVER_TYPE플래그를 사용하여 드라이버 유형을 지정합니다. 라고 써져 있는데 3D11CreateDeviceAndSwapChain 쪽이 Device와 Swapchain을 동시에 만들어 주는 것이니 조금 더 단순하다. 이 버전은 Device뿐만 아니라 SwapChain도 만들어 준다고 했으니까 SwapChian이 뭔지도 연구해야 한다.
처음으로 만들어줄 애 중에서 ComPtr<IDXGISwapChain>이라는 애가 등장을 한다. 다음과 같이 선언해 준다.
ComPtr<IDXGISwapChain> _swapChain = nullptr;
https://learn.microsoft.com/ko-kr/windows/win32/direct3ddxgi/d3d10-graphics-programming-guide-dxgi
구글에서 DirectX11 DXGI를 찾아보면 DXGI (DirectX Graphics Infrastructure) 가 왜 탄생했는지 알려준다.
느리게 발전하는 부분을 DXGI에 빼 놨는데 이 안에 스왑체인이 있다.
-> 애플리케이션은 프레임을 렌더링하는 데 걸리는 시간 또는 프레젠테이션에 필요한 프레임 속도에 따라 두 개 이상의 버퍼가 필요할 수 있습니다. 생성된 버퍼 집합을 스왑 체인이라고 합니다.
DX는 이렇게 문서 읽으며 찾아보고->익히고 이걸 반복 하며 공부한다.
3. CreateDeviceAndSwapChain
다음에 해야할 것은 만들어야 한다.
void CreateDeviceAndSwapChain(); 을 Game.h에 선언하고, Game.cpp에서 정의 한 뒤,
Game의 Init에서 호출해준다.
함수 단위로 만들어서 기능 단위로 구분할 수 있게 만들어 줄 것이다.
클래스를 옮겨 다닐 때 생기는 헷갈림을 줄이기 위해 오늘 할 작업은 모든 기능들을 Game 클래스에 넣을 것이다.
대장2개, 스왑체인1개 만들 것인데, SwapChain 은 무엇을 하는걸까?
더블 버퍼링을 쓰는 이유를 생각해보면, 그리는 작업과 보이게 하는 작업을 동시에 하면 문제 생길 수 있기 때문이었다.
그래서 후면버퍼가 완성되면 전면버퍼로 고속복사하는 방식과 전면, 후면 버퍼가 역할을 번갈아 가며 하는 방법이 있다. 지금은 전자 방법으로 할것이다. 그걸 담당하는게 SwapChain이다.
최종 결과물을 모니터에 렌더링하는 부분과 연관이 있구나 라는 것만 기억을 하면 된다.
void CreateDeviceAndSwapChain()를 정의할 때 ::D3D11CreateDeviceAndSwapChain() 함수를 호출해서 만들건데 이 함수의 인자가 너무 많다. 문서를 봐도 되지만 가끔은 남이 작업한 블로그의 결과물을 보고 역으로 추적하는 것도 방법이다.
::D3D11CreateDeviceAndSwapChain(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
// 그래픽 카드 사용하겠다는 내용, 그래픽 카드가 없으면 다른 거 선택하게끔 하는 옵션 있어.
nullptr,
0,
nullptr,
// feature level 에 대한 배열을 만들어 건내줘야 한다.
// 무슨 DX 버전들을 지원할것인지, 안채우면 지원 가능한 상위 버전 골라준다.
0, // 배열크기, nullptr로 했으니 0개
D3D11_SDK_VERSION, // 11버전에서 세부 버전이 몇번인지 매크로로 정의되어 있어.
&desc, // 스왑체인 디스크립션을 만들어서 넣어준다.
_swapChain.GetAddressOf(),
_device.GetAddressOf(), // _device에다가 결과물을 받아주는 거
nullptr,
_deviceContext.GetAddressOf()
);
}
에서 desc는 세팅해서 넣어줘야 한다.
DXGI_SWAP_CHAIN_DESC desc;
// 안에 또 구조체가 있기 때문에 복잡하다.
// CreateDeviceAndSwapChain 을 하고 있다는 것에 집중하는게 좋다.
ZeroMemory(&desc, sizeof(desc)); // desc를 0으로 밀어 버린다. ::memset(&desc, 0, sizeof(desc))이랑 마찬가지. 0으로 민 다음 필요한 걸로 채워줘야 해
{
desc.BufferDesc.Width = _width;
desc.BufferDesc.Height = _height; // 화면이 800x600이니 버퍼도 똑같이 800x600으로 만들어 주는 거
desc.BufferDesc.RefreshRate.Numerator = 60; // 화면 주사율
desc.BufferDesc.RefreshRate.Denominator = 1; // 이름으로 때려 맞춰 보는 연습도 재밌다.
desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // 8비트x4짜리로 만들어 주겠다
desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; // 지금 단계에선 신경 안써도 되는 옵션.
desc.SampleDesc.Count = 1; // 계단 현상 줄일 때 숫자 늘일 수 있어.
desc.SampleDesc.Quality = 0;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // 최종 결과물을 그려주는 역할로 사용하겠다는 옵션
desc.BufferCount = 1; // 후면 버퍼 개수
desc.OutputWindow = _hwnd; // 윈도우 핸들
desc.Windowed = true;
desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
}
이렇게 세팅을 한다.
앞으로 자주 쓰일텐데
_device.Get(); // ComPtr내부에서 관리하는 ID3D11Device를 꺼내고 싶을 때, 즉 ID3D11Device* 얘를 꺼내고 싶을 때
_device.GetAddressOf(); //ID3D11Device*의 주소값 즉 ID3D11Device**를 얻고 싶을 때
사용한다.
CreateDeviceAndSwapChain은 _device, _deviceContext, _swapChain을 동시에 채워주는 함수라고 볼 수 있다.
pch.h에 CHECK도 정의 해준다.
#define CHECK(p) assert(SUCCEEDED(p))
전체 코드를 보면
#include "pch.h"
#include "Game.h"
Game::Game()
{
}
Game::~Game()
{
}
void Game::Init(HWND hwnd)
{
_hwnd = hwnd;
_width = GWinSizeX;
_height = GWinSizeY;
// TODO
//_device->AddRef();
//_device->Release();
CreateDeviceAndSwapChain();
}
void Game::Update()
{
}
void Game::Render()
{
}
//
void Game::CreateDeviceAndSwapChain()
{
DXGI_SWAP_CHAIN_DESC desc; // 안에 또 구조체가 있기 때문에 복잡하다. Device and SwapChain을 하고 있다에 집중하는게 좋다.
ZeroMemory(&desc, sizeof(desc)); // desc를 0으로 밀어 버린다. ::memset(&desc, 0, sizeof(desc))이랑 마찬가지. 0으로 민 다음 필요한 걸로 채워줘야 해
{
desc.BufferDesc.Width = _width;
desc.BufferDesc.Height = _height; // 화면이 800x600이니 버퍼도 똑같이 800x600으로 만들어 주는 거
desc.BufferDesc.RefreshRate.Numerator = 60; // 화면 주사율
desc.BufferDesc.RefreshRate.Denominator = 1; // 이름으로 때려 맞춰 보는 연습도 재밌다.
desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // 8비트x4짜리로 만들어 주겠다
desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; // 지금 단계에선 신경 안써도 되는 옵션.
desc.SampleDesc.Count = 1; // 계단 현상 줄일 때 숫자 늘일 수 있어.
desc.SampleDesc.Quality = 0;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // 최종 결과물을 그려주는 역할로 사용하겠다는 옵션
desc.BufferCount = 1; // 후면 버퍼 개수
desc.OutputWindow = _hwnd; // 윈도우 핸들
desc.Windowed = true;
desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
}
//_device.Get(); // ComPtr내부에서 관리하는 ID3D11Device를 꺼내고 싶을 때, 즉 ID3D11Device* 얘를 꺼내고 싶을 때
//_device.GetAddressOf(); //ID3D11Device*의 주소값 즉 ID3D11Device**를 얻고 싶을 때
HRESULT hr = ::D3D11CreateDeviceAndSwapChain(
nullptr,
D3D_DRIVER_TYPE_HARDWARE, // 그래픽 카드 사용하겠다는 내용, 그래픽 카드가 없으면 다른 거 선택하게끔 하는 옵션 있어.
nullptr,
0,
nullptr, // feature level 에 대한 배열을 만들어 건내줘야 한다. 몇 DX 버전 지원할것인지, 안채워도 지원 가능한 상위 버전 골라준다.
0, // 배열크기, nullptr로 했으니 0개
D3D11_SDK_VERSION, // 11버전에서 세부 버전이 몇번인지 매크로로 정의되어 있어.
&desc, // 스왑체인 디스크립션을 위에서 만들어서 넣어준다.
_swapChain.GetAddressOf(), // _device에다가 결국 결과물을 받아주는 거
_device.GetAddressOf(),
nullptr,
_deviceContext.GetAddressOf()
);
//assert(SUCCEEDED(hr)); // 실패하면 크래시 나게 유도할 수 있다.
CHECK(hr);
}
이걸 실행하고 중단점을 찍어서 보면 D3D11CreateDeviceAndSwapChain의 인자에 주소 값들이 채워진 것을 볼 수 있다.
결국 _device, _deviceContext 커맨드센터를 할 아이 둘과, _swapChain을 만들었다.
이걸 기반으로 무엇인가를 해줘야 한다.
4. RenderBegin, RenderEnd, CreateRenderTargetView
void RenderBegin();
void RenderEnd();
void CreateRenderTargetView();
먼전 이 3가지 함수를 만들어 본다.
GPU 에도 메모리가 있는데 메모리에 정보를 건내줘서 사용해야 한다. D3D11CreateDeviceAndSwapChain로 만든 후면 버퍼라는 걸 알려줄 필요가 있고, 이 후면 버퍼에 그림을 그려달라 요청을 해야 한다. 그래서 RenderTargetView라는 걸 만들어서 후면 버퍼를 묘사하는 View라는 애를 만들어야 한다. DX12에서는 DescriptionHeap이라는 애로 통합이 되었지만 11에선 view라는 용어를 사용한다. 자원에 태그를 달아서 GPU에게 부연 설명하는 것이라 이해하면 된다.
Game.h에
// RTV
ComPtr<ID3D11RenderTargetView> _renderTargetView; // 후면 버퍼를 묘사하는 존재
이렇게 선언하고,
void Game::CreateRenderTargetView()
{
HRESULT hr;
ComPtr<ID3D11Texture2D> backBuffer = nullptr;
hr = _swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)backBuffer.GetAddressOf());
// 후면 버퍼를 Texture2D라는 타입으로 반환해 주는 거
// Texture는 png같은 건데 앞으로 어떻게 분석할지 모르는 거.
// RenderTargetView 용도로 사용할 것이라는 걸 명시해 줘야 해.
CHECK(hr);
_device->CreateRenderTargetView(backBuffer.Get(), nullptr, _renderTargetView.GetAddressOf());
CHECK(hr);
// 흐름:
// GetBuffer를 하면 SwapChain에서 후면 버퍼에 해당하는 리소스를 ComPtr<ID3D11Texture2D> backBuffer로 뱉어주고,
// 그거를 CreateRenderTargetView를 통해서 backBuffer를 묘사하는 RenderTargetView라는 형태로 만들어 줬고,
// GPU와 통신하면서 _renderTargetView를 건내주면 알아먹고, backBuffer에 그림을 그려주는 식으로 동작을 한다.
// 일종의 스페셜한 포인터
}
이렇게 GPU가 사용하는 포인터 RenderTargetView까지 만들었다.
Game.h에
// Misc
D3D11_VIEWPORT _viewport = { 0 }; // 화면의 크기를 묘사
이렇게 선언하고, void SetViewport();도 선언 한 뒤
void Game::SetViewport()
{
_viewport.TopLeftX = 0.f;
_viewport.TopLeftY = 0.f;
_viewport.Width = static_cast<float>(_width);
_viewport.Height = static_cast<float>(_height);
_viewport.MinDepth = 0.f;
_viewport.MaxDepth = 1.f;
}
SetViewport를 만들었으면 RenderBegin, RenderEnd만들 준비가 끝난거다.
Game.h에
private:
void RenderBegin();
void RenderEnd();
// Mics
float _clearColor[4] = { 0.5f, 0.5f, 0.5f, 0.5f };
Game.cpp에
void Game::Render()
{
RenderBegin();
// TODO
RenderEnd();
}
void Game::RenderBegin()
{
_deviceContext->OMSetRenderTargets(1, _renderTargetView.GetAddressOf(), nullptr);
_deviceContext->ClearRenderTargetView(_renderTargetView.Get(), _clearColor);
_deviceContext->RSSetViewports(1, &_viewport);
}
void Game::RenderEnd()
{
// RenderBegin에서 후면 버퍼에 그려달라 요청한 거고
// 여기서는 전면 버퍼에 복사를 해달라, 그리고 화면에 출력을 해달라 요청하는 거
// [ ] <- [ ]
HRESULT hr = _swapChain->Present(1, 0); // 그린 거를 제출하겠다. 전면 버퍼로 고속 복사
CHECK(hr);
}
이렇게 RenderBegin에서 _renderTargetView를 세팅 해주고, RenderEnd에서 전면 버퍼에 복사 해달라고 한다.
void Game::Init(HWND hwnd)
{
_hwnd = hwnd;
_width = GWinSizeX;
_height = GWinSizeY;
// TODO
CreateDeviceAndSwapChain();
CreateRenderTargetView();
SetViewport();
}
Init에서 함수들을 호출하고,
실행하면,
이런 회색 화면이 보여야 한다. RenderBegin의 _clearColor[4]의 값에 따라 색이 바뀐다.
일단 빈 도화지를 렌더링 파이프라인을 타고 보이게 하는 거 까지는 성공한 것이다.
5. 정리
1. 핵심 3총사를 만들었다. (커멘드센터 2개, 더블버퍼링 하는 애 1개) : _device, _deviceContext, _swapChain
2. 더블 버퍼링 할 때 후면 버퍼에 그려달라 요청하는애 _renderTargetView
Texture2D가 어떤 용도로 활용하는지 명확하지 않기 떄문에, 텍스쳐를 사용하는 용도는 최종 그림을 그리는 용도로 사용하겠다고 _renderTargetView라는 티켓을 붙여준 다음에 앞으로는 렌더링을 요청할 때 거기다가 뭔가를 그려주세요라고 RenderBegin에서 해주었다.
보통 책에서는 DXGI_SWAP_CHAIN_DESC에서 나가 떨어진다. 한바퀴 돌고 세부사항 보는 거 나쁘지 않지만, 처음 볼 때는 감으로 때려 맞춰보자. 지금은 큰 틀에서 함수 단위로 보는 걸 추천한다.
그 다음은 RenderBegin, RenderEnd 사이에 사물을 그리는 부분을 넣으면 완성이 된다.
이렇게 초기화는 완료했다.
다음 시간은 삼각형 그려 볼 것이다. GPU에게 일을 시킬 때 렌더링 파이프라인 작업을 해야한다. IA-VS-RS-PS-OM 이 5단계를 최소한 챙겨야 한다.함수 앞부분 보면 어느 단계인지 예측 가능하다.
Game.h
#pragma once
class Game
{
public:
Game();
~Game();
public:
void Init(HWND hwnd);
void Update();
void Render();
private:
void RenderBegin();
void RenderEnd();
private:
void CreateDeviceAndSwapChain();
void CreateRenderTargetView();
void SetViewport();
private:
HWND _hwnd;
uint32 _width = 0;
uint32 _height = 0;
private:
// Device & SwapChain
ComPtr<ID3D11Device> _device = nullptr;
ComPtr<ID3D11DeviceContext> _deviceContext = nullptr;
ComPtr<IDXGISwapChain> _swapChain = nullptr;
// RTV
ComPtr<ID3D11RenderTargetView> _renderTargetView; // 후면 버퍼를 묘사하는 존재
// Misc
D3D11_VIEWPORT _viewport = { 0 }; // 화면의 크기를 묘사
float _clearColor[4] = { 0.5f, 0.5f, 0.5f, 0.5f };
};
Game.cpp
#include "pch.h"
#include "Game.h"
Game::Game()
{
}
Game::~Game()
{
}
void Game::Init(HWND hwnd)
{
_hwnd = hwnd;
_width = GWinSizeX;
_height = GWinSizeY;
// TODO
//_device->AddRef();
//_device->Release();
CreateDeviceAndSwapChain();
CreateRenderTargetView();
SetViewport();
}
void Game::Update()
{
}
void Game::Render()
{
RenderBegin();
// TODO
RenderEnd();
}
void Game::RenderBegin()
{
_deviceContext->OMSetRenderTargets(1, _renderTargetView.GetAddressOf(), nullptr);
_deviceContext->ClearRenderTargetView(_renderTargetView.Get(), _clearColor);
_deviceContext->RSSetViewports(1, &_viewport);
}
void Game::RenderEnd()
{
// RenderBegin에서 후면 버퍼에 그려달라 요청한 거고
// 여기서는 전면 버퍼에 복사를 해달라, 그리고 화면에 출력을 해달라
// [ ] <- [ ]
HRESULT hr = _swapChain->Present(1, 0); // 그린 거를 제출하겠다.
CHECK(hr);
}
//
void Game::CreateDeviceAndSwapChain()
{
DXGI_SWAP_CHAIN_DESC desc; // 안에 또 구조체가 있기 때문에 복잡하다. Device and SwapChain을 하고 있다에 집중하는게 좋다.
ZeroMemory(&desc, sizeof(desc)); // desc를 0으로 밀어 버린다. ::memset(&desc, 0, sizeof(desc))이랑 마찬가지. 0으로 민 다음 필요한 걸로 채워줘야 해
{
desc.BufferDesc.Width = _width;
desc.BufferDesc.Height = _height; // 화면이 800x600이니 버퍼도 똑같이 800x600으로 만들어 주는 거
desc.BufferDesc.RefreshRate.Numerator = 60; // 화면 주사율
desc.BufferDesc.RefreshRate.Denominator = 1; // 이름으로 때려 맞춰 보는 연습도 재밌다.
desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // 8비트x4짜리로 만들어 주겠다
desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; // 지금 단계에선 신경 안써도 되는 옵션.
desc.SampleDesc.Count = 1; // 계단 현상 줄일 때 숫자 늘일 수 있어.
desc.SampleDesc.Quality = 0;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // 최종 결과물을 그려주는 역할로 사용하겠다는 옵션
desc.BufferCount = 1; // 후면 버퍼 개수
desc.OutputWindow = _hwnd; // 윈도우 핸들
desc.Windowed = true;
desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
}
//_device.Get(); // ComPtr내부에서 관리하는 ID3D11Device를 꺼내고 싶을 때, 즉 ID3D11Device* 얘를 꺼내고 싶을 때
//_device.GetAddressOf(); //ID3D11Device*의 주소값 즉 ID3D11Device**를 얻고 싶을 때
HRESULT hr = ::D3D11CreateDeviceAndSwapChain(
nullptr,
D3D_DRIVER_TYPE_HARDWARE, // 그래픽 카드 사용하겠다는 내용, 그래픽 카드가 없으면 다른 거 선택하게끔 하는 옵션 있어.
nullptr,
0,
nullptr, // feature level 에 대한 배열을 만들어 건내줘야 한다. 몇 DX 버전 지원할것인지, 안채워도 지원 가능한 상위 버전 골라준다.
0, // 배열크기, nullptr로 했으니 0개
D3D11_SDK_VERSION, // 11버전에서 세부 버전이 몇번인지 매크로로 정의되어 있어.
&desc, // 스왑체인 디스크립션을 위에서 만들어서 넣어준다.
_swapChain.GetAddressOf(),
_device.GetAddressOf(), // _device에다가 결국 결과물을 받아주는 거
nullptr,
_deviceContext.GetAddressOf()
);
//assert(SUCCEEDED(hr)); // 실패하면 크래시 나게 유도할 수 있다.
CHECK(hr);
}
void Game::CreateRenderTargetView()
{
HRESULT hr;
ComPtr<ID3D11Texture2D> backBuffer = nullptr;
hr = _swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)backBuffer.GetAddressOf()); // 후면 버퍼를 Texture2D라는 티입으로 반환해 주는 거
// Texture는 png같은 건데 앞으로 어떻게 분석할지 모르는 거. RenderTargetView 용도로 사용할 것이라는 걸 명시해 줘야 해.
CHECK(hr);
_device->CreateRenderTargetView(backBuffer.Get(), nullptr, _renderTargetView.GetAddressOf());
CHECK(hr);
// 흐름: SwapChain에서 후면 버퍼에 해당하는 리소스를 ComPtr<ID3D11Texture2D> backBuffer로 뱉어주고,
// 그거를 CreateRenderTargetView를 통해서 backBuffer를 묘사하는 _renderTargetView라는 형태로 만들어 줬고,
// GPU와 통신하면서 _renderTargetView를 건내주면 알아먹고, backBuffer에 그림을 그려주는 식으로 동작을 한다.
// 일종의 스페셜한 포인터
}
void Game::SetViewport()
{
_viewport.TopLeftX = 0.f;
_viewport.TopLeftY = 0.f;
_viewport.Width = static_cast<float>(_width);
_viewport.Height = static_cast<float>(_height);
_viewport.MinDepth = 0.f;
_viewport.MaxDepth = 1.f;
}
'DirectX' 카테고리의 다른 글
5. 텍스쳐와 UV (0) | 2023.12.13 |
---|---|
4. 삼각형 띄우기 (0) | 2023.12.09 |
2. 기본 프레임워크 (0) | 2023.12.02 |
1. 렌더링 OT (0) | 2023.12.01 |
0. DirectX OT 및 계획 (0) | 2023.12.01 |
댓글