レンダリングのフレームワーク II:ゲームのレンダリングRendering framework II: Game rendering

レンダリング フレームワーク I」では、シーン情報を取得し、ディスプレイの画面に表示する方法を説明しました。In Rendering framework I, we've covered how we take the scene info and present it to the display screen. ここでは、一歩戻って、レンダリングのためのデータを準備する方法について説明します。Now, we'll take a step back and learn how to prepare the data for rendering.

注意

このサンプルの最新ゲーム コードをダウンロードしていない場合は、Direct3D ゲーム サンプルのページに移動してください。If you haven't downloaded the latest game code for this sample, go to Direct3D game sample. このサンプルは、UWP 機能のサンプルの大規模なコレクションの一部です。This sample is part of a large collection of UWP feature samples. サンプルをダウンロードする手順については、「GitHub から UWP のサンプルを取得する」をご覧ください。For instructions on how to download the sample, see Get the UWP samples from GitHub.

目標Objective

目標について簡単に要約します。Quick recap on the objective. 基本的なレンダリング フレームワークを設定して、UWP DirectX ゲームのグラフィックス出力を表示する方法を理解することです。It is to understand how to set up a basic rendering framework to display the graphics output for a UWP DirectX game. これらはおおまかに 3 つの手順にグループ分けすることができます。We can loosely group them into these three steps.

  1. グラフィックス インターフェイスへの接続を確立するEstablish a connection to our graphics interface
  2. Preparation (準備): グラフィックスを描画する必要があります。 リソースを作成します。Preparation: Create the resources we need to draw the graphics
  3. グラフィックが表示されます。フレームをレンダリングします。Display the graphics: Render the frame

レンダリングのフレームワーク i:レンダリングの概要グラフィックスのレンダリング方法を説明する、手順 1. と 3. をカバーします。Rendering framework I: Intro to rendering explained how graphics are rendered, covering Steps 1 and 3.

この記事では、このフレームワークの他の部分を設定し、レンダリングの前に必要なデータを準備する方法 (プロセスの手順 2 に相当) について説明します。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.

レンダラーの設計Design the renderer

レンダラーは、ゲームの視覚効果を生成するために使用する、すべての D3D11 オブジェクトと D2D オブジェクトの作成と保守を担当します。The renderer is responsible for creating and maintaining all the D3D11 and D2D objects used to generate the game visuals. GameRenderer クラスは、このサンプル ゲームのレンダラーであり、し、ゲームのレンダリングのニーズに合わせて設計されています。The GameRenderer class is the renderer for this sample game and is designed to meet the game's rendering needs.

