DirectX11

[DirectX11] 1. DirectX11 렌더링 파이프라인

Vfly 2025. 6. 3. 00:57

1. DirectX 11 렌더링 파이프라인 개요

DirectX 11의 렌더링 파이프라인은 다음과 같은 단계로 구성된다.

IA → VS → HS → TS → DS → GS → RS → PS → OM

 

하지만 실제로 자주 사용하는 핵심 단계는:

IA → VS → RS → PS → OM

2. 파이프라인 단계별 상세 분석

2.1 IA (Input Assembler

역할: 정점 데이터를 읽어서 기하학적 프리미티브(삼각형, 선 등)로 조립

// IA 단계 설정 (Game.cpp의 Render() 함수에서)
uint32 stride = sizeof(Vertex);
uint32 offset = 0;

// 정점 버퍼 설정
_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);

주요 구성 요소:

  • Vertex Buffer: 정점 데이터 저장
  • Index Buffer: 정점 인덱스 저장 (메모리 효율성)
  • Input Layout: 정점 데이터 구조 정의
 
// 정점 데이터 생성 (CreateGeometry 함수)
_vertices[0].position = Vec3(-0.5f, -0.5f, 0.f);
_vertices[0].uv = Vec2(0.f, 3.f);

_vertices[1].position = Vec3(-0.5f, 0.5f, 0.f);
_vertices[1].uv = Vec2(0.f, 0.f);

// 인덱스 데이터 (삼각형 두 개로 사각형 구성)
_indices = { 0,1,2,2,1,3 }; // 012, 213 삼각형

 

 

