シェーダー オブジェクトの移植Port the shader objects

重要な APIImportant APIs

OpenGL ES 2.0 から簡単なレンダラーを移植する場合、最初の手順では、Direct3D 11 の対応する頂点シェーダー オブジェクトとフラグメント シェーダー オブジェクトを設定し、コンパイル後にメイン プログラムがシェーダー オブジェクトと通信できるようにします。When porting the simple renderer from OpenGL ES 2.0, the first step is to set up the equivalent vertex and fragment shader objects in Direct3D 11, and to make sure that the main program can communicate with the shader objects after they are compiled.

  新しい Direct3D プロジェクトを作成しましたか?Note   Have you created a new Direct3D project? 作成していない場合は、「テンプレートからの DirectX ゲーム プロジェクトの作成」の指示に従ってください。If not, follow the instructions in Create a new DirectX 11 project for Universal Windows Platform (UWP). このチュートリアルでは、画面に描画するために DXGI リソースと Direct3D リソースを作成していることを前提としています。これらのリソースは、テンプレートで提供されます。This walkthrough assumes that you have the created the DXGI and Direct3D resources for drawing to the screen, and which are provided in the template.

 

OpenGL ES 2.0 と同じように、Direct3D のコンパイル済みシェーダーは描画コンテキストに関連付ける必要があります。Much like OpenGL ES 2.0, the compiled shaders in Direct3D must be associated with a drawing context. ただし、Direct3D にはもともとシェーダー プログラム オブジェクトという概念がありません。そのため、代わりに、シェーダーを ID3D11DeviceContext に直接割り当てる必要があります。However, Direct3D does not have the concept of a shader program object per se; instead, you must assign the shaders directly to a ID3D11DeviceContext. この手順では、OpenGL ES 2.0 のシェーダー オブジェクトを作成してバインドするプロセスに従い、Direct3D で対応する API の動作を実現します。This step follows the OpenGL ES 2.0 process for creating and binding shader objects, and provides you with the corresponding API behaviors in Direct3D.

手順Instructions

手順 1:シェーダーをコンパイルします。Step 1: Compile the shaders

この簡単な OpenGL ES 2.0 のサンプルでは、シェーダーをテキスト ファイルとして保存し、実行時コンパイルのために文字列データとして読み込みます。In this simple OpenGL ES 2.0 sample, the shaders are stored as text files and loaded as string data for run-time compilation.

OpenGL ES 2.0:シェーダーをコンパイルします。OpenGL ES 2.0: Compile a shader

GLuint __cdecl CompileShader (GLenum shaderType, const char *shaderSrcStr)
// shaderType can be GL_VERTEX_SHADER or GL_FRAGMENT_SHADER. Returns 0 if compilation fails.
{
  GLuint shaderHandle;
  GLint compiledShaderHandle;
   
  // Create an empty shader object.
  shaderHandle = glCreateShader(shaderType);

  if (shaderHandle == 0)
  return 0;

  // Load the GLSL shader source as a string value. You could obtain it from
  // from reading a text file or hardcoded.
  glShaderSource(shaderHandle, 1, &shaderSrcStr, NULL);
   
  // Compile the shader.
  glCompileShader(shaderHandle);

  // Check the compile status
  glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compiledShaderHandle);

  if (!compiledShaderHandle) // error in compilation occurred
  {
    // Handle any errors here.
              
    glDeleteShader(shaderHandle);
    return 0;
  }

  return shaderHandle;

}

Direct3D では、シェーダーは実行時にコンパイルされず、常に、プログラムの他の部分をコンパイルしたときに、CSO ファイルにコンパイルされます。In Direct3D, shaders are not compiled during run-time; they are always compiled to CSO files when the rest of the program is compiled. Microsoft Visual Studio でアプリをコンパイルすると、HLSL ファイルは、アプリで読み込む必要がある CSO (.cso) ファイルにコンパイルされます。When you compile your app with Microsoft Visual Studio, the HLSL files are compiled to CSO (.cso) files that your app must load. アプリをパッケージ化するときは、これらの CSO ファイルを必ず含めてください。Make sure you include these CSO files with your app when you package it!

  シェーダーの読み込みおよびコンパイルを使用して非同期的に次の例では、自動キーワードとラムダ構文です。Note   The following example performs the shader loading and compilation asynchronously using the auto keyword and lambda syntax. ReadDataAsync() はテンプレートに実装されているメソッドで、CSO ファイルをバイト データの配列 (fileData) として読み取ります。ReadDataAsync() is a method implemented for the template that reads in a CSO file as an array of byte data (fileData).

 

