Renderingframework I: Einführung in das Rendering

Hinweis

Dieses Thema ist Teil der Tutorialreihe Erstellen eines einfachen Universelle Windows-Plattform -Spiels (UWP) mit DirectX. Das Thema unter diesem Link legt den Kontext für die Reihe fest.

Bisher haben wir beschrieben, wie Sie ein Universelle Windows-Plattform-Spiel (UWP) strukturieren und einen Zustandsautomat definieren, um den Spielfluss zu verarbeiten. Jetzt ist es an der Zeit, zu erfahren, wie Sie das Renderingframework entwickeln. Sehen wir uns an, wie das Beispielspiel die Spielszene mithilfe von Direct3D 11 rendert.

Direct3D 11 enthält eine Reihe von APIs, die Zugriff auf die erweiterten Features von Hochleistungsgrafikhardware bieten, die zum Erstellen von 3D-Grafiken für grafikintensive Anwendungen wie Spiele verwendet werden kann.

Das Rendern von Spielgrafiken auf dem Bildschirm bedeutet im Grunde, dass eine Sequenz von Frames auf dem Bildschirm gerendert wird. In jedem Frame müssen Sie Objekte rendern, die in der Szene sichtbar sind, basierend auf der Ansicht.

Um einen Frame zu rendern, müssen Sie die erforderlichen Szeneninformationen an die Hardware übergeben, damit sie auf dem Bildschirm angezeigt werden können. Wenn Sie möchten, dass etwas auf dem Bildschirm angezeigt wird, müssen Sie mit dem Rendern beginnen, sobald das Spiel ausgeführt wird.

Ziele

So richten Sie ein grundlegendes Renderingframework zum Anzeigen der Grafikausgabe für ein UWP DirectX-Spiel ein. Sie können dies lose in diese drei Schritte unterteilen.

  1. Stellen Sie eine Verbindung mit der Grafikschnittstelle her.
  2. Erstellen Sie die Ressourcen, die zum Zeichnen der Grafiken erforderlich sind.
  3. Zeigen Sie die Grafiken an, indem Sie den Frame rendern.

In diesem Thema wird erläutert, wie Grafiken gerendert werden, wobei die Schritte 1 und 3 behandelt werden.

Renderingframework II: Das Rendering von Spielen befasst sich mit Schritt 2, dem Einrichten des Renderingframeworks und der Vorbereitung von Daten, bevor das Rendering erfolgen kann.

Erste Schritte

Es ist eine gute Idee, sich mit grundlegenden Grafik- und Renderingkonzepten vertraut zu machen. Wenn Sie noch nicht mit Direct3D und Rendering vertraut sind, finden Sie unter Begriffe und Konzepte eine kurze Beschreibung der in diesem Thema verwendeten Grafiken und Renderingbegriffe.

Für dieses Spiel stellt die GameRenderer-Klasse den Renderer für dieses Beispielspiel dar. Es ist für das Erstellen und Verwalten aller Direct3D 11- und Direct2D-Objekte verantwortlich, die zum Generieren der Visuals des Spiels verwendet werden. Außerdem wird ein Verweis auf das Simple3DGame-Objekt zum Abrufen der Liste der zu rendernden Objekte sowie auf status des Spiels für die Heads-up-Anzeige (HUD) verwaltet.

In diesem Teil des Tutorials konzentrieren wir uns auf das Rendern von 3D-Objekten im Spiel.

Herstellen einer Verbindung mit der Grafikschnittstelle

Informationen zum Zugriff auf die Hardware zum Rendern finden Sie im Thema Definieren des UWP-App-Frameworks des Spiels .

Die App::Initialize-Methode

Die std::make_shared-Funktion wird wie unten gezeigt verwendet, um eine shared_ptr zu DX::D eviceResources zu erstellen, die auch Zugriff auf das Gerät ermöglicht.

In Direct3D 11 wird ein Gerät verwendet, um Objekte zuzuordnen und zu zerstören, Grundtypen zu rendern und mit den Grafiken Karte über den Grafiktreiber zu kommunizieren.

void Initialize(CoreApplicationView const& applicationView)
{
    ...

    // At this point we have access to the device. 
    // We can create the device-dependent resources.
    m_deviceResources = std::make_shared<DX::DeviceResources>();
}

Anzeigen der Grafiken durch Rendern des Frames

Die Spielszene muss gerendert werden, wenn das Spiel gestartet wird. Die Anweisungen zum Rendern beginnen in der GameMain::Run-Methode , wie unten gezeigt.

Der einfache Ablauf ist dies.

  1. Aktualisieren
  2. Rendern
  3. Anwesend

GameMain::Run-Methode

void GameMain::Run()
{
    while (!m_windowClosed)
    {
        if (m_visible) // if the window is visible
        {
            switch (m_updateState)
            {
            ...
            default:
                CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
                Update();
                m_renderer->Render();
                m_deviceResources->Present();
                m_renderNeeded = false;
            }
        }
        else
        {
            CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
        }
    }
    m_game->OnSuspending();  // Exiting due to window close, so save state.
}

Aktualisieren

Weitere Informationen dazu, wie Spielzustände in der GameMain::Update-Methode aktualisiert werden, finden Sie im Thema Spielflussverwaltung.

Rendern

Das Rendern wird durch Aufrufen der GameRenderer::Render-Methode aus GameMain::Run implementiert.

Wenn Das Stereorendering aktiviert ist, gibt es zwei Renderingdurchläufe – einen für das linke Auge und einen für das rechte Auge. In jedem Renderingdurchlauf binden wir das Renderziel und die Tiefenschablonenansicht an das Gerät. Wir löschen auch die Tiefenschablonenansicht danach.

Hinweis

Stereorendering kann mit anderen Methoden wie Single-Pass-Stereo mithilfe von Vertex-Instancing oder Geometry-Shadern erreicht werden. Die Methode mit zwei Renderingdurchläufen ist eine langsamere, aber bequemere Methode, um Stereorendering zu erreichen.

Sobald das Spiel ausgeführt wird und Ressourcen geladen sind, aktualisieren wir die Projektionsmatrix einmal pro Renderingdurchlauf. Objekte unterscheiden sich geringfügig von den einzelnen Ansichten. Als Nächstes richten wir die Grafikrenderingpipeline ein.

Hinweis

Weitere Informationen zum Laden von Ressourcen finden Sie unter Erstellen und Laden von DirectX-Grafikressourcen .

