Getting Started with DirectX 11

Welcome to the DirectX 11 getting‑started guide. This article walks you through the steps required to set up a basic DirectX 11 project, compile and run a simple “Hello Triangle” sample, and explore resources for deeper learning.

Prerequisites

Creating the Project

  1. Open Visual Studio → Create a new project.
  2. Select Win32 Project, give it a name (e.g., DX11HelloTriangle), and click Next.
  3. Choose Application SettingsEmpty projectFinish.
  4. Right‑click the project → Manage NuGet Packages → search for DirectXTK12 and install (optional for helper utilities).

Hello Triangle Sample

Copy the following source files into your project. The example creates a window, initializes DirectX 11, and renders a single colored triangle.

main.cpp

#include <windows.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <directxmath.h>
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dcompiler.lib")

using namespace DirectX;

// Vertex structure
struct Vertex {
    XMFLOAT3 position;
    XMFLOAT4 color;
};

// Global declarations
HWND g_hWnd = nullptr;
ID3D11Device*           g_pd3dDevice = nullptr;
ID3D11DeviceContext*    g_pImmediateContext = nullptr;
IDXGISwapChain*         g_pSwapChain = nullptr;
ID3D11RenderTargetView* g_pRenderTargetView = nullptr;
ID3D11InputLayout*      g_pVertexLayout = nullptr;
ID3D11Buffer*           g_pVertexBuffer = nullptr;

// Forward declarations
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
HRESULT InitDevice();
void CleanupDevice();
void Render();

// Entry point
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
{
    // Register class and create window
    WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.hInstance      = hInstance;
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.lpszClassName  = L"DX11SampleClass";
    RegisterClassEx(&wcex);

    RECT rc = { 0, 0, 800, 600 };
    AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
    g_hWnd = CreateWindowW(L"DX11SampleClass", L"DirectX 11 – Hello Triangle",
                           WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
                           rc.right - rc.left, rc.bottom - rc.top,
                           nullptr, nullptr, hInstance, nullptr);
    ShowWindow(g_hWnd, nCmdShow);

    if (FAILED(InitDevice())) {
        CleanupDevice();
        return 0;
    }

    // Main message loop
    MSG msg = {};
    while (msg.message != WM_QUIT) {
        if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        } else {
            Render();
        }
    }

    CleanupDevice();
    return (int)msg.wParam;
}

