Textures in DirectX Graphics

What are Textures?

In computer graphics, a texture is a data file (an image) used to add detail, color, or other surface properties to a 3D model or 2D sprite. Textures are mapped onto the surfaces of objects, allowing for realistic or stylized appearances without needing to model every minute detail. DirectX provides robust support for various texture types and operations.

Textures in DirectX can represent a wide range of data beyond just diffuse color:

Texture Formats

DirectX supports a wide array of texture formats to optimize for memory, performance, and visual quality. These formats dictate how pixel data is stored, including color channels (RGBA), bit depth, and compression. Common formats include:

Choosing the appropriate format is crucial for balancing visual fidelity, memory usage, and performance. The exact list of supported formats can vary depending on the hardware and DirectX feature level.

Texture Creation

Textures are typically created from image files (like .png, .jpg, .dds) or programmatically. In DirectX, you create a texture resource using methods that specify its dimensions, format, usage flags, and initial data.

For example, creating a 2D texture from memory:


ID3D11Device* pDevice = /* Get your D3D11 device */;
D3D11_TEXTURE2D_DESC texDesc;
ZeroMemory(&texDesc, sizeof(texDesc));

texDesc.Width = 256;
texDesc.Height = 256;
texDesc.MipLevels = 1; // Or calculate number of mip levels
texDesc.ArraySize = 1;
texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texDesc.Usage = D3D11_USAGE_IMMUTABLE; // Or D3D11_USAGE_DEFAULT
texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
texDesc.CPUAccessFlags = 0;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;

D3D11_SUBRESOURCE_DATA initialData;
ZeroMemory(&initialData, sizeof(initialData));
initialData.pSysMem = pPixelData; // Pointer to your pixel data
initialData.SysMemPitch = 256 * 4; // Bytes per row
initialData.SysMemSlicePitch = 0; // For 2D textures

ID3D11Texture2D* pTexture = nullptr;
HRESULT hr = pDevice->CreateTexture2D(&texDesc, &initialData, &pTexture);

if (SUCCEEDED(hr)) {
    // Create shader resource view for use in shaders
    ID3D11ShaderResourceView* pShaderResourceView = nullptr;
    pDevice->CreateShaderResourceView(pTexture, nullptr, &pShaderResourceView);
    // ... use pShaderResourceView
    pTexture->Release();
}
            

The D3D11_USAGE flag is important: D3D11_USAGE_IMMUTABLE is for textures that won't change after creation (best performance), while D3D11_USAGE_DEFAULT allows the GPU to update it. D3D11_USAGE_DYNAMIC allows CPU updates. D3D11_BIND_SHADER_RESOURCE indicates the texture will be bound to the shader pipeline.

Texture Sampling

To use a texture in a shader, you need to create a ID3D11ShaderResourceView (SRV) from the texture resource. This view describes how the shader should access the texture, including which mip level to use and the format for reading.

Inside a shader (HLSL), textures are accessed using Texture2D and SamplerState objects:


Texture2D myTexture;
SamplerState mySampler;

// In the pixel shader
float4 texColor = myTexture.Sample(mySampler, texCoord);
            

The SamplerState defines how the texture is sampled. This includes:

Texture Resources

Textures are a type of ID3D11Resource. Different dimensions and purposes result in specific resource types:

When you bind a texture to the pipeline, you bind its ID3D11ShaderResourceView. This abstraction allows for flexibility in how the underlying texture data is interpreted by shaders.

Example: Creating a Cubemap

Cubemaps are typically represented as an array of 6 ID3D11Texture2D resources, or a single ID3D11Texture2D with ArraySize = 6. The SRV created for a cubemap will have ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE.


// ... create device and texture descriptions ...
texDesc.ArraySize = 6; // For a cubemap
texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
// ... other properties

// Create the texture array
ID3D11Texture2D* pCubeTexture = nullptr;
pDevice->CreateTexture2D(&texDesc, nullptr, &pCubeTexture);

// Create the shader resource view for the cubemap
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = texDesc.Format;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
srvDesc.TextureCube.MipLevels = texDesc.MipLevels;

ID3D11ShaderResourceView* pCubeSRV = nullptr;
pDevice->CreateShaderResourceView(pCubeTexture, &srvDesc, &pCubeSRV);

// ... bind pCubeSRV to the shader pipeline ...
pCubeTexture->Release();