In diesem Beispielspiel ist der Renderer so konzipiert, dass er ein Standardvertexlayout für alle Objekte verwendet. Dies vereinfacht das Shaderdesign und ermöglicht einfache Änderungen zwischen Shadern, unabhängig von der Geometrie der Objekte.

GameRenderer::Render-Methode

Wir legen den Direct3D-Kontext so fest, dass ein Eingabevertexlayout verwendet wird. Eingabelayoutobjekte beschreiben, wie Vertexpufferdaten in die Renderingpipeline gestreamt werden.

Als Nächstes legen wir den Direct3D-Kontext so fest, dass die zuvor definierten Konstantenpuffer verwendet werden, die von der Vertex-Shader-Pipelinephase und der Pipelinephase des Pixelshaders verwendet werden.

Hinweis

Weitere Informationen zur Definition der Konstantenpuffer finden Sie unter Renderingframework II: Spielrendering .

Da das gleiche Eingabelayout und derselbe Satz von Konstantenpuffern für alle Shader in der Pipeline verwendet werden, wird es einmal pro Frame eingerichtet.

void GameRenderer::Render()
{
    bool stereoEnabled{ m_deviceResources->GetStereoState() };

    auto d3dContext{ m_deviceResources->GetD3DDeviceContext() };
    auto d2dContext{ m_deviceResources->GetD2DDeviceContext() };

    int renderingPasses = 1;
    if (stereoEnabled)
    {
        renderingPasses = 2;
    }

    for (int i = 0; i < renderingPasses; i++)
    {
        // Iterate through the number of rendering passes to be completed.
        // 2 rendering passes if stereo is enabled.
        if (i > 0)
        {
            // Doing the Right Eye View.
            ID3D11RenderTargetView* const targets[1] = { m_deviceResources->GetBackBufferRenderTargetViewRight() };

            // Resets render targets to the screen.
            // OMSetRenderTargets binds 2 things to the device.
            // 1. Binds one render target atomically to the device.
            // 2. Binds the depth-stencil view, as returned by the GetDepthStencilView method, to the device.
            // For more info, see
            // https://learn.microsoft.com/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-omsetrendertargets

            d3dContext->OMSetRenderTargets(1, targets, m_deviceResources->GetDepthStencilView());

            // Clears the depth stencil view.
            // A depth stencil view contains the format and buffer to hold depth and stencil info.
            // For more info about depth stencil view, go to: 
            // https://learn.microsoft.com/windows/uwp/graphics-concepts/depth-stencil-view--dsv-
            // A depth buffer is used to store depth information to control which areas of 
            // polygons are rendered rather than hidden from view. To learn more about a depth buffer,
            // go to: https://learn.microsoft.com/windows/uwp/graphics-concepts/depth-buffers
            // A stencil buffer is used to mask pixels in an image, to produce special effects. 
            // The mask determines whether a pixel is drawn or not,
            // by setting the bit to a 1 or 0. To learn more about a stencil buffer,
            // go to: https://learn.microsoft.com/windows/uwp/graphics-concepts/stencil-buffers

            d3dContext->ClearDepthStencilView(m_deviceResources->GetDepthStencilView(), D3D11_CLEAR_DEPTH, 1.0f, 0);

            // Direct2D -- discussed later
            d2dContext->SetTarget(m_deviceResources->GetD2DTargetBitmapRight());
        }
        else
        {
            // Doing the Mono or Left Eye View.
            // As compared to the right eye:
            // m_deviceResources->GetBackBufferRenderTargetView instead of GetBackBufferRenderTargetViewRight
            ID3D11RenderTargetView* const targets[1] = { m_deviceResources->GetBackBufferRenderTargetView() };

            // Same as the Right Eye View.
            d3dContext->OMSetRenderTargets(1, targets, m_deviceResources->GetDepthStencilView());
            d3dContext->ClearDepthStencilView(m_deviceResources->GetDepthStencilView(), D3D11_CLEAR_DEPTH, 1.0f, 0);

            // d2d -- Discussed later under Adding UI
            d2dContext->SetTarget(m_deviceResources->GetD2DTargetBitmap());
        }

        const float clearColor[4] = { 0.5f, 0.5f, 0.8f, 1.0f };

        // Only need to clear the background when not rendering the full 3D scene since
        // the 3D world is a fully enclosed box and the dynamics prevents the camera from
        // moving outside this space.
        if (i > 0)
        {
            // Doing the Right Eye View.
            d3dContext->ClearRenderTargetView(m_deviceResources->GetBackBufferRenderTargetViewRight(), clearColor);
        }
        else
        {
            // Doing the Mono or Left Eye View.
            d3dContext->ClearRenderTargetView(m_deviceResources->GetBackBufferRenderTargetView(), clearColor);
        }

        // Render the scene objects
        if (m_game != nullptr && m_gameResourcesLoaded && m_levelResourcesLoaded)
        {
            // This section is only used after the game state has been initialized and all device
            // resources needed for the game have been created and associated with the game objects.
            if (stereoEnabled)
            {
                // When doing stereo, it is necessary to update the projection matrix once per rendering pass.

                auto orientation = m_deviceResources->GetOrientationTransform3D();

                ConstantBufferChangeOnResize changesOnResize;
                // Apply either a left or right eye projection, which is an offset from the middle
                XMStoreFloat4x4(
                    &changesOnResize.projection,
                    XMMatrixMultiply(
                        XMMatrixTranspose(
                            i == 0 ?
                            m_game->GameCamera().LeftEyeProjection() :
                            m_game->GameCamera().RightEyeProjection()
                            ),
                        XMMatrixTranspose(XMLoadFloat4x4(&orientation))
                        )
                    );

                d3dContext->UpdateSubresource(
                    m_constantBufferChangeOnResize.get(),
                    0,
                    nullptr,
                    &changesOnResize,
                    0,
                    0
                    );
            }

            // Update variables that change once per frame.
            ConstantBufferChangesEveryFrame constantBufferChangesEveryFrameValue;
            XMStoreFloat4x4(
                &constantBufferChangesEveryFrameValue.view,
                XMMatrixTranspose(m_game->GameCamera().View())
                );
            d3dContext->UpdateSubresource(
                m_constantBufferChangesEveryFrame.get(),
                0,
                nullptr,
                &constantBufferChangesEveryFrameValue,
                0,
                0
                );

            // Set up the graphics pipeline. This sample uses the same InputLayout and set of
            // constant buffers for all shaders, so they only need to be set once per frame.
            // For more info about the graphics or rendering pipeline, see
            // https://learn.microsoft.com/windows/win32/direct3d11/overviews-direct3d-11-graphics-pipeline

            // IASetInputLayout binds an input-layout object to the input-assembler (IA) stage. 
            // Input-layout objects describe how vertex buffer data is streamed into the IA pipeline stage.
            // Set up the Direct3D context to use this vertex layout. For more info, see
            // https://learn.microsoft.com/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-iasetinputlayout
            d3dContext->IASetInputLayout(m_vertexLayout.get());

            // VSSetConstantBuffers sets the constant buffers used by the vertex shader pipeline stage.
            // Set up the Direct3D context to use these constant buffers. For more info, see
            // https://learn.microsoft.com/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-vssetconstantbuffers

            ID3D11Buffer* constantBufferNeverChanges{ m_constantBufferNeverChanges.get() };
            d3dContext->VSSetConstantBuffers(0, 1, &constantBufferNeverChanges);
            ID3D11Buffer* constantBufferChangeOnResize{ m_constantBufferChangeOnResize.get() };
            d3dContext->VSSetConstantBuffers(1, 1, &constantBufferChangeOnResize);
            ID3D11Buffer* constantBufferChangesEveryFrame{ m_constantBufferChangesEveryFrame.get() };
            d3dContext->VSSetConstantBuffers(2, 1, &constantBufferChangesEveryFrame);
            ID3D11Buffer* constantBufferChangesEveryPrim{ m_constantBufferChangesEveryPrim.get() };
            d3dContext->VSSetConstantBuffers(3, 1, &constantBufferChangesEveryPrim);

            // Sets the constant buffers used by the pixel shader pipeline stage. 
            // For more info, see
            // https://learn.microsoft.com/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-pssetconstantbuffers

            d3dContext->PSSetConstantBuffers(2, 1, &constantBufferChangesEveryFrame);
            d3dContext->PSSetConstantBuffers(3, 1, &constantBufferChangesEveryPrim);
            ID3D11SamplerState* samplerLinear{ m_samplerLinear.get() };
            d3dContext->PSSetSamplers(0, 1, &samplerLinear);

            for (auto&& object : m_game->RenderObjects())
            {
                // The 3D object render method handles the rendering.
                // For more info, see Primitive rendering below.
                object->Render(d3dContext, m_constantBufferChangesEveryPrim.get());
            }
        }

        // Start of 2D rendering
        ...
    }
}

