Renderingframework II: Spiel RenderingRendering framework II: Game rendering

Hinweis

Dieses Thema ist Teil der Tutorial-Reihe zum Erstellen eines einfachen universelle Windows-Plattform (UWP) mit DirectX .This topic is part of the Create a simple Universal Windows Platform (UWP) game with DirectX tutorial series. Das Thema unter diesem Link legt den Kontext für die Reihe fest.The topic at that link sets the context for the series.

In Renderingframework Ihaben wir erläutert, wie wir die szeneninformationen übernehmen und auf dem Bildschirm anzeigen.In Rendering framework I, we've covered how we take the scene info and present it to the display screen. Nun gehen wir einen Schritt zurück und erfahren, wie Sie die Daten für das Rendering vorbereiten.Now, we'll take a step back and learn how to prepare the data for rendering.

Hinweis

Wenn Sie den neuesten Spiel Code für dieses Beispiel nicht heruntergeladen haben, besuchen Sie das Direct3D-Beispiel Spiel.If you haven't downloaded the latest game code for this sample, go to Direct3D sample game. Dieses Beispiel ist Teil einer großen Auflistung von UWP-Funktions Beispielen.This sample is part of a large collection of UWP feature samples. Anweisungen zum Herunterladen des Beispiels finden Sie unter herunterladen der UWP-Beispiele von GitHub.For instructions on how to download the sample, see Get the UWP samples from GitHub.

ZielObjective

Schnelle Zusammenfassung des Ziels.Quick recap on the objective. Es wird erläutert, wie Sie ein einfaches Renderingframework einrichten, um die Grafikausgabe für ein UWP DirectX-Spiel anzuzeigen.It is to understand how to set up a basic rendering framework to display the graphics output for a UWP DirectX game. Diese drei Schritte können Sie locker gruppieren.We can loosely group them into these three steps.

  1. Herstellen einer Verbindung mit unserer GrafikschnittstelleEstablish a connection to our graphics interface
  2. Vorbereitung: Erstellen der Ressourcen, die zum Zeichnen der Grafiken erforderlich sindPreparation: Create the resources we need to draw the graphics
  3. Anzeigen der Grafik: renderden FrameDisplay the graphics: Render the frame

Rendering-Framework I: Einführung in das Rendering erläuterte, wie Grafiken gerendert werden, und deckt die Schritte 1 und 3 ab.Rendering framework I: Intro to rendering explained how graphics are rendered, covering Steps 1 and 3.

In diesem Artikel wird erläutert, wie Sie andere Teile dieses Frameworks einrichten und die erforderlichen Daten vor dem Rendering vorbereiten. Dies ist Schritt 2 des Vorgangs.This article explains how to set up other pieces of this framework and prepare the required data before rendering can happen, which is Step 2 of the process.

Entwerfen des RenderersDesign the renderer

Der Renderer ist verantwortlich für das Erstellen und Verwalten aller D3D11-und D2D-Objekte, die zum Generieren der visuellen Spielelemente verwendet werden.The renderer is responsible for creating and maintaining all the D3D11 and D2D objects used to generate the game visuals. Die gamerenderer -Klasse ist der Renderer für dieses Beispiel Spiel und wurde entwickelt, um die Renderinganforderungen des Spiels zu erfüllen.The GameRenderer class is the renderer for this sample game and is designed to meet the game's rendering needs.