Direct3D 11。シェーダーをコンパイルします。Direct3D 11: Compile a shader

auto loadVSTask = DX::ReadDataAsync(m_projectDir + "SimpleVertexShader.cso");
auto loadPSTask = DX::ReadDataAsync(m_projectDir + "SimplePixelShader.cso");

auto createVSTask = loadVSTask.then([this](Platform::Array<byte>^ fileData) {

m_d3dDevice->CreateVertexShader(
  fileData->Data,
  fileData->Length,
  nullptr,
  &m_vertexShader);

auto createPSTask = loadPSTask.then([this](Platform::Array<byte>^ fileData) {
  m_d3dDevice->CreatePixelShader(
    fileData->Data,
    fileData->Length,
    nullptr,
    &m_pixelShader;
};

手順 2:フラグメントの (ピクセル) シェーダーを作成し、頂点の読み込みStep 2: Create and load the vertex and fragment (pixel) shaders

OpenGL ES 2.0 にはシェーダー "プログラム" という概念があります。この概念は、CPU で実行されるメイン プログラムと GPU で実行されるシェーダーの間のインターフェイスとして機能します。OpenGL ES 2.0 has the notion of a shader "program", which serves as the interface between the main program running on the CPU and the shaders, which are executed on the GPU. シェーダーはコンパイルされ (またはコンパイル済みのソースから読み込まれ)、プログラムに関連付けられることで、GPU で実行できるようになります。Shaders are compiled (or loaded from compiled sources) and associated with a program, which enables execution on the GPU.

OpenGL ES 2.0:網掛けプログラムへの頂点とフラグメントのシェーダーの読み込みOpenGL ES 2.0: Loading the vertex and fragment shaders into a shading program

GLuint __cdecl LoadShaderProgram (const char *vertShaderSrcStr, const char *fragShaderSrcStr)
{
  GLuint programObject, vertexShaderHandle, fragmentShaderHandle;
  GLint linkStatusCode;

  // Load the vertex shader and compile it to an internal executable format.
  vertexShaderHandle = CompileShader(GL_VERTEX_SHADER, vertShaderSrcStr);
  if (vertexShaderHandle == 0)
  {
    glDeleteShader(vertexShaderHandle);
    return 0;
  }

   // Load the fragment/pixel shader and compile it to an internal executable format.
  fragmentShaderHandle = CompileShader(GL_FRAGMENT_SHADER, fragShaderSrcStr);
  if (fragmentShaderHandle == 0)
  {
    glDeleteShader(fragmentShaderHandle);
    return 0;
  }

  // Create the program object proper.
  programObject = glCreateProgram();
   
  if (programObject == 0)    return 0;

  // Attach the compiled shaders
  glAttachShader(programObject, vertexShaderHandle);
  glAttachShader(programObject, fragmentShaderHandle);

  // Compile the shaders into binary executables in memory and link them to the program object..
  glLinkProgram(programObject);

  // Check the project object link status and determine if the program is available.
  glGetProgramiv(programObject, GL_LINK_STATUS, &linkStatusCode);

  if (!linkStatusCode) // if link status <> 0
  {
    // Linking failed; delete the program object and return a failure code (0).

    glDeleteProgram (programObject);
    return 0;
  }

  // Deallocate the unused shader resources. The actual executables are part of the program object.
  glDeleteShader(vertexShaderHandle);
  glDeleteShader(fragmentShaderHandle);

  return programObject;
}

// ...

glUseProgram(renderer->programObject);

Direct3D には、シェーダー プログラム オブジェクトという概念がありません。Direct3D does not have the concept of a shader program object. そのため、シェーダーは、ID3D11Device インターフェイスでいずれかのシェーダー作成メソッド (ID3D11Device::CreateVertexShaderID3D11Device::CreatePixelShader など) が呼び出されたときに作成されます。Rather, the shaders are created when one of the shader creation methods on the ID3D11Device interface (such as ID3D11Device::CreateVertexShader or ID3D11Device::CreatePixelShader) is called. 現在の描画コンテキストのシェーダーを設定するには、シェーダー設定メソッド (頂点シェーダーの ID3D11DeviceContext::VSSetShader やフラグメント シェーダーの ID3D11DeviceContext::PSSetShader など) を使って、シェーダーを対応する ID3D11DeviceContext に渡します。To set the shaders for the current drawing context, we provide them to corresponding ID3D11DeviceContext with a set shader method, such as ID3D11DeviceContext::VSSetShader for the vertex shader or ID3D11DeviceContext::PSSetShader for the fragment shader.

Direct3D 11。グラフィックス デバイスの描画コンテキストのシェーダーを設定します。Direct3D 11: Set the shaders for the graphics device drawing context.

m_d3dContext->VSSetShader(
  m_vertexShader.Get(),
  nullptr,
  0);

m_d3dContext->PSSetShader(
  m_pixelShader.Get(),
  nullptr,
  0);

手順 3:シェーダーに提供するデータを定義します。Step 3: Define the data to supply to the shaders

OpenGL ES 2.0 の例では、シェーダー パイプラインに対して宣言する次の uniform が 1 つあります。In our OpenGL ES 2.0 example, we have one uniform to declare for the shader pipeline:

  • u_mvpMatrix: モデルを最終的なモデル-ビュー-射影変換行列を表す浮動小数点数の 4 x 4 配列は、キューブの調整し、スキャンの変換の投影が 2D 座標に変換します。u_mvpMatrix: a 4x4 array of floats that represents the final model-view-projection transformation matrix that takes the model coordinates for the cube and transforms them into 2D projection coordinates for scan conversion.

さらに、頂点データ用の次の attribute 値が 2 つあります。And two attribute values for the vertex data:

  • _位置: 頂点のモデルの座標を表す 4 float ベクトル。a_position: a 4-float vector for the model coordinates of a vertex.
  • _色:頂点に関連付けられている RGBA 色の値を 4 float ベクトル。a_color: A 4-float vector for the RGBA color value associated with the vertex.

Opengl ES 2.0:GLSL 定義制服と属性Open GL ES 2.0: GLSL definitions for the uniforms and attributes

uniform mat4 u_mvpMatrix;
attribute vec4 a_position;
attribute vec4 a_color;

この場合は、対応するメイン プログラムの変数をレンダラー オブジェクトのフィールドとして定義します The corresponding main program variables are defined as fields on the renderer object, in this case. (でヘッダーを参照してください方法: direct3d11 を単純な OpenGL ES 2.0 レンダラーをポート)。処理が完了したら、メインのプログラムが通常の方法で描画呼び出しの直前、シェーダー パイプラインのこれらの値を提供するためのメモリ内の場所を指定する必要があります。(Refer to the header in How to: port a simple OpenGL ES 2.0 renderer to Direct3D 11.) Once we've done that, we need to specify the locations in memory where the main program will supply these values for the shader pipeline, which we typically do right before a draw call:

OpenGL ES 2.0:一様と属性データの場所をマークします。OpenGL ES 2.0: Marking the location of the uniform and attribute data


// Inform the shader of the attribute locations
loc = glGetAttribLocation(renderer->programObject, "a_position");
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 
    sizeof(Vertex), 0);
glEnableVertexAttribArray(loc);

loc = glGetAttribLocation(renderer->programObject, "a_color");
glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, 
    sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));
glEnableVertexAttribArray(loc);


// Inform the shader program of the uniform location
renderer->mvpLoc = glGetUniformLocation(renderer->programObject, "u_mvpMatrix");

Direct3D には、同じ意味での "attribute" と "uniform" の概念がありません (または、少なくともこの構文を共有しません)。Direct3D does not have the concept of an "attribute" or a "uniform" in the same sense (or, at least, it does not share this syntax). その代わり、Direct3D サブリソースとして表される定数バッファーがあります。これは、メイン プログラムとシェーダー プログラムの間で共有されるリソースです。Rather, it has constant buffers, represented as Direct3D subresources -- resources that are shared between the main program and the shader programs. 頂点の位置や色など、これらのサブリソースの一部は HLSL セマンティクスと呼ばれます。Some of these subresources, such as vertex positions and colors, are described as HLSL semantics. OpenGL ES 2.0 の概念に関連する定数バッファーと HLSL セマンティクスについて詳しくは、「OpenGL ES 2.0 のバッファー、uniform、頂点 attribute と Direct3D の比較」を参照してください。For more info on constant buffers and HLSL semantics as they relate to OpenGL ES 2.0 concepts, read Port frame buffer objects, uniforms, and attributes.

このプロセスを Direct3D に移行する場合は、uniform を Direct3D の定数バッファー (cbuffer) に変換し、register HLSL セマンティクスを使って、検索のために cbuffer をレジスタに割り当てます。When moving this process to Direct3D, we convert the uniform to a Direct3D constant buffer (cbuffer) and assign it a register for lookup with the register HLSL semantic. 2 つの頂点 attribute はシェーダー パイプライン ステージの入力要素として処理され、シェーダーに通知する HLSL セマンティクス (POSITION と COLOR0) が割り当てられます。The two vertex attributes are handled as input elements to the shader pipeline stages, and are also assigned HLSL semantics (POSITION and COLOR0) that inform the shaders. ピクセル シェーダーは、SV_位置を SV_ GPU によって生成されたシステムの値であることを示すプレフィックス。The pixel shader takes an SV_POSITION, with the SV_ prefix indicating that it is a system value generated by the GPU. (この場合、これはスキャンの変換中に生成されたピクセル位置) です。VertexShaderInput と PixelShaderInput 定数前者を頂点バッファーの定義に使用するためのバッファーとしてを宣言されていない (を参照してください頂点バッファーとデータをポート)、後者の場合、データがの結果として生成されると、頂点シェーダーをここでは、パイプラインの前のステージ。(In this case, it is a pixel position generated during scan conversion.) VertexShaderInput and PixelShaderInput are not declared as constant buffers because the former will be used to define the vertex buffer (see Port the vertex buffers and data), and the data for the latter is generated as the result of a previous stage in the pipeline, which in this case is the vertex shader.

Direct3D:定数バッファーと頂点データの HLSL の定義Direct3D: HLSL definitions for the constant buffers and vertex data

cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
  matrix mvp;
};

