次の方法で共有


ストリーム出力ステージの基礎知識 (Direct3D 10)

ストリーム出力ステージを初期化し、実行するには、次の手順を実行します。

  1. ジオメトリ シェーダーのコンパイル
  2. ストリーム出力によるジオメトリ シェーダー オブジェクトの作成
  3. 出力ターゲットの設定

ジオメトリ シェーダーのコンパイル

チュートリアル 13」のジオメトリ シェーダー (GS) は各三角形の面の法線を計算し、位置、法線、およびテクスチャーの座標データを出力します。

 struct GSPS_INPUT {     float4 Pos : SV_POSITION;     float3 Norm : TEXCOORD0;     float2 Tex : TEXCOORD1; };  [maxvertexcount(12)] void GS( triangle GSPS_INPUT input[3], inout TriangleStream<GSPS_INPUT> TriStream ) {     GSPS_INPUT output;          //     // Calculate the face normal     //     float3 faceEdgeA = input[1].Pos - input[0].Pos;     float3 faceEdgeB = input[2].Pos - input[0].Pos;     float3 faceNormal = normalize( cross(faceEdgeA, faceEdgeB) );     float3 ExplodeAmt = faceNormal*Explode;          //     // Calculate the face center     //     float3 centerPos = (input[0].Pos.xyz + input[1].Pos.xyz + input[2].Pos.xyz)/3.0;     float2 centerTex = (input[0].Tex + input[1].Tex + input[2].Tex)/3.0;     centerPos += faceNormal*Explode;          //     // Output the pyramid     //     for( int i=0; i<3; i++ )     {         output.Pos = input[i].Pos + float4(ExplodeAmt,0);         output.Pos = mul( output.Pos, View );         output.Pos = mul( output.Pos, Projection );         output.Norm = input[i].Norm;         output.Tex = input[i].Tex;         TriStream.Append( output );                  int iNext = (i+1)%3;         output.Pos = input[iNext].Pos + float4(ExplodeAmt,0);         output.Pos = mul( output.Pos, View );         output.Pos = mul( output.Pos, Projection );         output.Norm = input[iNext].Norm;         output.Tex = input[iNext].Tex;         TriStream.Append( output );                  output.Pos = float4(centerPos,1) + float4(ExplodeAmt,0);         output.Pos = mul( output.Pos, View );         output.Pos = mul( output.Pos, Projection );         output.Norm = faceNormal;         output.Tex = centerTex;         TriStream.Append( output );                  TriStream.RestartStrip();     }          for( int i=2; i>=0; i-- )     {         output.Pos = input[i].Pos + float4(ExplodeAmt,0);         output.Pos = mul( output.Pos, View );         output.Pos = mul( output.Pos, Projection );         output.Norm = -input[i].Norm;         output.Tex = input[i].Tex;         TriStream.Append( output );     }     TriStream.RestartStrip(); }

このコードでは、ジオメトリ シェーダーが頂点シェーダーやピクセル シェーダーとよく似ていることがわかります。ただし、関数の戻り型、入力パラメーターの宣言、および組み込み関数が異なります。

  • 関数の戻り型
    関数の戻り型は、シェーダーから出力可能な頂点の最大数を宣言するだけです。この場合は、maxvertexcount(12) によって、出力が最大 12 つの頂点となるように定義されています。

  • 入力パラメーターの宣言
    この関数は、2 つの入力パラメーターを取得します。

    triangle GSPS_INPUT input[3] , inout TriangleStream<GSPS_INPUT> TriStream
    

    最初のパラメーターは頂点 (この場合は 3 つ) の配列で、GSPS_INPUT 構造体によって定義されています (この構造体は、頂点単位のデータを位置、法線、およびテクスチャーの座標として定義します)。また、最初のパラメーターは、triangle キーワードを使用しています。これは、入力アセンブラー ステージで三角形プリミティブ タイプのいずれか (三角形リストまたは三角形ストリップ) としてジオメトリ シェーダーにデータを出力する必要があることを意味します。

    2 番目のパラメーターは、TriangleStream<GSPS_INPUT> 型によって定義された三角形ストリームです。これは、このパラメーターが三角形の配列で、それぞれが 3 つの頂点で構成されていることを意味します (各三角形は GSPS_INPUT のメンバーからのデータを含みます)。

    triangle および TriangleStream キーワードを使用して、GS で個別の三角形または三角形のストリームを示します。

  • 組み込み関数
    シェーダー関数内のコードの行は、共通シェーダー コア HLSL 組み込み関数を使用しています。ただし、Append および RestartStrip を呼び出す最後の 2 行を除きます。これらの関数は、ジオメトリ シェーダーのみで使用できます。Append は、ジオメトリ シェーダーで、現在のストリップに出力を追加するように指定します。RestartStrip は、新しいプリミティブ ストリップを作成します。新しいストリップは、GS ステージのすべての呼び出しで暗黙的に作成されます。

シェーダーの残りの部分は、頂点シェーダーやピクセル シェーダーと非常に類似しています。ジオメトリ シェーダーは、構造体を使用して入力パラメーターを宣言し、SV_POSITION セマンティクスで Position メンバーをマークすることで、これが位置データであることをハードウェアに知らせます。入力構造体は、他の 2 つのパラメーターをテクスチャー座標として示します (一方のパラメーターが面の法線を含む場合でも同様です)。必要に応じて、面の法線に独自のカスタム セマンティクスを使用することもできます。

ジオメトリ シェーダーの設計が完了したら、D3D10CompileShader を呼び出して、次のコード例のようにコンパイルします。

 DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS; ID3D10Blob** ppShader;  D3D10CompileShader( pSrcData, sizeof( pSrcData ),    "Tutorial13.fx", NULL, NULL, "GS", "gs_4_0",    dwShaderFlags, &ppShader, NULL ); 

頂点シェーダーやピクセル シェーダーと同様に、シェーダー フラグで、シェーダーのコンパイル方法 (デバッグ用途や速度の最適化など)、エントリ ポイント関数、および検証対象のシェーダー モデルをコンパイラに指示する必要があります。この例では、GS 関数を使用して、Tutorial13.fx ファイルから構築されたジオメトリ シェーダーを作成しています。シェーダーは、シェーダー モデル 4.0 用にコンパイルされます。

ストリーム出力によるジオメトリ シェーダー オブジェクトの作成

データがジオメトリから出力されることがわかり、シェーダーを正しくコンパイルしたら、次に ID3D10Device::CreateGeometryShaderWithStreamOutput を呼び出して、ジオメトリ シェーダー オブジェクトを作成します。

ただし、最初に、ストリーム出力 (SO) ステージの入力シグネチャを宣言する必要があります。このシグネチャは、オブジェクト作成時に GS 出力と SO 入力を照合または検証します。次のコードは、SO 宣言の例です。

 D3D10_STREAM_OUTPUT_DECLARATION_ENTRY pDecl[] = {     // semantic name, semantic index, start component, component count, output slot     { "SV_POSITION", 0, 0, 4, 0 },   // output all components of position     { "TEXCOORD0", 0, 0, 3, 0 },     // output the first 3 of the normal     { "TEXCOORD1", 0, 0, 2, 0 },     // output the first 2 texture coordinates };  D3D10Device->CreateGeometryShaderWithStreamOut( pShaderBytecode, pDecl, 3,      sizeof(pDecl), &pGS ); 

この関数は、次のパラメーターを取得します。

  • コンパイル済みジオメトリ シェーダー (ジオメトリ シェーダーが存在せず、データが頂点シェーダーから直接ストリーム出力される場合は頂点シェーダー) へのポインター。このポインターの取得方法については、「コンパイル済みシェーダーへのポインターの取得」を参照してください。
  • ストリーム出力ステージの入力データを記述する宣言の配列へのポインター(「D3D10_SO_DECLARATION_ENTRY」を参照してください)。SO ステージから出力される要素の型ごとに 1 つずつ、最大 64 の宣言を指定できます。宣言エントリの配列は、ストリーム出力にバインドされるのが 1 つのバッファーのみであるか、複数のバッファーであるかに関係なく、データ レイアウトを記述します。
  • SO ステージによって書き出される要素の数。
  • 作成されるジオメトリ シェーダー オブジェクトへのポインター (「ID3D10GeometryShader インターフェイス」を参照してください)。

ストリーム出力宣言は、データをバッファー リソースに書き込む方法を定義します。出力宣言には、必要な数の要素を追加できます。SO ステージを使用して、1 つのバッファー リソースまたは複数のバッファー リソースに書き込みます。1 つのバッファーの場合、SO ステージでは頂点ごとに多数の異なる要素を書き込むことができます。複数のバッファーの場合、SO ステージでは頂点単位のデータの 1 つ要素しか各バッファーに書き込むことができません。

ジオメトリ シェーダーを使用せずに SO ステージを使用するには、ID3D10Device::CreateGeometryShaderWithStreamOutput を呼び出し、pShaderBytecode パラメーターに頂点シェーダーへのポインターを渡します。

出力ターゲットの設定

最後の手順では、SO ステージ バッファーを設定します。データは、後で使用するために、メモリー内の 1 つまたは複数のバッファーに読み込むことができます。次のコードは、頂点データや、データを読み込む SO ステージに使用できる 1 つのバッファーの作成方法を示しています。

 ID3D10Buffer *m_pBuffer; int m_nBufferSize = 1000000;  D3D10_BUFFER_DESC bufferDesc = {     m_nBufferSize,     D3D10_USAGE_DEFAULT,     D3D10_BIND_STREAM_OUTPUT,     0,     0 }; D3D10Device->CreateBuffer( &bufferDesc, NULL, &m_pBuffer ); 

ID3D10Device::CreateBuffer を呼び出してバッファーを作成します。この例は、デフォルトの使用方法を示しています。これは、CPU によってかなり頻繁に更新されることが予想されるバッファー リソースに一般的な方法です。バインド フラグは、リソースをバインドできるパイプラインのステージを示します。また、SO ステージによって使用されるリソースは、バインド フラグ D3D10_BIND_STREAM_OUTPUT を指定して作成されている必要があります。

バッファーを正しく作成したら、ID3D10Device::SOSetTargets を呼び出して現在のデバイスに設定します。

 UINT offset[1] = 0; D3D10Device->SOSetTargets( 1, &m_pBuffer, offset ); 

この呼び出しは、バッファーの数、バッファーへのポインター、およびオフセットの配列を取得します (データの書き込みを開始する位置を示すオフセットが各バッファーに 1 つずつ格納されます)。データは、描画関数の呼び出し時にこれらのストリーム出力バッファーに書き込まれます。内部変数は、ストリーミング出力バッファーへのデータの書き込みを開始する位置を追跡します。この変数は、SOSetTargets が再度呼び出されて、新しいオフセット値が指定されるまで増え続けます。

ターゲット バッファーに書き出されるデータはすべて、32 ビット値です。

関連項目

パイプライン ステージ (Direct3D 10)