建立深度緩衝區裝置資源

瞭解如何建立支援著色器磁碟區深度測試所需的 Direct3D 裝置資源。 Part 1 of Walkthrough:在 Direct3D 11 中使用深度緩衝區實作著色器磁碟區。

您需要的資源

若要轉譯著色器磁碟區的深度對應,需要下列 Direct3D 裝置相關資源:

  • 深度對映的資源 (緩衝區)
  • 資源的深度樣板檢視和著色器資源檢視
  • 比較取樣器狀態物件
  • 輕型 POV 矩陣的常數緩衝區
  • 用於呈現著色器貼圖的視角 (通常為方形視角)
  • 啟用正面剔除的彩現狀態物件
  • 如果您尚未使用彩現狀態物件,則也需要將彩現狀態物件切換回背面剔除狀態。

請備註,這些資源的建立需要包含在依賴於裝置的資源建立常式中,這樣,例如,如果安裝新的裝置驅動程式,或者使用者將應用程式移到連線到其他圖形介面卡的監視器,渲染器就可以重新建立這些資源。

檢查功能支援

建立深度對映之前,請在 Direct3D 裝置上呼叫 CheckFeatureSupport,要求 D3D11_FEATURE_D3D9_SHADOW_SUPPORT,提供 D3D11_FEATURE_DATA_D3D9_SHADOW_SUPPORT 結構。

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 編譯的著色器。 在許多情況下,缺乏此功能的支援表示 GPU 是舊式裝置,其驅動程式並未更新為至少支援 WDDM 1.2。 如果裝置至少支援特徵層級 10_0,則您可以改為載入針對著色器模型 4_0 編譯的範例比較著色器。

建立深度緩衝區

首先,嘗試建立具有更高精確度深度格式的深度對映。 請先設定相符的著色器資源檢視屬性。 如果資源建立失敗,例如由於裝置記憶體不足或硬體不支援的格式所致,請嘗試較低精度的格式並變更屬性以符合。

如果您只需要低精度的深度格式,例如在中解析度的 Direct3D 功能層級 9_1 裝置上彩現時,此步驟是可選的。

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
    );

然後建立資源檢視。 在深度樣板檢視上將 mip 層切面設定為零,並在著色器資源檢視上將 mip 層級設定為1。 兩者都具有 TEXTURE2D 的紋理維度,並且都需要使用相符的 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
    );

建立比較狀態

現在建立比較取樣器狀態物件。 特徵層級 9_1 僅支援 D3D11_COMPARISON_LESS_EQUAL。 在支持著色器圖在一系列硬體上,或您可以只選取點篩選來加快著色器圖的速度。

請備註,您可以指定 D3D11_TEXTURE_ADDRESS_BORDER 位址模式,它將在特徵層級 9_1 裝置上運作。 這適用於在執行深度測試之前,不會測試畫素是否位於光源的視錐台中的畫素著色器。 透過為每個框線指定 0 或 1,您可以控制光源視錐截圖外的畫素是否透過深度測試,進而控制它們是否亮或著色器。

在功能層級 9_1 上,必須設定下列必要值:MinLOD 設定為零,MaxLOD 設定為 D3D11_FLOAT32_MAX,MaxAnisotropy 設定為零。

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
        )
    );

建立轉譯狀態

現在可建立可用於啟用正面剔除的彩現狀態。 請備註,功能層級 9_1 裝置需要將 DepthClipEnable 設定為 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
        )
    );

建立可用於啟用背面剔除的渲染狀態。 如果您的轉譯程式碼已經開啟背面剔除,則可以跳過此步驟。

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
        )
    );

建立常數緩衝區

不要忘記建立從光源角度進行轉譯的常數緩衝區。 您也可以使用此常數緩衝區來指定著色器的光源位置。 對點光源使用透視矩陣,對平行光 (例如陽光)使用正交矩陣。

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

填充常數緩衝區資料。 在初始化期間更新一次常數緩衝區,如果自上一幀以來亮度值已更改,則再次更新常數緩衝區。

{
    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
    );

建立視角

您需要一個單獨的視角來渲染到著色器貼圖。 檢視區不是以裝置為基礎的資源;您可以在程式碼的其他地方自由建立。 與著色器貼圖一起建立視角有助於更方便地保持視角的尺寸與著色器貼圖尺寸一致。

// 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;

在本演練的下一部分中,學習如何透過渲染至深度緩衝區來建立著色器貼圖。