Freigeben über


Multisampling in Apps der Universellen Windows-Plattform

Erfahren Sie, wie Sie Multisampling in UWP-Apps (Universelle Windows-Plattform) 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 Rendering-Ziel enthalten sind, um dann die Werte zu mitteln und das Erscheinungsbild eines teilweisen Randes in bestimmten Pixeln beizubehalten. Eine detaillierte Beschreibung, wie Multisampling tatsächlich in Direct3D funktioniert, finden Sie unter Regeln zur Rasterisierung für die Multisample-Antialiasierung.

Multisampling und die Austauschkette im Flipmodell

UWP-Apps, die DirectX verwenden, müssen Flip-Modell-Swapchains verwenden. Flipmodell-Swapchains unterstützen multisampling nicht direkt, aber multisampling kann dennoch anders angewendet werden: indem die Szene in einer multisampling-Renderzielansicht gerendert wird und das multisampling-Renderziel vor dem Präsentieren 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.

Wie man Multisampling verwendet

Direct3D-Featureebenen garantieren die Unterstützung für spezielle, minimale Sample-Count-Fähigkeiten und stellen sicher, 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 Unterstützung für Multisampling-Renderzielformategarantieren, ist die Unterstützung für Multisampling-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 Multisampling-Unterstü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. Rufen Sie für jedes unterstützte Format die Unterstützung für die Beispielanzahl ab, indem Sie ID3D11Device::CheckMultisampleQualityLevelsaufrufen.

    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 ID3D11Device2::CheckMultisampleQualityLevels1 stattdessen, wenn Sie die Multisampleunterstützung für nebeneinander angeordnete Ressourcenpuffer überprüfen müssen.

     

  3. Erstellen Sie eine Pufferansicht und eine Renderzielansicht mit der gewünschten Beispielanzahl. Verwenden Sie denselben DXGI_FORMAT, dieselbe Breite und Höhe wie die Swap-Chain, geben Sie jedoch eine Anzahl an Beispielen 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 multisampeltes 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 multigesampelten 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 zum Multisampling-Rendertarget. Rufen Sie ID3D11DeviceContext::ResolveSubresource auf, nachdem das Rendering abgeschlossen ist, bevor Sie den Frame präsentieren. Dadurch wird Direct3D angewiesen, den Multisampling-Vorgang auszuführen, 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 auf, bevor der Frame angezeigt wird.

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