현재는 삼각형만 있지만 모델링이 삼각형 몇십만개인애들 관리하려면 인덱스버퍼 라는게필요
사각형을 만들려면 인덱스버퍼가없다면 삼각형 두개를 이어붙여야한다
→ 메모리 낭비가 굉장히 심해짐 , 지금은 정점이 정보가 별로없지만 나중에는 여러 정보가들어감
따라서 엄청나게 무거워짐
이걸 해결하기위해서 Index buffer 가 필요함 , 만약 사각형을 정점 4개로 만든다면
해당 정점 4개를 순서대로 indexbuffer가 넘버링을 붙여줘서 012, 하나 213 하나 만들어달라고 요청
→ 사각형 생성
vetex buffer는 추가할일없고 , index buffer를 만들어야함
geometry에 포함되는것 , 일단 4바이트짜리로
// header
vector<uint32> _indices; // 인덱스목록
ComPtr<ID3D11Buffer> _indexBuffer = nullptr;
// cpp
void Game::CreateGeometry()
{
//index
{
_indices = { 0 ,1 ,2 , 2 ,1 ,3 };
}
//index Buffer
{
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Usage = D3D11_USAGE_IMMUTABLE; // IMMUTABLE까지는 같다
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
desc.ByteWidth = (uint32)(sizeof(uint32) * _indices.size());
D3D11_SUBRESOURCE_DATA data;
ZeroMemory(&data, sizeof(data));
data.pSysMem = &_indices[0]; // _indicies.data() 도 가능
HRESULT hr = _device->CreateBuffer(&desc, &data, _indexBuffer.GetAddressOf());
CHECK(hr);
}
}
인덱스 버퍼는 input assembler 단계에서 끼워줘야한다
이걸 세팅하는 부분이 어디에있냐 - > set vertexbuffer랑 똑같이 해주면된다
_deviceContext->IASetIndexBuffer(_indexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0);
//_deviceContext->Draw(_vertices.size(), 0); // 그려달라고 요청
_deviceContext->DrawIndexed(_indices.size(),0, 0); //인덱스기반 draw
IndexBuffer 와 VertexBuffer 의 차이점
→ 인덱스 버퍼는 확실히 삼각형의 개수를 넘겨주는 그 정점의 개수를 줄일수 있기 때문에
당연히 메모리적으로 효율적으로 작업할수있다.
우리가 어떻게 만들어달라고한 그 VertexBuffer와 IndexBuffer 를 기반으로 조합을 통해 삼각형이
어떻게 만들지를 얘네들이 판단한다
여기에 이제 이미지를 띄워야한다 -
이게 UV좌표라는걸 알아야 작업을 할수있다.
쉐이더에서 수정을해서 쉐이더 쪽에서 일반색상이아니라 , 이미지 파일에서의 좌표를 꺼내서 색상을
float4 PS(VS_OUTPUT input) : SV_Target // 이 결과물을 SV_Target에 쏴줘야하니 이 키워드를 붙여줘야한다
{
//float4 color =
//모든 픽셀대상으로 실행하는 함수 , 색상관련이라고 간단하게 생각해보면된다
//우리가 넣어준 색 -> input.color
return input.color;
}
여기에 리턴을 하게끔 유도해야한다
struct Vertex
{
Vec3 position; // vector3
//Color color; // RGB
Vec2 uv; // uv 좌표 float 2개
};
uv 좌표를 vertex에 생성 , 그냥 0 ~ 1 사이의 값 2개를 들고있다
얘가 하고싶은건 뭐냐면