ゲームのレンダラーを設計する際に役立ついくつかの概念を以下に示します。These are some concepts you can use to help design the renderer for your game:

  • Direct3D 11 API は COM API として定義されるため、これらの API で定義されたオブジェクトへの ComPtr 参照を指定する必要があります。Because Direct3D 11 APIs are defined as COM APIs, you must provide ComPtr references to the objects defined by these APIs. これらのオブジェクトは、アプリ終了時に最後の参照がスコープ外になったときに自動的に解放されます。These objects are automatically freed when their last reference goes out of scope when the app terminates. 詳細については、「ComPtr」を参照してください。For more information, see ComPtr. このようなオブジェクトの例として、定数バッファー、シェーダー オブジェクト (頂点シェーダーピクセル シェーダー)、シェーダー リソース オブジェクトがあります。Example of these objects: constant buffers, shader objects - vertex shader, pixel shader, and shader resource objects.
  • 定数バッファーは、レンダリングに必要なさまざまなデータを保持するために、このクラスで定義されます。Constant buffers are defined in this class to hold various data needed for rendering.
    • GPU に送信するデータの 1 フレームあたりの量を減らすために、更新頻度の異なる複数の定数バッファーを使用します。Use multiple constant buffers with different frequencies to reduce the amount of data that must be sent to the GPU per frame. このサンプルでは、更新する必要のある頻度に基づいて定数を異なるバッファーに分けています。This sample separates constants into different buffers based on the frequency that they must be updated. Direct3D プログラミングでは、このような処理をお勧めします。This is a best practice for Direct3D programming.
    • このゲームのサンプルでは、4 つの定数バッファーを定義します。In this game sample, 4 constant buffers are defined.
      1. __m_constantBufferNeverChanges__ライティング パラメーターが含まれています。m_constantBufferNeverChanges contains the lighting parameters. これは、FinalizeCreateGameDeviceResources メソッドで一度設定されると、再び変更されることはありません。It's set one time in the FinalizeCreateGameDeviceResources method and never changes again.
      2. __m_constantBufferChangeOnResize__射影行列が含まれています。m_constantBufferChangeOnResize contains the projection matrix. プロジェクション マトリックスは、ウィンドウのサイズと縦横比に依存します。The projection matrix is dependent on the size and aspect ratio of the window. これは、CreateWindowSizeDependentResources で設定され、FinalizeCreateGameDeviceResources メソッドでリソースが読み込まれた後で更新されます。It's set in CreateWindowSizeDependentResources and then updated after resources are loaded in the FinalizeCreateGameDeviceResources method. 3D でレンダリングする場合は、フレームごとに 2 回変更されます。If rendering in 3D, it is also changed twice per frame.
      3. m_constantBufferChangesEveryFrame view 行列が含まれています。m_constantBufferChangesEveryFrame contains the view matrix. このマトリックスは、カメラ位置とルック方向 (標準はプロジェクション方向) に依存し、Render メソッドで 1 フレームあたり 1 回変更されます。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. 先ほど説明したこの__レンダリング framework i:レンダリングの概要__下で、 __GameRenderer::Render__メソッドします。This was discussed earlier in Rendering framework I: Intro to rendering, under the GameRenderer::Render method.
      4. __m_constantBufferChangesEveryPrim__各プリミティブのモデルのマトリックスと素材のプロパティが含まれています。m_constantBufferChangesEveryPrim contains the model matrix and material properties of each primitive. モデル マトリックスは、頂点をローカル座標からワールド座標に変換します。The model matrix transforms vertices from local coordinates into world coordinates. これらの定数は各プリミティブに固有で、描画呼び出しのたびに更新されます。These constants are specific to each primitive and are updated for every draw call. 先ほど説明したこの__レンダリング framework i:レンダリングの概要__下で、プリミティブのレンダリングします。This was discussed earlier in Rendering framework I: Intro to rendering, under the Primitive rendering.
  • プリミティブのテクスチャを保持するシェーダー リソース オブジェクトも、このクラスで定義されます。Shader resource objects that hold textures for the primitives are also defined in this class.
    • 一部のテクスチャは事前に定義されています (DDS は、圧縮および非圧縮テクスチャを格納するために使用されるファイル形式です。Some textures are pre-defined (DDS is a file format that can be used to store compressed and uncompressed textures. DDS テクスチャは、ワールドの壁や床、弾薬の球体に使用されます)。DDS textures are used for the walls and floor of the world as well as the ammo spheres.)
    • シェーダー リソース オブジェクトは、このゲームのサンプル: m_sphereTexturem_cylinderTexturem_ceilingTexturem_floorTexture、 __m_wallsTexture__します。In this game sample, shader resource objects are: m_sphereTexture, m_cylinderTexture, m_ceilingTexture, m_floorTexture, m_wallsTexture.
  • シェーダー オブジェクトは、プリミティブやテクスチャを計算するために、このクラスで定義されます。Shader objects are defined in this class to compute our primitives and textures.
    • このゲームのサンプルでは、シェーダー オブジェクトは__m_vertexShader__、 m_vertexShaderFlat、および__m_pixelShader__、__m_pixelShaderFlat__します。In this game sample, the shader objects are m_vertexShader, m_vertexShaderFlat, and m_pixelShader, m_pixelShaderFlat.
    • 頂点シェーダーはプリミティブと基本的な照明を処理し、ピクセル シェーダー (フラグメント シェーダーとも呼ばれます) はテクスチャとピクセルごとの効果を処理します。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.
    • これらのシェーダーには、異なるプリミティブをレンダリングするための 2 つのバージョン (標準とフラット) があります。There are two versions of these shaders (regular and flat) for rendering different primitives. 異なるバージョンを用意しているでは、フラット バージョンは、標準と比べるときわめて単純であり、鏡面ハイライトやピクセル単位の照明効果が一切実行されないためです。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. 壁に使われ、低電力デバイスでレンダリングを高速化します。These are used for the walls and make rendering faster on lower powered devices.