Primitives Rendering

Beim Rendern der Szene durchlaufen Sie alle Objekte, die gerendert werden müssen. Die folgenden Schritte werden für jedes Objekt (grundtyp) wiederholt.

  • Aktualisieren Sie den Konstantenpuffer (m_constantBufferChangesEveryPrim) mit der Welttransformationsmatrix und den Materialinformationen des Modells.
  • Die m_constantBufferChangesEveryPrim enthält Parameter für jedes Objekt. Sie enthält die Objekt-zu-Welt-Transformationsmatrix sowie Materialeigenschaften wie Farbe und Spiegelexponenten für Beleuchtungsberechnungen.
  • Legen Sie den Direct3D-Kontext so fest, dass das Eingabevertexlayout für die Daten des Gitterobjekts verwendet wird, die in die Input-Assembler-Phase (IA) der Renderingpipeline gestreamt werden sollen.
  • Legen Sie den Direct3D-Kontext so fest, dass in der IA-Phase ein Indexpuffer verwendet wird. Geben Sie die primitiven Informationen an: Typ, Datenreihenfolge.
  • Übermitteln Sie einen Zeichnungsaufruf, um den indizierten Grundtyp ohne Instanz zu zeichnen. Die GameObject::Render-Methode aktualisiert den Grundkonstantenpuffer mit den Daten, die für einen bestimmten Grundtyp spezifisch sind. Dies führt zu einem DrawIndexed-Aufruf für den Kontext, um die Geometrie der einzelnen Grundtypen zu zeichnen. Insbesondere werden mit diesem Draw-Aufruf Befehle und Daten in die GPU (Graphics Processing Unit) eingereiht, wie sie durch die Konstantenpufferdaten parametrisiert werden. Jeder Zeichnungsaufruf führt den Vertex-Shader einmal pro Scheitelpunkt und dann einmal den Pixel-Shader für jedes Pixel jedes Dreiecks im Grundtyp aus. Die Texturen sind Teil des Zustands, den der Pixelshader für das Rendering verwendet.

Dies sind die Gründe für die Verwendung mehrerer Konstantenpuffer.

  • Das Spiel verwendet mehrere Konstantenpuffer, muss diese Puffer jedoch nur einmal pro Grundtyp aktualisieren. Wie bereits erwähnt, sind Konstantenpuffer wie Eingaben für die Shader, die für jeden Grundtyp ausgeführt werden. Einige Daten sind statisch (m_constantBufferNeverChanges); einige Daten sind über den Frame konstant (m_constantBufferChangesEveryFrame), z. B. die Position der Kamera; und einige Daten sind spezifisch für den Grundtyp, z. B. seine Farbe und Texturen (m_constantBufferChangesEveryPrim).
  • Der Spielrenderer teilt diese Eingaben in verschiedene Konstantenpuffer auf, um die von CPU und GPU verwendete Speicherbandbreite zu optimieren. Dieser Ansatz trägt auch dazu bei, die Datenmenge zu minimieren, die die GPU nachverfolgen muss. Die GPU verfügt über eine große Warteschlange mit Befehlen, und jedes Mal, wenn das Spiel Draw aufruft, wird dieser Befehl zusammen mit den zugeordneten Daten in die Warteschlange gestellt. Wenn das Spiel den Grundtypkonstantenpuffer aktualisiert und den nächsten Draw-Befehl ausgibt, fügt der Grafiktreiber diesen Befehl und die dazugehörigen Daten der Warteschlange hinzu. Zeichnet das Spiel 100 Grundtypen, kann die Warteschlange 100 Kopien der Konstantenpufferdaten enthalten. Um die Datenmenge zu minimieren, die das Spiel an die GPU sendet, verwendet das Spiel einen separaten Grundkonstantenpuffer, der nur die Updates für jeden Grundtyp enthält.

GameObject::Render-Methode