Dies sind einige Konzepte, die Sie beim Entwerfen des Renderers für das Spiel verwenden können:These are some concepts you can use to help design the renderer for your game:

  • Da Direct3D 11-APIs als com -APIs definiert sind, müssen Sie comptr -Verweise auf die Objekte bereitstellen, die durch diese APIs definiert werden.Because Direct3D 11 APIs are defined as COM APIs, you must provide ComPtr references to the objects defined by these APIs. Diese Objekte werden automatisch freigegeben, wenn ihr letzter Verweis den gültigen Bereich verlässt und die App beendet wird.These objects are automatically freed when their last reference goes out of scope when the app terminates. Weitere Informationen finden Sie unter comptr.For more information, see ComPtr. Beispiel für diese Objekte: Konstante Puffer, Shader-Objekte- Vertex-Shader, Pixel-Shaderund Shader-Ressourcen Objekte.Example of these objects: constant buffers, shader objects - vertex shader, pixel shader, and shader resource objects.
  • Konstantenpuffer werden in dieser Klasse definiert, um die für das Rendering erforderlichen Daten zu speichern.Constant buffers are defined in this class to hold various data needed for rendering.
    • Verwenden Sie mehrere Konstante Puffer mit unterschiedlichen Frequenzen, um die Datenmenge zu reduzieren, die pro Frame an die GPU gesendet werden muss.Use multiple constant buffers with different frequencies to reduce the amount of data that must be sent to the GPU per frame. In diesem Beispiel werden Konstanten basierend auf der Häufigkeit, mit der Sie aktualisiert werden müssen, in unterschiedliche Puffer eingeteilt.This sample separates constants into different buffers based on the frequency that they must be updated. Dies ist die empfohlene Methode für die Direct3D-Programmierung.This is a best practice for Direct3D programming.
    • In diesem Beispiel Spiel werden 4 Konstante Puffer definiert.In this sample game, 4 constant buffers are defined.
      1. m _ constantbufferneverchanges enthält die Beleuchtungs Parameter.m_constantBufferNeverChanges contains the lighting parameters. Es wird einmal in der finalizecreategamedeviceresources -Methode festgelegt und nie wieder geändert.It's set one time in the FinalizeCreateGameDeviceResources method and never changes again.
      2. m _ constantbufferchangeonresize enthält die Projektions Matrix.m_constantBufferChangeOnResize contains the projection matrix. Die Projektionsmatrix hängt von der Größe und dem Seitenverhältnis des Fensters ab.The projection matrix is dependent on the size and aspect ratio of the window. Sie wird in createwindowsizedependentresources festgelegt und dann aktualisiert, nachdem Ressourcen in die finalizecreategamedeviceresources -Methode geladen wurden.It's set in CreateWindowSizeDependentResources and then updated after resources are loaded in the FinalizeCreateGameDeviceResources method. Wenn das Rendering in 3D erfolgt, wird es auch zweimal pro Frame geändert.If rendering in 3D, it is also changed twice per frame.
      3. m _ constantbufferchangeseveryframe enthält die Ansichts Matrix.m_constantBufferChangesEveryFrame contains the view matrix. Diese Matrix hängt von der Kameraposition und der Ausrichtung (der normal zur Projektion) ab und ändert sich einmal pro Frame in der Renderingmethode .This matrix is dependent on the camera position and look direction (the normal to the projection) and changes one time per frame in the Render method. Dies wurde bereits in Renderingframework I: Einführung in Rendering unter der gamerenderer:: Rendering -Methodeerläutert.This was discussed earlier in Rendering framework I: Intro to rendering, under the GameRenderer::Render method.
      4. m _ constantbufferchangeseveryprim enthält die Modell Matrix-und Materialeigenschaften der einzelnen primitiven.m_constantBufferChangesEveryPrim contains the model matrix and material properties of each primitive. Die Modellmatrix transformiert Scheitelpunkte aus lokalen Koordinaten in globale Koordinaten.The model matrix transforms vertices from local coordinates into world coordinates. Diese Konstanten gelten speziell für die einzelnen Grundtypen und werden für jeden Draw-Aufruf aktualisiert.These constants are specific to each primitive and are updated for every draw call. Dies wurde bereits in Renderingframework I: Einführung in Rendering unter dem primitiven Renderingerläutert.This was discussed earlier in Rendering framework I: Intro to rendering, under the Primitive rendering.
  • Shader-Ressourcen Objekte, die Texturen für die primitiven enthalten, werden ebenfalls in dieser Klasse definiert.Shader resource objects that hold textures for the primitives are also defined in this class.
    • Einige Texturen sind vordefiniert (DDS ist ein Dateiformat, das zum Speichern von komprimierten und unkomprimierten Texturen verwendet werden kann.Some textures are pre-defined (DDS is a file format that can be used to store compressed and uncompressed textures. DDS-Texturen werden für die Wände und den Boden der Welt sowie für die Ammo-Sphären verwendet.)DDS textures are used for the walls and floor of the world as well as the ammo spheres.)
    • In diesem Beispiel Spiel lauten Shader-Ressourcen Objekte: m _ spheretexture, m _ zylindridertexture, m _ ceilingtexture, m _ floortexture, m _ wallstexture.In this sample game, shader resource objects are: m_sphereTexture, m_cylinderTexture, m_ceilingTexture, m_floorTexture, m_wallsTexture.
  • Shader-Objekte werden in dieser Klasse definiert, um die primitiven und Texturen zu berechnen.Shader objects are defined in this class to compute our primitives and textures.
    • In diesem Beispiel Spiel sind die Shader-Objekte m _ Vertexshader, __m _ vertexshaderflat__und m _ Pixelshader, m _ pixelshaderflat.In this sample game, the shader objects are m_vertexShader, m_vertexShaderFlat, and m_pixelShader, m_pixelShaderFlat.
    • Der Vertexshader verarbeitet die Grundtypen und die grundlegende Beleuchtung. Der Pixelshader (auch als Fragmentshader bezeichnet) verarbeitet die Texturen und alle pixelgenauen Effekte.The vertex shader processes the primitives and the basic lighting, and the pixel shader (sometimes called a fragment shader) processes the textures and any per-pixel effects.
    • Es existieren zwei Versionen dieser Shader (regulär und flach) zum Rendern verschiedener Grundtypen.There are two versions of these shaders (regular and flat) for rendering different primitives. Der Grund für verschiedene Versionen ist, dass die flachen Versionen sehr viel einfacher sind und keine Glanzlichter oder irgendwelche pro-Pixel-Beleuchtungseffekte darstellen.The reason we have different versions is that the flat versions are much simpler and don't do specular highlights or any per pixel lighting effects. Sie werden für die Wände verwendet und beschleunigen das Rendern auf Geräten mit geringerer Leistung.These are used for the walls and make rendering faster on lower powered devices.

GameRenderer.hGameRenderer.h

Sehen wir uns nun den Code im Renderer-Klassenobjekt des Beispiel Spiels an.Now let's look at the code in the sample game's renderer class object.

// Class handling the rendering of the game
class GameRenderer : public std::enable_shared_from_this<GameRenderer>
{
public:
    GameRenderer(std::shared_ptr<DX::DeviceResources> const& deviceResources);

    void CreateDeviceDependentResources();
    void CreateWindowSizeDependentResources();
    void ReleaseDeviceDependentResources();
    void Render();
    // --- end of async related methods section

    winrt::Windows::Foundation::IAsyncAction CreateGameDeviceResourcesAsync(_In_ std::shared_ptr<Simple3DGame> game);
    void FinalizeCreateGameDeviceResources();
    winrt::Windows::Foundation::IAsyncAction LoadLevelResourcesAsync();
    void FinalizeLoadLevelResources();

    Simple3DGameDX::IGameUIControl* GameUIControl() { return &m_gameInfoOverlay; };

    DirectX::XMFLOAT2 GameInfoOverlayUpperLeft()
    {
        return DirectX::XMFLOAT2(m_gameInfoOverlayRect.left, m_gameInfoOverlayRect.top);
    };
    DirectX::XMFLOAT2 GameInfoOverlayLowerRight()
    {
        return DirectX::XMFLOAT2(m_gameInfoOverlayRect.right, m_gameInfoOverlayRect.bottom);
    };
    bool GameInfoOverlayVisible() { return m_gameInfoOverlay.Visible(); }
    // --- end of rendering overlay section
...
private:
    // Cached pointer to device resources.
    std::shared_ptr<DX::DeviceResources>        m_deviceResources;