GameRenderer.hGameRenderer.h

ここでは、ゲーム サンプルのレンダラー クラス オブジェクトのコードについて説明し、DirectX 11 アプリ テンプレートで提供されている Sample3DSceneRenderer.h と比較してみます。Now let's look at the code in the game sample's renderer class object and compare it with the Sample3DSceneRenderer.h provided in the DirectX 11 App template.

// Class object handling the rendering of the game
ref class GameRenderer
{
internal:
    GameRenderer(const std::shared_ptr<DX::DeviceResources>& deviceResources);
    
    // Compared with Sample3DSceneRenderer.h in the DirectX 11 App template sample. 
    
    // These methods are present.
    void CreateDeviceDependentResources();
    void CreateWindowSizeDependentResources();
    void ReleaseDeviceDependentResources();
    void Render();

    // Added: Async related methods to prepare 3D game objects for rendering
    concurrency::task<void> CreateGameDeviceResourcesAsync(_In_ Simple3DGame^ game);
    void FinalizeCreateGameDeviceResources();
    concurrency::task<void> LoadLevelResourcesAsync();
    void FinalizeLoadLevelResources();
    // --- end of async related methods section

    // Added: Methods for rendering overlay
    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

    //...
    protected private:
    // Cached pointer to device resources.
    std::shared_ptr<DX::DeviceResources>                m_deviceResources;

    // ...

    // Shader resource objects
    Microsoft::WRL::ComPtr<ID3D11ShaderResourceView>    m_sphereTexture;
    Microsoft::WRL::ComPtr<ID3D11ShaderResourceView>    m_cylinderTexture;
    Microsoft::WRL::ComPtr<ID3D11ShaderResourceView>    m_ceilingTexture;
    Microsoft::WRL::ComPtr<ID3D11ShaderResourceView>    m_floorTexture;
    Microsoft::WRL::ComPtr<ID3D11ShaderResourceView>    m_wallsTexture;

    // Constant Buffers
    Microsoft::WRL::ComPtr<ID3D11Buffer>                m_constantBufferNeverChanges;
    Microsoft::WRL::ComPtr<ID3D11Buffer>                m_constantBufferChangeOnResize;
    Microsoft::WRL::ComPtr<ID3D11Buffer>                m_constantBufferChangesEveryFrame;
    Microsoft::WRL::ComPtr<ID3D11Buffer>                m_constantBufferChangesEveryPrim;

    // Texture sampler
    Microsoft::WRL::ComPtr<ID3D11SamplerState>          m_samplerLinear;

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

コンストラクターConstructor

ここでは、ゲーム サンプルの GameRenderer コンストラクターについて説明し、DirectX 11 アプリ テンプレートで提供されている Sample3DSceneRenderer コンストラクターと比較してみます。Next, let's examine the game sample'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(const std::shared_ptr<DX::DeviceResources>& deviceResources) : //...
{
    // Compared with Sample3DSceneRenderer::Sample3DSceneRenderer in the DirectX 11 App template sample. 
    
    // Added: Create a new GameHud object to rendered text on the top left corner of the screen
    m_gameHud = ref new GameHud(
        deviceResources,
        "Windows platform samples",
        "DirectX first-person game sample"
        );
    //--- end of new GameHud object section
        
    // Added: Game info rendered as an overlay on the top right corner of the screen (eg. Hits, Shots, Time)    
    m_gameInfoOverlay = ref new GameInfoOverlay(deviceResources);
    //--- end of game info rendered as overlay section

    // These methods are present.
    CreateDeviceDependentResources();
    CreateWindowSizeDependentResources();
}

DirectX グラフィックス リソースの作成と読み込みCreate and load DirectX graphic resources

ゲーム サンプル (および Visual Studio の DirectX 11 アプリ (ユニバーサル Windows) テンプレート) では、ゲームのリソースの作成と読み込みは、GameRenderer コンストラクターから呼び出される次の 2 つのメソッドを使用して実装されます。In the game sample (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 メソッドCreateDeviceDependentResources method

DirectX 11 アプリ テンプレートでは、このメソッドを使用して、頂点シェーダーとピクセル シェーダーの非道敵的な読み込み、シェーダーと定数バッファーの作成、位置と色の情報を含む頂点を持つメッシュの作成が行われます。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.

サンプル ゲームでは、シーン オブジェクトのこれらの操作は、CreateGameDeviceResourcesAsync メソッドと FinalizeCreateGameDeviceResources メソッドに分割されています。In the sample game, these operations of the scene objects are instead split among the CreateGameDeviceResourcesAsync and FinalizeCreateGameDeviceResources methods.

このゲームのサンプルでは、このメソッドに何が含まれているでしょうか。For this game sample, what goes into this method?

  • 変数をインスタンス化 (m_gameResourcesLoaded = false と__m_levelResourcesLoaded__ = false) のリソースを移動する前に読み込まれているかどうかを示す今回の読み込みに非同期的にあるため、表示するために転送します。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.
  • HUD とオーバーレイのレンダリングは別のクラスのオブジェクトで行われるため、ここでは GameHud::CreateDeviceDependentResources メソッドと GameInfoOverlay::CreateDeviceDependentResources メソッドを呼び出します。Since HUD and overlay rendering are in separate class objects, call GameHud::CreateDeviceDependentResources and GameInfoOverlay::CreateDeviceDependentResources methods here.

GameRenderer::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 if 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();
}

次の表に、リソースを作成して読み込むために使用するメソッドを示します。The table below lists the methods that are used to create and load resources. リソースを非同期的に読み込むことができるように、サンプル ゲームには、CreateGameDeviceResourcesAsyncFinalizeCreateGameDeviceResources が追加されています。CreateGameDeviceResourcesAsync and FinalizeCreateGameDeviceResources are added in the sample game so that resources are loaded asynchronously.

元の DirectX 11 アプリ テンプレートOriginal DirectX 11 App template サンプル ゲームSample game
CreateDeviceDependentResourcesCreateDeviceDependentResources CreateDeviceDependentResourcesCreateDeviceDependentResources
- CreateGameDeviceResourcesAsync (追加)- CreateGameDeviceResourcesAsync (Added)
- FinalizeCreateGameDeviceResources (追加)- FinalizeCreateGameDeviceResources (Added)
CreateWindowSizeDependentResourcesCreateWindowSizeDependentResources CreateWindowSizeDependentResourcesCreateWindowSizeDependentResources

リソースの作成と読み込みに使用される他のメソッドについて解説する前に、まずレンダラーを作成し、ゲーム ループに適していることを確認してみましょう。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.

レンダラーの作成Create the renderer

GameRendererGameMain のコンストラクターで作成されます。The GameRenderer is created in the GameMain's constructor. また、リソースの作成と読み込みのために追加された、他の 2 つメソッド CreateGameDeviceResourcesAsyncFinalizeCreateGameDeviceResources も呼び出します。It also calls the two other methods, CreateGameDeviceResourcesAsync and FinalizeCreateGameDeviceResources that are added to help create and load resources.


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

    // These methods are used in the DirectX 11 App template to create the class objects used for rendering. 
    // But are replaced in this game sample with GameRenderer as shown below.
    // m_sceneRenderer = std::unique_ptr<Sample3DSceneRenderer>(new Sample3DSceneRenderer(m_deviceResources));
    // m_fpsTextRenderer = std::unique_ptr<SampleFpsTextRenderer>(new SampleFpsTextRenderer(m_deviceResources));
    
    // Creation of GameRenderer
    m_renderer = ref new GameRenderer(m_deviceResources);
    
    //...

     create_task([this]()
    {
        // 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);

        return m_renderer->CreateGameDeviceResourcesAsync(m_game);

    }).then([this]()
    {
        // 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.
        m_renderer->FinalizeCreateGameDeviceResources();

        InitializeGameState();
    
    //...
}

CreateGameDeviceResourcesAsync メソッドCreateGameDeviceResourcesAsync method

__CreateGameDeviceResourcesAsync__から呼び出される、 __GameMain__コンス トラクター メソッドで、__作成_タスク__ループにゲームのリソースを非同期的に読み込むしているためです。CreateGameDeviceResourcesAsync is called from the GameMain constructor method in the create_task loop since we're loading game resources asynchronously.

CreateDeviceResourcesAsync は、ゲームのリソースを読み込むための一連の非同期タスクとして別個に実行されるメソッドです。CreateDeviceResourcesAsync is a method that runs as a separate set of async tasks to load the game resources. 個別のスレッドで実行されると想定されるので、Direct3D 11 デバイス メソッド (ID3D11Device で定義されているメソッド) にのみアクセスでき、デバイス コンテキスト メソッド (ID3D11DeviceContext で定義されているメソッド) にはアクセスできないため、レンダリングは実行されません。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.

FinalizeCreateGameDeviceResources メソッドはメイン スレッドで実行され、Direct3D 11 デバイス コンテキスト メソッドにアクセスできます。FinalizeCreateGameDeviceResources method runs on the main thread and does have access to the Direct3D 11 device context methods.

原則は次のとおりです。In principle:

  • CreateGameDeviceResourcesAsync では ID3D11Device のメソッドのみを使用します。これは、フリー スレッド化されている (任意のスレッドで実行できることを意味する) ためです。Use only ID3D11Device methods in CreateGameDeviceResourcesAsync because they are free-threaded, which means that they are able to run on any thread. また、GameRenderer が作成されたスレッドと同じスレッドでは実行されないことも想定されています。It is also expected that they do not run on the same thread as the one GameRenderer was created on.
  • 1 つのスレッドで実行する必要があり、かつ GameRenderer と同じスレッドで実行する必要があるため、ここでは ID3D11DeviceContext のスレッドを使用しないでください。Do not use methods in ID3D11DeviceContext here because they need to run on a single thread and on the same thread as GameRenderer.
  • 定数バッファーを作成するには、このメソッドを使用します。Use this method to create constant buffers.
  • テクスチャ (.dds ファイルなど) やシェーダー情報 (.cso ファイルなど) を、シェーダーに読み込むには、このメソッドを使用します。Use this method to load textures (like the .dds files) and shader info (like the .cso files) into the shaders.

このメソッドを使用して、次の処理を行います。This method is used to:

  • 作成、4定数バッファー: m_constantBufferNeverChangesm_constantBufferChangeOnResizem_constantBufferChangesEveryFramem_constantBufferChangesEveryPrimCreate the 4 constant buffers: m_constantBufferNeverChanges, m_constantBufferChangeOnResize, m_constantBufferChangesEveryFrame, m_constantBufferChangesEveryPrim
  • テクスチャーのサンプリング情報をカプセル化するサンプラー ステート オブジェクトを作成します。Create a sampler-state object that encapsulates sampling information for a texture
  • メソッドで作成されたすべての非同期タスクを含むタスク グループを作成します。Create a task group that contains all async tasks created by the method. メソッドは、これらすべての非同期タスクが完了するまで待機してから FinalizeCreateGameDeviceResources を呼び出します。It waits for the completion of all these async tasks, and then calls FinalizeCreateGameDeviceResources.
  • Basic Loader を使用してローダーを作成します。Create a loader using Basic Loader. 前の手順で作成したタスク グループに、ローダーの非同期読み込み操作をタスクとして追加します。Add the loader's async loading operations as tasks into the task group created earlier.
  • BasicLoader::LoadShaderAsyncBasicLoader::LoadTextureAsync などのメソッドは、以下を読み込むために使用されます。Methods like BasicLoader::LoadShaderAsync and BasicLoader::LoadTextureAsync are used to load:
    • コンパイル済みのシェーダー オブジェクト (VertextShader.cso、VertexShaderFlat.cso、PixelShader.cso、PixelShaderFlat.cso)。compiled shader objects (VertextShader.cso, VertexShaderFlat.cso, PixelShader.cso, and PixelShaderFlat.cso). 詳細については、「さまざまなシェーダー ファイル形式」を参照してください。For more info, go to Various shader file formats.
    • ゲームのテクスチャの特定 (資産\seafloor.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).
task<void> GameRenderer::CreateGameDeviceResourcesAsync(_In_ Simple3DGame^ game)
{
    // 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.
    // For API ref, go to: https://msdn.microsoft.com/library/windows/desktop/ff476092.aspx
    D3D11_BUFFER_DESC bd;
    ZeroMemory(&bd, sizeof(bd));
    
    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, go to: https://msdn.microsoft.com/library/windows/desktop/ff476501.aspx
    
    DX::ThrowIfFailed(
        d3dDevice->CreateBuffer(&bd, nullptr, &m_constantBufferNeverChanges) 
        );
    // ...
    
    // Define D3D11_SAMPLER_DESC. For API ref, go to: https://msdn.microsoft.com/library/windows/desktop/ff476207.aspx
    D3D11_SAMPLER_DESC sampDesc;

    // ZeroMemory fills a block of memory with zeros. 
    // For API ref, go to: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366920(v=vs.85).aspx
    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.
    DX::ThrowIfFailed(
        d3dDevice->CreateSamplerState(&sampDesc, &m_samplerLinear)
        );

    // Start the async tasks to load the shaders and textures (resources).
    
    // 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, go to: https://docs.microsoft.com/windows/uwp/gaming/complete-code-for-basicloader
    BasicLoader^ loader = ref new BasicLoader(d3dDevice);

    std::vector<task<void>> tasks;

    uint32 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("VertexShader.cso", PNTVertexLayout, numElements, &m_vertexShader, &m_vertexLayout));
    tasks.push_back(loader->LoadShaderAsync("VertexShaderFlat.cso", nullptr, numElements, &m_vertexShaderFlat, nullptr));
    tasks.push_back(loader->LoadShaderAsync("PixelShader.cso", &m_pixelShader));
    tasks.push_back(loader->LoadShaderAsync("PixelShaderFlat.cso", &m_pixelShaderFlat));

    // Make sure the previous versions are set to NULL before any of the textures are loaded.
    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("Assets\\seafloor.dds", nullptr, &m_sphereTexture));
    // ...
    
    tasks.push_back(create_task([]()
    {
        // Simulate loading additional resources by introducing a delay.
        wait(GameConstants::InitialLoadingDelay);
    }));

    // Returns when all the async tasks for loading the shader and texture assets have completed.
    return when_all(tasks.begin(), tasks.end());
}