1 이라는 값은 해당 이미지의 비율 같은 느낌 , 우리가 설정한 사각형에 이 이미지의 몇퍼센트의
비율로 넣을지를 우리가 uv값을 넣어주면 ex) 0.5를넣으면 해당이미지의 50%
해당 이미지를 내가 넣어준 값으로 출력해준다는것
따라서 vertex의 color 값을 주석처리하고 uv 값을 세팅해줘야한다
void Game::CreateGeometry()
{
//vertex data
{
_vertices.resize(4);
// 좌표는 - 1 ~ 1 사이 반시계로
//어떻게 삼각형을 표현할지 데이터로 만들어주기 아직까진 CPU <->RAM
//GPU에 똑같이 만들어줘야한다
// 시계방향으로 만들었으면 시계방향으로 유지
_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);
}
또한 우리가 이 정보들을 처리할때 Create Input Layout 이라는 함수에서
void CreateInputLayout()
{
//배열 형태로 제작
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{"POSITION" , 0 , DXGI_FORMAT_R32G32B32_FLOAT,0 ,0,D3D11_INPUT_PER_VERTEX_DATA,0},//FLOAT가 각각 32BIT (VEC3)
{"COLOR" , 0 , DXGI_FORMAT_R32G32B32A32_FLOAT,0 ,12,D3D11_INPUT_PER_VERTEX_DATA,0}, //Vec4 COLOR RGBA + 구조묘사
};
// 배열의 크기에 배열하나의 아이템크기를 나누면 배열에 해당 아이템 갯수가 나온다 . size로 계산하니깐
const int32 count = sizeof(layout) / sizeof(D3D11_INPUT_ELEMENT_DESC); // element갯수 구하기
_device->CreateInputLayout(layout, count, _vsBlob->GetBufferPointer(),_vsBlob->GetBufferSize(), _inputLayout.GetAddressOf());
}
이런식으로 vertex가 어떻게 구성되어있는지를 묘사하는 친구가있는데
이 친구를 COLOR값이 빠지고 UV 값이 들어가야하니 수정해줘야한다
void CreateInputLayout()
{
//배열 형태로 제작
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{"POSITION" , 0 , DXGI_FORMAT_R32G32B32_FLOAT,0 ,0,D3D11_INPUT_PER_VERTEX_DATA,0},//FLOAT가 각각 32BIT (VEC3)
{"TEXCOORD" , 0 , DXGI_FORMAT_R32G32_FLOAT,0 ,12,D3D11_INPUT_PER_VERTEX_DATA,0}, //Vec4 COLOR RGBA + 구조묘사
//Texture의 좌표다 라는의미 , float 값2개니깐 R32G32에서 끊어줘야한다
};
// 배열의 크기에 배열하나의 아이템크기를 나누면 배열에 해당 아이템 갯수가 나온다 . size로 계산하니깐
const int32 count = sizeof(layout) / sizeof(D3D11_INPUT_ELEMENT_DESC); // element갯수 구하기
_device->CreateInputLayout(layout, count, _vsBlob->GetBufferPointer(),_vsBlob->GetBufferSize(), _inputLayout.GetAddressOf());
}
또한 이 수정에 맞춰서 쉐이더도 수정해줘야한다
struct VS_INPUT
{
float4 position : POSITION;
//float4 color : COLOR;
float2 uv : TEXCOORD;
};
struct VS_OUTPUT
{
float4 position : SV_POSITION; //system value , 얘는 필수적으로 있어야한다 라고명시 (SV)
//float4 color : COLOR;
float2 uv : TEXCOORD;
};
// 처음에 VS INPUT으로 들어온다
// IA - VS - RS - PS - OM
//VS단계는 이 포멧이 맞게끔 가야 도형이 일단 넘어온다
// 우리가 game.cpp에서 넘겨준 값들이 여기에 들어온다는 의미 , 다만 얘는 정점단위로 실행
VS_OUTPUT VS(VS_INPUT input) // 함수 리턴값 함수이름 함수 파라미터 형식
{
// 위치와 관련된 부분을 넣어준다고보면되고 , 정점 관련부분
VS_OUTPUT output;
// 일단 인풋 그대로 넘겨주기
output.position = input.position;
output.uv = input.uv;
//output.color = input.color;
return output;
}
이제 이 uv 좌표를 모든 그런 점들을 대상으로 나만의 uv 좌표가 생기고
임이의 점에 uv좌표 ( ex) 0.8 , 0.4 )라면 해당 좌표를 GPU에 넘겨줘야한다
일단 이 이미지 파일이라는 리소스 자체를 GPU한테 건네줘가지고 걔가 이걸 알고있어야한다
이런 등록단계를 코드로하면
Texture2D texture0 : register(t0);
//t->Texture의 약자
SamplerState sampler0 : register(s0);
//정해진 규약에따른 레지스터 번호
float4 PS(VS_OUTPUT input) : SV_Target
float4 color = texture0.Sample(sampler0, input.uv);
//Sample이라는 함수를이용해서 sampler0번이랑 input의uv를 각각건네준다
// texture0번의 uv 좌표를 가져와서 거기해당하는 색상을 뺴온다라는 느낌
return color;
}
이제 이 텍스쳐 0 번을 사용하기로 한거까지는 됬는데 , 이 이미지 파일 하나를 여기는
즉 우리가 이 파일을 로드해서 cpu 메모리에다가 그걸 그냥 들고있으면 안되고
그거역시 리소스로 만들어서 gpu쪽에도 만들어준다음
만들어 준 아이를 연결해달라고 우리가 렌더링 파이프라인에 연결해줘야한다
픽셀 쉐이더 단계에서 넣어줄수있는 아이
외부 리소스를 가져오는 함수만들기
Direct X tex 라이브러리안에 사용할수있는 함수가있다
// header
void CreateSRV()
// cpp
void Game::CreateSRV()
{
//이미지를 가져오는 함수는 여러개가있다
DirectX::TexMetadata md;
DirectX::ScratchImage img;
HRESULT hr = ::LoadFromWICFile(L"Sample.png", WIC_FLAGS_NONE, &md, img);
CHECK(hr);
//여기까지하면 이미지를 로드한것
}
이제 두번째 view
저번에 한건 RTV ( render Target view ) 라고 해서
resource 를 우리가 render target 용도로 사용할때 , render target view 라는걸 만들었는데
이번엔 우리가 똑같이 이미지 파일 하나를 긁어 왔는데 어떻게 활용할것이냐는 질문에
Shader resource view SRV 로 만들겠다고 만들것이다
//header
//SRV
ComPtr<ID3D11ShaderResourceView> _shaderResourceView = nullptr;
//cpp
void Game::CreateSRV()
{
//이미지를 가져오는 함수는 여러개가있다
DirectX::TexMetadata md;
DirectX::ScratchImage img;
HRESULT hr = ::LoadFromWICFile(L"Sample.png", WIC_FLAGS_NONE, &md, img);
CHECK(hr);
//여기까지하면 이미지를 로드한것
//shader resource view 라는걸 만들어야한다
hr = ::CreateShaderResourceView(_device.Get(), img.GetImage(), img.GetImageCount(), md, _shaderResourceView.GetAddressOf());
CHECK(hr);
}
당장 뭔가가 복사되는게아니라 나중에 우리가 이걸 통해서 건내주면서 뭔가일어난다고 볼수있다
그럼이제 이걸 이용해서 실질적으로 우리가 연결을 해주면된다
이미지 UV좌표를 연동을 해줬는데 . 우리가 shader에서 보면 PS 단계에서 연결을 해주었으니깐
Render 부분에서 ps 부분에서 deviceContext를 통해서 연결을 해줘야한다는걸 유추할수있다
void Render()
{
/// IA - VS - RS
//PS
_deviceContext->PSSetShader(_pixelShader.Get(), nullptr, 0);
_deviceContext->PSSetShaderResources(0, 1, _shaderResourceView.GetAddressOf());
//OM
}
////////// init 부분에서 CreateSRV() 함수 추가 해줘야함
결과값