// Per-vertex data used as input to the vertex shader.
struct VertexShaderInput
{
  float4 pos : POSITION;
  float4 color : COLOR0;
};

// Per-vertex color data passed through the pixel shader.
struct PixelShaderInput
{
  float4 pos : SV_POSITION;
  float3 color : COLOR0;
};

定数バッファーへの移植と HLSL セマンティクスの利用について詳しくは、「OpenGL ES 2.0 のバッファー、uniform、頂点 attribute と Direct3D の比較」をご覧ください。For more info on porting to constant buffers and the application of HLSL semantics, read Port frame buffer objects, uniforms, and attributes.

定数バッファーまたは頂点バッファーを使ってシェーダー パイプラインに渡されるデータのレイアウトの構造体を次に示します。Here are the structures for the layout of the data passed to the shader pipeline with a constant or vertex buffer.

Direct3D 11。定数と頂点バッファー レイアウトを宣言します。Direct3D 11: Declaring the constant and vertex buffers layout

// Constant buffer used to send MVP matrices to the vertex shader.
struct ModelViewProjectionConstantBuffer
{
  DirectX::XMFLOAT4X4 modelViewProjection;
};

// Used to send per-vertex data to the vertex shader.
struct VertexPositionColor
{
  DirectX::XMFLOAT4 pos;
  DirectX::XMFLOAT4 color;
};

