DirectX 11 Sample – Texture Mapping
This sample demonstrates how to apply a 2‑D texture to a 3‑D model using DirectX 11. It covers:
- Creating a texture resource and shader resource view.
- Loading an image with
WICand creating aID3D11ShaderResourceView. - Setting up vertex and pixel shaders that sample the texture.
- Rendering a rotating, textured cube.
The code is fully commented and intended for developers who are familiar with the DirectX 11 pipeline.
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);
}