Создание ресурсов устройства буфера глубиныCreate depth buffer device resources

Научитесь создавать ресурсы устройств Direct3D, необходимые для поддержки тестирования глубины для теневых томов.Learn how to create the Direct3D device resources necessary to support depth testing for shadow volumes. Пошаговое руководство. Реализация теневых объемов с помощью буферов глубины в Direct3D 11, часть 1.Part 1 of Walkthrough: Implement shadow volumes using depth buffers in Direct3D 11.

Необходимые ресурсыResources you'll need

Для прорисовки карты глубины для теневых томов требуются следующие аппаратно-зависимые ресурсы Direct3D:Rendering a depth map for shadow volumes requires the following Direct3D device-dependent resources:

  • Ресурс (буфер) для карты глубиныA resource (buffer) for the depth map
  • Представление набора элементов глубины и представление ресурсов шейдера для ресурсаA depth stencil view and shader resource view for the resource
  • Объект сравнения состояний дискретизатораA comparison sampler state object
  • Буферы констант для матриц освещения точки обзораConstant buffers for light POV matrices
  • Окно просмотра для прорисовки карты теней (обычно прямоугольное окно просмотра)A viewport for rendering the shadow map (typically a square viewport)
  • Объект состояния прорисовки для включения выбора передней поверхностиA rendering state object to enable front face culling
  • Объект состояния прорисовки (если он уже не используется) также потребуется вам для возвращения к выбору задней поверхности.You will also need a rendering state object to switch back to back face culling, if you don't already use one.

Отметим, что создание таких ресурсов должно быть включено в программу создания аппаратно-зависимых ресурсов. При этом ваше средство визуализации сможет, например, заново создавать их, когда устанавливается новый драйвер устройства или когда пользователь переносит ваше приложение на монитор, связанный с другим графическим адаптером.Note that creation of these resources needs to be included in a device-dependent resource creation routine, that way your renderer can recreate them if (for example) a new device driver is installed, or the user moves your app to a monitor attached to a different graphics adapter.

Проверка поддержки функцииCheck feature support

Прежде чем создавать карту глубины, вызовите метод чеккфеатуресуппорт на устройстве Direct3D, запросите **D3D11 _ функцию _ d3d9 _ теневой копии _ **и укажите D3D11 _ функции _ _ d3d9 _ теневого _ отображения данных .Before creating the depth map, call the CheckFeatureSupport method on the Direct3D device, request D3D11_FEATURE_D3D9_SHADOW_SUPPORT, and provide a D3D11_FEATURE_DATA_D3D9_SHADOW_SUPPORT structure.

D3D11_FEATURE_DATA_D3D9_SHADOW_SUPPORT isD3D9ShadowSupported;
ZeroMemory(&isD3D9ShadowSupported, sizeof(isD3D9ShadowSupported));
pD3DDevice->CheckFeatureSupport(
    D3D11_FEATURE_D3D9_SHADOW_SUPPORT,
    &isD3D9ShadowSupported,
    sizeof(D3D11_FEATURE_D3D9_SHADOW_SUPPORT)
    );