void GameObject::Render(
    _In_ ID3D11DeviceContext* context,
    _In_ ID3D11Buffer* primitiveConstantBuffer
    )
{
    if (!m_active || (m_mesh == nullptr) || (m_normalMaterial == nullptr))
    {
        return;
    }

    ConstantBufferChangesEveryPrim constantBuffer;

    // Put the model matrix info into a constant buffer, in world matrix.
    XMStoreFloat4x4(
        &constantBuffer.worldMatrix,
        XMMatrixTranspose(ModelMatrix())
        );

    // Check to see which material to use on the object.
    // If a collision (a hit) is detected, GameObject::Render checks the current context, which 
    // indicates whether the target has been hit by an ammo sphere. If the target has been hit, 
    // this method applies a hit material, which reverses the colors of the rings of the target to 
    // indicate a successful hit to the player. Otherwise, it applies the default material 
    // with the same method. In both cases, it sets the material by calling Material::RenderSetup, 
    // which sets the appropriate constants into the constant buffer. Then, it calls 
    // ID3D11DeviceContext::PSSetShaderResources to set the corresponding texture resource for the 
    // pixel shader, and ID3D11DeviceContext::VSSetShader and ID3D11DeviceContext::PSSetShader 
    // to set the vertex shader and pixel shader objects themselves, respectively.

    if (m_hit && m_hitMaterial != nullptr)
    {
        m_hitMaterial->RenderSetup(context, &constantBuffer);
    }
    else
    {
        m_normalMaterial->RenderSetup(context, &constantBuffer);
    }

    // Update the primitive constant buffer with the object model's info.
    context->UpdateSubresource(primitiveConstantBuffer, 0, nullptr, &constantBuffer, 0, 0);

    // Render the mesh.
    // See MeshObject::Render method below.
    m_mesh->Render(context);
}

MeshObject::Render-Methode

void MeshObject::Render(_In_ ID3D11DeviceContext* context)
{
    // PNTVertex is a struct. stride provides us the size required for all the mesh data
    // struct PNTVertex
    //{
    //  DirectX::XMFLOAT3 position;
    //  DirectX::XMFLOAT3 normal;
    //  DirectX::XMFLOAT2 textureCoordinate;
    //};
    uint32_t stride{ sizeof(PNTVertex) };
    uint32_t offset{ 0 };

    // Similar to the main render loop.
    // Input-layout objects describe how vertex buffer data is streamed into the IA pipeline stage.
    ID3D11Buffer* vertexBuffer{ m_vertexBuffer.get() };
    context->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);

    // IASetIndexBuffer binds an index buffer to the input-assembler stage.
    // For more info, see
    // https://learn.microsoft.com/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-iasetindexbuffer.
    context->IASetIndexBuffer(m_indexBuffer.get(), DXGI_FORMAT_R16_UINT, 0);

    // Binds information about the primitive type, and data order that describes input data for the input assembler stage.
    // For more info, see
    // https://learn.microsoft.com/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-iasetprimitivetopology.
    context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    // Draw indexed, non-instanced primitives. A draw API submits work to the rendering pipeline.
    // For more info, see
    // https://learn.microsoft.com/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-drawindexed.
    context->DrawIndexed(m_indexCount, 0, 0);
}

DeviceResources::P resent-Methode

Wir rufen die DeviceResources::P resent-Methode auf, um den Inhalt anzuzeigen, den wir in den Puffern platziert haben.

Der Begriff Swapchain wird für eine Sammlung von Puffern verwendet, die zum Anzeigen von Frames für den Benutzer verwendet werden. Jedes Mal, wenn eine Anwendung einen neuen Frame zur Anzeige vorstellt, tritt der erste Puffer in der Swapchain an die Stelle des angezeigten Puffers. Dieser Vorgang wird als Austauschen oder Kippen bezeichnet. Weitere Informationen finden Sie unter Swapchains.

  • Die Present-Methode der IDXGISwapChain1-Schnittstelle weist DXGI an, zu blockieren, bis die vertikale Synchronisierung (VSync) erfolgt, wodurch die Anwendung bis zum nächsten VSync in den Standbymodus versetzt wird. Dadurch wird sichergestellt, dass Sie keine Zyklen für das Rendern von Frames verschwenden, die niemals auf dem Bildschirm angezeigt werden.
  • Die DiscardView-Methode der ID3D11DeviceContext3-Schnittstelle verwirft den Inhalt des Renderziels. Dies ist nur dann gültig, wenn der vorhandene Inhalt vollständig überschrieben wird. Wenn modifiziert oder Scroll rects verwendet werden, sollte dieser Aufruf entfernt werden.
  • Verwerfen Sie mit derselben DiscardView-Methode den Inhalt der Tiefenschablone.
  • Die HandleDeviceLost-Methode wird verwendet, um das Szenario zu verwalten, in dem das Gerät entfernt wird. Wenn das Gerät entweder durch eine Trennung oder ein Treiberupgrade entfernt wurde, müssen Sie alle Geräteressourcen neu erstellen. Weitere Informationen finden Sie unter Behandeln von Szenarien mit entfernten Geräten in Direct3D 11.

Tipp

Um eine gleichmäßige Bildfrequenz zu erzielen, müssen Sie sicherstellen, dass der Aufwand zum Rendern eines Frames in die Zeit zwischen VSyncs passt.

// Present the contents of the swap chain to the screen.
void DX::DeviceResources::Present()
{
    // The first argument instructs DXGI to block until VSync, putting the application
    // to sleep until the next VSync. This ensures we don't waste any cycles rendering
    // frames that will never be displayed to the screen.
    HRESULT hr = m_swapChain->Present(1, 0);

    // Discard the contents of the render target.
    // This is a valid operation only when the existing contents will be entirely
    // overwritten. If dirty or scroll rects are used, this call should be removed.
    m_d3dContext->DiscardView(m_d3dRenderTargetView.get());

    // Discard the contents of the depth stencil.
    m_d3dContext->DiscardView(m_d3dDepthStencilView.get());

    // If the device was removed either by a disconnection or a driver upgrade, we 
    // must recreate all device resources.
    if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
    {
        HandleDeviceLost();
    }
    else
    {
        winrt::check_hresult(hr);
    }
}

Nächste Schritte

In diesem Thema wurde erläutert, wie Grafiken auf dem Display gerendert werden, und es enthält eine kurze Beschreibung für einige der verwendeten Renderingbegriffe (unten). Weitere Informationen zum Rendern finden Sie im Thema Renderingframework II: Spielerendering , und erfahren Sie, wie Sie die vor dem Rendern erforderlichen Daten vorbereiten.