    ...

    // Shader resource objects
    winrt::com_ptr<ID3D11ShaderResourceView>    m_sphereTexture;
    winrt::com_ptr<ID3D11ShaderResourceView>    m_cylinderTexture;
    winrt::com_ptr<ID3D11ShaderResourceView>    m_ceilingTexture;
    winrt::com_ptr<ID3D11ShaderResourceView>    m_floorTexture;
    winrt::com_ptr<ID3D11ShaderResourceView>    m_wallsTexture;

    // Constant buffers
    winrt::com_ptr<ID3D11Buffer>                m_constantBufferNeverChanges;
    winrt::com_ptr<ID3D11Buffer>                m_constantBufferChangeOnResize;
    winrt::com_ptr<ID3D11Buffer>                m_constantBufferChangesEveryFrame;
    winrt::com_ptr<ID3D11Buffer>                m_constantBufferChangesEveryPrim;

    // Texture sampler
    winrt::com_ptr<ID3D11SamplerState>          m_samplerLinear;

    // Shader objects: Vertex shaders and pixel shaders
    winrt::com_ptr<ID3D11VertexShader>          m_vertexShader;
    winrt::com_ptr<ID3D11VertexShader>          m_vertexShaderFlat;
    winrt::com_ptr<ID3D11PixelShader>           m_pixelShader;
    winrt::com_ptr<ID3D11PixelShader>           m_pixelShaderFlat;
    winrt::com_ptr<ID3D11InputLayout>           m_vertexLayout;
};

KonstruktorConstructor

Als nächstes untersuchen wir den gamerenderer -Konstruktor des Beispiel Spiels und vergleichen ihn mit dem Sample3DSceneRenderer -Konstruktor, der in der DirectX 11-App-Vorlage bereitgestellt wird.Next, let's examine the sample game's GameRenderer constructor and compare it with the Sample3DSceneRenderer constructor provided in the DirectX 11 App template.

// Constructor method of the main rendering class object
GameRenderer::GameRenderer(std::shared_ptr<DX::DeviceResources> const& deviceResources) : ...
    m_gameInfoOverlay(deviceResources),
    m_gameHud(deviceResources, L"Windows platform samples", L"DirectX first-person game sample")
{
    // m_gameInfoOverlay is a GameHud object to render text in the top left corner of the screen.
    // m_gameHud is Game info rendered as an overlay on the top-right corner of the screen,
    // for example hits, shots, and time.

    CreateDeviceDependentResources();
    CreateWindowSizeDependentResources();
}

Erstellen und Laden von DirectX-Grafik RessourcenCreate and load DirectX graphic resources

