수업


주제

DirectX11에서 IndexBuffer와 UV 좌표를 활용한 사각형 출력 및 텍스처 매핑 시스템 구축


개념

✅ IndexBuffer란?

사각형은 실제로 삼각형 2개로 구성되며, 삼각형 하나당 정점이 3개씩 필요하므로 총 6개의 정점이 필요하다.
하지만 같은 정점을 중복해서 메모리에 넣는 건 비효율적이다.
→ 이때 필요한 것이 IndexBuffer.

정점(Vertex)은 4개만 정의하고,
삼각형 2개를 구성하기 위한 인덱스만 따로 정의하여 메모리를 절약할 수 있다.

✅ UV 좌표란?

  • U는 텍스처의 가로(x축), V는 세로(y축)를 의미.
  • 보통 좌상단이 (0,0), 우하단이 (1,1).
  • 각 정점에 UV 좌표를 지정하면 텍스처 이미지를 어떤 비율로 사각형에 입힐지 결정할 수 있음.
  • HLSL의 Sample() 함수를 통해 input.uv 위치의 픽셀 색상을 추출한다.

✅ 텍스처 매핑 핵심 구성요소

  • Vertex에 UV 좌표 추가
  • InputLayout에서 TEXCOORD 세팅
  • HLSL Shader 수정 (VS_INPUT, VS_OUTPUT, PS)
  • Texture2D + SamplerState 선언 (register(t0), register(s0))
  • 텍스처 로딩: DirectXTex 라이브러리 사용 (LoadFromWICFile, CreateShaderResourceView)
  • Render 시 PixelShader에 텍스처 바인딩

용어 정리

용어설명
IndexBuffer정점을 재사용하여 삼각형을 구성하는 인덱스 배열
UV 좌표텍스처 좌표계, 보통 (0,0)~(1,1) 사이 값
TEXCOORD셰이더에서 UV 값을 전달하는 세마틱
Texture2DHLSL에서 텍스처 객체를 나타내는 타입
SamplerState텍스처 보간/샘플링 방식 정의 객체
ShaderResourceView (SRV)GPU의 텍스처 리소스를 셰이더에서 접근하게 해주는 인터페이스
register(t0), register(s0)텍스처 및 샘플러의 바인딩 위치

코드 분석

✅ Vertex + Index 정의

_vertices.resize(4);
_vertices[0].position = Vec3(-0.5f, -0.5f, 0.f); _vertices[0].uv = Vec2(0.f, 1.f);
_vertices[1].position = Vec3(-0.5f, 0.5f, 0.f);  _vertices[1].uv = Vec2(0.f, 0.f);
_vertices[2].position = Vec3(0.5f, -0.5f, 0.f);  _vertices[2].uv = Vec2(1.f, 1.f);
_vertices[3].position = Vec3(0.5f, 0.5f, 0.f);   _vertices[3].uv = Vec2(1.f, 0.f);
_indices = { 0, 1, 2, 2, 1, 3 };
  • 총 정점은 4개지만 삼각형은 인덱스를 이용해 6개 구성.

✅ IndexBuffer 생성

D3D11_BUFFER_DESC desc = {};
desc.Usage = D3D11_USAGE_IMMUTABLE;
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
desc.ByteWidth = sizeof(uint32) * _indices.size();

D3D11_SUBRESOURCE_DATA data = {};
data.pSysMem = _indices.data();

HRESULT hr = _device->CreateBuffer(&desc, &data, _indexBuffer.GetAddressOf());
CHECK(hr);
  • GPU에서 읽기 전용(IMMUTABLE) IndexBuffer를 생성하고 바인딩.

✅ IA 단계 설정 및 Draw 호출

_deviceContext->IASetVertexBuffers(0, 1, _vertexBuffer.GetAddressOf(), &stride, &offset);
_deviceContext->IASetIndexBuffer(_indexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0);
_deviceContext->IASetInputLayout(_inputLayout.Get());
_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

_deviceContext->DrawIndexed(_indices.size(), 0, 0);
  • IA(Input Assembler)에서 IndexBuffer를 셋팅 후, DrawIndexed()로 인덱스 기반 렌더링.

✅ Vertex 구조체 수정

struct Vertex
{
    Vec3 position;
    Vec2 uv;
};
  • Color는 제거하고, uv 추가.

✅ InputLayout 수정

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 }
};
  • Offset 12은 Vec3(position)이 12바이트이기 때문.

✅ HLSL 셰이더 수정

struct VS_INPUT
{
    float4 position : POSITION;
    float2 uv       : TEXCOORD;
};

struct VS_OUTPUT
{
    float4 position : SV_POSITION;
    float2 uv       : TEXCOORD;
};

VS_OUTPUT VS(VS_INPUT input)
{
    VS_OUTPUT output;
    output.position = input.position;
    output.uv = input.uv;
    return output;
}
Texture2D texture0 : register(t0);
SamplerState sampler0 : register(s0);

float4 PS(VS_OUTPUT input) : SV_Target
{
    float4 color = texture0.Sample(sampler0, input.uv);
    return color;
}
  • register(t0), register(s0)로 바인딩한 텍스처와 샘플러를 통해 UV 위치에서 픽셀 추출.

✅ 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);
}
  • DirectXTex 라이브러리로 텍스처 로딩 후 SRV 생성.

✅ 렌더링 연결 (PS 바인딩)

_deviceContext->PSSetShader(_pixelShader.Get(), nullptr, 0);
_deviceContext->PSSetShaderResources(0, 1, _shaderResourceView.GetAddressOf());
  • 셰이더와 SRV 연결 완료. t0에 텍스처가 바인딩된다.

핵심

IndexBuffer를 활용하면 정점 재사용이 가능해져 메모리 최적화에 큰 도움이 된다.

UV 좌표는 텍스처 맵핑의 기본이며, 이미지의 (0,0)~(1,1) 사이 좌표계를 기반으로 한다.

HLSL Shader와 InputLayout 간의 세마틱 이름은 반드시 정확하게 일치해야 한다.

Shader에서 텍스처 색상을 추출하려면 Sample() 함수를 통해 UV 좌표 기반 샘플링이 필요하다.

텍스처를 GPU에 연결하려면 SRV를 생성하고, PSSetShaderResources()로 바인딩해야 한다.

DirectX11의 렌더링 파이프라인은 Input Assembler → Vertex Shader → Rasterizer → Pixel Shader → Output Merger 단계로 구성되며, 각각에 맞는 자원 설정이 필요하다.

추후 다중 텍스처 처리, 머티리얼 시스템, 셰이더 조건 분기 등으로 확장할 수 있다.


profile
李家네_공부방

0개의 댓글