Freigeben über


Multisampling in Universelle Windows-Plattform (UWP)-Apps

Erfahren Sie, wie Sie Multisampling in Universelle Windows-Plattform (UWP)-Apps verwenden, die mit Direct3D erstellt wurden. Multisampling, auch als Multi-Sample-Antialiasing bezeichnet, ist eine Grafiktechnik, die verwendet wird, um das Aussehen von aliasierten Kanten zu reduzieren. Es funktioniert, indem mehr Pixel gezeichnet werden, als tatsächlich im endgültigen Renderziel enthalten sind, und dann durchschnittlichen Werten, um das Erscheinungsbild eines "partiellen" Rands in bestimmten Pixeln beizubehalten. Eine detaillierte Beschreibung der Funktionsweise von Multisampling in Direct3D finden Sie unter Regeln zur Rasterung von Multisample-Antialiasen.

Multisampling und die Flipmodell-Swapchain

UWP-Apps, die DirectX verwenden, müssen Flip-Modell-Swapchains verwenden. Flipmodell-Swapchains unterstützen multisampling nicht direkt, aber Multisampling kann weiterhin auf eine andere Weise angewendet werden, indem die Szene in einer Multisampling-Renderzielansicht gerendert wird, und dann das Multisampling-Renderziel vor der Darstellung in den Hintergrundpuffer aufgelöst wird. In diesem Artikel werden die Schritte erläutert, die zum Hinzufügen von Multisampling zu Ihrer UWP-App erforderlich sind.

Verwenden von Multisampling

Direct3D-Featureebenen garantieren Unterstützung für bestimmte, minimale Beispielanzahlsfunktionen und garantieren, dass bestimmte Pufferformate verfügbar sind, die Multisampling unterstützen. Grafikgeräte unterstützen häufig eine breitere Palette von Formaten und Beispielanzahlen als die mindest erforderliche Anzahl. Die Multisampling-Unterstützung kann zur Laufzeit ermittelt werden, indem die Featureunterstützung für Multisampling mit bestimmten DXGI-Formaten überprüft und dann die Beispielanzahl überprüft wird, die Sie mit jedem unterstützten Format verwenden können.

  1. Rufen Sie ID3D11Device::CheckFeatureSupport auf, um herauszufinden, welche DXGI-Formate mit Multisampling verwendet werden können. Geben Sie die Renderzielformate an, die Ihr Spiel verwenden kann. Sowohl das Renderziel als auch das Auflösungsziel müssen das gleiche Format verwenden. Überprüfen Sie daher sowohl auf D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET als auch auf D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE.

    **Featureebene 9: ** Obwohl Geräte der Featureebene 9 die Unterstützung für Multisampling-Renderzielformate garantieren, ist die Unterstützung für Multisample-Auflösungsziele nicht garantiert. Daher ist diese Überprüfung erforderlich, bevor Sie versuchen, die in diesem Thema beschriebene Multisampling-Technik zu verwenden.

    Der folgende Code überprüft die Multisamplingunterstützung für alle DXGI_FORMAT Werte:

    // 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. Fragen Sie für jedes unterstützte Format die Unterstützung der Beispielanzahl durch Aufrufen von ID3D11Device::CheckMultisampleQualityLevels ab.

    Der folgende Code überprüft die Beispielgrößenunterstützung für unterstützte DXGI-Formate:

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

    Hinweis Verwenden Sie stattdessen ID3D11Device2::CheckMultisampleQualityLevels1 , wenn Sie die Multisampleunterstützung für nebeneinander angeordnete Ressourcenpuffer überprüfen müssen.

     

  3. Erstellen Sie eine Puffer- und Renderzielansicht mit der gewünschten Beispielanzahl. Verwenden Sie dieselbe DXGI_FORMAT, Breite und Höhe wie die Swapchain, geben Sie jedoch eine Beispielanzahl größer als 1 an, und verwenden Sie eine Texturdimension mit Multisampling (z. B. D3D11_RTV_DIMENSION_TEXTURE2DMS ). Bei Bedarf können Sie die Swapchain mit neuen Einstellungen neu erstellen, die für das Multisampling optimal sind.

    Der folgende Code erstellt ein Multisampling-Renderziel:

    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. Der Tiefenpuffer muss dieselbe Breite, Höhe, Beispielanzahl und Texturdimension aufweisen, um dem Multisampling-Renderziel zu entsprechen.

    Der folgende Code erstellt einen Multisampling-Tiefenpuffer:

    // 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. Jetzt ist ein guter Zeitpunkt zum Erstellen des Viewports, da die Breite und Höhe des Viewports auch mit dem Renderziel übereinstimmen muss.

    Der folgende Code erstellt einen Viewport:

    // 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. Rendern Sie jeden Frame im Multisampling-Renderziel. Rufen Sie nach Abschluss des Renderings ID3D11DeviceContext::ResolveSubresource auf, bevor Sie den Frame darstellen. Dadurch wird Direct3D angewiesen, den Multisampling-Vorgang darzustellen, den Wert jedes Pixels für die Anzeige zu berechnen und das Ergebnis im Hintergrundpuffer zu platzieren. Der Hintergrundpuffer enthält dann das endgültige antialiasierte Bild und kann dargestellt werden.

    Der folgende Code löst die Unterressource vor der Darstellung des Frames auf:

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