← SEARCHABLE ARCHIVE
DirectX 12 · 2026-07-04

DirectX 12 기본 삼각형 렌더링

Command List와 Resource Barrier로 삼각형 그리기

INTERACTIVE READING MODE →

본 블로그 작성 글들은, 강의를 목표로 하고 제작되었습니다. 또한 작성된 글의 정보도 틀렸을 수 있으니, 주의해주세요.

DirectX 12에서 삼각형을 그리는 전체 흐름은 DX11과 비슷하지만, 자원 상태와 명령 제출을 개발자가 직접 관리한다. Device만 만든 뒤 바로 DrawInstanced를 호출할 수 있는 구조가 아니다.

필요한 객체

Device
CommandQueue
SwapChain
DescriptorHeap(RTV)
CommandAllocator
GraphicsCommandList
Fence
VertexBuffer
RootSignature
PipelineState

정점 버퍼

struct Vertex
{
    DirectX::XMFLOAT3 Position;
    DirectX::XMFLOAT4 Color;
};

const Vertex Vertices[] =
{
    { {  0.0f,  0.5f, 0.0f }, { 1, 0, 0, 1 } },
    { {  0.5f, -0.5f, 0.0f }, { 0, 1, 0, 1 } },
    { { -0.5f, -0.5f, 0.0f }, { 0, 0, 1, 1 } }
};

const UINT BufferSize = sizeof(Vertices);

CD3DX12_HEAP_PROPERTIES HeapProperties(D3D12_HEAP_TYPE_UPLOAD);
CD3DX12_RESOURCE_DESC BufferDescription =
    CD3DX12_RESOURCE_DESC::Buffer(BufferSize);

Device->CreateCommittedResource(
    &HeapProperties,
    D3D12_HEAP_FLAG_NONE,
    &BufferDescription,
    D3D12_RESOURCE_STATE_GENERIC_READ,
    nullptr,
    IID_PPV_ARGS(&VertexBuffer)
);

void* MappedData = nullptr;
VertexBuffer->Map(0, nullptr, &MappedData);
std::memcpy(MappedData, Vertices, BufferSize);
VertexBuffer->Unmap(0, nullptr);

VertexBufferView.BufferLocation = VertexBuffer->GetGPUVirtualAddress();
VertexBufferView.SizeInBytes = BufferSize;
VertexBufferView.StrideInBytes = sizeof(Vertex);

예제는 간단하게 Upload Heap을 사용했다. 실전에서 자주 읽는 정점 데이터는 Default Heap으로 복사하는 편이 GPU 접근 성능에 유리하다.

Command List에 그리기 기록

CommandAllocator->Reset();
CommandList->Reset(CommandAllocator, PipelineState);

auto ToRenderTarget = CD3DX12_RESOURCE_BARRIER::Transition(
    BackBuffers[FrameIndex],
    D3D12_RESOURCE_STATE_PRESENT,
    D3D12_RESOURCE_STATE_RENDER_TARGET
);
CommandList->ResourceBarrier(1, &ToRenderTarget);

CommandList->RSSetViewports(1, &Viewport);
CommandList->RSSetScissorRects(1, &ScissorRect);
CommandList->OMSetRenderTargets(1, &CurrentRTV, FALSE, nullptr);

const float ClearColor[] = { 0.08f, 0.08f, 0.12f, 1.0f };
CommandList->ClearRenderTargetView(CurrentRTV, ClearColor, 0, nullptr);

CommandList->SetGraphicsRootSignature(RootSignature);
CommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
CommandList->IASetVertexBuffers(0, 1, &VertexBufferView);
CommandList->DrawInstanced(3, 1, 0, 0);

auto ToPresent = CD3DX12_RESOURCE_BARRIER::Transition(
    BackBuffers[FrameIndex],
    D3D12_RESOURCE_STATE_RENDER_TARGET,
    D3D12_RESOURCE_STATE_PRESENT
);
CommandList->ResourceBarrier(1, &ToPresent);
CommandList->Close();

ID3D12CommandList* Lists[] = { CommandList };
CommandQueue->ExecuteCommandLists(1, Lists);
SwapChain->Present(1, 0);

BackBuffer는 Present 상태와 RenderTarget 상태를 오간다. 이 상태 전환을 빼먹으면 Debug Layer에서 오류가 나오거나 화면이 올바르게 그려지지 않는다.

DX12의 삼각형은 코드가 길지만 구조는 분명하다. 명령을 기록하고, Queue에 제출하고, GPU 완료 시점을 Fence로 확인하는 세 단계가 핵심이다.