인덱스버퍼
현재 -> 사각형- 삼각형 2개 만약 이런식이라면 그 많은 도형을 표현하기엔 메모리가 너무 많이 소모된다.
-> 인덱스 버퍼사용
정점들에 인덱스(넘버)를 부여하여 사용
이걸 코드로 만들어보자 일단 정점을 하나 추가해보자 그리고 정점 순서에 맞게 좌표를 수정해준다.
//13 -> 012
//02 -> 213
_vertices[0].position = Vec3(-0.5f, -0.5f, 0.f);
_vertices[0].color = Color(1.f, 0.f, 0.f, 1.f);
_vertices[1].position = Vec3(-0.5f, 0.5f, 0.f);
_vertices[1].color = Color(1.f, 0.f, 0.f, 1.f);
_vertices[2].position = Vec3(0.5f, -0.5f, 0.f);
_vertices[2].color = Color(1.f, 0.f, 0.f, 1.f);
_vertices[3].position = Vec3(0.5f, 0.5f, 0.f);
_vertices[3].color = Color(1.f, 0.f, 0.f, 1.f);
인덱스버퍼에 필요한 변수를 만들고 Geometry에 인덱스 버퍼 부분을 만들어주자
변수
//인덱스버퍼 - 이거도 Geometry에 포함
vector<uint32> _indices;
ComPtr<ID3D11Buffer> _indexBuffer = nullptr;
//Index
{
_indices = { 0,1,2,2,1,3 };
}
//IndexBuffer
{
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Usage = D3D11_USAGE_IMMUTABLE; //gpu만 read only
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
desc.ByteWidth = (uint32)(sizeof(uint32) * _indices.size());
D3D11_SUBRESOURCE_DATA data;
ZeroMemory(&data, sizeof(data));
data.pSysMem = _indices.data(); //첫번째 시작주소 cpu값이 복사된다.
HRESULT hr= _device->CreateBuffer(&desc, &data, _indexBuffer.GetAddressOf());
CHECK(hr);
}
인덱스 버퍼 세팅
IA 세팅 과정 중에 -> 랜더에 있는 세팅부분에 추가해줘야한다.
기존
//IA - 세팅부분
_deviceContext->IASetVertexBuffers(0, 1, _vertexBuffer.GetAddressOf(),&stride, &offset);
_deviceContext->IASetInputLayout(_inputLayout.Get());
_deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); //삼각형으로 만들어주기
수정
//IA - 세팅부분
_deviceContext->IASetVertexBuffers(0, 1, _vertexBuffer.GetAddressOf(),&stride, &offset);
_deviceContext->IASetIndexBuffer(_indexBuffer.Get(), DXGI_FORMAT_R32_UINT,0);
_deviceContext->IASetInputLayout(_inputLayout.Get());
_deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); //삼각형으로 만들어주기
//인덱스를 통해 그려주기
_deviceContext->DrawIndexed(_indices.size(), 0, 0);
이렇게하면 Index버퍼를 사용할 준비가 완료되었다.
정점버퍼와 인덱스버퍼의 차이점
-> 인덱스버퍼는 삼각형에 넘어가는 정점 개수를 줄여줘 메모리적으로 효율적으로 작업할 수 있다.
정점버퍼와 인덱스버퍼의 조합으로 삼각형이 어떻게 만들어지는지 판단할 수 있다.
이제 사각에 이미지를 띄워보자
중요한 점 : uv좌표, 쉐이더코드 수정
uv좌표 - 이미지의 좌상단 0,0 우하단 1,1로 했을 때 퍼센티지로 가져오기 위함
Stuct.h 수정 및 정점정보 수정
#pragma once
#include "Types.h"
struct Vertex
{
Vec3 position; //12바이트 0부터시작
//Color color; //12부터시작
Vec2 uv;
};
//정점정보
{
_vertices.resize(4);
//13 -> 012
//02 -> 213
_vertices[0].position = Vec3(-0.5f, -0.5f, 0.f);
_vertices[0].uv = Vec2(0.f, 1.f);
//_vertices[0].color = Color(1.f, 0.f, 0.f, 1.f);
_vertices[1].position = Vec3(-0.5f, 0.5f, 0.f);
_vertices[1].uv = Vec2(0.f, 0.f);
//_vertices[1].color = Color(1.f, 0.f, 0.f, 1.f);
_vertices[2].position = Vec3(0.5f, -0.5f, 0.f);
_vertices[2].uv = Vec2(1.f, 1.f);
//_vertices[2].color = Color(1.f, 0.f, 0.f, 1.f);
_vertices[3].position = Vec3(0.5f, 0.5f, 0.f);
_vertices[3].uv = Vec2(1.f, 0.f);
//_vertices[3].color = Color(1.f, 0.f, 0.f, 1.f);
}
그리고 이에 맞게 InputLayout을 고쳐줘야하는데 이 때 쉐이더와 맞춰주어야하기 때문에
많이 사용하는 TEXCOORD - 텍스처의 좌를 사용한다.
InputLayout 및 쉐이더 수정
struct VS_INPUT
{
float4 position : POSITION;
//float4 color : COLOR;
float2 uv : TEXCOORD;
};
struct VS_OUTPUT
{
float4 position : SV_POSITION; //시스템 VALUE 무조건 있어야한다.
//float4 color : COLOR;
float2 uv : TEXCOORD;
};
//입력에 대한 정보 ~바이트부터 뛰면 칼러인지
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0},
{"TEXCOORD",0,DXGI_FORMAT_R32G32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0}
};
이미지파일 소스를 gpu쪽에도 건네줘서 알고있도록 해야한다.
레지스터에 등록해주기
//함수의 인자같은 존재, 오브젝트마다 달라질수있다.
Texture2D texture0 : register(t0); //레지스터에 등록
SamplerState sampler0 : register(s0);
등록해준 레지스터를 통해 텍스처 색상을 가져오기
//모든 픽셀단위 대상 - 색상관련
float4 PS(VS_OUTPUT input) : SV_Target //랜더 타켓하는 곳으로 보내주기
{
float4 color = texture0.Sample(sampler0, input.uv); //텍스처0번 uv좌표를 통해 색상 빼오기
return color;
}
해당 이미지파일을 cpu에서 리소스로 가지고 gpu쪽에도 만들어준 다음 파이프라인에 연결
픽셀쉐이더부분에서 CreateSRV를 통해 할 수 있다.
SRV 쉐이더 리소스 뷰 만들어주기
SRV변수 추가 -이미지를 어떻게 쓸것인가
이것을 통해 이미지를 건네준다.
//SRV - 이미지를 어떻게 쓸것인가
ComPtr<ID3D11ShaderResourceView> _shaderResourceView = nullptr;
void Game::CreateSRV()
{
DirectX::TexMetadata md;
DirectX::ScratchImage img;
HRESULT hr = ::LoadFromWICFile(L"cat.png", WIC_FLAGS_NONE, &md, img);
CHECK(hr);
//쉐이더리소스뷰 만들기
hr = ::CreateShaderResourceView(_device.Get(), img.GetImages(), img.GetImageCount(), md, _shaderResourceView.GetAddressOf());
CHECK(hr);
}
이제 Init부분에 함수를 넣고 Render의 PS부분에서 이미지와 연결시켜주자
void Game::Init(HWND hwnd)
{
_hwnd = hwnd;
_width = GWinSizeX;
_height = GwinSizeY;
CreateDeviceAndSwapChain();
CreateRenderTargetView();
SetViewport();
//삼각형 그리기 파트
CreateGeometry();
CreateVS();
CreateInputLayout();
CreatePS();
CreateSRV();
}
//PS
_deviceContext->PSSetShader(_pixelShader.Get(), nullptr, 0);
_deviceContext->PSSetShaderResources(0, 1, _shaderResourceView.GetAddressOf()); //0번슬롯에 1개
실행화면
uv 1일때
uv 0.5일때
uv좌표가 1을 초과했을 때 어떻게 할지
-> 레스터라이저단계의 샘플스테이트를 통해 관리
어떤게 범용적 어떤게 오브젝트에 종속적인지 생각해보기
ex) GeoMetry - 매쉬 - 오브젝트 대상
쉐이더 - 범용적
'게임공부 > Directx11' 카테고리의 다른 글
[Directx11]7. RasterizerState, SampleState, BlendState (0) | 2024.07.10 |
---|---|
[Directx11]6. Constant Buffer(상수 버퍼) (0) | 2024.07.09 |
[Directx11][C++]4. 삼각형 그리기 (1) | 2024.07.01 |
[Directx11]3.장치초기화 (0) | 2024.06.27 |
[Directx11]2.초기설정 (0) | 2024.06.26 |