삼각형 띄우기부터 거슬러 올라갈 수 있다.
TriangleDemo::Render에서 호출하는 Draw 함수를 f12로 보면 원리는 지난 시간에 했던 것과 비슷하게 된다는 걸 알 수 있다.
1. 새로운 02. QuadDemo 클래스를 만들고 Main.cpp의 WinMain에서 desc.app에 넣어주기
그다음 Demo로는 Rectangle 사각형을 그려 볼 건데
3D에서 사각형을 Quad라고 하기도 하기 때문에 Quad라고 하자.
탐색기로 Client 프로젝트에 들어가서 01. TriangleDemo.h, .cpp 파일을 복붙 해서 02. QuadDemo라고 이름을 바꾼다.
그리고 Client 프로젝트의 Game 필터에 넣어준다.
코드에서 class 이름도 QuadDemo로 수정한다.
#include "02. QuadDemo.h"
이렇게 수정하고 함수 구현부도 TriangleDemo에서 QuadDemo로 수정한다.
Init에서
_shader = make_shared<Shader>(L"02. Quad.fx");
이렇게 바꾼다.
Shader도 탐색기에서 복붙해서 이름을 02. Quad.fx로 한다.
그리고 Sahder 필터에 넣는다.
Main.cpp로 가서
#include "02. QuadDemo.h"
를 추가하고
desc.app = make_shared<QuadDemo>(); // 실행 단위
이렇게 바꿔주면
나머지 부분들이 다 똑같이 동작을 하게 된다.
app이 한번에 하나만 실행되지 않아도 되긴 하다.
2. GeometryHelper클래스에서 Geometry의 _vertices와 _indices를 세팅하는 CreateQuad함수 만들기
QuadDemo에서 사각형을 그려볼 것이다.
삼각형에서 사각형으로 넘어갈 때 정점이 6개가 일반적이었는데, 인덱스를 사용하면 4개가 필요하다. 연습을 해볼 수 있다.
여러 가지 방식이 있었다.
원래는 GeometryHelper라는 클래스에서 했다.
01. Graphics/Buffer 필터에 GeometryHelper클래스를 생성해서 넣는다.
VertexData.h에 있는 struct 중에서 무엇을 사용할지 선택할 수 있다.
ShaderInput이랑 맞춰야 한다.
이번에는 VertexColorData를 이용해서 사각형을 만들어 보자.
GeometryHelper.h로 가서
#pragma once
#include "Geometry.h"
#include "VertexData.h"
class GeometryHelper
{
public:
static void CreateQuad(shared_ptr<Geometry<VertexColorData>> geometry, Color color);
};
이렇게 하고 GeometryHelper.cpp에 가서 구현을 해준다면
#include "pch.h"
#include "GeometryHelper.h"
void GeometryHelper::CreateQuad(shared_ptr<Geometry<VertexColorData>> geometry, Color color)
{
vector<VertexColorData> vtx;
vtx.resize(4);
vtx[0].position = Vec3(-0.5f, -0.5f, 0.f);
vtx[0].color = color;
vtx[1].position = Vec3(-0.5f, 0.5f, 0.f);
vtx[1].color = color;
vtx[2].position = Vec3(0.5f, -0.5f, 0.f);
vtx[2].color = color;
vtx[3].position = Vec3(0.5f, 0.5f, 0.f);
vtx[3].color = color;
geometry->SetVertices(vtx);
// 1 3
// 0 2
// 시계방향, 반시계 방향 하나로 정해서 해야 한다. 컬링 옵션중에서 선택하는게 있었기 때문
vector<uint32> idx = { 0, 1, 2, 2, 1, 3 };
geometry->SetIndices(idx);
}
Engine을 수정했으면 빌드를 해줘야 한다.
빌드를 안 하고 클라를 실행하면 이전 상태의 엔진을 사용하게 된다.
GeometryHelper를 이용해서 인덱스 버퍼까지 구현할 수 있게 되었다.
3. QuadDemo 클래스의 Init에서 GeometryHelper의 CreateQuad를 호출해 _vertices와 _indices를 세팅하고, 이를 이용해 _vertexBuffer와 _indexBuffer를 만들기
02. QuadDemo.h에서
vector<VertexData> _vertices;
얘를 지우고
shared_ptr<Geometry<VertexColorData>> _geometry;
이걸 넣는다.
#include "Geometry.h"
이렇게 추가해 준다.
QuadDemo::Init을
void QuadDemo::Init()
{
_shader = make_shared<Shader>(L"02. Quad.fx");
_geometry = make_shared<Geometry<VertexColorData>>();
GeometryHelper::CreateQuad(_geometry, Color(1.f, 0.f, 0.f, 1.f));
_buffer = make_shared<VertexBuffer>();
_buffer->Create(_vertices);
}
이렇게 수정한다.
02. QuadDemo.h에서
shared_ptr<VertexBuffer> _buffer;
을 구분하기 위해서 _vertexBuffer라고 이름을 바꿔준다. ( rename으로 다른 곳에서 쓰이는 것도 변경)
그리고 IndexBuffer도 추가한다.
#pragma once
#include "IExecute.h"
#include "Geometry.h"
class QuadDemo : public IExecute
{
public:
void Init() override;
void Update() override;
void Render() override;
shared_ptr<Shader> _shader;
shared_ptr<Geometry<VertexColorData>> _geometry;
shared_ptr<VertexBuffer> _vertexBuffer;
shared_ptr<IndexBuffer> _indexBuffer;
};
void QuadDemo::Init()
{
_shader = make_shared<Shader>(L"02. Quad.fx");
_geometry = make_shared<Geometry<VertexColorData>>();
GeometryHelper::CreateQuad(_geometry, Color(1.f, 0.f, 0.f, 1.f));
_vertexBuffer = make_shared<VertexBuffer>();
_vertexBuffer->Create(_geometry->GetVertices());
_indexBuffer = make_shared<IndexBuffer>();
_indexBuffer->Create(_geometry->GetIndices());
}
이렇게 해줬으면 렌더링을 해줄 준비를 하면 된다.
4. 02. Quad.fx 쉐이더를 COLOR를 받고, 하나의 PS를 사용하고, RasterizerState를 세팅해 WireFrame으로 그릴 수 있게 수정하기
02. Quad.fx 쉐이더에 가서
컬러까지 포함해서 뭔가 해주겠다고 하면, 그거에 맞춰주면 된다.
struct VertexInput
{
float4 position : POSITION; // POSITION을 찾아서 연결해 줄 것이다.
float4 color : COLOR;
};
만약 COLOR를 무시해도 문제는 없다. 하지만 이렇게 받아준 거라고 한다면
struct VertexInput
{
float4 position : POSITION; // POSITION을 찾아서 연결해 줄 것이다.
float4 color : COLOR;
};
struct VertexOutput
{
float4 position : SV_POSITION; // System Value 라고 예약된 이름이라 명시
float4 color : COLOR;
};
VertexOutput VS( VertexInput input)
{
VertexOutput output;
output.position = input.position;
output.color = input.color;
return output;
}
이렇게 해주면 되고 VertexShader단계에서 넘어가면 Rasterizer 단계에서 그려야 하는 영역만 끄집어 와서 2D로 넘어가서 PixelShader로 넘어가는데
더 이상 픽셀 셰이더를 여러 개 사용하지 않기로 한다면 PS를 한 개만 남기 지워주면 된다.
struct VertexInput
{
float4 position : POSITION; // POSITION을 찾아서 연결해 줄 것이다.
float4 color : COLOR;
};
struct VertexOutput
{
float4 position : SV_POSITION; // System Value 라고 예약된 이름이라 명시
float4 color : COLOR;
};
VertexOutput VS( VertexInput input)
{
VertexOutput output;
output.position = input.position;
output.color = input.color;
return output;
}
float4 PS(VertexOutput input) : SV_TARGET // 지정한 RenderTarget에 색상을 그려줄 것이다.
{
return input.color;
}
RasterizerState FillModeWireFrame
{
FillMode = Wireframe;
};
technique11 T0
{
pass P0
{
SetVertexShader(CompileShader(vs_5_0, VS())); // 버전은 5.0, main 함수는 VS다는 뜻
SetPixelShader(CompileShader(ps_5_0, PS())); // 버전은 5.0, main 함수는 VS다는 뜻
}
pass P1
{
SetRasterizerState(FillModeWireFrame);
SetVertexShader(CompileShader(vs_5_0, VS())); // 버전은 5.0, main 함수는 VS다는 뜻
SetPixelShader(CompileShader(ps_5_0, PS())); // 버전은 5.0, main 함수는 VS다는 뜻
}
};
color를 return 해주면 color를 뱉은 걸 그대로 그려줄 수 있다.
pass P1을 사용하면 Wireframe으로 그려줄 수 있게 했다.
5. QuadDemo::Render에서 _vertexBuffer와 _indexBuffer를 InputAssmbler 단계에 세팅하고, DrawIndexed를 호출해 사각형 그리기
다시 QuadDemo::Render로 가서
void QuadDemo::Render()
{
uint32 stride = _vertexBuffer->GetStride();
uint32 offset = _vertexBuffer->GetOffset();
DC->IASetVertexBuffers(0, 1, _vertexBuffer->GetComPtr().GetAddressOf(), &stride, &offset);
DC->IASetIndexBuffer(_indexBuffer->GetComPtr().Get(), DXGI_FORMAT_R32_UINT, 0);
//_shader->Draw(1, 0, 3);
_shader->DrawIndexed(0, 0, _indexBuffer->GetCount(), 0, 0);
}
이렇게 짝을 맞춰주면 VertexBuffer와 IndexBuffer를 동시에 활용할 수 있다.
그리고 IndexBuffer를 사용하니 DrawIndexed를 사용한다.
빌드를 하면 'main': entrypoint not found에러가 뜬다.
Client의 properties로 가서
HLSL Compiler로 가서
이렇게 수정해서
빌드를 하면 02. Quad.fx에도 기본적으로 적용이 되는 것이기 때문에 통과가 된다고 보면 된다.
실행을 하면
사각형이 잘 뜬다.
6. GuadDemo::Init에서 GeometryHelper::CreateQuad에서 색을 바꾸어 보, QuadDemo::Render의 pass 인자를 바꿔 쉐이더 세팅을 바꿔서 Wireframe으로 사각형을 그려보기
GuadDemo::Init에서
_geometry = make_shared<Geometry<VertexColorData>>();
GeometryHelper::CreateQuad(_geometry, Color(0.f, 1.f, 0.f, 1.f));
이렇게 색을 바꾸면
잘 뜬다.
그리고 만약 QuadDemo::Render에서
_shader->DrawIndexed(0, 1, _indexBuffer->GetCount(), 0, 0);
이렇게 pass를 1로 하면
이렇게 뜬다.
이렇게 파이프라인은 신경 안 쓰고 로직에만 신경 쓰게 되었다.
7. 맺음말
알아서 채워주는 부분은 Shader 클래스를 보면 래핑 하는 게 있다.
Shader의 CreateEffect가 핵심적인 부분이다.
여기서 파싱을 하고 설정하는 부분들이 들어간다.
CreateInputLayer는 간단하게 InputLayout이 나오게 해 주는데 원래는 VertexData라는 걸 만들어 준 다음에 이거에 해당하는 걸 수동으로 만들었었다. 지금은 이펙트라는 라이브러리 기술에서는 찾아서 알맞은 포맷을 넣어준다.
이렇게 Pass, Technique, Shader클래스의 세부적인 부분은 여유가 있으면 봐도 되지만 기본적으로는 스킵을 해도 된다. 중요한 건 편리하다는 것이다.
파이프라인 코드를 굳이 이전 작업한 코드에서 안 가져온 이유는 Shader가 Material가 Shader를 1+1으로 해준다라고 보면 된다. 표준이거나 그런 건 아니다 DX12에서는 훨씬 복잡하니까 effect12 이런 라이브러리는 없고 비슷한 다른 부류의 라이브러리가 있으니 그중에서 하나를 찾아서 해도 되고 material 부분을 만들어서 하는 것도 충분히 맞는 방법이다.
Rendering pipeline과 교류해서 세팅하는 부분들이 엔진에서도 핵심적인 부분이라고 볼 수 있는 거니까 직접 만들거나 지금처럼 긁어서 사용하거나 택하면 된다.
이렇게 Index Buffer도 작업을 했다. 결국에는 셰이더를 다룰 때 셰이더에 집중할 수 있는 게 차이점이다. 원래는 Shader를 작업을 하고 맞추는 작업이 많았는데 그런 부담을 많이 벗었다고 볼 수 있다.
'DirectX' 카테고리의 다른 글
35. DirectX11 3D 입문_카메라 (0) | 2024.02.05 |
---|---|
34. DirectX11 3D 입문_Constant Buffer (0) | 2024.02.02 |
32. DirectX11 3D 입문_프로젝트 설정 (0) | 2024.01.31 |
31. 엔진구조_Data (0) | 2024.01.29 |
30. 엔진구조_Animation (0) | 2024.01.28 |
댓글