Im Beispiel Spiel (und in der DirectX 11-App-Vorlage von Visual Studio (universelle Windows -Vorlage) wird das Erstellen und Laden von Spiel Ressourcen mit diesen beiden Methoden implementiert, die vom gamerenderer -Konstruktor aufgerufen werden:In the sample game (and in Visual Studio's DirectX 11 App (Universal Windows) template), creating and loading game resources is implemented using these two methods that are called from GameRenderer constructor:

Createdevicedependentresources-MethodeCreateDeviceDependentResources method

In der DirectX 11-App-Vorlage wird diese Methode verwendet, um den Scheitelpunkt und den Pixel-Shader asynchron zu laden, den Shader und den konstanten Puffer zu erstellen, ein Mesh mit Scheitel Punkten zu erstellen, die Positions-und Farbinformationen enthalten.In the DirectX 11 App template, this method is used to load vertex and pixel shader asynchronously, create the shader and constant buffer, create a mesh with vertices that contain position and color info.

Im Beispiel Spiel werden diese Vorgänge der Scene-Objekte stattdessen zwischen den Methoden " aliategamedeviceresourcesasync " und " finalizecreategamedeviceresources " aufgeteilt.In the sample game, these operations of the scene objects are instead split among the CreateGameDeviceResourcesAsync and FinalizeCreateGameDeviceResources methods.

Was ist für dieses Beispiel Spiel die Methode?For this sample game, what goes into this method?

  • Instanziierte Variablen (m _ gameresourcesloaded = false und m _ levelresourcesloaded = false), die angeben, ob Ressourcen geladen wurden, bevor Sie zum Rendering verschoben werden, da Sie asynchron geladen werden.Instantiated variables (m_gameResourcesLoaded = false and m_levelResourcesLoaded = false) that indicate whether resources have been loaded before moving forward to render, since we're loading them asynchronously.
  • Da die HUD-und Overlay-Rendering in separaten Klassen Objekten vorliegen, müssen Sie hier gamehud:: createdevicedependentresources und gameinfooverlay:: createdevicedependentresources -Methoden aufrufen.Since HUD and overlay rendering are in separate class objects, call GameHud::CreateDeviceDependentResources and GameInfoOverlay::CreateDeviceDependentResources methods here.

Im folgenden finden Sie den Code für " gamerderderer:: createdevicedependentresources".Here's the code for GameRenderer::CreateDeviceDependentResources.

// This method is called in GameRenderer constructor when it's created in GameMain constructor.
void GameRenderer::CreateDeviceDependentResources()
{
    // instantiate variables that indicate whether resources were loaded.
    m_gameResourcesLoaded = false;
    m_levelResourcesLoaded = false;

    // game HUD and overlay are design as separate class objects.
    m_gameHud.CreateDeviceDependentResources();
    m_gameInfoOverlay.CreateDeviceDependentResources();
}

Im folgenden finden Sie eine Liste der Methoden, die zum Erstellen und Laden von Ressourcen verwendet werden.Below is a list of the methods that are used to create and load resources.

  • CreatedevicedependentresourcesCreateDeviceDependentResources
    • "Kreategamedeviceresourcesasync" (hinzugefügt)CreateGameDeviceResourcesAsync (Added)
    • Finalizecreategamedeviceresources (hinzugefügt)FinalizeCreateGameDeviceResources (Added)
  • CreateWindowSizeDependentResourcesCreateWindowSizeDependentResources

Bevor wir uns mit den anderen Methoden befassen, die zum Erstellen und Laden von Ressourcen verwendet werden, erstellen wir zunächst den Renderer und sehen, wie er in die Spiel Schleife passt.Before diving into the other methods that are used to create and load resources, let's first create the renderer and see how it fits into the game loop.

Renderer erstellenCreate the renderer

Der gamerenderer wird im Konstruktor von __gamemain__erstellt.The GameRenderer is created in the GameMain's constructor. Außerdem werden die beiden anderen Methoden " creategamedeviceresourcesasync " und " finalizecreategamedeviceresources " aufgerufen, die zum Erstellen und Laden von Ressourcen hinzugefügt werden.It also calls the two other methods, CreateGameDeviceResourcesAsync and FinalizeCreateGameDeviceResources that are added to help create and load resources.

GameMain::GameMain(std::shared_ptr<DX::DeviceResources> const& deviceResources) : ...
{
    m_deviceResources->RegisterDeviceNotify(this);

    // Creation of GameRenderer
    m_renderer = std::make_shared<GameRenderer>(m_deviceResources);

    ...

    ConstructInBackground();
}

winrt::fire_and_forget GameMain::ConstructInBackground()
{
    ...

    // Asynchronously initialize the game class and load the renderer device resources.
    // By doing all this asynchronously, the game gets to its main loop more quickly
    // and in parallel all the necessary resources are loaded on other threads.
    m_game->Initialize(m_controller, m_renderer);

    co_await m_renderer->CreateGameDeviceResourcesAsync(m_game);

    // The finalize code needs to run in the same thread context
    // as the m_renderer object was created because the D3D device context
    // can ONLY be accessed on a single thread.
    // co_await of an IAsyncAction resumes in the same thread context.
    m_renderer->FinalizeCreateGameDeviceResources();

    InitializeGameState();

    ...
}

Methode "| ategamedeviceresourcesasync"CreateGameDeviceResourcesAsync method

Creategamedeviceresourcesasync wird von der gamemain -Konstruktormethode in der Create _ Task -Schleife aufgerufen, da wir Spiel Ressourcen asynchron laden.CreateGameDeviceResourcesAsync is called from the GameMain constructor method in the create_task loop since we're loading game resources asynchronously.

CreateDeviceResourcesAsync ist eine Methode, die als gesonderte Reihe asynchroner Aufgaben ausgeführt wird, um die Spielressourcen zu laden.CreateDeviceResourcesAsync is a method that runs as a separate set of async tasks to load the game resources. Da erwartet wird, dass Sie in einem separaten Thread ausgeführt wird, hat Sie nur Zugriff auf die Geräte Methoden Direct3D 11 (die für __ID3D11Device__definiert sind) und nicht auf die Gerätekontext Methoden (die für __Verknüpfung id3d11devicecontext aus__definierten Methoden), sodass keine Renderingvorgänge ausgeführt werden.Because it's expected to run on a separate thread, it only has access to the Direct3D 11 device methods (those defined on ID3D11Device) and not the device context methods (the methods defined on ID3D11DeviceContext), so it does not perform any rendering.

Die finalizecreategamedeviceresources -Methode wird im Haupt Thread ausgeführt und verfügt über Zugriff auf die Gerätekontext Methoden Direct3D 11.FinalizeCreateGameDeviceResources method runs on the main thread and does have access to the Direct3D 11 device context methods.

Im Prinzip:In principle:

  • Verwenden Sie in " forategamedeviceresourcesasync " nur ID3D11Device -Methoden, weil Sie frei Thread sind, was bedeutet, dass Sie in jedem Thread ausgeführt werden können.Use only ID3D11Device methods in CreateGameDeviceResourcesAsync because they are free-threaded, which means that they are able to run on any thread. Außerdem wird davon ausgegangen, dass Sie nicht im gleichen Thread ausgeführt werden, in dem der einzige gamerenderer erstellt wurde.It is also expected that they do not run on the same thread as the one GameRenderer was created on.
  • Verwenden Sie hier keine Methoden in Verknüpfung id3d11devicecontext aus , da Sie in einem einzelnen Thread und im gleichen Thread wie __gamerenderer__ausgeführt werden müssen.Do not use methods in ID3D11DeviceContext here because they need to run on a single thread and on the same thread as GameRenderer.
  • Verwenden Sie diese Methode, um konstante Puffer zu erstellen.Use this method to create constant buffers.
  • Verwenden Sie diese Methode, um Texturen (z. b. die DDS-Dateien) und Shaderinformationen(z. b. die CSO-Dateien) in die Shader zu laden.Use this method to load textures (like the .dds files) and shader info (like the .cso files) into the shaders.

Diese Methode wird für Folgendes verwendet:This method is used to:

  • Erstellen Sie die 4 Konstanten Puffer: m _ constantbufferneverchanges, m _ constantbufferchangeonresize, m _ constantbufferchangeseveryframe, m _ constantbufferchangeseveryprimCreate the 4 constant buffers: m_constantBufferNeverChanges, m_constantBufferChangeOnResize, m_constantBufferChangesEveryFrame, m_constantBufferChangesEveryPrim
  • Erstellen eines samplerstatusobjekts , das Stichproben Informationen für eine Textur kapseltCreate a sampler-state object that encapsulates sampling information for a texture
  • Erstellen Sie eine Aufgaben Gruppe, die alle asynchronen Tasks enthält, die von der-Methode erstellt wurden.Create a task group that contains all async tasks created by the method. Er wartet auf den Abschluss aller asynchronen Aufgaben und ruft dann __finalizecreategamedeviceresources__auf.It waits for the completion of all these async tasks, and then calls FinalizeCreateGameDeviceResources.
  • Erstellen Sie ein Lade Modul mithilfe des Basic-LadeModuls.Create a loader using Basic Loader. Fügen Sie die Async-Ladevorgänge des Lade Moduls als Aufgaben in die zuvor erstellte Aufgaben Gruppe ein.Add the loader's async loading operations as tasks into the task group created earlier.
  • Methoden wie basicloader:: loadshaderasync und basicloader:: loadtextureasync werden zum Laden von verwendet:Methods like BasicLoader::LoadShaderAsync and BasicLoader::LoadTextureAsync are used to load:
    • kompilierte Shader-Objekte (vertextshader. CSO, vertexshaderflat. CSO, Pixelshader. CSO und pixelshaderflat. CSO).compiled shader objects (VertextShader.cso, VertexShaderFlat.cso, PixelShader.cso, and PixelShaderFlat.cso). Weitere Informationen finden Sie unter verschiedene Shader-Dateiformate.For more info, go to Various shader file formats.
    • Spiele spezifische Texturen (Assets \ seeloor. DDS, metal_texture. DDS, cellceiling. DDS, cellfloor. DDS, cellwall. DDS).game specific textures (Assets\seafloor.dds, metal_texture.dds, cellceiling.dds, cellfloor.dds, cellwall.dds).
IAsyncAction GameRenderer::CreateGameDeviceResourcesAsync(_In_ std::shared_ptr<Simple3DGame> game)
{
    auto lifetime = shared_from_this();

    // Create the device dependent game resources.
    // Only the d3dDevice is used in this method. It is expected
    // to not run on the same thread as the GameRenderer was created.
    // Create methods on the d3dDevice are free-threaded and are safe while any methods
    // in the d3dContext should only be used on a single thread and handled
    // in the FinalizeCreateGameDeviceResources method.
    m_game = game;

    auto d3dDevice = m_deviceResources->GetD3DDevice();

    // Define D3D11_BUFFER_DESC. See
    // https://docs.microsoft.com/windows/win32/api/d3d11/ns-d3d11-d3d11_buffer_desc
    D3D11_BUFFER_DESC bd;
    ZeroMemory(&bd, sizeof(bd));

    // Create the constant buffers.
    bd.Usage = D3D11_USAGE_DEFAULT;
    ...

    // Create the constant buffers: m_constantBufferNeverChanges, m_constantBufferChangeOnResize,
    // m_constantBufferChangesEveryFrame, m_constantBufferChangesEveryPrim
    // CreateBuffer is used to create one of these buffers: vertex buffer, index buffer, or 
    // shader-constant buffer. For CreateBuffer API ref info, see
    // https://docs.microsoft.com/windows/win32/api/d3d11/nf-d3d11-id3d11device-createbuffer.
    winrt::check_hresult(
        d3dDevice->CreateBuffer(&bd, nullptr, m_constantBufferNeverChanges.put())
        );

    ...

    // Define D3D11_SAMPLER_DESC. For API ref, see
    // https://docs.microsoft.com/windows/win32/api/d3d11/ns-d3d11-d3d11_sampler_desc.
    D3D11_SAMPLER_DESC sampDesc;

    // ZeroMemory fills a block of memory with zeros. For API ref, see
    // https://docs.microsoft.com/previous-versions/windows/desktop/legacy/aa366920(v=vs.85).
    ZeroMemory(&sampDesc, sizeof(sampDesc));

    sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    ...

    // Create a sampler-state object that encapsulates sampling information for a texture.
    // The sampler-state interface holds a description for sampler state that you can bind to any 
    // shader stage of the pipeline for reference by texture sample operations.
    winrt::check_hresult(
        d3dDevice->CreateSamplerState(&sampDesc, m_samplerLinear.put())
        );

    // Start the async tasks to load the shaders and textures.

    // Load compiled shader objects (VertextShader.cso, VertexShaderFlat.cso, PixelShader.cso, and PixelShaderFlat.cso).
    // The BasicLoader class is used to convert and load common graphics resources, such as meshes, textures, 
    // and various shader objects into the constant buffers. For more info, see
    // https://docs.microsoft.com/windows/uwp/gaming/complete-code-for-basicloader.
    BasicLoader loader{ d3dDevice };

    std::vector<IAsyncAction> tasks;

    uint32_t numElements = ARRAYSIZE(PNTVertexLayout);

    // Load shaders asynchronously with the shader and pixel data using the
    // BasicLoader::LoadShaderAsync method. Push these method calls into a list of tasks.
    tasks.push_back(loader.LoadShaderAsync(L"VertexShader.cso", PNTVertexLayout, numElements, m_vertexShader.put(), m_vertexLayout.put()));
    tasks.push_back(loader.LoadShaderAsync(L"VertexShaderFlat.cso", nullptr, numElements, m_vertexShaderFlat.put(), nullptr));
    tasks.push_back(loader.LoadShaderAsync(L"PixelShader.cso", m_pixelShader.put()));
    tasks.push_back(loader.LoadShaderAsync(L"PixelShaderFlat.cso", m_pixelShaderFlat.put()));

    // Make sure the previous versions if any of the textures are released.
    m_sphereTexture = nullptr;
    ...

    // Load Game specific textures (Assets\\seafloor.dds, metal_texture.dds, cellceiling.dds,
    // cellfloor.dds, cellwall.dds).
    // Push these method calls also into a list of tasks.
    tasks.push_back(loader.LoadTextureAsync(L"Assets\\seafloor.dds", nullptr, m_sphereTexture.put()));
    ...

    // Simulate loading additional resources by introducing a delay.
    tasks.push_back([]() -> IAsyncAction { co_await winrt::resume_after(GameConstants::InitialLoadingDelay); }());

    // Returns when all the async tasks for loading the shader and texture assets have completed.
    for (auto&& task : tasks)
    {
        co_await task;
    }
}

Finalizecreategamedeviceresources-MethodeFinalizeCreateGameDeviceResources method

Die finalizecreategamedeviceresources -Methode wird aufgerufen, nachdem alle Tasks der Lade Ressourcen, die sich in der creategamedeviceresourcesasync -Methode befinden, abgeschlossen sind.FinalizeCreateGameDeviceResources method is called after all the load resources tasks that are in the CreateGameDeviceResourcesAsync method completes.

  • Initialisieren Sie constantbufferneverchanges mit den hellen Positionen und der Farbe.Initialize constantBufferNeverChanges with the light positions and color. Lädt die anfänglichen Daten mit einem Gerätekontext Methoden-Aufrufen von __Verknüpfung id3d11devicecontext aus:: updatesubresource__in die Konstanten Puffer.Loads the initial data into the constant buffers with a device context method call to ID3D11DeviceContext::UpdateSubresource.
  • Seit das Laden von asynchron geladenen Ressourcen abgeschlossen ist, ist es an der Zeit, Sie den entsprechenden Spielobjekten zuzuordnen.Since asynchronously loaded resources have completed loading, it's time to associate them with the appropriate game objects.
  • Erstellen Sie für jedes Spielobjekt das Mesh und das Material mithilfe der-Texturen, die geladen wurden.For each game object, create the mesh and the material using the textures that have been loaded. Ordnen Sie dann das Mesh und Material dem Spielobjekt zu.Then associate the mesh and material to the game object.
  • Für das Targets-Spielobjekt wird die Textur, die aus konzentrischen farbigen Ringen besteht, mit einem numerischen Wert im oberen Bereich, nicht aus einer Textur Datei geladen.For the targets game object, the texture which is composed of concentric colored rings, with a numeric value on the top, is not loaded from a texture file. Stattdessen wird er mithilfe des Codes in " targettexture. cpp" prozedursch generiert.Instead, it's procedurally generated using the code in TargetTexture.cpp. Die targettexture -Klasse erstellt die erforderlichen Ressourcen, um die Textur zur Initialisierungs Zeit in eine Offscreen-Ressource zu zeichnen.The TargetTexture class creates the necessary resources to draw the texture into an off screen resource at initialization time. Die resultierende Textur wird dann den entsprechenden Ziel Spielobjekten zugeordnet.The resulting texture is then associated with the appropriate target game objects.

" Finalizecreategamedeviceresources " und " createwindowsizedependentresources " verwenden ähnliche Teile von Code für diese:FinalizeCreateGameDeviceResources and CreateWindowSizeDependentResources share similar portions of code for these:

  • Verwenden Sie setprojparameams , um sicherzustellen, dass die Kamera über die richtige Projektions Matrix verfügt.Use SetProjParams to ensure that the camera has the right projection matrix. Weitere Informationen finden Sie unter Kamera und Koordinaten Bereich.For more info, go to Camera and coordinate space.
  • Behandeln Sie die Bildschirmdrehung, indem Sie die 3D-Rotations Matrix mit der Projektions Matrix der Kamera multiplizieren.Handle screen rotation by post multiplying the 3D rotation matrix to the camera's projection matrix. Aktualisieren Sie dann den konstanten-Puffer constantbufferchangeonresize mit der resultierenden Projektions Matrix.Then update the ConstantBufferChangeOnResize constant buffer with the resulting projection matrix.
  • Legen Sie die globale Variable " m _ gameresourcesloaded " fest, um anzugeben, dass die Ressourcen nun in den Puffern geladen sind und für den nächsten Schritt bereit sind.Set the m_gameResourcesLoaded Boolean global variable to indicate that the resources are now loaded in the buffers, ready for the next step. Beachten Sie, dass wir diese Variable zunächst in der Konstruktormethode des __gamerenderer__mithilfe der Methode gamerenderer:: createdevicedependentresources als false initialisiert haben.Recall that we first initialized this variable as FALSE in the GameRenderer's constructor method, through the GameRenderer::CreateDeviceDependentResources method.
  • Wenn dieses m _ gameresourcesloaded auf __true__festgelegt ist, kann das Rendering der Scene-Objekte stattfinden.When this m_gameResourcesLoaded is TRUE, rendering of the scene objects can take place. Dies wurde im Artikel " Rendering-Framework I: Intro to Rendering " unter der gamerenderer:: Rendering-Methodebehandelt.This was covered in the Rendering framework I: Intro to rendering article, under GameRenderer::Render method.
// This method is called from the GameMain constructor.
// Make sure that 2D rendering is occurring on the same thread as the main rendering.
void GameRenderer::FinalizeCreateGameDeviceResources()
{
    // All asynchronously loaded resources have completed loading.
    // Now associate all the resources with the appropriate game objects.
    // This method is expected to run in the same thread as the GameRenderer
    // was created. All work will happen behind the "Loading ..." screen after the
    // main loop has been entered.

    // Initialize the Constant buffer with the light positions
    // These are handled here to ensure that the d3dContext is only
    // used in one thread.

    auto d3dDevice = m_deviceResources->GetD3DDevice();

    ConstantBufferNeverChanges constantBufferNeverChanges;
    constantBufferNeverChanges.lightPosition[0] = XMFLOAT4(3.5f, 2.5f, 5.5f, 1.0f);
    ...
    constantBufferNeverChanges.lightColor = XMFLOAT4(0.25f, 0.25f, 0.25f, 1.0f);

    // CPU copies data from memory (constantBufferNeverChanges) to a subresource 
    // created in non-mappable memory (m_constantBufferNeverChanges) which was created in the earlier 
    // CreateGameDeviceResourcesAsync method. For UpdateSubresource API ref info, 
    // go to: https://msdn.microsoft.com/library/windows/desktop/ff476486.aspx
    // To learn more about what a subresource is, go to:
    // https://msdn.microsoft.com/library/windows/desktop/ff476901.aspx

    m_deviceResources->GetD3DDeviceContext()->UpdateSubresource(
        m_constantBufferNeverChanges.get(),
        0,
        nullptr,
        &constantBufferNeverChanges,
        0,
        0
        );

    // For the objects that function as targets, they have two unique generated textures.
    // One version is used to show that they have never been hit and the other is 
    // used to show that they have been hit.
    // TargetTexture is a helper class to procedurally generate textures for game
    // targets. The class creates the necessary resources to draw the texture into 
    // an off screen resource at initialization time.

    TargetTexture textureGenerator(
        d3dDevice,
        m_deviceResources->GetD2DFactory(),
        m_deviceResources->GetDWriteFactory(),
        m_deviceResources->GetD2DDeviceContext()
        );

    // CylinderMesh is a class derived from MeshObject and creates a ID3D11Buffer of
    // vertices and indices to represent a canonical cylinder (capped at
    // both ends) that is positioned at the origin with a radius of 1.0,
    // a height of 1.0 and with its axis in the +Z direction.
    // In the game sample, there are various types of mesh types:
    // CylinderMesh (vertical rods), SphereMesh (balls that the player shoots), 
    // FaceMesh (target objects), and WorldMesh (Floors and ceilings that define the enclosed area)

    auto cylinderMesh = std::make_shared<CylinderMesh>(d3dDevice, (uint16_t)26);
    ...

    // The Material class maintains the properties that represent how an object will
    // look when it is rendered.  This includes the color of the object, the
    // texture used to render the object, and the vertex and pixel shader that
    // should be used for rendering.

    auto cylinderMaterial = std::make_shared<Material>(
        XMFLOAT4(0.8f, 0.8f, 0.8f, .5f),
        XMFLOAT4(0.8f, 0.8f, 0.8f, .5f),
        XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f),
        15.0f,
        m_cylinderTexture.get(),
        m_vertexShader.get(),
        m_pixelShader.get()
        );

    ...

    // Attach the textures to the appropriate game objects.
    // We'll loop through all the objects that need to be rendered.
    for (auto&& object : m_game->RenderObjects())
    {
        if (object->TargetId() == GameConstants::WorldFloorId)
        {
            // Assign a normal material for the floor object.
            // This normal material uses the floor texture (cellfloor.dds) that was loaded asynchronously from
            // the Assets folder using BasicLoader::LoadTextureAsync method in the earlier 
            // CreateGameDeviceResourcesAsync loop

            object->NormalMaterial(
                std::make_shared<Material>(
                    XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f),
                    XMFLOAT4(0.8f, 0.8f, 0.8f, 1.0f),
                    XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f),
                    150.0f,
                    m_floorTexture.get(),
                    m_vertexShaderFlat.get(),
                    m_pixelShaderFlat.get()
                    )
                );
            // Creates a mesh object called WorldFloorMesh and assign it to the floor object.
            object->Mesh(std::make_shared<WorldFloorMesh>(d3dDevice));
        }
        ...
        else if (auto cylinder = dynamic_cast<Cylinder*>(object.get()))
        {
            cylinder->Mesh(cylinderMesh);
            cylinder->NormalMaterial(cylinderMaterial);
        }
        else if (auto target = dynamic_cast<Face*>(object.get()))
        {
            const int bufferLength = 16;
            wchar_t str[bufferLength];
            int len = swprintf_s(str, bufferLength, L"%d", target->TargetId());
            auto string{ winrt::hstring(str, len) };

            winrt::com_ptr<ID3D11ShaderResourceView> texture;
            textureGenerator.CreateTextureResourceView(string, texture.put());
            target->NormalMaterial(
                std::make_shared<Material>(
                    XMFLOAT4(0.8f, 0.8f, 0.8f, 0.5f),
                    XMFLOAT4(0.8f, 0.8f, 0.8f, 0.5f),
                    XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f),
                    5.0f,
                    texture.get(),
                    m_vertexShader.get(),
                    m_pixelShader.get()
                    )
                );

            texture = nullptr;
            textureGenerator.CreateHitTextureResourceView(string, texture.put());
            target->HitMaterial(
                std::make_shared<Material>(
                    XMFLOAT4(0.8f, 0.8f, 0.8f, 0.5f),
                    XMFLOAT4(0.8f, 0.8f, 0.8f, 0.5f),
                    XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f),
                    5.0f,
                    texture.get(),
                    m_vertexShader.get(),
                    m_pixelShader.get()
                    )
                );

            target->Mesh(targetMesh);
        }
        ...
    }

    // The SetProjParams method calculates the projection matrix based on input params and
    // ensures that the camera has been initialized with the right projection
    // matrix.  
    // The camera is not created at the time the first window resize event occurs.

    auto renderTargetSize = m_deviceResources->GetRenderTargetSize();
    m_game->GameCamera().SetProjParams(
        XM_PI / 2,
        renderTargetSize.Width / renderTargetSize.Height,
        0.01f,
        100.0f
        );

    // Make sure that the correct projection matrix is set in the ConstantBufferChangeOnResize buffer.

    // Get the 3D rotation transform matrix. We are handling screen rotations directly to eliminate an unaligned 
    // fullscreen copy. So it is necessary to post multiply the 3D rotation matrix to the camera's projection matrix
    // to get the projection matrix that we need.

    auto orientation = m_deviceResources->GetOrientationTransform3D();

    ConstantBufferChangeOnResize changesOnResize;

    // The matrices are transposed due to the shader code expecting the matrices in the opposite
    // row/column order from the DirectX math library.

    // XMStoreFloat4x4 takes a matrix and writes the components out to sixteen single-precision floating-point values at the given address. 
    // The most significant component of the first row vector is written to the first four bytes of the address, 
    // followed by the second most significant component of the first row, and so on. The second row is then written out in a 
    // like manner to memory beginning at byte 16, followed by the third row to memory beginning at byte 32, and finally 
    // the fourth row to memory beginning at byte 48. For more API ref info, go to: 
    // https://msdn.microsoft.com/library/windows/desktop/microsoft.directx_sdk.storing.xmstorefloat4x4.aspx

    XMStoreFloat4x4(
        &changesOnResize.projection,
        XMMatrixMultiply(
            XMMatrixTranspose(m_game->GameCamera().Projection()),
            XMMatrixTranspose(XMLoadFloat4x4(&orientation))
            )
        );

    // UpdateSubresource method instructs CPU to copy data from memory (changesOnResize) to a subresource 
    // created in non-mappable memory (m_constantBufferChangeOnResize ) which was created in the earlier 
    // CreateGameDeviceResourcesAsync method.

    m_deviceResources->GetD3DDeviceContext()->UpdateSubresource(
        m_constantBufferChangeOnResize.get(),
        0,
        nullptr,
        &changesOnResize,
        0,
        0
        );

    // Finally we set the m_gameResourcesLoaded as TRUE, so we can start rendering.
    m_gameResourcesLoaded = true;
}

