ImGui 활용한 DirectX 11 3D를 이용한 2D를 만드는 내용입니다.
본 내용은 똑같이 사용할 수 없음을 알립니다. (참고및 공부자료로 만들어진 내용임을 밝힙니다.)
전 과정에 대해 이해를 해야 다음 이 부분에 대한 이해를 할 수 있음을 밝힙니다
이전 자료) https://ppatabox.tistory.com/36
1) AlphaBlending with Rendertarget
앞부분을 이론 파트임
이번에는 RenderTarget을 이해해야 하는데
Rendering의 개념에서 생각해 보면
Stage = 옵션을 주어서 시스템을 수행하는 부분
IA(정점입력) -> VS(정점을 3D공간에서 다룸) ->
RS(Rasterizer Stage)3D공간을 2D로 변환시켜주는 ->
PS(Pixel shader) 픽셀을 다뤄주는 ->
OM(Output Merger) 2개의 결과 RS로 나오면 1) PS로 거칠애 2) OM으로 바로 들어갈애
OM에 RTV(Render Target View)라는 것이 들어가 있는데.
이 RTV에는 어떠한 Texture가 연결되어있다.
지난번 Texture에 이러한 함수를 썻는데
D3DXCreateshaderViewFromFile
자동으로 내부적으로 텍스쳐를 만들어준 것 system에다가
ID3D11ShadersourceView
하나가 더있는데
ID3DTexture2D 인터페이스가 있는데
ID3D11ShadersourceView
이것을 부르면 이것을 System한테 자동으로 ID3DTexture2D 이것을 불러들이는 명령어 이다.
실제로 이 2개는 다른것으로 생각해야한다.
ID3D11ShadersourceView(SRV)
하는 역할이 무엇이냐면 SRV라고 표현하는데
쉐이더 한테 내가 리소스(텍스쳐,버퍼)를 줄껀데
개입장에서 어떻게 받아들일지 모르니까 알려주는 역할
"텍스쳐 이런식으로 보낼테니까 니가 이런식으로 받아 쉐이더에서 처리해 " 라는 역할
RTV에도 Texture2D 가있다.
이것은 지정한 화면사이즈가 있다고 하자
1024X768
화면사이즈를 만들어주는 Texture가 있다.
픽셀쉐이더에서 처리한 결과가 스크린 안으로 들어간다.
여기에 있는 Texture2D는 시스템에 있는 Texture 2D이다.
이곳에 텍스쳐를 그리게 되면
나중에 프레젠트 라는 영역에 의해서 화면에 더블버퍼링으로 나간다.
중요) 더블버퍼링이란?(Double Buffering)
그래픽프로그래밍 기본
버퍼 라는 것은 항상 프로그래밍 에서는 임의의 기억장소 라고 한다.
흔히 항상 유지 할 것은 아니고 필요없을때 제거 할려고 하는 것이라서
임시 기억장소 라고도 불린다.
버텍스 버퍼도 렌더링 끝나고 나서 지울 건데 그래서 버퍼 라고 불린다.
이 Double Buffering의 Buffer는 의미는 Texture를 의미하는데
Ex) Buffer가 하나 있다 (화면Texture) 이곳에 캐릭터도 그리고 배경도 그리고 태양도 그리고 할 것이다.
근데 이 그리는 과정이 그대로 사용자 한테 보여지면 어떨까?( 겁나게 깜빡인다 1초의 60번을 그리는데 )
움직일 때 마다 캐릭터 그리고 뭐 그리고 한다 하면 그게임 눈아파서 안한다.
그래서 버퍼를 2개를 둔다.
첫번째 버퍼가 다 그려지고 나면 먼저 화면으로 보내준다
그리고나서 그려질 것을 다시 한번 다른 버퍼에 그려준다 그래서 이게 다 그려지면 다음으로 나가게 된다.
그러니까 두번째꺼 나가기 전까지 첫번째꺼가 나가있는다고 생각하면 된다.
그렇게 왔다 갔다 해주는 원리 (그린 결과만 보여주는것 )
그럼 깜빡임이 사라짐
그래서 여기 연결되어있는 Texture가 자동으로 Double buffer이다
그래서 Texture2D가 최종결과
이곳에 그려지는 애가 저 중에 하나의 버퍼 이다.
다 그려지고 나면 1번째께 화면으로 나가면 그다음
두번째 에다 또 그린다. 그 용도로 쓰임
좀더 확장해서 보자
Texture를 PixelShader에 넣어서 다뤄 본적이 있었는데 (SRV만 가지고 했었음) Texture 를 쉐이더에 넣어서 그렸었다.
그럼 이런것도 가능하지 않은가?
- 포스트 이펙트 ( Video post-processing) 방법
예를들어
IA 에서 부터 한꺼번에 처리해주고 Texture2D에다 마리오를 하나 그려넣었다.
이 그려준 장면이 Texture라고 했는데 이 그려준 텍스쳐를 가져다가 정점 4개 사각형을 그리는데 (화면크기 만큼) 텍스쳐를 PS에 넣을 수 있지 않을까?(가능하다)
그다음 PS에 어떤 조작을 가지고 OM으로 이때 시스템 texture2D 더블버퍼링 연결되어있는 텍스쳐로 나가는 방법도 가능하다
화면을 일그러 트리거나 , 피흘리면 흐려진다거나 , 마법에 걸리면 울렁울렁등의 결과를 일으킬때
전체 결과를 그려놓고 -> 그려놓은 텍스쳐를 가져다가 다시한번 조작하는 것
이 포스트 이펙트 일때 RTV를 한장만 쓰는 것이 아니라. PS에서 렌더링을 할때 최대 8장 까지 한번에 RTV를 만들어 낸다.3D에서 디퍼드 렌더링 할때 쓰인다. 8장 까지 쓸 수 있다고 알아두고 이렇게 쓰는 것을 Multie Render Target 이라고 불린다 MRT한번에 하나의 렌더링으로 8장의 서로 다른 결과를 만들어 내는것
요약 : 한번 그린 결과를 다시한번 가져와서 쓰겠다라는 의미
처리결과를 Texture2D에 저장이 되고 상황에 따라 Buffer를 선택해서 double Buffering이 일어나서화면이 끊기지 않게 보여준다.
알파블렌딩 하는데 좀 알고 가면 좋다.일반 학업이나 책에서 제대로 알 수 없다.그냥 이론적으로 만 알고 현업에서 어떻게 쓰이는지 잘 몰라서 옵션을 세세하게 풀어 줄 수 없는 것
OM에 텍스쳐 부분이 이루어지는 부분을 잘 알고 가면 좋다.
알파블렌딩 하면서 쓸 것이 OM에서 이루어지기 때문에 윗부분을 설명한 것인데.
이것을
OMSetBlendState
라고 불린다.
우리가 지금 쓰는 알파 블렌딩은 그려진 색이 있고 그려야할 색이 존재한다.
화면에다가 처음에 사각형을 그리고 (배경화면이 그려져 있겠지만)
픽셀쉐이더에서 이 사각형을 빨간색을 칠했다.
그럼 OM으로 가서
이 텍스쳐 에는 빨간색의 배경이 그려졌을 것이다.
그다음에 마리오를 그리기 위해서 위에 사진처럼 단계적으로 타고 Draw까지 가서
마리오를 그리는 시점에서 보면 이미 그려진 색이 있다.
마리오는 그려질 색인것이고
이게 바로 Texture에서 일어나고 Texture는 OM 단계에 연결되어 있기 때문에
OM에 Blend라는 옵션이 들어가는 것이다.
그런데 OM에 어떤 옵션이 나오냐면 RenderTartget이라는 게 나온다
알파블렌드 식을 이곳에 넣을 것인데.
이것은 배열로 되어있다. 배열 8개
RenderTartget[8]
이번편에서는 1장을 쓸거기 떄문에 0을 쓰고 사용할텐데
나중에 8장으로 분할 된다.
Texture.cpp/ h
에서 셋팅을 좀 해주자
Texture.h
#pragma once
class Texture
{
public:
Texture(wstring file);
~Texture();
void Position(float x, float y, float z = 0);
void Position(const D3DXVECTOR3& position);
void Position(D3DXVECTOR3* position);
void Scale(float x, float y, float z = 1);
void Scale(const D3DXVECTOR3& scale);
void Scale(D3DXVECTOR3* scale);
void Rotation(float z);
void Rotation(float* z);
void RotationRadian(float z);
void RotationRadian(float* z);
void Render();
private:
struct Vertex
{
D3DXVECTOR3 Location;
D3DXVECTOR2 Uv;
Vertex()
{
Location = D3DXVECTOR3();
Uv = D3DXVECTOR2();
}
Vertex(D3DXVECTOR3 location, D3DXVECTOR2 uv)
{
Location = location;
Uv = uv;
}
};
struct WVP
{
D3DXMATRIX World;
D3DXMATRIX View;
D3DXMATRIX Projection;
} wvp;
private:
D3DXVECTOR3 position;
D3DXVECTOR3 scale;
D3DXVECTOR3 rotation;
private:
int blendIndex = 0;
Shader* shader;
Vertex vertices[6];
VertexBuffer* vertexBuffer;
ConstantBuffer* wvpBuffer;
ID3D11ShaderResourceView* srv;
ID3D11SamplerState* sampler;
ID3D11BlendState* blendStates[4]; // 얘도 똑같이 인터페이스 이니까 디스크립션이 있다.
};
간단한 경우 그냥 ZeroMemory 사용하겠음
BlendEnable 이전에 그려진 것과 현재 그려진것을 섞기 시작할 것인가 섞는 연산인데 필요할때만 켜야함 매우 느린 연산
D3D11_COLOR_WRITE_ENABLE_ALL 우린 모든 색상을 쓰겠다 라고 받아들이는 것 컬러마스팅 기법?
전 시간 것을 보면
SRC * A + Dest * B 에 대해서 설명하였는데 그부분이
선형으로 알파값 섞는것
additive애서 하나는 1 넣었고 b는 1 넣어줘서
src + dest 그대로 더해준것
modulate A에다 DestColor넣었고 SRC * DestColor되었음
뒤에꺼는 제로 넣어줘서 없앰 결국엔 곱한값이랑 동일
D3D11_BLEND_DESC blendDesc;
ZeroMemory(&blendDesc, sizeof(D3D11_BLEND_DESC)); //간단한 경우 그냥 ZeroMemory 사용하겠음
blendDesc.RenderTarget[0].BlendEnable = false; //0번 옵션을 8장을 다 동일하게 묶겠다
blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
hr = Device->CreateBlendState(&blendDesc, &blendStates[0]); //
assert(SUCCEEDED(hr));
blendDesc.RenderTarget[0].BlendEnable = true;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; //op 연산자 add더할 것임
blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; //SRC알파값
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; //B값 InvSrc값 선형으로 섞이게
hr = Device->CreateBlendState(&blendDesc, &blendStates[1]);
assert(SUCCEEDED(hr));
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; //addtive할려면 둘다 1 만들어버리면 그냥 더하기가 된다.
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE; // 원본 값이니까.
hr = Device->CreateBlendState(&blendDesc, &blendStates[2]);
assert(SUCCEEDED(hr));
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_DEST_COLOR; //컬러 (곱하기가 된다)
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; //제로 들어가니까 뒤에꺼 사라짐
hr = Device->CreateBlendState(&blendDesc, &blendStates[3]);
assert(SUCCEEDED(hr));
Texture.cpp
#include "stdafx.h"
#include "Texture.h"
Texture::Texture(wstring file)
{
vertices[0] = Vertex(D3DXVECTOR3(-0.5f, -0.5f, 0), D3DXVECTOR2(0, 1));
vertices[1] = Vertex(D3DXVECTOR3(-0.5f, +0.5f, 0), D3DXVECTOR2(0, 0));
vertices[2] = Vertex(D3DXVECTOR3(+0.5f, -0.5f, 0), D3DXVECTOR2(1, 1));
vertices[3] = Vertex(D3DXVECTOR3(+0.5f, -0.5f, 0), D3DXVECTOR2(1, 1));
vertices[4] = Vertex(D3DXVECTOR3(-0.5f, +0.5f, 0), D3DXVECTOR2(0, 0));
vertices[5] = Vertex(D3DXVECTOR3(+0.5f, +0.5f, 0), D3DXVECTOR2(1, 0));
D3D11_INPUT_ELEMENT_DESC layoutDesc[] =
{
"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0,
"UV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0
};
UINT elementCount = ARRAYSIZE(layoutDesc);
shader = new Shader(L"effect.hlsl");
shader->CreateInputLayout(layoutDesc, elementCount);
vertexBuffer = new VertexBuffer(vertices, 6, sizeof(Vertex));
wvpBuffer = new ConstantBuffer(&wvp, sizeof(WVP));
D3DXMatrixIdentity(&wvp.World);
D3DXMatrixIdentity(&wvp.View);
D3DXMatrixIdentity(&wvp.Projection);
D3DXVECTOR3 eye(0, 0, -1);
D3DXVECTOR3 lookAt(0, 0, 0);
D3DXVECTOR3 up(0, 1, 0);
D3DXMatrixLookAtLH(&wvp.View, &eye, &lookAt, &up);
D3DXMatrixTranspose(&wvp.View, &wvp.View);
D3DXMatrixOrthoOffCenterLH(&wvp.Projection, 0, (float)Width, 0, (float)Height, -1, +1);
D3DXMatrixTranspose(&wvp.Projection, &wvp.Projection);
wstring textureFile = L"../_Textures/" + file;
HRESULT hr = D3DX11CreateShaderResourceViewFromFile(Device, textureFile.c_str(), NULL, NULL, &srv, NULL);
assert(SUCCEEDED(hr));
D3D11_SAMPLER_DESC samplerDesc;
ZeroMemory(&samplerDesc, sizeof(D3D11_SAMPLER_DESC));
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
hr = Device->CreateSamplerState(&samplerDesc, &sampler);
assert(SUCCEEDED(hr));
D3D11_BLEND_DESC blendDesc;
ZeroMemory(&blendDesc, sizeof(D3D11_BLEND_DESC)); //간단한 경우 그냥 ZeroMemory 사용하겠음
blendDesc.RenderTarget[0].BlendEnable = false; //0번 옵션을 8장을 다 동일하게 묶겠다
blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
hr = Device->CreateBlendState(&blendDesc, &blendStates[0]); //
assert(SUCCEEDED(hr));
blendDesc.RenderTarget[0].BlendEnable = true;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
hr = Device->CreateBlendState(&blendDesc, &blendStates[1]);
assert(SUCCEEDED(hr));
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE;
hr = Device->CreateBlendState(&blendDesc, &blendStates[2]);
assert(SUCCEEDED(hr));
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_DEST_COLOR;
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
hr = Device->CreateBlendState(&blendDesc, &blendStates[3]);
assert(SUCCEEDED(hr));
}
Texture::~Texture()
{
for (int i = 0; i < 4; i++)
SAFE_RELEASE(blendStates[i]);
SAFE_RELEASE(sampler);
SAFE_RELEASE(srv);
SAFE_DELETE(vertexBuffer);
SAFE_DELETE(wvpBuffer);
SAFE_DELETE(shader);
}
void Texture::Position(float x, float y, float z)
{
Position(D3DXVECTOR3(x, y, z));
}
void Texture::Position(const D3DXVECTOR3 & position)
{
this->position = position;
}
void Texture::Position(D3DXVECTOR3 * position)
{
memcpy(position, this->position, sizeof(D3DXVECTOR3));
}
void Texture::Scale(float x, float y, float z)
{
Scale(D3DXVECTOR3(x, y, z));
}
void Texture::Scale(const D3DXVECTOR3 & scale)
{
this->scale = scale;
}
void Texture::Scale(D3DXVECTOR3 * scale)
{
memcpy(scale, this->scale, sizeof(D3DXVECTOR3));
}
void Texture::Rotation(float z)
{
rotation = D3DXVECTOR3(0, 0, 0);
rotation.z = -Math::ToRadian(z);
}
void Texture::Rotation(float * z)
{
*z = Math::ToDegree(rotation.z);
}
void Texture::RotationRadian(float z)
{
rotation = D3DXVECTOR3(0, 0, 0);
rotation.z = -z;
}
void Texture::RotationRadian(float * z)
{
*z = rotation.z;
}
void Texture::Render()
{
D3DXMATRIX S, R, T;
D3DXMatrixScaling(&S, scale.x, scale.y, scale.z);
D3DXMatrixTranslation(&T, position.x, position.y, position.z);
//D3DXMatrixIdentity(&R);
//
//R._11 = cosf(rotation.z);
//R._12 = sinf(rotation.z);
//R._13 = 0.0f;
//R._21 = -sinf(rotation.z);
//R._22 = cosf(rotation.z);
//R._23 = 0.0f;
D3DXMatrixRotationZ(&R, rotation.z);
wvp.World = S * R * T;
D3DXMatrixTranspose(&wvp.World, &wvp.World);
ImGui::SliderInt("Blend", &blendIndex, 0, 3);
DeviceContext->OMSetBlendState(blendStates[blendIndex], NULL, 0xFF);
DeviceContext->PSSetSamplers(0, 1, &sampler);
DeviceContext->PSSetShaderResources(0, 1, &srv);
DeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
shader->Render();
vertexBuffer->Render();
wvpBuffer->Render();
DeviceContext->Draw(6, 0);
}
Device에서 Background 좀 바꿔줘서 확인해 보았다.
D3DXCOLOR background = D3DXCOLOR(0, 0, 1, 1);
실행 시켜 보면 1번이 반투명 (알파값)
2번하면 파란색 계열로 밝아지고 ( 더하기는 색을올리니까 밝음)
3번은 파란색 계열로 어두워짐 ( 곱하기는 색을 떨어뜨려서 어두워짐)
다음시간에는 상속에 대해 알아보겠음
다음시간)
'🅿🆁🅾🅶🆁🅰🅼🅼🅸🅽🅶 > DɪʀᴇᴄᴛX 2D' 카테고리의 다른 글
[C++]DirectX 객체 지향과 4대 속성 | What is OOP(Object-Oriented Programming) Four basic concepts (attributes) (0) | 2021.11.23 |
---|---|
[C++] DirectX 원과 회전 Rotation (0) | 2021.11.22 |
[C++] DirectX World|View|Projection 활용 구현 랜덤 사각형 (0) | 2021.11.20 |