if (isD3D9ShadowSupported.SupportsDepthAsTextureWithLessEqualComparisonFilter)
{
    // Init shadow map resources

Если эта функция не поддерживается, не пытайтесь загрузить шейдеры, скомпилированные для модели шейдеров 4 уровня 9 _ x, которые вызывают примеры функций сравнения.If this feature is not supported, do not try to load shaders compiled for shader model 4 level 9_x that call sample comparison functions. Во многих случаях отсутствие поддержки этой функции означает, что GPU — это устаревшее устройство, и его драйвер не обновлен для поддержки по крайней мере WDDM 1.2.In many cases, lack of support for this feature means that the GPU is a legacy device with a driver that isn't updated to support at least WDDM 1.2. Если устройство поддерживает по меньшей мере уровень компонентов 10 _ 0, вместо этого можно загрузить образец шейдера сравнения, скомпилированный для модели шейдеров 4 _ 0.If the device supports at least feature level 10_0 then you can load a sample comparison shader compiled for shader model 4_0 instead.

Создание буфера глубиныCreate depth buffer

Сначала попробуйте создать карту глубины с максимально точным форматом глубины.First, try creating the depth map with a higher-precision depth format. Задайте соответствующие свойства представления ресурса шейдера.Set up matching shader resource view properties first. Если создать ресурс не удалось, например из-за недостаточной памяти устройства или потому, что формат не поддерживается оборудованием, попытайтесь применить менее точный формат и измените свойства соответствующим образом.If the resource creation fails, for example due to low device memory or a format that the hardware doesn't support, try a lower-precision format and change properties to match.

Этот шаг является необязательным, если требуется только формат глубины с низкой точностью, например при подготовке к просмотру на устройствах с уровнями Direct3D с низким разрешением 9 _ 1.This step is optional if you only need a low-precision depth format, for example when rendering on medium-resolution Direct3D feature level 9_1 devices.

D3D11_TEXTURE2D_DESC shadowMapDesc;
ZeroMemory(&shadowMapDesc, sizeof(D3D11_TEXTURE2D_DESC));
shadowMapDesc.Format = DXGI_FORMAT_R24G8_TYPELESS;
shadowMapDesc.MipLevels = 1;
shadowMapDesc.ArraySize = 1;
shadowMapDesc.SampleDesc.Count = 1;
shadowMapDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DEPTH_STENCIL;
shadowMapDesc.Height = static_cast<UINT>(m_shadowMapDimension);
shadowMapDesc.Width = static_cast<UINT>(m_shadowMapDimension);

HRESULT hr = pD3DDevice->CreateTexture2D(
    &shadowMapDesc,
    nullptr,
    &m_shadowMap
    );

Затем создайте представления ресурсов.Then create the resource views. Задайте нулевое значение для MIP-среза в представлении трафарета глубины и значение 1 для уровней MIP в представлении ресурса шейдера.Set the mip slice to zero on the depth stencil view and set mip levels to 1 on the shader resource view. Оба имеют измерение текстуры TEXTURE2D, и оба должны использовать соответствующий ** _ Формат DXGI**.Both have a texture dimension of TEXTURE2D, and both need to use a matching DXGI_FORMAT.

D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
ZeroMemory(&depthStencilViewDesc, sizeof(D3D11_DEPTH_STENCIL_VIEW_DESC));
depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
depthStencilViewDesc.Texture2D.MipSlice = 0;

D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc;
ZeroMemory(&shaderResourceViewDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
shaderResourceViewDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
shaderResourceViewDesc.Texture2D.MipLevels = 1;

hr = pD3DDevice->CreateDepthStencilView(
    m_shadowMap.Get(),
    &depthStencilViewDesc,
    &m_shadowDepthView
    );

hr = pD3DDevice->CreateShaderResourceView(
    m_shadowMap.Get(),
    &shaderResourceViewDesc,
    &m_shadowResourceView
    );

Создание состояния сравненияCreate comparison state

Теперь создайте объект сравнения состояний дискретизатора.Now create the comparison sampler state object. Уровень Feature 9 _ 1 поддерживает только _ Сравнение D3D11 _ меньшего _ равенства.Feature level 9_1 only supports D3D11_COMPARISON_LESS_EQUAL. Возможности фильтрации подробнее объясняются в документе Поддержка карт теней на разном оборудовании. Можно также выбрать точечную фильтрацию для ускорения работы карт теней.Filtering choices are explained more in Supporting shadow maps on a range of hardware - or you can just pick point filtering for faster shadow maps.

Обратите внимание, что можно указать _ режим адреса текстуры D3D11, который _ _ будет работать на устройствах с уровнями 9 _ 1.Note that you can specify the D3D11_TEXTURE_ADDRESS_BORDER address mode and it will work on feature level 9_1 devices. Это применимо к шейдерам, которые не проверяют, находится ли пиксель в конусе представления освещения, перед выполнением теста глубины.This applies to pixel shaders that don't test whether the pixel is in the light's view frustum before doing the depth test. Указывая значения 0 или 1 для каждой границы, вы можете контролировать, проходят или не проходят пиксели вне конуса освещения тест на глубину, то есть освещены они или находятся в тени.By specifying 0 or 1 for each border, you can control whether pixels outside the light's view frustum pass or fail the depth test, and therefore whether they are lit or in shadow.

На уровне компонентов 9 _ 1 должны быть установлены следующие обязательные значения: минлод имеет значение 0, макслод имеет значение D3D11 _ FLOAT32 _ Max, а максанисотропи имеет значение 0.On feature level 9_1, the following required values must be set: MinLOD is set to zero, MaxLOD is set to D3D11_FLOAT32_MAX, and MaxAnisotropy is set to zero.

D3D11_SAMPLER_DESC comparisonSamplerDesc;
ZeroMemory(&comparisonSamplerDesc, sizeof(D3D11_SAMPLER_DESC));
comparisonSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
comparisonSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
comparisonSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
comparisonSamplerDesc.BorderColor[0] = 1.0f;
comparisonSamplerDesc.BorderColor[1] = 1.0f;
comparisonSamplerDesc.BorderColor[2] = 1.0f;
comparisonSamplerDesc.BorderColor[3] = 1.0f;
comparisonSamplerDesc.MinLOD = 0.f;
comparisonSamplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
comparisonSamplerDesc.MipLODBias = 0.f;
comparisonSamplerDesc.MaxAnisotropy = 0;
comparisonSamplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL;
comparisonSamplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT;

// Point filtered shadows can be faster, and may be a good choice when
// rendering on hardware with lower feature levels. This sample has a
// UI option to enable/disable filtering so you can see the difference
// in quality and speed.

DX::ThrowIfFailed(
    pD3DDevice->CreateSamplerState(
        &comparisonSamplerDesc,
        &m_comparisonSampler_point
        )
    );

Создание состояний прорисовкиCreate render states

Теперь создайте состояние прорисовки, которое можно использовать для выбора передней поверхности.Now create a render state you can use to enable front face culling. Обратите внимание на то, что для устройств уровня Feature 9 _ 1 требуется, чтобы депсклипенабле было установлено значение true.Note that feature level 9_1 devices require DepthClipEnable set to true.

D3D11_RASTERIZER_DESC drawingRenderStateDesc;
ZeroMemory(&drawingRenderStateDesc, sizeof(D3D11_RASTERIZER_DESC));
drawingRenderStateDesc.CullMode = D3D11_CULL_BACK;
drawingRenderStateDesc.FillMode = D3D11_FILL_SOLID;
drawingRenderStateDesc.DepthClipEnable = true; // Feature level 9_1 requires DepthClipEnable == true
DX::ThrowIfFailed(
    pD3DDevice->CreateRasterizerState(
        &drawingRenderStateDesc,
        &m_drawingRenderState
        )
    );

Создайте состояние прорисовки, которое можно использовать для выбора задней поверхности.Create a render state you can use to enable back face culling. Если ваш код прорисовки уже включает выбор задней поверхности, этот шаг можно пропустить.If your rendering code already turns on back face culling, then you can skip this step.

D3D11_RASTERIZER_DESC shadowRenderStateDesc;
ZeroMemory(&shadowRenderStateDesc, sizeof(D3D11_RASTERIZER_DESC));
shadowRenderStateDesc.CullMode = D3D11_CULL_FRONT;
shadowRenderStateDesc.FillMode = D3D11_FILL_SOLID;
shadowRenderStateDesc.DepthClipEnable = true;

DX::ThrowIfFailed(
    pD3DDevice->CreateRasterizerState(
        &shadowRenderStateDesc,
        &m_shadowRenderState
        )
    );

Создание буферов константCreate constant buffers

Не забудьте создать буфер констант для прорисовки с точки зрения освещения.Don't forget to create a constant buffer for rendering from the light's point of view. Этот буфер констант можно также использовать, чтобы указывать шейдеру позицию источника освещения.You can also use this constant buffer to specify the light position to the shader. Используйте матрицу перспективы для точечных источников света и ортогональную матрицу для направленных источников света (например, для солнечного света).Use a perspective matrix for point lights, and use an orthogonal matrix for directional lights (such as sunlight).

DX::ThrowIfFailed(
    m_deviceResources->GetD3DDevice()->CreateBuffer(
        &viewProjectionConstantBufferDesc,
        nullptr,
        &m_lightViewProjectionBuffer
        )
    );

Заполните данные буфера констант.Fill the constant buffer data. Обновляйте буферы констант один раз при инициализации и затем снова, если значения освещения были изменены по сравнению с предыдущим кадром.Update the constant buffers once during initialization, and again if the light values have changed since the previous frame.

{
    XMMATRIX lightPerspectiveMatrix = XMMatrixPerspectiveFovRH(
        XM_PIDIV2,
        1.0f,
        12.f,
        50.f
        );

    XMStoreFloat4x4(
        &m_lightViewProjectionBufferData.projection,
        XMMatrixTranspose(lightPerspectiveMatrix)
        );

    // Point light at (20, 15, 20), pointed at the origin. POV up-vector is along the y-axis.
    static const XMVECTORF32 eye = { 20.0f, 15.0f, 20.0f, 0.0f };
    static const XMVECTORF32 at = { 0.0f, 0.0f, 0.0f, 0.0f };
    static const XMVECTORF32 up = { 0.0f, 1.0f, 0.0f, 0.0f };

    XMStoreFloat4x4(
        &m_lightViewProjectionBufferData.view,
        XMMatrixTranspose(XMMatrixLookAtRH(eye, at, up))
        );

    // Store the light position to help calculate the shadow offset.
    XMStoreFloat4(&m_lightViewProjectionBufferData.pos, eye);
}
context->UpdateSubresource(
    m_lightViewProjectionBuffer.Get(),
    0,
    NULL,
    &m_lightViewProjectionBufferData,
    0,
    0
    );

Создание окна просмотраCreate a viewport

Для прорисовки на карте глубины требуется отдельное окно просмотра.You need a separate viewport to render to the shadow map. Окно просмотра не является аппаратно-зависимым ресурсом. Вы можете создать его в любом месте кода.The viewport isn't a device-based resource; you're free to create it elsewhere in your code. Создание окна просмотра вместе с картой теней делает более удобным согласование размеров окна просмотра с размерами карты теней.Creating the viewport along with the shadow map can help make it more convenient to keep the dimension of the viewport congruent with the shadow map dimension.

// Init viewport for shadow rendering
ZeroMemory(&m_shadowViewport, sizeof(D3D11_VIEWPORT));
m_shadowViewport.Height = m_shadowMapDimension;
m_shadowViewport.Width = m_shadowMapDimension;
m_shadowViewport.MinDepth = 0.f;
m_shadowViewport.MaxDepth = 1.f;

В следующей части этого руководства вы научитесь создавать карту теней путем прорисовки в буфер глубины.In the next part of this walkthrough, learn how to create the shadow map by rendering to the depth buffer.