FinalizeCreateGameDeviceResources メソッドFinalizeCreateGameDeviceResources method

__FinalizeCreateGameDeviceResources__メソッドは、__CreateGameDeviceResourcesAsync__メソッド内のすべてのリソース読み込みタスクが完了した後で呼び出されます。FinalizeCreateGameDeviceResources method is called after all the load resources tasks that are in the CreateGameDeviceResourcesAsync method completes.

  • ライトの位置と色を使用して constantBufferNeverChanges を初期化します。Initialize constantBufferNeverChanges with the light positions and color. デバイス コンテキスト メソッド ID3D11DeviceContext::UpdateSubresource の呼び出しによって、最初のデータを定数バッファーに読み込みます。Loads the initial data into the constant buffers with a device context method call to ID3D11DeviceContext::UpdateSubresource.
  • 非同期的に読み込まれるリソースの読み込みが完了したら、適切なゲーム オブジェクトに関連付けます。Since asynchronously loaded resources have completed loading, it's time to associate them with the appropriate game objects.
  • ゲーム オブジェクトごとに、読み込まれたテクスチャを使用して、メッシュとマテリアルを作成します。For each game object, create the mesh and the material using the textures that have been loaded. 次に、メッシュとマテリアルをゲーム オブジェクトに関連付けます。Then associate the mesh and material to the game object.
  • ターゲットのゲーム オブジェクトの場合、同心円の色付きのリングとその上の数値で構成されるテクスチャは、テクスチャー ファイルからは読み込まれません。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. 代わりに、TargetTexture.cpp 内のコードを使用して手続き的に生成されます。Instead, it's procedurally generated using the code in TargetTexture.cpp. TargetTexture クラスは、初期化時にオフスクリーン リソースにテクスチャを描画するために必要なリソースを作成します。The TargetTexture class creates the necessary resources to draw the texture into an off screen resource at initialization time. 生成されたテクスチャは、適切なターゲット ゲーム オブジェクトに関連付けられます。The resulting texture is then associated with the appropriate target game objects.

