Lecture #18. Textures

Computer graphics in Game development

Ivan Belyavtsev

02.12.2022

Plan

  1. Get texture path for each shape in model class
  2. Add root parameter for SRV
  3. Add static sampler to a root signature
  4. Create and compile PS shader for textured objects
  5. Make PSO for rendering textured objects
  6. Create and upload resources with texture’s data
  7. Create shader resource view for each texture
  8. Based on draw call number set appropriate PSO and bind descriptor table [1]

Get texture path for each shape

textures.resize(shapes.size());
for (const auto& shape: shapes)
{
    // ..
    if (!materials[mesh.material_ids[0]].diffuse_texname.empty())
        textures[shape_id] = 
            model_path.parent_path() / 
            materials[mesh.material_ids[0]].diffuse_texname;
    shape_id++;
}

Add root parameter for SRV

ranges[1].Init(
    D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0,
    D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);
root_parameters[1].InitAsDescriptorTable(
    1, &ranges[1], D3D12_SHADER_VISIBILITY_PIXEL);
D3D12_ROOT_SIGNATURE_FLAGS rs_flags =
    D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;

Static sampler descriptor

D3D12_STATIC_SAMPLER_DESC sampler_desc{};
sampler_desc.Filter = D3D12_FILTER_ANISOTROPIC;
sampler_desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
sampler_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
sampler_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
sampler_desc.MipLODBias = 0;
sampler_desc.MaxAnisotropy = 16;
sampler_desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
sampler_desc.BorderColor =
    D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
sampler_desc.MinLOD = 0;
sampler_desc.MaxLOD = D3D12_FLOAT32_MAX;
sampler_desc.ShaderRegister = 0;
sampler_desc.RegisterSpace = 0;
sampler_desc.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;

Add static sampler to a root signature

CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rs_descriptor;
rs_descriptor.Init_1_1(
    _countof(root_parameters), root_parameters, 1,
    &sampler_desc, rs_flags);

Shader’ global definitions

Texture2D g_texture : register(t0);
SamplerState g_sampler : register(s0);

struct PSInput
{
    float4 position : SV_POSITION;
    float4 color: COLOR;
    float2 uv : TEXCOORD;
};

Vertex shader

PSInput VSMain(float4 position : POSITION, float4 normal: NORMAL, float4 ambient : COLOR0, float4 diffuse : COLOR1,  float4 emissive : COLOR2, float4 texcoords : TEXCOORD)
{
    PSInput result;

    result.position = mul(mwpMatrix, position);
    result.color = ambient;
    result.uv = texcoords.xy;

    return result;
}

Pixel shader


float4 PSMain_texture(PSInput input) : SV_TARGET
{
    return g_texture.Sample(g_sampler, input.uv);
}

Make PSO for rendering textured objects

pso_descriptor.PS =
    CD3DX12_SHADER_BYTECODE(pixel_shader_texture.Get());

THROW_IF_FAILED(device->CreateGraphicsPipelineState(
    &pso_descriptor, IID_PPV_ARGS(&pipeline_state_texture)));

Load texture data

std::string full_name = std::filesystem::absolute(
    model->get_per_shape_texture_files()[s]).string();

int tex_width, tex_height, tex_channels;
unsigned char* image =
    stbi_load(full_name.c_str(), &tex_width,
        &tex_height, &tex_channels, STBI_rgb_alpha);

if (image == nullptr)
{
    throw std::runtime_error("Can't load texture");
}

Create texture resources

  • Size: tex_width, tex_height
  • Format: DXGI_FORMAT_R8G8B8A8_UNORM
  • Mip level: 1
  • Upload buffer size: GetRequiredIntermediateSize(textures[s].Get(), 0, 1)
  • RowPitch: tex_width * STBI_rgb_alpha
  • SlicePitch: texture_data.RowPitch * tex_height
  • State after copy: PIXEL_SHADER_RESOURCE

Create shader resource view for each texture

D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc{};
srv_desc.Shader4ComponentMapping =
D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srv_desc.Format = texture_desc.Format;
srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srv_desc.Texture2D.MipLevels = 1;

device->CreateShaderResourceView(textures[s].Get(), &srv_desc,
 cbv_srv_handle);

Based on draw call number set appropriate PSO and bind descriptor table

if (!model->get_per_shape_texture_files()[s].empty()) {
    cbv_srv_handle.InitOffsetted(
        cbv_srv_heap->GetGPUDescriptorHandleForHeapStart(),
        static_cast<INT>(s + 1), cbv_srv_descriptor_size);
    command_list->SetGraphicsRootDescriptorTable(1, 
                                            cbv_srv_handle);
    command_list->SetPipelineState(
                            pipeline_state_texture.Get());
} else {
    command_list->SetPipelineState(pipeline_state.Get());
}

Dabrovic Sponza

From: [2]

References

1.
Satran M. et al. Direct3D 12 programming guide [Electronic resource]. 2019. URL: https://docs.microsoft.com/en-us/windows/win32/direct3d12/directx-12-programming-guide.
2.
McGuire M. Computer graphics archive. 2017.