2.2 VS (Vertex Shader

역할: 각 정점에 대해 변환(좌표 변환, 조명 계산 등) 수행

shader
// Default.hlsl의 Vertex Shader
struct VS_INPUT
{
    float4 position : POSITION;
    float2 uv : TEXCOORD;
};

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

cbuffer TransformData : register(b0)
{
    float4 offset;
}

VS_OUTPUT VS(VS_INPUT input)
{
    VS_OUTPUT output;
    
    // 정점 위치에 오프셋 적용 (월드 변환)
    output.position = input.position + offset;
    output.uv = input.uv;
    
    return output;
}

주요 기능:

  • 좌표 변환: 로컬 → 월드 → 뷰 → 프로젝션
  • Constant Buffer: 셰이더에 전달되는 상수 데이터
 
// Constant Buffer 업데이트 (Update 함수)
D3D11_MAPPED_SUBRESOURCE subResource;
ZeroMemory(&subResource, sizeof(subResource));

_deviceContext->Map(_constantBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
::memcpy(subResource.pData, &_transformData, sizeof(_transformData));
_deviceContext->Unmap(_constantBuffer.Get(), 0);

 

 

2.3 RS (Rasterizer Stage)

역할: 정점으로 구성된 프리미티브를 픽셀로 변환

// Rasterizer State 생성
void Game::CreateRasterizerState()
{
    D3D11_RASTERIZER_DESC desc;
    ZeroMemory(&desc, sizeof(desc));
    desc.FillMode = D3D11_FILL_SOLID;      // solid fill
    desc.CullMode = D3D11_CULL_BACK;       // 뒷면 제거
    desc.FrontCounterClockwise = false;    // 시계방향이 앞면

    HRESULT hr = _device->CreateRasterizerState(&desc, _rasterizerState.GetAddressOf());
    CHECK(hr);
}

주요 기능:

  • Face Culling: 보이지 않는 면 제거
  • Clipping: 화면 밖 부분 제거
  • 픽셀 생성: 삼각형 내부의 픽셀들 생성

 

2.4 PS (Pixel Shader)

역할: 각 픽셀의 최종 색상 결정

shader
// Pixel Shader
Texture2D texture0 : register(t0);
Texture2D texture1 : register(t1);
SamplerState sampler0 : register(s0);

float4 PS(VS_OUTPUT input) : SV_Target
{  
    // 텍스처에서 색상 샘플링
    float4 color = texture1.Sample(sampler0, input.uv);
    
    return color;
}

주요 기능:

  • 텍스처 샘플링: UV 좌표로 텍스처 색상 추출
  • 조명 계산: 픽셀별 조명 효과
  • 최종 색상 출력

 

2.5 OM (Output Merger) 

역할: 최종 렌더 타겟에 픽셀 쓰기, 블렌딩 처리

// Output Merger 설정 (RenderBegin 함수)
_deviceContext->OMSetRenderTargets(1, _renderTargetView.GetAddressOf(), nullptr);
_deviceContext->ClearRenderTargetView(_renderTargetView.Get(), _clearColor);

 

 

 

3. 핵심 DirectX 11 객체들

3.1 Device와 DeviceContext

// Device: 리소스 생성의 팩토리
ComPtr<ID3D11Device> _device = nullptr;

// DeviceContext: GPU 명령 실행
ComPtr<ID3D11DeviceContext> _deviceContext = nullptr;
  • Device: 모든 DirectX 리소스 생성
  • DeviceContext: GPU에 명령 전송

3.2 SwapChain과 Double Buffering

ComPtr<IDXGISwapChain> _swapChain = nullptr;
ComPtr<ID3D11RenderTargetView> _renderTargetView;

// Present: 후면 버퍼 → 전면 버퍼
HRESULT hr = _swapChain->Present(1, 0);

Double Buffering 원리:

  1. 후면 버퍼에 렌더링
  2. Present() 호출로 전면/후면 버퍼 교체
  3. 깜빡임 없는 부드러운 화면 출력

3.3 Shader Resource View (SRV)

// 텍스처 로딩 및 SRV 생성
DirectX::TexMetadata md;
DirectX::ScratchImage img;
HRESULT hr = ::LoadFromWICFile(L"baby_alien.png", WIC_FLAGS_NONE, &md, img);

hr = ::CreateShaderResourceView(_device.Get(), img.GetImages(), 
    img.GetImageCount(), md, _shaderResourceView.GetAddressOf());

 

 

4. 렌더링 루프 분석

void Game::Render()
{
    RenderBegin();   // 렌더 타겟 설정, 화면 클리어

    // 파이프라인 설정
    // IA 단계
    _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);

    // VS 단계
    _deviceContext->VSSetShader(_vertexShader.Get(), nullptr, 0);
    _deviceContext->VSSetConstantBuffers(0, 1, _constantBuffer.GetAddressOf());

    // RS 단계
    _deviceContext->RSSetState(_rasterizerState.Get());

    // PS 단계
    _deviceContext->PSSetShader(_pixelShader.Get(), nullptr, 0);
    _deviceContext->PSSetShaderResources(0, 1, _shaderResourceView.GetAddressOf());
    _deviceContext->PSSetShaderResources(1, 1, _shaderResourceView2.GetAddressOf());
    _deviceContext->PSSetSamplers(0, 1, _samplerState.GetAddressOf());

    // 실제 드로우 콜
    _deviceContext->DrawIndexed(_indices.size(), 0, 0);

    RenderEnd();     // Present() 호출
}

 

 

5. 중요한 개념들

5.1 Constant Buffer vs Vertex Buffer

Vertex Buffer:

  • 정점의 형태 정보 (도형의 모양)
  • 변경 빈도가 낮음
  • GPU 메모리에서 효율적으로 접근

Constant Buffer:

  • 변환 매트릭스, 오프셋 등
  • 매 프레임 업데이트 가능
  • CPU에서 쉽게 수정 가능
 
// Constant Buffer의 장점
// 정점 데이터 직접 수정 → 매우 느림
// Constant Buffer로 오프셋 적용 → 빠름
_transformData.offset.x += 0.0003f;  // 이동 효과

 

5.2 Index Buffer의 메모리 효율성

// 사각형을 삼각형 2개로 구성
// Vertex Buffer: 4개 정점
_vertices[0] = 좌하단;
_vertices[1] = 좌상단;
_vertices[2] = 우하단;
_vertices[3] = 우상단;

// Index Buffer: 6개 인덱스 (정점 재사용)
_indices = { 0,1,2,2,1,3 };  // 삼각형1: 012, 삼각형2: 213

5.3 텍스처 샘플링

// UV 좌표와 텍스처 매핑
_vertices[0].uv = Vec2(0.f, 3.f);   // 텍스처 반복
_vertices[1].uv = Vec2(0.f, 0.f);
_vertices[2].uv = Vec2(3.f, 3.f);
_vertices[3].uv = Vec2(3.f, 0.f);

UV 좌표가 0-1 범위를 벗어나면 Sampler State 설정에 따라 처리:

  • D3D11_TEXTURE_ADDRESS_BORDER: 경계 색상
  • D3D11_TEXTURE_ADDRESS_WRAP: 반복
  • D3D11_TEXTURE_ADDRESS_CLAMP: 가장자리 확장