Begriffe und Konzepte

Einfache Spielszene

Eine einfache Spielszene besteht aus wenigen Objekten mit mehreren Lichtquellen.

Die Form eines Objekts wird durch eine Reihe von X-, Y- und Z-Koordinaten im Raum definiert. Der tatsächliche Renderort in der Spielwelt kann bestimmt werden, indem eine Transformationsmatrix auf die Positionskoordinaten X, Y, Z angewendet wird. Es kann auch über eine Reihe von Texturkoordinaten ( Sie und V ) verfügen, die angeben, wie ein Material auf das Objekt angewendet wird. Dies definiert die Oberflächeneigenschaften des Objekts und gibt Ihnen die Möglichkeit, zu sehen, ob ein Objekt eine raue Oberfläche (wie ein Tennisball) oder eine glatte glänzende Oberfläche (wie eine Bowlkugel) hat.

Szenen- und Objektinformationen werden vom Renderingframework verwendet, um die Szene Frame für Frame neu zu erstellen, sodass sie auf Ihrem Bildschirm lebendig wird.

Renderingpipeline

Die Renderingpipeline ist der Prozess, bei dem 3D-Szeneninformationen in ein Bild übersetzt werden, das auf dem Bildschirm angezeigt wird. In Direct3D 11 ist diese Pipeline programmierbar. Sie können die Phasen anpassen, um Ihre Renderinganforderungen zu unterstützen. Phasen mit gemeinsamen Shaderkernen können mithilfe der Programmiersprache HLSL programmiert werden. Sie wird auch als Grafikrenderingpipeline oder einfach als Pipeline bezeichnet.

Damit Sie diese Pipeline erstellen können, müssen Sie mit diesen Details vertraut sein.

Weitere Informationen finden Sie unter Grundlegendes zur Direct3D 11-Renderingpipeline und Grafikpipeline.

HLSL

HLSL ist die allgemeine Shadersprache für DirectX. Mithilfe von HLSL können Sie C-ähnliche programmierbare Shader für die Direct3D-Pipeline erstellen. Weitere Informationen finden Sie unter HLSL.

Shader