UV 매핑이라는걸 해봤다 ← 가장 중요한 부분
겸사겸사 Index Buffer를 이용해서 관리하는것도 알아봄
어떤 텍스쳐를 붙일때 PS 단계에서 동작하는거고 PS 에서 텍스쳐를 넣어준다음
이 아이의 UV 좌표를 가져와서 색상을 가지고 온다는것 ,
이 중간에 꽂아 넣어서 인자를 넣는 작업이 단순하지 않다는것
무조건 우리가 쉐이더랑 뭔가 통신을 해가지고 이런식으로 Texture를만들어서 넣어준다거나
다양한 방식을 응용할수있다는것
VS도 우리가 추가적인 값을 넣어주고싶을때 , constant Buffer 상수 버퍼를 만들어준다음에
똑같이 Register 등록해주고 Set Constant Buffer등등을 이용해서 Render에서 DeviceContext를
연결해 가지고 작업하는 식으로
Rendering Pipe Line에 따라서 클래스 배치를 옮겨보면서 이걸 조금더 보기 쉽게 옮겨야한다
지금은 한클래스에 때려박았지만 어떤게 공용적인건지 어떤게 종속적인건지를 생각해봐야한다
Geometry → vertex와 index와 관련된정보 - 상용엔진의 Mesh 의 정보
메쉬는 하나의 리소스인것이고 , 이 리소스를 이용해서 오크를 그려주건 플레이어를 그려주건
그런작업들을 해주는거고 , shader는 모든애들이 공용으로 사용하는건가 ? → 공용일것같다
유니티나 언리얼에서 공용적으로 사용하는 쉐이더가있으니깐 ,공용이라고 생각하면된다
이런걸 구분할줄알아야한다 .
차츰차츰이걸 구조로 쪼개서 보면 좀더 감이 온다 .
PS에서 SRV 를 끼워넣는것을 해본것
이다음은 Constant Buffer를 만들어서 Vertext에 꽂는 작업을 할것이다
상수버퍼를 이용해서 VS 단계에서 꽂는 작업도 굉장히 중요