共用方式為


通用 Windows 平台 (UWP) 應用程式中的多重取樣

瞭解如何在以 Direct3D 建置的通用 Windows 平台 (UWP) 應用程式中使用多重取樣。 多重取樣,也稱為多重取樣反鋸齒,是一種用於減少鋸齒邊緣出現的圖形技術。 它的工作原理是繪製比最終轉譯目標中實際數量更多的像素,然後對值進行平均以保持某些像素中「部分」邊緣的外觀。 有關多重取樣在 Direct3D 中實際運作原理的詳細說明,請參閱多重取樣反鋸齒點陣化規則

多重取樣和翻轉模型交換鏈結

使用 DirectX 的 UWP 應用程式必須使用翻轉模型交換鏈結。 翻轉模型交換鏈結不直接支援多重取樣,但仍可以透過將場景轉譯到多重取樣轉譯目標檢視,然後在呈現之前將多重取樣轉譯目標解析到後端緩衝區,來以不同的方式套用多重取樣。 本文說明將多重取樣新增至 UWP 應用程式所需的步驟。

如何使用多重取樣

Direct3D 功能層級保證支援特定、最小樣本計數功能,以及保證支援多重取樣的特定緩衝區格式。 圖形裝置通常支援比所需的最小值更廣的格式和範例計數。 可以在執行階段確定多重採樣支援,方法是檢查對特定 DXGI 格式的多重採樣的功能支援,然後檢查可用於每種支持格式的樣本計數。

  1. 呼叫 ID3D11Device::CheckFeatureSupport 以找出哪些 DXGI 格式可用於多重採樣。 提供遊戲可以使用的轉譯目標格式。 轉譯目標和解析目標必須使用相同的格式,因此請檢查 D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGETD3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE

    **功能層級 9:** 儘管功能層級 9 裝置能保證支援多重取樣轉譯目標格式,但不保證支援多重取樣解析目標。 因此,在嘗試使用本主題所述的多重取樣技術之前,必須先進行這項檢查。

    下列程式碼會檢查所有 DXGI_FORMAT 值的多重取樣支援:

    // Determine the format support for multisampling.
    for (UINT i = 1; i < DXGI_FORMAT_MAX; i++)
    {
        DXGI_FORMAT inFormat = safe_cast<DXGI_FORMAT>(i);
        UINT formatSupport = 0;
        HRESULT hr = m_d3dDevice->CheckFormatSupport(inFormat, &formatSupport);
    
        if ((formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE) &&
            (formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET)
            )
        {
            m_supportInfo->SetFormatSupport(i, true);
        }
        else
        {
            m_supportInfo->SetFormatSupport(i, false);
        }
    }
    
  2. 對於每種支援的格式,透過呼叫 ID3D11Device::CheckMultisampleQualityLevels 來查詢樣本計數支援。

    下列程式碼會檢查支援的 DXGI 格式範例大小支援:

    // Find available sample sizes for each supported format.
    for (unsigned int i = 0; i < DXGI_FORMAT_MAX; i++)
    {
        for (unsigned int j = 1; j < MAX_SAMPLES_CHECK; j++)
        {
            UINT numQualityFlags;
    
            HRESULT test = m_d3dDevice->CheckMultisampleQualityLevels(
                (DXGI_FORMAT) i,
                j,
                &numQualityFlags
                );
    
            if (SUCCEEDED(test) && (numQualityFlags > 0))
            {
                m_supportInfo->SetSampleSize(i, j, 1);
                m_supportInfo->SetQualityFlagsAt(i, j, numQualityFlags);
            }
        }
    }
    

    注意:如果您需要檢查圖塊資源緩衝區的多重取樣支援,請改用 ID3D11Device2::CheckMultisampleQualityLevels1

     

  3. 建立具有所需樣本計數的緩衝區和轉譯目標檢視。 使用與交換鏈結相同的 DXGI_FORMAT、寬度和高度,但指定大於 1 的樣本計數並使用多重採樣紋理尺寸 (例如 D3D11_RTV_DIMENSION_TEXTURE2DMS)。 如有必要,您可以使用最適合多重取樣的新設定,重新建立交換鏈結。

    下列程式碼會建立多重取樣的轉譯目標:

    float widthMulti = m_d3dRenderTargetSize.Width;
    float heightMulti = m_d3dRenderTargetSize.Height;
    
    D3D11_TEXTURE2D_DESC offScreenSurfaceDesc;
    ZeroMemory(&offScreenSurfaceDesc, sizeof(D3D11_TEXTURE2D_DESC));
    
    offScreenSurfaceDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
    offScreenSurfaceDesc.Width = static_cast<UINT>(widthMulti);
    offScreenSurfaceDesc.Height = static_cast<UINT>(heightMulti);
    offScreenSurfaceDesc.BindFlags = D3D11_BIND_RENDER_TARGET;
    offScreenSurfaceDesc.MipLevels = 1;
    offScreenSurfaceDesc.ArraySize = 1;
    offScreenSurfaceDesc.SampleDesc.Count = m_sampleSize;
    offScreenSurfaceDesc.SampleDesc.Quality = m_qualityFlags;
    
    // Create a surface that's multisampled.
    DX::ThrowIfFailed(
        m_d3dDevice->CreateTexture2D(
        &offScreenSurfaceDesc,
        nullptr,
        &m_offScreenSurface)
        );
    
    // Create a render target view. 
    CD3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc(D3D11_RTV_DIMENSION_TEXTURE2DMS);
    DX::ThrowIfFailed(
        m_d3dDevice->CreateRenderTargetView(
        m_offScreenSurface.Get(),
        &renderTargetViewDesc,
        &m_d3dRenderTargetView
        )
        );
    
  4. 深度緩衝區必須具有相同的寬度、高度、樣本計數和紋理維度,才能符合多重取樣的轉譯目標。

    下列程式碼會建立多重取樣深度緩衝區:

    // Create a depth stencil view for use with 3D rendering if needed.
    CD3D11_TEXTURE2D_DESC depthStencilDesc(
        DXGI_FORMAT_D24_UNORM_S8_UINT,
        static_cast<UINT>(widthMulti),
        static_cast<UINT>(heightMulti),
        1, // This depth stencil view has only one texture.
        1, // Use a single mipmap level.
        D3D11_BIND_DEPTH_STENCIL,
        D3D11_USAGE_DEFAULT,
        0,
        m_sampleSize,
        m_qualityFlags
        );
    
    ComPtr<ID3D11Texture2D> depthStencil;
    DX::ThrowIfFailed(
        m_d3dDevice->CreateTexture2D(
        &depthStencilDesc,
        nullptr,
        &depthStencil
        )
        );
    
    CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2DMS);
    DX::ThrowIfFailed(
        m_d3dDevice->CreateDepthStencilView(
        depthStencil.Get(),
        &depthStencilViewDesc,
        &m_d3dDepthStencilView
        )
        );
    
  5. 現在是建立檢視區的好時機,因為檢視區的寬度和高度也必須與轉譯目標相符。

    以下程式碼會建立檢視區:

    // Set the 3D rendering viewport to target the entire window.
    m_screenViewport = CD3D11_VIEWPORT(
        0.0f,
        0.0f,
        widthMulti / m_scalingFactor,
        heightMulti / m_scalingFactor
        );
    
    m_d3dContext->RSSetViewports(1, &m_screenViewport);
    
  6. 將每個畫面轉譯為多重取樣的轉譯目標。 轉譯完成後,在呈現畫面之前呼叫 ID3D11DeviceContext::ResolveSubresource。 這會指示 Direct3D 執行多重取樣作業,計算要顯示的每個像素的值並將結果放入後端緩衝區。 然後,後端緩衝區包含最終的反鋸齒影像並且可以顯示。

    下列程式碼會先解析子資源,再呈現畫面:

    if (m_sampleSize > 1)
    {
        unsigned int sub = D3D11CalcSubresource(0, 0, 1);
    
        m_d3dContext->ResolveSubresource(
            m_backBuffer.Get(),
            sub,
            m_offScreenSurface.Get(),
            sub,
            DXGI_FORMAT_B8G8R8A8_UNORM
            );
    }
    
    // The first argument instructs DXGI to block until VSync, putting the application
    // to sleep until the next VSync. This ensures that we don't waste any cycles rendering
    // frames that will never be displayed to the screen.
    hr = m_swapChain->Present(1, 0);