Ein Shader kann als eine Reihe von Anweisungen betrachtet werden, die bestimmen, wie die Oberfläche eines Objekts beim Rendern angezeigt wird. Diejenigen, die mit HLSL programmiert werden, werden als HLSL-Shader bezeichnet. Quellcodedateien für [HLSL])(#hlsl)-Shader verfügen über die .hlsl Dateierweiterung. Diese Shader können zur Buildzeit oder zur Laufzeit kompiliert und zur Laufzeit in die entsprechende Pipelinephase festgelegt werden. Ein kompiliertes Shaderobjekt verfügt über eine .cso Dateierweiterung.

Direct3D 9-Shader können mit Shadermodell 1, Shadermodell 2 und Shadermodell 3 entworfen werden; Direct3D 10-Shader können nur mit Shadermodell 4 entworfen werden. Direct3D 11-Shader können mit Shadermodell 5 entworfen werden. Direct3D 11.3 und Direct3D 12 können auf Shadermodell 5.1 und Direct3D 12 auch auf Shadermodell 6 entworfen werden.

Vertexshader und Pixelshader

Daten gelangen als Stream von Grundtypen in die Grafikpipeline und werden von verschiedenen Shadern wie den Vertex-Shadern und Pixelshadern verarbeitet.

Vertexshader verarbeiten Scheitelpunkte und führen in der Regel Vorgänge wie Transformationen, Skinning und Beleuchtung aus. Pixelshader ermöglichen umfassende Schattierungstechniken, z. B. pixelgenaue Beleuchtung und Nachbearbeitung. Es kombiniert konstante Variablen, Texturdaten, interpolierte Werte pro Scheitelpunkt und andere Daten, um Ausgaben pro Pixel zu erzeugen.

Shaderphasen

Eine Sequenz dieser verschiedenen Shader, die für die Verarbeitung dieses Datenstroms von Grundtypen definiert sind, wird als Shaderphasen in einer Renderingpipeline bezeichnet. Die tatsächlichen Phasen hängen von der Version von Direct3D ab, umfassen jedoch in der Regel die Vertex-, Geometrie- und Pixelphasen. Es gibt auch andere Phasen, z. B. den Hull- und Domänen-Shader für die Tessellation und den Compute-Shader. Alle diese Phasen sind mit HLSL vollständig programmierbar. Weitere Informationen finden Sie unter Grafikpipeline.

Verschiedene Shaderdateiformate

Hier sind die Shadercodedateierweiterungen.

  • Eine Datei mit der .hlsl Erweiterung enthält [HLSL])(#hlsl) Quellcode.
  • Eine Datei mit der .cso Erweiterung enthält ein kompiliertes Shaderobjekt.
  • Eine Datei mit der .h Erweiterung ist eine Headerdatei, aber in einem Shadercodekontext definiert diese Headerdatei ein Bytearray, das Shaderdaten enthält.
  • Eine Datei mit der .hlsli Erweiterung enthält das Format der Konstantenpuffer. Im Beispielspiel lautet die Datei Shaders>ConstantBuffers.hlsli.

Hinweis

Sie betten einen Shader ein, indem Sie entweder eine .cso Datei zur Laufzeit laden oder indem Sie dem ausführbaren Code eine .h Datei hinzufügen. Sie würden jedoch nicht beides für denselben Shader verwenden.

Tiefere Kenntnisse von DirectX

Direct3D 11 ist eine Reihe von APIs, die uns helfen können, Grafiken für grafikintensive Anwendungen wie Spiele zu erstellen, bei denen wir eine gute Grafik Karte für die Verarbeitung intensiver Berechnungen benötigen. In diesem Abschnitt werden kurz die Konzepte der Direct3D 11-Grafikprogrammierung erläutert: Ressource, Unterressource, Gerät und Gerätekontext.

Resource

Sie können sich Ressourcen (auch als Geräteressourcen bezeichnet) als Informationen zum Rendern eines Objekts vorstellen, z. B. Textur, Position oder Farbe. Ressourcen stellen Daten für die Pipeline bereit und definieren, was während ihrer Szene gerendert wird. Ressourcen können von Ihren Spielmedien geladen oder dynamisch zur Laufzeit erstellt werden.

Eine Ressource ist tatsächlich ein Bereich im Arbeitsspeicher, auf den die Direct3D-Pipeline zugreifen kann. Damit die Pipeline effizient auf den Speicher zugreifen kann, müssen für die Pipeline bereitgestellte Daten (etwa Eingabegeometrie, Shaderressourcen und Texturen) in einer Ressource gespeichert werden. Es gibt zwei Arten von Ressourcen, aus denen alle Direct3D-Ressourcen abgeleitet sind: Puffer und Textur. Für jede Pipelinephase können bis zu 128 Ressourcen aktiv sein. Weitere Informationen finden Sie unter Ressourcen.

Unterressource

Der Begriff Unterressource bezieht sich auf eine Teilmenge einer Ressource. Direct3D kann auf eine gesamte Ressource verweisen oder auf Teilmengen einer Ressource verweisen. Weitere Informationen finden Sie unter Unterressourcen.

Tiefenschablone

Eine Tiefenschablonenressource enthält das Format und den Puffer für Tiefen- und Schabloneninformationen. Sie wird mithilfe einer Texturressource erstellt. Weitere Informationen zum Erstellen einer Tiefenschablonenressource finden Sie unter Konfigurieren Depth-Stencil Funktionalität. Wir greifen auf die Tiefenschablonenressource über die Tiefenschablonenansicht zu, die mithilfe der ID3D11DepthStencilView-Schnittstelle implementiert wurde.

Tiefeninformationen geben uns an, welche Polygonbereiche sich hinter anderen befinden, sodass wir bestimmen können, welche ausgeblendet sind. Schabloneninformationen sagen uns, welche Pixel maskiert sind. Es kann verwendet werden, um Spezialeffekte zu erzeugen, da es bestimmt, ob ein Pixel gezeichnet wird oder nicht. legt das Bit auf 1 oder 0 fest.

Weitere Informationen finden Sie unter Tiefenschablonenansicht, Tiefenpuffer und Schablonenpuffer.

Renderziel

Ein Renderziel ist eine Ressource, in die wir am Ende eines Renderdurchlaufs schreiben können. Sie wird häufig mit der ID3D11Device::CreateRenderTargetView-Methode erstellt, wobei der Swapchain-Back-Puffer (der auch eine Ressource ist) als Eingabeparameter verwendet wird.

Jedes Renderziel sollte auch über eine entsprechende Tiefenschablonenansicht verfügen, denn wenn wir OMSetRenderTargets verwenden, um das Renderziel festzulegen, bevor es verwendet wird, ist auch eine Tiefenschablonenansicht erforderlich. Wir greifen auf die Renderzielressource über die Renderzielansicht zu, die mithilfe der ID3D11RenderTargetView-Schnittstelle implementiert wurde.

Gerät

Sie können sich ein Gerät als möglichkeit vorstellen, Objekte zuzuordnen und zu zerstören, Grundtypen zu rendern und mit den Grafiken Karte über den Grafiktreiber zu kommunizieren.

Für eine genauere Erklärung ist ein Direct3D-Gerät die Renderingkomponente von Direct3D. Ein Gerät kapselt und speichert den Renderstatus, führt Transformationen und Beleuchtungsvorgänge aus und rastert ein Bild auf einer Oberfläche. Weitere Informationen finden Sie unter Geräte.

Ein Gerät wird durch die ID3D11Geräteschnittstelle dargestellt. Anders ausgedrückt: Die ID3D11Device-Schnittstelle stellt einen virtuellen Grafikkarte dar und wird verwendet, um Ressourcen zu erstellen, die sich im Besitz eines Geräts befinden.

Es gibt verschiedene Versionen von ID3D11Geräte. ID3D11Device5 ist die neueste Version und fügt neue Methoden zu denen in ID3D11Device4 hinzu. Weitere Informationen zur Kommunikation von Direct3D mit der zugrunde liegenden Hardware finden Sie unter Windows Device Driver Model (WDDM)-Architektur.

Jede Anwendung muss über mindestens ein Gerät verfügen. Die meisten Anwendungen erstellen nur eine. Erstellen Sie ein Gerät für einen der auf Ihrem Computer installierten Hardwaretreiber, indem Sie D3D11CreateDevice oder D3D11CreateDeviceAndSwapChain aufrufen und den Treibertyp mit dem flag D3D_DRIVER_TYPE angeben. Jedes Gerät kann je nach gewünschter Funktionalität einen oder mehrere Gerätekontexte verwenden. Weitere Informationen finden Sie unter D3D11CreateDevice-Funktion.

Gerätekontext

Ein Gerätekontext wird verwendet, um den Pipelinestatus festzulegen und Renderingbefehle mithilfe der Ressourcen zu generieren, die sich im Besitz eines Geräts befinden.

Direct3D 11 implementiert zwei Arten von Gerätekontexten: einen für das sofortige Rendern und den anderen für verzögertes Rendern. Beide Kontexte werden mit einer ID3D11DeviceContext-Schnittstelle dargestellt.

Die ID3D11DeviceContext-Schnittstellen verfügen über unterschiedliche Versionen. ID3D11DeviceContext4 fügt denen in ID3D11DeviceContext3 neue Methoden hinzu.

ID3D11DeviceContext4 wird im Windows 10 Creators Update eingeführt und ist die neueste Version der ID3D11DeviceContext-Schnittstelle. Anwendungen für Windows 10 Creators Update und höher sollten diese Schnittstelle anstelle früherer Versionen verwenden. Weitere Informationen finden Sie unter ID3D11DeviceContext4.

DX::D eviceResources

Die DX::D eviceResources-Klasse befindet sich in den Dateien DeviceResources.cpp.h/ und steuert alle DirectX-Geräteressourcen.

Buffer

Eine Pufferressource ist eine Sammlung vollständig typisierter Daten, die in Elementen gruppiert sind. Sie können Puffer verwenden, um eine Vielzahl von Daten zu speichern, einschließlich Positionsvektoren, Normalvektoren, Texturkoordinaten in einem Vertexpuffer, Indizes in einem Indexpuffer oder Gerätezustand. Pufferelemente können gepackte Datenwerte (z. B. R8G8B8A8-Oberflächenwerte ), einzelne 8-Bit-Ganzzahlen oder vier 32-Bit-Gleitkommawerte enthalten.

Es gibt drei Typen von Puffern: Vertexpuffer, Indexpuffer und Konstantenpuffer.

Vertexpuffer

Enthält die Vertexdaten, die zum Definieren Ihrer Geometrie verwendet werden. Vertexdaten umfassen Positionskoordinaten, Farbdaten, Texturkoordinatendaten, Normaldaten usw.

Indexpuffer

Enthält ganzzahlige Offsets in Vertexpuffer und dient zum effizienteren Rendern von Grundtypen. Ein Indexpuffer enthält einen sequenziellen Satz von 16-Bit- oder 32-Bit-Indizes. Jeder Index wird verwendet, um einen Scheitelpunkt in einem Vertexpuffer zu identifizieren.

Konstantenpuffer oder Shaderkonstantenpuffer

Ermöglicht die effiziente Bereitstellung von Shaderdaten für die Pipeline. Sie können Konstantenpuffer als Eingaben für die Shader verwenden, die für jeden Grundtyp ausgeführt werden, und Ergebnisse der Streamausgabephase der Renderingpipeline speichern. Vom Konzept her sieht ein Konstantenpuffer genauso aus wie ein Einzelner-Element-Vertexpuffer.

Entwurf und Implementierung von Puffern

Sie können Puffer basierend auf dem Datentyp entwerfen, z. B. wie in unserem Beispielspiel wird ein Puffer für statische Daten erstellt, ein anderer für Daten, die über dem Frame konstant sind, und ein anderer für Daten, die für einen Grundtyp spezifisch sind.

Alle Puffertypen werden von der ID3D11Buffer-Schnittstelle gekapselt, und Sie können eine Pufferressource erstellen, indem Sie ID3D11Device::CreateBuffer aufrufen. Ein Puffer muss jedoch an die Pipeline gebunden sein, bevor darauf zugegriffen werden kann. Puffer können zum Lesen gleichzeitig an mehrere Pipelinephasen gebunden werden. Ein Puffer kann auch zum Schreiben an eine einzelne Pipelinephase gebunden werden. Derselbe Puffer kann jedoch nicht gleichzeitig für Lese- und Schreibvorgänge gebunden werden.

Sie können Puffer auf diese Weise binden.

  • Zur Input-Assembler-Phase, indem Sie ID3D11DeviceContext-Methoden wie ID3D11DeviceContext::IASetVertexBuffers und ID3D11DeviceContext::IASetIndexBuffer aufrufen.
  • Zur Streamausgabephase, indem Sie ID3D11DeviceContext::SOSetTargets aufrufen.
  • Zur Shaderphase, indem Sie Shadermethoden aufrufen, z. B. ID3D11DeviceContext::VSSetConstantBuffers.

Weitere Informationen finden Sie unter Einführung in Puffer in Direct3D 11.

DXGI

Microsoft DirectX Graphics Infrastructure (DXGI) ist ein Subsystem, das einige der für Direct3D erforderlichen Aufgaben auf niedriger Ebene kapselt. Bei der Verwendung von DXGI in einer Multithreadanwendung ist besondere Vorsicht erforderlich, um sicherzustellen, dass keine Deadlocks auftreten. Weitere Informationen finden Sie unter Multithreading und DXGI.

Featureebene

Die Featureebene ist ein Konzept, das in Direct3D 11 eingeführt wurde, um die Vielfalt von Grafikkarten in neuen und vorhandenen Computern zu bewältigen. Eine Featureebene ist ein klar definierter Satz von GPU-Funktionen (Graphics Processing Unit).

Jedes Video Karte implementiert abhängig von den installierten GPUs eine bestimmte DirectX-Funktionalität. In früheren Versionen von Microsoft Direct3D konnten Sie herausfinden, welche Version von Direct3D das Video implementiert Karte, und dann Ihre Anwendung entsprechend programmieren.

Mit Featureebene können Sie beim Erstellen eines Geräts versuchen, ein Gerät für die Featureebene zu erstellen, die Sie anfordern möchten. Wenn die Geräteerstellung funktioniert, ist diese Featureebene vorhanden. Wenn dies nicht der Fall ist, unterstützt die Hardware diese Featureebene nicht. Sie können entweder versuchen, ein Gerät auf einer niedrigeren Featureebene neu zu erstellen, oder Sie können die Anwendung beenden. Für instance erfordert die Featureebene 12_0 Direct3D 11.3 oder Direct3D 12 und das Shadermodell 5.1. Weitere Informationen finden Sie unter Direct3D-Featureebenen: Übersicht für jede Featureebene.

Mithilfe von Featureebenen können Sie eine Anwendung für Direct3D 9, Microsoft Direct3D 10 oder Direct3D 11 entwickeln und diese dann mit 9, 10 oder 11 Hardware (mit einigen Ausnahmen) ausführen. Weitere Informationen finden Sie unter Direct3D-Featureebenen.

Stereorendering

Stereorendering wird verwendet, um die Illusion der Tiefe zu verbessern. Es werden zwei Bilder verwendet, eines vom linken Auge und das andere vom rechten Auge, um eine Szene auf dem Bildschirm anzuzeigen.

Mathematisch wenden wir dazu eine Stereoprojektionsmatrix an, bei der es sich um einen leichten horizontalen Offset rechts und links der regulären Monoprojektionsmatrix handelt.

Wir haben in diesem Beispielspiel zwei Renderingdurchläufe ausgeführt, um Stereorendering zu erreichen.

  • Binden Sie an das rechte Renderziel, wenden Sie die rechte Projektion an, und zeichnen Sie dann das primitive Objekt.
  • Binden Sie an das linke Renderziel, wenden Sie die linke Projektion an, und zeichnen Sie dann das primitive Objekt.

Kamera- und Koordinatenraum

Das Spiel enthält den erforderlichen Code, um die Spielwelt in seinem eigenen Koordinatensystem (auch als Spielweltbereich oder Szenenbereich bezeichnet) zu aktualisieren. Alle Objekte, einschließlich der Kamera, werden in diesem Bereich positioniert und ausgerichtet. Weitere Informationen finden Sie unter Koordinatensysteme.

Ein Vertex-Shader führt das schwere Anheben der Konvertierung von den Modellkoordinaten in Gerätekoordinaten mit dem folgenden Algorithmus durch (wobei V ein Vektor und M eine Matrix ist).

V(device) = V(model) x M(model-to-world) x M(world-to-view) x M(view-to-device)

  • M(model-to-world) ist eine Transformationsmatrix für Modellkoordinaten zu Weltkoordinaten, die auch als Welttransformationsmatrix bezeichnet wird. Diese Matrix wird vom Grundtyp bereitgestellt.
  • M(world-to-view) ist eine Transformationsmatrix für Weltkoordinaten zum Anzeigen von Koordinaten, auch bekannt als Ansichtstransformationsmatrix.
    • Diese Matrix wird von der Ansichtsmatrix der Kamera bereitgestellt. Sie wird durch die Position der Kamera zusammen mit den Blickvektoren definiert (der Vektor , der von der Kamera direkt auf die Szene zeigt, und dem Nachschlagevektor , der senkrecht nach oben steht).
    • Im Beispielspiel ist m_viewMatrix die Ansichtstransformationsmatrix und wird mit Camera::SetViewParams berechnet.
  • M(view-to-device) ist eine Transformationsmatrix für Ansichtskoordinaten zu Gerätekoordinaten, die auch als Projektionstransformationsmatrix bezeichnet wird.
    • Diese Matrix wird von der Projektion der Kamera bereitgestellt. Es enthält Informationen darüber, wie viel dieses Raums tatsächlich in der letzten Szene sichtbar ist. Das Sichtfeld (FoV), das Seitenverhältnis und die Clippingebenen definieren die Projektionstransformationsmatrix.
    • Im Beispielspiel definiert m_projectionMatrix die Transformation zu den Projektionskoordinaten, die mit Camera::SetProjParams berechnet wird (Für die Stereoprojektion verwenden Sie zwei Projektionsmatrizen – eine für die Ansicht jedes Auges).

Der Shadercode in VertexShader.hlsl wird mit diesen Vektoren und Matrizen aus den Konstantenpuffern geladen und führt diese Transformation für jeden Scheitelpunkt aus.

Transformation in Koordinatensystemen

Direct3D verwendet drei Transformationen, um ihre 3D-Modellkoordinaten in Pixelkoordinaten (Bildschirmraum) zu ändern. Diese Transformationen sind Welttransformationen, Sichttransformationen und Projektionstransformationen. Weitere Informationen finden Sie unter Übersicht über die Transformation.

Welttransformationsmatrix

Eine Welttransformation ändert die Koordinaten vom Modellraum, in dem Scheitelpunkte relativ zum lokalen Ursprung eines Modells definiert werden, in einen Weltraum, in dem Scheitelpunkte relativ zu einem Ursprung definiert werden, der allen Objekten in einer Szene gemeinsam ist. Im Wesentlichen platziert die Welt ein Modell in die Welt; daher sein Name. Weitere Informationen finden Sie unter Welttransformation.

Transformationsmatrix anzeigen

Die Ansichtstransformation findet den Betrachter im Weltraum und wandelt Scheitelpunkte in den Kameraraum um. Im Kameraraum befindet sich die Kamera oder der Betrachter am Ursprung und sieht in positiver Z-Richtung aus. Weitere Informationen finden Sie unter Transformation anzeigen.

Projektionstransformationsmatrix

Die Projektionstransformation wandelt das Anzeige frustum in eine Quaderform um. Ein Anzeige frustum ist ein 3D-Volume in einer Szene, die relativ zur Kamera des Viewports positioniert ist. Ein Viewport ist ein 2D-Rechteck, in das eine 3D-Szene projiziert wird. Weitere Informationen finden Sie unter Viewports und Clipping.

Da das nahe Ende des Sicht frustums kleiner ist als das ferne Ende, hat dies den Effekt, dass Objekte, die sich in der Nähe der Kamera befinden, erweitert werden; So wird die Perspektive auf die Szene angewendet. Objekte, die näher am Player sind, erscheinen also größer; Weiter entfernte Objekte werden kleiner angezeigt.

Mathematisch gesehen ist die Projektionstransformation eine Matrix, die in der Regel sowohl eine Skalierung als auch eine perspektivische Projektion ist. Es funktioniert wie das Objektiv einer Kamera. Weitere Informationen finden Sie unter Projektionstransformation.

Samplerzustand

Der Samplerzustand bestimmt, wie Texturdaten mithilfe von Texturadressierungsmodi, Filterung und Detailgrad erfasst werden. Die Stichprobenerstellung erfolgt jedes Mal, wenn ein Texturpixel (oder Texel) aus einer Textur gelesen wird.

Eine Textur enthält ein Array von Texels. Die Position jedes Texels wird durch (u,v)bezeichnet, wobei u die Breite und v die Höhe ist und basierend auf der Texturbreite und -höhe zwischen 0 und 1 zugeordnet wird. Die resultierenden Texturkoordinaten werden verwendet, um einen Texel beim Sampling einer Textur zu adressieren.

Wenn Texturkoordinaten unter 0 oder über 1 liegen, definiert der Texturadressmodus, wie die Texturkoordinate eine Texelposition adressiert. Wenn Sie beispielsweise TextureAddressMode.Clamp verwenden, wird jede Koordinate außerhalb des Bereichs 0-1 auf einen Maximalwert von 1 und den Mindestwert 0 vor dem Sampling geklemmt.

Wenn die Textur für das Polygon zu groß oder zu klein ist, wird die Textur so gefiltert, dass sie dem Raum entspricht. Ein Vergrößerungsfilter vergrößert eine Textur, ein Verkleinerungsfilter reduziert die Textur, um in einen kleineren Bereich zu passen. Die Texturvergrößerung wiederholt das Beispiel texel für eine oder mehrere Adressen, was zu einem verschwommenen Bild führt. Die Texturminierung ist komplizierter, da mehr als ein Texelwert in einem einzelnen Wert kombiniert werden muss. Dies kann je nach Texturdaten zu Aliasen oder zerklüfteten Kanten führen. Der beliebteste Ansatz für die Minimierung ist die Verwendung einer mipmap. Eine mipmap ist eine Textur mit mehreren Ebenen. Die Größe jeder Ebene ist eine Leistung von 2 kleiner als die vorherige Ebene bis zu einer Textur von 1x1. Wenn die Minimierung verwendet wird, wählt ein Spiel die Mipmap-Ebene aus, die der Größe, die zur Renderzeit benötigt wird, am nächsten kommt.

Die BasicLoader-Klasse

BasicLoader ist eine einfache Ladeprogrammklasse, die Unterstützung zum Laden von Shadern, Texturen und Meshes aus Dateien auf dem Datenträger bietet. Es stellt sowohl synchrone als auch asynchrone Methoden bereit. In diesem Beispielspiel befinden sich die BasicLoader.h/.cpp Dateien im Ordner Hilfsprogramme .

Weitere Informationen finden Sie unter Basic Loader.