DirectX Graphics Infrastructure

Microsoft Developer Network - Windows Graphics

DirectX 11 Instancing Sample Code

This sample demonstrates how to implement instancing using DirectX 11. Instancing is a technique that allows you to draw multiple copies of the same mesh with a single draw call, significantly improving performance for scenes with many similar objects.

Overview

Instancing in DirectX 11 is achieved through the use of Input Layouts and Vertex Buffers that contain per-instance data. This per-instance data is typically sent to the vertex shader and used to transform, color, or otherwise modify each instance of the object.

Key Concepts

Sample Implementation Details

This sample typically includes the following components:

Example Vertex Shader (HLSL)


struct VS_INPUT
{
    float4 Pos : POSITION;
    float2 Tex : TEXCOORD;
};

struct VS_OUTPUT
{
    float4 Pos : SV_POSITION;
    float2 Tex : TEXCOORD;
};

// Per-instance data structure
struct INSTANCE_DATA
{
    float4x4 World : WORLDMATRIX;
    float4 Color : COLOR;
};

// Buffer holding per-instance data
cbuffer cbInstanceData : register(b0)
{
    INSTANCE_DATA instances[MAX_INSTANCES];
};

VS_OUTPUT Main(VS_INPUT input, uint instanceID : SV_InstanceID)
{
    VS_OUTPUT output;

    float4 worldPos = mul(input.Pos, instances[instanceID].World);
    output.Pos = mul(worldPos, ViewProjection); // ViewProjection matrix would be a constant buffer
    output.Tex = input.Tex;

    return output;
}
            

Example C++ Setup

The C++ code would involve creating two vertex buffers: one for the mesh geometry and one for the instance data. The input layout would be configured to read from both buffers, with the instance data buffer marked for per-instance data access.

Here's a conceptual snippet of setting up the input layout and buffers:


// Device and DeviceContext objects are assumed to be initialized

// Vertex Buffer for mesh geometry
D3D11_BUFFER_DESC vbDesc;
vbDesc.ByteWidth = sizeof(MeshVertex) * numVertices;
vbDesc.Usage = D3D11_USAGE_DEFAULT;
vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbDesc.CPUAccessFlags = 0;
vbDesc.MiscFlags = 0;
// Create and fill vbDesc.pSysMem with vertex data

// Instance Data Buffer
D3D11_BUFFER_DESC instanceBufferDesc;
instanceBufferDesc.ByteWidth = sizeof(InstanceData) * numInstances;
instanceBufferDesc.Usage = D3D11_USAGE_DEFAULT;
instanceBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
instanceBufferDesc.CPUAccessFlags = 0;
instanceBufferDesc.MiscFlags = 0;
// Create and fill instanceBufferDesc.pSysMem with instance data (world matrices, colors, etc.)

// Input Layout Description
std::vector<D3D11_INPUT_ELEMENT_DESC> layout;
// Add elements for mesh geometry (POSITION, TEXCOORD, etc.)
// Add elements for instance data (WORLDMATRIX, COLOR, etc.) with InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA
// and InstanceDataStepRate set appropriately (e.g., 1 for world matrix)

// Create Input Layout
// Compile vertex shader, get shader signature
// device->CreateInputLayout(&layout[0], layout.size(), shaderBlob->GetBufferPointer(), shaderBlob->GetBufferSize(), &inputLayout);

// Set Vertex Buffers for rendering
UINT strides[2];
UINT offsets[2];
ID3D11Buffer* vertexBuffers[2];

// Mesh vertex buffer
vertexBuffers[0] = meshVertexBuffer;
strides[0] = sizeof(MeshVertex);
offsets[0] = 0;

// Instance data buffer
vertexBuffers[1] = instanceBuffer;
strides[1] = sizeof(InstanceData);
offsets[1] = 0;

context->IASetVertexBuffers(0, 2, vertexBuffers, strides, offsets);
context->IASetInputLayout(inputLayout);
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

// Draw call
context->DrawInstanced(numVertices, numInstances, 0, 0); // Or DrawIndexedInstanced
            

Download Sample

You can download the complete Visual Studio project for this DirectX 11 instancing sample to explore the code in detail.

Download Sample (ZIP)

Related Topics