FinalizeCreateGameDeviceResourcesCreateWindowSizeDependentResources は、以下について、コードの同様の部分を共有します。FinalizeCreateGameDeviceResources and CreateWindowSizeDependentResources share similar portions of code for these:

  • SetProjParams を使用して、カメラのプロジェクション マトリックスが適切になるように設定します。Use SetProjParams to ensure that the camera has the right projection matrix. 詳しくは、「カメラと座標空間」をご覧ください。For more info, go to Camera and coordinate space.
  • カメラのプロジェクション マトリックスに 3D 回転マトリックスを乗算することにより、画面の向きを処理します。Handle screen rotation by post multiplying the 3D rotation matrix to the camera's projection matrix. 結果として得られるプロジェクション マトリックスを使って、ConstantBufferChangeOnResize 定数バッファーを更新します。Then update the ConstantBufferChangeOnResize constant buffer with the resulting projection matrix.
  • 設定、 m_gameResourcesLoaded __ブール__グローバル変数を示すリソースは次の手順の準備として、バッファーに読み込まれています。Set the m_gameResourcesLoaded Boolean global variable to indicate that the resources are now loaded in the buffers, ready for the next step. 最初に GameRenderer のコンストラクター メソッドで、GameRenderer::CreateDeviceDependentResources メソッドを使用して、この変数を FALSE として初期化したことを思い出してください。Recall that we first initialized this variable as FALSE in the GameRenderer's constructor method, through the GameRenderer::CreateDeviceDependentResources method.
  • ときにこの__m_gameResourcesLoaded__は__TRUE__シーンのオブジェクトのレンダリングが行うことができます。When this m_gameResourcesLoaded is TRUE, rendering of the scene objects can take place. これについては、__レンダリング framework i:レンダリングの概要__記事 GameRenderer::Render メソッドします。This was covered in the Rendering framework I: Intro to rendering article, under GameRenderer::Render method.
