← SEARCHABLE ARCHIVE
DirectX 12 · 2026-07-04

Natives DirectX 12-Dreiecks-Rendering

Zeichnen eines Dreiecks mit Befehlsliste und Ressourcenbarriere

INTERACTIVE READING MODE →

Die in diesem Blog verfassten Artikel wurden mit dem Ziel erstellt, zu unterrichten. Außerdem können die Informationen im Artikel falsch sein, also seien Sie bitte vorsichtig.

Der Gesamtablauf beim Zeichnen eines Dreiecks in DirectX 12 ähnelt dem von DX11, der Ressourcenstatus und die Befehlsübermittlung werden jedoch direkt vom Entwickler verwaltet. Unmittelbar nach dem Erstellen des GerätsDrawInstancedEs ist keine Struktur, die aufgerufen werden kann.

Objekt benötigt

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

Scheitelpunktpuffer

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);

Im Beispiel wurde einfach der Upload-Heap verwendet. In der Praxis ist das Kopieren häufig gelesener Vertex-Daten in den Standard-Heap von Vorteil für die GPU-Zugriffsleistung.

Zeichnen Sie die Zeichnung in der Befehlsliste auf

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 wechselt zwischen dem aktuellen Status und dem RenderTarget-Status hin und her. Wenn Sie diesen Zustandsübergang weglassen, tritt ein Fehler in der Debug-Ebene auf oder der Bildschirm wird nicht korrekt gezeichnet.

Der Dreieckscode von DX12 ist lang, aber seine Struktur ist klar. Die drei wichtigsten Schritte sind das Aufzeichnen des Befehls, das Senden an die Warteschlange und das Überprüfen der GPU-Fertigstellung mit Fence.