Methode "kreatewindowsizedependentresource"CreateWindowSizeDependentResource method

Die createwindowsizedependentresources-Methoden werden jedes Mal aufgerufen, wenn die Fenstergröße, die Ausrichtung, das Stereo aktivierte Rendering oder die Auflösung geändert wird.CreateWindowSizeDependentResources methods are called every time the window size, orientation, stereo-enabled rendering, or resolution changes. Im Beispiel Spiel wird die Projektions Matrix in __constantbufferchangeonresize__aktualisiert.In the sample game, it updates the projection matrix in ConstantBufferChangeOnResize.

Die Fenstergröße wird auf diese Weise aktualisiert:Window size resources are updated in this manner:

  • Das App-Framework ruft eines von mehreren möglichen Ereignissen ab, das eine Änderung des Fenster Zustands angibt.The App framework gets one of several possible events indicating a change in the window state.
  • Die Hauptspiel Schleife wird dann über das Ereignis informiert und ruft createwindowsizedependentresources auf der Hauptklasse (gamemain) ab, die dann die createwindowsizedependentresources -Implementierung in der Game Renderer-Klasse (gamerenderer) aufruft.Your main game loop is then informed about the event and calls CreateWindowSizeDependentResources on the main class (GameMain) instance, which then calls the CreateWindowSizeDependentResources implementation in the game renderer (GameRenderer) class.
  • Der primäre Auftrag dieser Methode besteht darin, sicherzustellen, dass die visuellen Elemente aufgrund einer Änderung der Fenster Eigenschaften nicht verwirrt oder ungültig werden.The primary job of this method is to make sure the visuals don't become confused or invalid because of a change in window properties.