// When creating this sample game using the DirectX 11 App template, this method needs to be created.
// This new method is called from GameMain constructor in the .then loop.
// Make sure the 2D rendering is occurring on the same thread as the main rendering.
// Note: Helper class .h and .cpp files used in this method are located in the SharedContent/cpp/GameContent folder
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 constantBufferNeverChanges with the light positions and color.
    // 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 = ref new TargetTexture(
        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)

    MeshObject^ cylinderMesh = ref new CylinderMesh(d3dDevice, 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.

    Material^ cylinderMaterial = ref new 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()
        );

    // ...
    auto objects = m_game->RenderObjects();

    // Attach the textures to the appropriate game objects.
    // We'll loop through all the objects that need to be rendered.
    for (auto object = objects.begin(); object != objects.end(); object++)
    {

        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(
                ref new 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(ref new WorldFloorMesh(d3dDevice));
        }
        // ...
        else if (Cylinder^ cylinder = dynamic_cast<Cylinder^>(*object))
        {
            cylinder->Mesh(cylinderMesh);
            cylinder->NormalMaterial(cylinderMaterial);
        }
        else if (Face^ target = dynamic_cast<Face^>(*object))
        {
            const int bufferLength = 16;
            char16 str[bufferLength];
            int len = swprintf_s(str, bufferLength, L"%d", target->TargetId());
            Platform::String^ string = ref new Platform::String(str, len);

            ComPtr<ID3D11ShaderResourceView> texture;
            textureGenerator->CreateTextureResourceView(string, &texture);
            target->NormalMaterial(
                ref new 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()
                    )
                );

            textureGenerator->CreateHitTextureResourceView(string, &texture);
            target->HitMaterial(
                ref new 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;
}

CreateWindowSizeDependentResource メソッドCreateWindowSizeDependentResource method

CreateWindowSizeDependentResources メソッドは、ウィンドウのサイズ、向き、ステレオに対応したレンダリング、解像度を変更するたびに呼び出されます。CreateWindowSizeDependentResources methods are called every time the window size, orientation, stereo-enabled rendering, or resolution changes. サンプルのゲームの更新で射影行列__ConstantBufferChangeOnResize__します。In the sample game, it updates the projection matrix in ConstantBufferChangeOnResize.

ウィンドウ サイズのリソースは、次の方法で更新されます。Window size resources are updated in this manner:

  • アプリ フレームワークが、ウィンドウの状態の変更を表すいくつかの考えられるイベントのいずれかを取得します。The App framework gets one of several possible events indicating a change in the window state.
  • メイン ゲーム ループにイベントが通知され、メイン クラス (GameMain) インスタンスで CreateWindowSizeDependentResources を呼び出します。これは、次に、ゲーム レンダラー (GameRenderer) クラスでの CreateWindowSizeDependentResources の実装を呼び出します。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.
  • このメソッドの主な役割は、ウィンドウのプロパティが変化したために視覚効果が混乱したり、誤ったものにならないようにすることです。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.

このゲーム サンプルでは、多くのメソッド呼び出しが FinalizeCreateGameDeviceResources メソッドと同じです。For this game sample, a number of method calls are the same as the FinalizeCreateGameDeviceResources method. コード チュートリアルについては、前のセクションを参照してください。For code walkthrough, go to the previous section.

ゲームの HUD とオーバーレイ ウィンドウ サイズのレンダリングの調整については、「ユーザー インターフェイスの追加」を参照してください。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
            );
    }
}

次のステップNext steps

これは、ゲームのグラフィックス レンダリング フレームワークを実装する基本的なプロセスです。This is the basic process for implementing the graphics rendering framework of a game. ゲームの規模が大きくなるほど、オブジェクトの種類とアニメーションの動作の階層を処理するために必要な抽象化も増加します。The larger your game, the more abstractions you would have to put in place to handle hierarchies of object types and animation behaviors. メッシュやテクスチャなどのアセットを読み込んで管理するために、より複雑なメソッドの実装が必要になります。You need to implement more complex methods for loading and managing assets such as meshes and textures. 次に、ユーザー インターフェイスを追加する方法について説明します。Next, let's learn how to add a user interface.