MultiStreamRendering サンプル
Path
ソース : | (SDK ルート)\Samples\C++\Direct3D10\MultiStreamRendering |
実行可能ファイル : | (SDK ルート)\Samples\C++\Direct3D10\Bin\x86 or x64\MultiStreamRendering.exe |
サンプルの概要
このサンプルでは、Direct3D 9 および Direct3D 10 プラットフォームでマルチストリーム レンダリングを実行する方法を示します。マルチストリーム レンダリングを使用すると、異なる頂点ストリーム間で頂点属性を分けることができます。複数のストリームの参照には、単一のインデックス バッファーを使用します。さらに、Direct3D 10 では、さまざまな周波数で格納された頂点データに複数のインデックスを使ってアクセスする場合、マルチストリームと複数インデックスによるレンダリングを実行できます。このサンプルの Direct3D 10 のコードパスは、頂点ごとに 1 度ずつ格納された位置を参照します。また、同じシェーダー内で、三角形ごとに 1 度ずつ格納された法線を参照します。
Direct3D 9 でのマルチストリーム単一インデックス レンダリング
マルチストリーム単一インデックス レンダリングは、同じインデックス バッファーによってインデックスが付けられた複数の頂点ストリームを使用して、ジオメトリをレンダリングします。これは、すべてのデータを同じ周波数で格納する (つまり、頂点ごとにデータを格納する) 必要があることを意味します。マルチストリーム単一インデックス レンダリングでは、4 つの入力頂点バッファーを作成します。これらのバッファーは、位置、法線、テクスチャー座標、および代替テクスチャー座標をそれぞれ格納します。
最初の手順では、個々のすべての頂点ストリームを組み込む頂点宣言を作成します。この頂点宣言の目的は、複数の個別のストリームを 1 つの統合されたストリームとして頂点シェーダーに認識させることです。
// Create a Vertex Decl for the MultiStream data.
// Notice that the first parameter is the stream index. This indicates the
// VB that the particular data comes from. In this case, position data
// comes from stream 0. Normal data comes from stream 1. Texture coordinate
// data comes from stream 2.
D3DVERTEXELEMENT9 declDesc[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
{2, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
{0xFF,0,D3DDECLTYPE_UNUSED, 0,0,0}// D3DDECL_END
};
pd3dDevice->CreateVertexDeclaration( declDesc, &g_pDecl );
レンダリングの前に、すべてのストリームがバインドされていること、インデックス バッファーがバインドされていること、および正しい頂点宣言が設定されていることを確認する必要があります。3 番目の頂点ストリーム (ストリーム番号 2) は、他のストリームに影響を与えることなく、最初のテクスチャー座標セットか代替テクスチャー座標セットに切り替えることができます。
// Setup our multiple streams
pd3dDevice->SetStreamSource( 0, g_pVBs[ST_VERTEX_POSITION], 0, sizeof(D3DXVECTOR3) );
pd3dDevice->SetStreamSource( 1, g_pVBs[ST_VERTEX_NORMAL], 0, sizeof(D3DXVECTOR3) );
if(g_bUseAltUV)
pd3dDevice->SetStreamSource( 2, g_pVBs[ST_VERTEX_TEXTUREUV2], 0, sizeof(D3DXVECTOR2) );
else
pd3dDevice->SetStreamSource( 2, g_pVBs[ST_VERTEX_TEXTUREUV], 0, sizeof(D3DXVECTOR2) );
// Set our index buffer as well
pd3dDevice->SetIndices( g_pIB );
// Set A Multistream Vertex Decl insted of FVF
pd3dDevice->SetVertexDeclaration( g_pDecl );
Direct3D 9 でマルチストリーム単一インデックス レンダリングを実行するために必要な作業は以上です。頂点シェーダーは、すべての入力が単一ストリームからのものであるかのように作成されます。
Direct3D 10 でのマルチストリーム単一インデックス レンダリング
Direct3D 10 でマルチストリーム単一インデックス レンダリングを実行する場合も同様の設定を行います。Direct3D 9 と同じ頂点バッファー (位置、法線、テクスチャー座標、代替テクスチャー座標) をそれぞれ作成します。サンプルでは、次に、個別の頂点ストリームを取り込む入力レイアウトを作成しています。目的は同様に、複数の頂点ストリームを 1 つのストリームとして頂点シェーダーに認識させることにあります。
// Create a Input Layout for the MultiStream data.
// Notice that the 4th parameter is the stream index. This indicates the
// VB that the particular data comes from. In this case, position data
// comes from stream 0. Normal data comes from stream 1. Texture coordinate
// data comes from stream 2.
const D3D10_INPUT_ELEMENT_DESC vertlayout_singleindex[] =
{
{ "SV_POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 1, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD0", 0, DXGI_FORMAT_R32G32_FLOAT, 2, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
};
UINT iNumElements = sizeof(vertlayout_singleindex)/sizeof(D3D10_INPUT_ELEMENT_DESC);
D3D10_PASS_DESC PassDesc;
g_pRenderScene_SI->GetPassByIndex( 0 )->GetDesc( &PassDesc );
V_RETURN( pd3dDevice->CreateInputLayout( vertlayout_singleindex, iNumElements, PassDesc.pIAInputSignature, &g_pVertexLayout_SI ) );
レンダリングの前に、すべてのストリームがバインドされていること、インデックス バッファーがバインドされていること、および正しい入力レイアウトが設定されていることを確認する必要があります。3 番目の頂点ストリーム (ストリーム番号 2) は、他のストリームに影響を与えることなく、最初のテクスチャー座標セットか代替テクスチャー座標セットに切り替えることができます。
UINT strides[3];
UINT offsets[3] = {0, 0, 0};
// Set the parameters for MultiIndex or SingleIndex
ID3D10Buffer* pBuffers[3];
...
pd3dDevice->IASetInputLayout( g_pVertexLayout_SI );
pBuffers[0] = g_pVBs[ST_VERTEX_POSITION];
pBuffers[1] = g_pVBs[ST_VERTEX_NORMAL];
if( g_bUseAltUV )
pBuffers[2] = g_pVBs[ST_VERTEX_TEXTUREUV2];
else
pBuffers[2] = g_pVBs[ST_VERTEX_TEXTUREUV];
strides[0] = sizeof(D3DXVECTOR3);
strides[1] = sizeof(D3DXVECTOR3);
strides[2] = sizeof(D3DXVECTOR2);
numVBsSet = 3;
...
pd3dDevice->IASetVertexBuffers( 0, numVBsSet, pBuffers, strides, offsets );
pd3dDevice->IASetIndexBuffer( g_pIB, DXGI_FORMAT_R32_UINT, 0 );
pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
マルチストリーム複数インデックス レンダリング
Direct3D 10 のコードパスでは、異なる周波数で格納された頂点ストリームも使用できます。この異なる周波数で格納された頂点データにアクセスするには、複数のインデックス バッファーが必要になります。しかし、Direct3D 10 には、ユーザーが一度に複数のインデックス バッファーを設定できる API がありません。このマルチストリーム複数インデックス レンダリングを実行するには、やや高度なシェーダー処理を実行する必要があります。
最初にバッファーを作成します。このシナリオでは、5 つのストリームを作成します。内訳は次のとおりです。
- FewVertexPositions:NumVertices の一意の位置を格納します。
- PositionIndices:NumFaces*3 のインデックスを位置バッファーに格納します。
- VertexTextureUV: NumFaces*3 のテクスチャー座標を格納します。
- VertexTextureUV2: NumFaces*3 のテクスチャー座標を格納します。
- FaceNormals: NumFaces の頂点法線を格納します。
FewVertexPosition は NumVertices の位置を格納しますが、PositionIndices、VertexTextureUV、および VertexTextureUV2 は NumFaces*3 の値を格納することに注意してください。また、FaceNormals は NumFaces の値のみを格納します。したがって、このシナリオでは NumVertices != NumFaces*3 になるため、データの周波数に大きな違いが現れます。
位置のインデックスとテクスチャー座標は同じ周波数を共有しているので、どちらも入力レイアウトに追加できます。
// Create a Input Layout for the MultiStream MultiIndex data.
//
const D3D10_INPUT_ELEMENT_DESC vertlayout_multiindex[] =
{
{ "POSINDEX", 0, DXGI_FORMAT_R32_UINT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD0", 0, DXGI_FORMAT_R32G32_FLOAT, 1, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
};
iNumElements = sizeof(vertlayout_multiindex)/sizeof(D3D10_INPUT_ELEMENT_DESC);
g_pRenderScene_MI->GetPassByIndex( 0 )->GetDesc( &PassDesc );
V_RETURN( pd3dDevice->CreateInputLayout( vertlayout_multiindex, iNumElements, PassDesc.pIAInputSignature, &g_pVertexLayout_MI ) );
また、これらはマルチストリーム単一インデックス レンダリングと同様の処理方法で、頂点バッファーとしてバインドします。
pd3dDevice->IASetInputLayout( g_pVertexLayout_MI );
pBuffers[0] = g_pVBs[ST_POSITION_INDEX];
if( g_bUseAltUV )
pBuffers[1] = g_pVBs[ST_VERTEX_TEXTUREUV2];
else
pBuffers[1] = g_pVBs[ST_VERTEX_TEXTUREUV];
strides[0] = sizeof(UINT);
strides[1] = sizeof(D3DXVECTOR2);
ただし、異なる周波数で格納されたデータは、バッファーとして渡す必要があります。
g_pPosBuffer->SetResource( g_pFewVertexPosRV );
g_pNormBuffer->SetResource( g_pFaceNormalRV );
残りの高度な処理は頂点シェーダーで実行します。頂点の位置を入力位置インデックスに基づいて位置バッファーから読み込みます。面の法線は vertexID/3 を使用して法線バッファーから読み込みます。SV_VertexID は入力アセンブラーによって自動的に生成されます。
float4 Pos = g_posBuffer.Load( input.PositionIndex );
float4 Norm = g_normBuffer.Load( input.vertID/3 );