Für dieses Beispiel Spiel ist eine Reihe von Methoden aufrufen identisch mit der finalizecreategamedeviceresources -Methode.For this sample game, a number of method calls are the same as the FinalizeCreateGameDeviceResources method. Informationen zu Code exemplarischen Vorgehensweisen finden Sie im vorherigen Abschnitt.For code walkthrough, go to the previous section.

Die Renderingleistung für Spiel-HUD und über Lagerungs Fenster werden unter Benutzeroberfläche hinzufügenbehandelt.The game HUD and overlay window size rendering adjustments is covered under Add a user interface.

// Initializes view parameters when the window size changes.
void GameRenderer::CreateWindowSizeDependentResources()
{
    // Game HUD and overlay window size rendering adjustments are done here
    // but they'll be covered in the UI section instead.

    m_gameHud.CreateWindowSizeDependentResources();

    ...

    auto d3dContext = m_deviceResources->GetD3DDeviceContext();
    // In Sample3DSceneRenderer::CreateWindowSizeDependentResources, we had:
    // Size outputSize = m_deviceResources->GetOutputSize();

    auto renderTargetSize = m_deviceResources->GetRenderTargetSize();

    ...

    m_gameInfoOverlay.CreateWindowSizeDependentResources(m_gameInfoOverlaySize);

    if (m_game != nullptr)
    {
        // Similar operations as the last section of FinalizeCreateGameDeviceResources method
        m_game->GameCamera().SetProjParams(
            XM_PI / 2, renderTargetSize.Width / renderTargetSize.Height,
            0.01f,
            100.0f
            );

        XMFLOAT4X4 orientation = m_deviceResources->GetOrientationTransform3D();

        ConstantBufferChangeOnResize changesOnResize;
        XMStoreFloat4x4(
            &changesOnResize.projection,
            XMMatrixMultiply(
                XMMatrixTranspose(m_game->GameCamera().Projection()),
                XMMatrixTranspose(XMLoadFloat4x4(&orientation))
                )
            );

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

Nächste SchritteNext steps

Dies ist der grundlegende Prozess zum Implementieren des Grafik Rendering-Frameworks eines Spiels.This is the basic process for implementing the graphics rendering framework of a game. Je größer das Spiel ist, desto mehr Abstraktionen müssten Sie zum Verarbeiten von Hierarchien von Objekttypen und Animations Verhalten einsetzen.The larger your game, the more abstractions you would have to put in place to handle hierarchies of object types and animation behaviors. Sie müssen komplexere Methoden zum Laden und Verwalten von Ressourcen wie z. b. Netzen und Texturen implementieren.You need to implement more complex methods for loading and managing assets such as meshes and textures. Als Nächstes erfahren Sie, wie Sie eine Benutzeroberfläche hinzufügen.Next, let's learn how to add a user interface.