필요한 개념
IA -> VS -> GS -> SO -> RS -> PS -> OM -> BackBuffer
RTV -> Texture
OM 다음에는 정확히 SwapChain의 BackBuffer Present() 명령으로 BackBuffer에 있는 내용을 그래픽 카드를 거쳐 모니터에 출력한다.
OM에서 멈춤다음에 다시
IA -> VS -> GS -> SO -> RS -> PS -> OM -> BackBuffer 과정으로 보낸다.
IA에 사각형 주고 PS에서 사각형에 RTV->Texture를 입혀서 효과를 준다.(흑백화를 준다던가, 색상을 반사시킨다던가)-> 이런걸 PostEffect라고 한다.
한번 처리하고 후에 Effect를 준다해서 PostEffect라고 한다.
피가 떨어지면 적색효과, 뽀샤시 보이는것들은 다 후처리로 한다.(식이 되게 많다, 복잡하지 않음, 상당히 뽀대나게 보인다.)
Bloom이라고 해서 뽀샤시는 다룰 것이다.
backbuffer를 생성할때
backbuffer포인터는 swapchain(모니터랑 연결된 애, 정확히는 그래픽카드에 가상화되어있는 애, 어떤 그래픽카드든 동일하게 사용위해)에 에서 가져온다.
결국엔 그래픽카드에 있는 백버퍼를 가져와서 RTV에 연결해줌, RTV에 그려주면 모니터로 바로 나감
OM에는 RTV와 DSV가 있다.
RTV는 컬러 자체를 픽셀에 저장, DSV는 깊이를 픽셀에 저장
Texture의 크기는 RTV와 DSV가 같아야함
따로 세팅안하면 SwapChain에서 세팅된 애들을 쓰게된다.
PostEffect : RTV의 렌더링된 텍스쳐 결과를 다시 한번 렌더링 할때 효과를 적용하는 방식(RTV에 있는 텍스쳐를 가져다가)
RenderTarget.h
#pragma once
class RenderTarget
{
public:
// DXGI_FORMAT_R8G8B8A8_UNORM 기본으로 줬다.
// 따른값줘도 되지 않나? 가능하다. 예를들어 DXGI_FORMAT_R32G32B32A32_UNORM
// 주게 되면 정밀도(깊이나 색상 정밀도, 프레임 속도 떨어짐, Upscaling 방식을 쓰기도함)를 높이는 것이 된다.
RenderTarget(UINT width = 0, UINT height = 0, DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM);
~RenderTarget();
ID3D11RenderTargetView* RTV() { return rtv; }
ID3D11ShaderResourceView* SRV() { return srv; }
void SaveTexture(wstring file);
// DepthStencil 넣은 이유가, OM에서 RTV와 DSV가 합쳐짐
// 그래서 두개의 크기가 일치해야한다(두개의 크기가 다르면 렌더링이 안됨), 또 DX에서 렌더링할떄
// RTV와 DSV가 묶어서 받도록 됨
void PreRender(class DepthStencil* depthStencil);
private:
// 렌더타켓은 텍스쳐를 가지고 있으므로
UINT width, height;
DXGI_FORMAT format; // 픽셀의 크기
ID3D11Texture2D* texture;
ID3D11RenderTargetView* rtv;
// 렌더 타켓에서 렌더링 된 텍스쳐를 넘긴다.
ID3D11ShaderResourceView* srv;
};
RenderTarget.cpp
#include "Framework.h"
#include "RenderTarget.h"
RenderTarget::RenderTarget(UINT width, UINT height, DXGI_FORMAT format) :
format(format)
{
// 사이즈 0놓면 화면 사이즈를 받는다.
this->width = (width < 1) ? (UINT)D3D::Width() : width;
this->height = (height < 1) ? (UINT)D3D::Height() : height;
// 생성
D3D11_TEXTURE2D_DESC textureDesc;
ZeroMemory(&textureDesc, sizeof(D3D11_TEXTURE2D_DESC));
textureDesc.Width = this->width;
textureDesc.Height = this->height;
textureDesc.ArraySize = 1;
textureDesc.Format = format;
// SRV | RTV에 연결됨
// D3D11_BIND_RENDER_TARGET : RTV에 연결될 텍스쳐 명시
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
// 민맵핑
textureDesc.MipLevels = 1;
// 샘플링 몇번할지 : 1번은 해야함
textureDesc.SampleDesc.Count = 1;
Check(D3D::GetDevice()->CreateTexture2D(&textureDesc, NULL, &texture));
D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
ZeroMemory(&rtvDesc, sizeof(D3D11_RENDER_TARGET_VIEW_DESC));
rtvDesc.Format = format;
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
// 1. 연결할 리소스 2. desc 3.만들 객체
Check(D3D::GetDevice()->CreateRenderTargetView(texture, &rtvDesc, &rtv));
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
// 텍스쳐의 포맷과 일치
srvDesc.Format = format;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = 1;
// 1. 연결할 리소스 2. desc 3.만들 객체
Check(D3D::GetDevice()->CreateShaderResourceView(texture, &srvDesc, &srv));
}
RenderTarget::~RenderTarget()
{
SafeRelease(texture);
SafeRelease(rtv);
SafeRelease(srv);
}
// 렌더링 한 결과를 파일로 저장해볼려고
void RenderTarget::SaveTexture(wstring file)
{
// 1. DC 2. 저장할 텍스쳐 3. 저장할 포맷 4. 파일명
Check(D3DX11SaveTextureToFile(D3D::GetDC(), texture, D3DX11_IFF_PNG, file.c_str()));
}
void RenderTarget::PreRender(DepthStencil* depthStencil)
{
// 렌더타켓 설정해주고 Clear 시킴
// 이전 장면을 지워야 덮어씌워지지 않으니깐
// 1. 몇개 세팅할거냐(MRT는 여러개 세팅가능), 2.RTV, 3.DSV
D3D::GetDC()->OMSetRenderTargets(1, &rtv, depthStencil->DSV());
// 백버퍼를(RTV의 backbuffer를 시스템backbuffer라고도 함)
// 그걸 clear 시킴
// 1. 클리어 시킬 색상, 2 : rtv
D3D::Get()->Clear(Color(0, 0, 0, 1), rtv, depthStencil->DSV());
}
DepthStencil.h
#pragma once
// 만드는 방법은 RTV와 유사
class DepthStencil
{
public:
DepthStencil(UINT width = 0, UINT height = 0, bool bUseStencil = false);
~DepthStencil();
ID3D11ShaderResourceView* SRV() { return srv; }
void SaveTexture(wstring saveFile);
ID3D11DepthStencilView* DSV() { return dsv; }
private:
bool bUseStencil; // 스텐실을 사용할 거냐
UINT width, height;
ID3D11Texture2D* texture; // 연결될 텍스쳐
ID3D11DepthStencilView* dsv;
ID3D11ShaderResourceView* srv; // 텍스쳐 넘기기 위해
};
DepthStencil.cpp
#include "Framework.h"
#include "DepthStencil.h"
DepthStencil::DepthStencil(UINT width, UINT height, bool bUseStencil)
{
this->width = (width < 1) ? (UINT)D3D::Width() : width;
this->height = (height < 1) ? (UINT)D3D::Height() : height;
//Create Texture
{
D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
desc.Width = this->width;
desc.Height = this->height;
desc.MipLevels = 1;
desc.ArraySize = 1;
// 스텐실을 사용하느냐 마냐에 따라 포맷이 바뀜 그거 말고 차이는 없다.
// bUseStencil 스텐실을 사용하면 DXGI_FORMAT_R24G8_TYPELESS(R24, G8(깊이 24비트, 스텐실 8비트)을 사용, 아니라면 DXGI_FORMAT_R32(깊이를 32비트로 전부 사용)_TYPELESS이다.
desc.Format = bUseStencil ? DXGI_FORMAT_R24G8_TYPELESS : DXGI_FORMAT_R32_TYPELESS;
desc.SampleDesc.Count = 1;
// D3D11_BIND_DEPTH_STENCIL : DSV에 연결을 명시
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DEPTH_STENCIL;
Check(D3D::GetDevice()->CreateTexture2D(&desc, NULL, &texture));
}
//Create DSV
{
D3D11_DEPTH_STENCIL_VIEW_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_DEPTH_STENCIL_VIEW_DESC));
// DXGI_FORMAT_D24_UNORM_S8_UINT : D24(Depth를 24비트로), S8(Stencil을 8비트로), 아니라면 32비트 플롯을 사용하겠다.
desc.Format = bUseStencil ? DXGI_FORMAT_D24_UNORM_S8_UINT : DXGI_FORMAT_D32_FLOAT;
desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
Check(D3D::GetDevice()->CreateDepthStencilView(texture, &desc, &dsv));
}
//Create SRV
{
D3D11_SHADER_RESOURCE_VIEW_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
// X8_TYPELESS : 스텐실에 대한 타입을 SRV에서 정확히 알 수가 없어서 모르겠다는 의미
desc.Format = bUseStencil ? DXGI_FORMAT_R24_UNORM_X8_TYPELESS : DXGI_FORMAT_R32_FLOAT;
desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
desc.Texture2D.MipLevels = 1;
Check(D3D::GetDevice()->CreateShaderResourceView(texture, &desc, &srv));
}
}
DepthStencil::~DepthStencil()
{
SafeRelease(texture);
SafeRelease(dsv);
SafeRelease(srv);
}
void DepthStencil::SaveTexture(wstring saveFile)
{
Check(D3DX11SaveTextureToFile
(
D3D::GetDC(), texture, D3DX11_IFF_PNG, saveFile.c_str()
));
}
D3D.cpp 설명된 내용
...
void D3D::SetRenderTarget(ID3D11RenderTargetView* rtv, ID3D11DepthStencilView* dsv)
{
// null일 경우 시스템 껄 세팅
if (rtv == nullptr)
rtv = renderTargetView;
if (dsv == nullptr)
dsv = depthStencilView;
D3D::GetDC()->OMSetRenderTargets(1, &rtv, dsv);
}
void D3D::Clear(D3DXCOLOR color, ID3D11RenderTargetView* rtv, ID3D11DepthStencilView* dsv)
{
// null이면 시스템껄 사용
if (rtv == nullptr)
rtv = renderTargetView;
if (dsv == nullptr)
dsv = depthStencilView;
deviceContext->ClearRenderTargetView(rtv, color);
// D3D11_CLEAR_DEPTH : 깊이를 가지고 클리어 하느냐
// D3D11_CLEAR_STENCIL : 스텐실도 클리어 할거냐
deviceContext->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1, 0);
}
Window.cpp 설명된 내용
void Window::MainRender()
{
...
//Update
mainExecute->Update();
// RenderTarget 화면에다가 렌더링하려고 쓰는 함수
mainExecute->PreRender();
D3DDesc desc = D3D::GetDesc();
// null 줘서 시스템께 세팅
D3D::Get()->SetRenderTarget();
// 시스템께 클리어됨
D3D::Get()->Clear(desc.Background);
{
//Render
Context::Get()->Render();
mainExecute->Render();
DebugLine::Get()->Render();
mainExecute->PostRender();
Gui::Get()->Render();
}
// Present
D3D::Get()->Present();
}
'DirectX11 3D > 기본 문법' 카테고리의 다른 글
<DirectX11 3D> 103 - MRT(MultiRenderTarget) (0) | 2022.03.21 |
---|---|
<DirectX11 3D> 100 - ColorTone(PostEffect) (0) | 2022.03.21 |
<DirectX11 3D> 96 - GS(Geometry Shader) (0) | 2022.03.16 |
<DirectX11 3D> 89 - ParticleSystem (0) | 2022.03.16 |
<DirectX11 3D> 88 - Snow (0) | 2022.03.14 |