DirectX 11 Sample – Texture Mapping

Author: John Doe • Published: 2023‑04‑12

This sample demonstrates how to apply a 2‑D texture to a 3‑D model using DirectX 11. It covers:

The code is fully commented and intended for developers who are familiar with the DirectX 11 pipeline.

Download Sample ZIP View on GitHub

Sample Source (C++)

#include <d3d11.h>
#include <DirectXMath.h>
#include <wrl/client.h>
using Microsoft::WRL::ComPtr;

struct Vertex {
    DirectX::XMFLOAT3 pos;
    DirectX::XMFLOAT2 tex;
};

ComPtr<ID3D11Device>           gDevice;
ComPtr<ID3D11DeviceContext>    gContext;
ComPtr<IDXGISwapChain>         gSwapChain;
ComPtr<ID3D11RenderTargetView> gRenderTargetView;
ComPtr<ID3D11VertexShader>    gVertexShader;
ComPtr<ID3D11PixelShader>     gPixelShader;
ComPtr<ID3D11InputLayout>     gInputLayout;
ComPtr<ID3D11Buffer>          gVertexBuffer;
ComPtr<ID3D11ShaderResourceView> gTextureView;
ComPtr<ID3D11SamplerState>    gSamplerState;

// Load texture from file (WIC)
HRESULT LoadTexture(const wchar_t* filename) {
    ComPtr<IWICImagingFactory> wicFactory;
    CoInitializeEx(nullptr, COINITBASE_MULTITHREADED);
    CoCreateInstance(
        CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&wicFactory));

    ComPtr<IWICBitmapDecoder> decoder;
    wicFactory->CreateDecoderFromFilename(
        filename, nullptr, GENERIC_READ, WICDecodeMetadataCacheOnLoad,
        &decoder);

    ComPtr<IWICBitmapFrameDecode> frame;
    decoder->GetFrame(0, &frame);

    ComPtr<IWICFormatConverter> converter;
    wicFactory->CreateFormatConverter(&converter);
    converter->Initialize(
        frame.Get(), GUID_WICPixelFormat32bppRGBA,
        WICBitmapDitherTypeNone, nullptr, 0.f,
        WICBitmapPaletteTypeCustom);

    UINT width, height;
    converter->GetSize(&width, &height);
    std::vector<BYTE> pixels(width * height * 4);
    converter->CopyPixels(nullptr, width * 4, static_cast(pixels.size()), pixels.data());

    D3D11_TEXTURE2D_DESC texDesc = {};
    texDesc.Width              = width;
    texDesc.Height             = height;
    texDesc.MipLevels          = 1;
    texDesc.ArraySize          = 1;
    texDesc.Format             = DXGI_FORMAT_R8G8B8A8_UNORM;
    texDesc.SampleDesc.Count   = 1;
    texDesc.Usage              = D3D11_USAGE_IMMUTABLE;
    texDesc.BindFlags          = D3D11_BIND_SHADER_RESOURCE;

    D3D11_SUBRESOURCE_DATA initData = {};
    initData.pSysMem          = pixels.data();
    initData.SysMemPitch      = width * 4;

    ComPtr<ID3D11Texture2D> texture;
    HRESULT hr = gDevice->CreateTexture2D(&texDesc, &initData, &texture);
    if (FAILED(hr)) return hr;

    D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
    srvDesc.Format                         = texDesc.Format;
    srvDesc.ViewDimension                  = D3D11_SRV_DIMENSION_TEXTURE2D;
    srvDesc.Texture2D.MostDetailedMip      = 0;
    srvDesc.Texture2D.MipLevels            = 1;

    return gDevice->CreateShaderResourceView(texture.Get(), &srvDesc, &gTextureView);
}

// Rendering loop (simplified)
void Render() {
    float clearColor[4] = {0.1f, 0.1f, 0.2f, 1.0f};
    gContext->ClearRenderTargetView(gRenderTargetView.Get(), clearColor);
    gContext->VSSetShader(gVertexShader.Get(), nullptr, 0);
    gContext->PSSetShader(gPixelShader.Get(), nullptr, 0);
    gContext->PSSetShaderResources(0, 1, gTextureView.GetAddressOf());
    gContext->PSSetSamplers(0, 1, gSamplerState.GetAddressOf());
    UINT stride = sizeof(Vertex);
    UINT offset = 0;
    gContext->IASetVertexBuffers(0, 1, gVertexBuffer.GetAddressOf(), &stride, &offset);
    gContext->IASetInputLayout(gInputLayout.Get());
    gContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    gContext->Draw(36, 0);
    gSwapChain->Present(1, 0);
}

Live Demo (WebGL)