// ---------------------------------------------------------------------------
// Initialize Direct3D
HRESULT InitDevice()
{
    // Swap chain description
    DXGI_SWAP_CHAIN_DESC sd = {};
    sd.BufferCount = 1;
    sd.BufferDesc.Width  = 800;
    sd.BufferDesc.Height = 600;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferDesc.RefreshRate.Numerator   = 60;
    sd.BufferDesc.RefreshRate.Denominator = 1;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.OutputWindow = g_hWnd;
    sd.SampleDesc.Count   = 1;
    sd.SampleDesc.Quality = 0;
    sd.Windowed = TRUE;

    // Create device and swap chain
    UINT createDeviceFlags = 0;
    D3D_FEATURE_LEVEL featureLevel;
    const D3D_FEATURE_LEVEL FeatureLevelsRequested[] = {
        D3D_FEATURE_LEVEL_11_0,
    };
    HRESULT hr = D3D11CreateDeviceAndSwapChain(
        nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags,
        FeatureLevelsRequested, 1, D3D11_SDK_VERSION,
        &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel,
        &g_pImmediateContext);
    if (FAILED(hr)) return hr;

    // Create render target view
    ID3D11Texture2D* pBackBuffer = nullptr;
    g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
    g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_pRenderTargetView);
    pBackBuffer->Release();

    g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, nullptr);

    // Setup viewport
    D3D11_VIEWPORT vp;
    vp.Width    = (FLOAT)800;
    vp.Height   = (FLOAT)600;
    vp.MinDepth = 0.0f;
    vp.MaxDepth = 1.0f;
    vp.TopLeftX = 0;
    vp.TopLeftY = 0;
    g_pImmediateContext->RSSetViewports(1, &vp);

    // Compile the vertex shader
    ID3DBlob* pVSBlob = nullptr;
    const char* szVS = R"(
        struct VS_INPUT {
            float3 Pos : POSITION;
            float4 Col : COLOR;
        };
        struct PS_INPUT {
            float4 Pos : SV_POSITION;
            float4 Col : COLOR;
        };
        PS_INPUT VSMain(VS_INPUT input) {
            PS_INPUT output;
            output.Pos = float4(input.Pos, 1.0);
            output.Col = input.Col;
            return output;
        }
    )";
    D3DCompile(szVS, strlen(szVS), nullptr, nullptr, nullptr, "VSMain", "vs_5_0",
               0, 0, &pVSBlob, nullptr);
    ID3D11VertexShader* pVertexShader = nullptr;
    g_pd3dDevice->CreateVertexShader(pVSBlob->GetBufferPointer(),
                                     pVSBlob->GetBufferSize(),
                                     nullptr, &pVertexShader);
    g_pImmediateContext->VSSetShader(pVertexShader, nullptr, 0);

    // Define input layout
    D3D11_INPUT_ELEMENT_DESC layout[] = {
        {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,
         D3D11_INPUT_PER_VERTEX_DATA, 0},
        {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12,
         D3D11_INPUT_PER_VERTEX_DATA, 0},
    };
    g_pd3dDevice->CreateInputLayout(layout, 2,
                                    pVSBlob->GetBufferPointer(),
                                    pVSBlob->GetBufferSize(),
                                    &g_pVertexLayout);
    pVSBlob->Release();
    g_pImmediateContext->IASetInputLayout(g_pVertexLayout);

    // Compile the pixel shader
    ID3DBlob* pPSBlob = nullptr;
    const char* szPS = R"(
        struct PS_INPUT {
            float4 Pos : SV_POSITION;
            float4 Col : COLOR;
        };
        float4 PSMain(PS_INPUT input) : SV_TARGET {
            return input.Col;
        }
    )";
    D3DCompile(szPS, strlen(szPS), nullptr, nullptr, nullptr, "PSMain",
               "ps_5_0", 0, 0, &pPSBlob, nullptr);
    ID3D11PixelShader* pPixelShader = nullptr;
    g_pd3dDevice->CreatePixelShader(pPSBlob->GetBufferPointer(),
                                    pPSBlob->GetBufferSize(),
                                    nullptr, &pPixelShader);
    g_pImmediateContext->PSSetShader(pPixelShader, nullptr, 0);
    pPSBlob->Release();

    // Create vertex buffer
    Vertex vertices[] = {
        { XMFLOAT3( 0.0f,  0.5f, 0.0f), XMFLOAT4(1,0,0,1) },
        { XMFLOAT3( 0.5f, -0.5f, 0.0f), XMFLOAT4(0,1,0,1) },
        { XMFLOAT3(-0.5f, -0.5f, 0.0f), XMFLOAT4(0,0,1,1) },
    };
    D3D11_BUFFER_DESC bd = {};
    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof(Vertex) * 3;
    bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    D3D11_SUBRESOURCE_DATA InitData = {};
    InitData.pSysMem = vertices;
    g_pd3dDevice->CreateBuffer(&bd, &InitData, &g_pVertexBuffer);

    UINT stride = sizeof(Vertex);
    UINT offset = 0;
    g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);
    g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    return S_OK;
}

// ---------------------------------------------------------------------------
// Clean up the objects we've created
void CleanupDevice()
{
    if (g_pImmediateContext) g_pImmediateContext->ClearState();
    if (g_pRenderTargetView) g_pRenderTargetView->Release();
    if (g_pSwapChain)        g_pSwapChain->Release();
    if (g_pVertexBuffer)     g_pVertexBuffer->Release();
    if (g_pVertexLayout)     g_pVertexLayout->Release();
    if (g_pd3dDevice)        g_pd3dDevice->Release();
    if (g_pImmediateContext) g_pImmediateContext->Release();
}

// ---------------------------------------------------------------------------
// Render a single frame
void Render()
{
    // Clear the back buffer
    FLOAT ClearColor[4] = { 0.1f, 0.1f, 0.1f, 1.0f };
    g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, ClearColor);

    // Draw the triangle
    g_pImmediateContext->Draw(3, 0);

    // Present the information rendered to the back buffer to the front buffer (the screen)
    g_pSwapChain->Present(0, 0);
}

// ---------------------------------------------------------------------------
// Window procedure
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_PAINT:
        ValidateRect(hWnd, nullptr);
        return 0;
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}

Build and Run

  1. Right‑click the project → Properties.
  2. Under Configuration Properties → Linker → Input, add d3d11.lib;d3dcompiler.lib to Additional Dependencies.
  3. Set SubsystemWindows (/SUBSYSTEM:WINDOWS).
  4. Apply → OK, then Build Solution.
  5. Run the executable (F5). You should see a window with a simple colored triangle.

Next Steps

Back to DirectX 11 Home