1 つ以上のストリームのプログラミング (Direct3D 9)
このセクションでは、プログラム可能なストリーム モデルに使用できるシェーダーについて説明します。
Streamsの使用
DirectX 8 では、シェーダーで使用するために入力レジスタにデータをバインドするストリームの概念が導入されました。 ストリームは、コンポーネント データの均一な配列です。各コンポーネントは、位置、法線、色などの 1 つのエンティティを表す 1 つ以上の要素で構成されます。 ストリームを使用すると、グラフィック チップを使用して、複数の頂点バッファーからの直接メモリ アクセスを並列で実行したり、アプリケーション データからのより自然なマッピングを提供したりできます。 また、単純なマルチテクスチャとマルチパスを有効にします。 次のように考えてください。
- 頂点は n 個のストリームで構成されます。
- ストリームは m 要素で構成されます。
- 要素は [位置、色、法線、テクスチャ座標] です。
IDirect3DDevice9::SetStreamSource メソッドは、頂点バッファーをデバイス データ ストリームにバインドし、頂点データとプリミティブ処理関数をフィードするいくつかのデータ ストリーム ポートの 1 つの間に関連付けを作成します。 ストリーム データへの実際の参照は、 IDirect3DDevice9::D rawPrimitive などの描画メソッドが呼び出されるまで発生しません。
プログラミング可能な頂点シェーダーの頂点入力レジスタへの入力頂点要素のマッピングはシェーダー宣言で定義されていますが、入力頂点要素にはその使用に関する特定のセマンティクスはありません。 入力頂点要素の解釈は、シェーダー命令を使用してプログラムされます。 頂点シェーダー関数は、各頂点に適用される命令の配列によって定義されます。 頂点出力レジスタは、シェーダー関数の命令を使用して明示的に書き込まれます。
ただし、この説明では、レジスタへの要素のセマンティック マッピングにあまり関心を持たず、ストリームを使用する理由と、ストリームを使用して解決される問題についてより関心を持つ必要があります。 ストリームのメインの利点は、以前にマルチテクスチャに関連付けられた頂点データ コストを削除することです。 ストリームの前に、ユーザーは頂点データ セットを複製して、未使用のデータ要素のない単一およびマルチテキストケースを処理するか、マルチテクスチャの場合を除いて使用されないデータ要素を運ぶ必要がありました。
頂点データの 2 つのセットを使用する例を次に示します。1 つは単一テクスチャ用、もう 1 つはマルチテクスチャ化用です。
struct CUSTOMVERTEX_TEX1
{
FLOAT x, y, z; // The untransformed position for the vertex
DWORD diffColor; // The vertex diffuse color
DWORD specColor; // The vertex specular color
float tu_1, tv_1; // Texture coordinates for a single texture
};
struct CUSTOMVERTEX_TEX2
{
FLOAT x, y, z; // The untransformed position for the vertex
DWORD diffColor; // The vertex diffuse color
DWORD specColor; // The vertex specular color
float tu_2, tv_2; // Texture coordinates for multitexturing
};
別の方法は、テクスチャ座標の両方のセットを含む単一の頂点要素を持つことでした。
struct CUSTOMVERTEX_TEX2
{
FLOAT x, y, z; // The untransformed position for the vertex
DWORD diffColor; // The vertex diffuse color
DWORD specColor; // The vertex specular color
float tu_1, tv_1; // Texture coordinates for a single texture
float tu_2, tv_2; // Texture coordinates for multitexturing
};
この頂点データを使用すると、位置データとカラー データのコピーは 1 つだけメモリに格納され、単一のテクスチャ ケースでもレンダリング用にテクスチャ座標の両方のセットを保持する必要があります。
トレードオフが明確になったので、ストリームは、このジレンマにエレガントな修正を提供します。 3 つのストリームをサポートする頂点定義のセットを次に示します。1 つは位置と色、もう 1 つはテクスチャ座標の最初のセット、もう 1 つはテクスチャ座標のセットです。
// Multistream vertex
// Stream 0, pos, diffuse, specular
struct POSCOLORVERTEX
{
FLOAT x, y, z;
DWORD diffColor, specColor;
};
#define D3DFVF_POSCOLORVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_SPECULAR)
// Stream 1, tex coord 0
struct TEXC0VERTEX
{
FLOAT tu1, tv1;
};
#define D3DFVF_TEXC0VERTEX (D3DFVF_TEX1)
// Stream 2, tex coord 1
struct TEXC1VERTEX
{
FLOAT tu2, tv2;
};
#define D3DFVF_TEXC1VERTEX (D3DFVF_TEX0)
頂点宣言は次のようになります。
// Multitexture - multistream
D3DVERTEXELEMENT9 dwDecl3[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 0},
{0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 1},
{1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_TEXCOORD, 0},
{2, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_TEXCOORD, 1},
D3DDECL_END()
};
次に、頂点宣言オブジェクトを作成し、次のように設定します。
LPDIRECT3DVERTEXDECLARATION9 m_pVertexDeclaration;
g_d3dDevice->CreateVertexDeclaration(dwDecl3, &m_pVertexDeclaration);
m_pd3dDevice->SetVertexDeclaration(m_pVertexDeclaration);
組み合わせの例
1 つのストリーム拡散色
拡散カラー レンダリングの頂点宣言とストリーム設定は次のようになります。
D3DVERTEXELEMENT9 dwDecl3[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 0 ,
{0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 1},
D3DDECL_END()
};
m_pd3dDevice->SetStreamSource(0, m_pVBVertexShader0, 0,
sizeof(CUSTOMVERTEX));
m_pd3dDevice->SetStreamSource(1, NULL, 0, 0);
m_pd3dDevice->SetStreamSource(2, NULL, 0, 0);
色とテクスチャを持つ 2 つのストリーム
単一テクスチャ レンダリングの頂点宣言とストリーム設定は次のようになります。
D3DVERTEXELEMENT9 dwDecl3[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 0},
{0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 1},
{1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_TEXCOORD, 0},
D3DDECL_END()
};
m_pd3dDevice->SetStreamSource(0, m_pVBPosColor, 0,
sizeof(POSCOLORVERTEX));
m_pd3dDevice->SetStreamSource(1, m_pVBTexC0, 0,
sizeof(TEXC0VERTEX));
m_pd3dDevice->SetStreamSource(2, NULL, 0, 0);
色と 2 つのテクスチャを持つ 2 つのストリーム
2 テクスチャ マルチテクスチャ レンダリングの頂点宣言とストリーム設定は次のようになります。
D3DVERTEXELEMENT9 dwDecl3[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 0},
{0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 1},
{1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_TEXCOORD, 0},
{2, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_TEXCOORD, 1},
D3DDECL_END()
};
m_pd3dDevice->SetStreamSource(0, m_pVBPosColor, 0,
sizeof(POSCOLORVERTEX));
m_pd3dDevice->SetStreamSource(1, m_pVBTexC0, 0,
sizeof(TEXC0VERTEX));
m_pd3dDevice->SetStreamSource(2, m_pVBTexC1, 0,
sizeof(TEXC1VERTEX));
いずれの場合も、次の IDirect3DDevice9::D rawPrimitive 呼び出しで十分です。
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, NUM_TRIS);
これは、バス間でのデータ重複/冗長データ転送 (つまり、帯域幅の無駄) の問題を解決するストリームの柔軟性を示しています。
関連トピック