使用して、DirectXMath XM*シェーダー パイプラインに送信されるときに適切なパッキングと内容の配置を提供するために、定数の型が、要素をバッファーします。Use the DirectXMath XM* types for your constant buffer elements, since they provide proper packing and alignment for the contents when they are sent to the shader pipeline. Windows プラットフォームの標準の浮動小数点型と配列を使う場合は、手動でパッキングとアラインメントを実行する必要があります。If you use standard Windows platform float types and arrays, you must perform the packing and alignment yourself.

定数バッファーをバインドするとしてレイアウトの説明を作成、 CD3D11_バッファー_DESC 構造体に渡すと ID3DDevice:。CreateBufferします。To bind a constant buffer, create a layout description as a CD3D11_BUFFER_DESC structure, and pass it to ID3DDevice::CreateBuffer. 次に、レンダリング メソッドで、定数バッファーを ID3D11DeviceContext::UpdateSubresource に渡してから、描画します。Then, in your render method, pass the constant buffer to ID3D11DeviceContext::UpdateSubresource before drawing.

Direct3D 11。定数バッファーをバインドします。Direct3D 11: Bind the constant buffer

CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);

m_d3dDevice->CreateBuffer(
  &constantBufferDesc,
  nullptr,
  &m_constantBuffer);

// ...

// Only update shader resources that have changed since the last frame.
m_d3dContext->UpdateSubresource(
  m_constantBuffer.Get(),
  0,
  NULL,
  &m_constantBufferData,
  0,
  0);

同じように頂点バッファーを作成して更新します。これについては、次の手順の「頂点バッファーと頂点データの移植」で説明します。The vertex buffer is created and updated similarly, and is discussed in the next step, Port the vertex buffers and data.

次の手順Next step

頂点バッファーと頂点データの移植Port the vertex buffers and data

方法: direct3d11 を単純な OpenGL ES 2.0 レンダラーのポートHow to: port a simple OpenGL ES 2.0 renderer to Direct3D 11

頂点バッファーと頂点データの移植Port the vertex buffers and data

GLSL の移植Port the GLSL

画面への描画Draw to the screen