DirectX10 始めました -第2回-

前回は初期化およびクリア処理までだったので、
今回は最初の三角形をだす部分までをやってみます。

■ 頂点バッファの準備

DirectX10では頂点およびインデックス格納には、バッファオブジェクトが必須です。
以前のDrawPrimitiveUPとかが消えてしまったので。
今回はインデックスを使わずに頂点バッファだけを準備します。

[cpp]
struct Vertex {
D3DXVECTOR3 Pos;
DWORD Color;
};
// 1. 頂点バッファを用意する
// 1.1 頂点バッファそのものの設定
D3D10_BUFFER_DESC descVB;
ZeroMemory( &descVB, sizeof(descVB) );
descVB.Usage = D3D10_USAGE_DEFAULT;
descVB.ByteWidth = sizeof(Vertex) * 3;
descVB.BindFlags = D3D10_BIND_VERTEX_BUFFER;
ID3D10Buffer* pVertexBuffer = 0;
// 頂点バッファに送る実データ
Vertex vbdata[] = {
D3DXVECTOR3( 0.0f, 0.0f, 0.0f ), 0xffffffff,
D3DXVECTOR3( 1.0f, 0.0f, 0.0f ), 0xffff0000,
D3DXVECTOR3( 0.0f,-1.0f, 0.0f ), 0xff00ff00,
};
// 1.2 頂点バッファの中身に対する設定
D3D10_SUBRESOURCE_DATA subdataVB;
ZeroMemory( &subdataVB, sizeof(subdataVB) );
subdataVB.pSysMem = vbdata;
// 1.3 頂点バッファの作成
hr = pDevice->CreateBuffer( &descVB, &subdataVB, &pVertexBuffer );
[/cpp]

バッファの作成時に、データを設定することが出来ます。
D3D10_USAGE_IMMUTABLEでバッファを作成すると、この初期化タイミングでしかデータを設定することが出来ません。

他に使いそうなフラグとしては、D3D10_USAGE_DYNAMIC, D3D10_USAGE_STAGING があります。
後者の設定は、GPUからCPUにデータを書き戻すときに使用します。

概念自体は従来と変更無く、頂点バッファを作成して、
その中身をサブリソースという設定に従って書き込むという感じでしょうか。

■ シェーダーの準備(C++側)

ピクセルシェーダー側もほとんど同じなので、ここでは頂点シェーダーだけ説明します。
DX9の頃と変わりなく、シェーダーファイルを読み込んでコンパイルさせ、
そのデータからシェーダーを作成します。

注意点は、頂点シェーダーのシェーダーバイナリである pBlobVSというデータは、
後段で使用するため破棄してはいけません。このあたりがDX9のころと大きく変わっています。

[cpp]
ID3D10Blob* pBlobVS = 0;
ID3D10Blob* pErrMsg = 0;
D3DX10CompileFromFile(
L”shader.vs”, NULL, NULL, “mainVS”, “vs_4_0″,
D3D10_SHADER_ENABLE_STRICTNESS| D3D10_SHADER_PACK_MATRIX_COLUMN_MAJOR,
0, NULL, &pBlobVS, &pErrMsg, &hr );
if( pErrMsg ) {
OutputDebugStringA( (const char*)pErrMsg->GetBufferPointer() );
OutputDebugStringW( L”\n” );
DebugBreak();
}
ID3D10VertexShader* pVertexShader = 0;
pDevice->CreateVertexShader(
pBlobVS->GetBufferPointer(),
pBlobVS->GetBufferSize(),
&pVertexShader );
[/cpp]

■ シェーダーの準備(C++) その2

頂点シェーダーのコンパイル結果から、入力レイアウトを作成します。
これは、従来のVertexDeclarationに相当します。

[cpp]
// 頂点入力の要素情報.
// 入力レイアウトオブジェクトはシェーダーのバイトコードを要求する
D3D10_INPUT_ELEMENT_DESC layout[] = {
“POSITION”, 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0,
“COLOR”, 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0,
};
ID3D10InputLayout* pInputLayout = 0;
pDevice->CreateInputLayout( layout, 2, pBlobVS->GetBufferPointer(), pBlobVS->GetBufferSize(), &pInputLayout );
[/cpp]

■ シェーダーファイル

頂点シェーダー、ピクセルシェーダーはこんな感じで作成しました。
今回は最低限で作成するため、定数レジスタは未使用です。

[cpp]
struct VS_INPUT {
float3 Pos : POSITION;
float4 Col : COLOR0;
};
struct VS_OUTPUT {
float4 Pos : SV_POSITION;
float4 Col : COLOR;
};
VS_OUTPUT mainVS( VS_INPUT _In ) {
VS_OUTPUT Out = (VS_OUTPUT)0;
Out.Pos = float4( _In.Pos, 1 );
Out.Col = _In.Col;
return Out;
}
float4 mainPS( VS_OUTPUT _In ) : SV_TARGET {
return _In.Col;
}
[/cpp]

■描画処理

今まで準備した各データを設定して描画コールするだけです。

[cpp]
// クリア処理
float clearColor[4] = { 0.5f, 0.0f, 0.0f, 0.0f; };

pDevice->ClearRenderTargetView( pRenderTargetView, clearColor );
pDevice->ClearDepthStencilView(
pDepthStencilView,
D3D10_CLEAR_DEPTH |D3D10_CLEAR_STENCIL,
1.0f, 0 );
// バッファのセット
UINT strides[1] = sizeof(Vertex);
UINT offsets[1] = 0;
pDevice->IASetVertexBuffers( 0, 1, &pVertexBuffer, strides, offsets );
pDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
pDevice->IASetInputLayout( pInputLayout );
// シェーダーのセット
pDevice->VSSetShader( pVertexShader );
pDevice->PSSetShader( pPixelShader );
// 描画
pDevice->Draw( 3, 0 );
pSwapChain->Present( 0, 0 );
[/cpp]

■結果

HelloDX10_2 ソースコード

今回の結果プレビューはこんな感じ

■ 苦労したポイント、ひっかかったポイント

今回はいろいろと罠に引っかかりました。
同じように誰かが引っかからないように、また自分の防備録としてここにポイントを記載します。

* 頂点入力は正しい?

シェーダー内で float4 Col : COLOR などと受け取っていると忘れてしまいがち。
この中には正規化した 0.0-1.0の値が格納されてくること、
頂点データ内にあるときには、各要素8ビットのRGBA値が入っていること期待している。
そのため、頂点カラーは DXGI_FORMAT_R8G8B8A8_UNORMにして入力レイアウトを作成しなくてはならない。

従来 DWORDで送っていたために、つい頂点カラーは DXGI_FORMAT_R8G8B8A8_UINTにしてしまいそうだが、
これをやってしまうと、シェーダーとレイアウトの不一致が起こり描画されない結果となる。

* シェーダーはあってる?

いろいろと出力セマンティクスが変わっている。
ここに注意しないと、絵が描画されない結果につながる。

頂点シェーダーからの位置出力

SV_POSITION というセマンティクスで出力する。
従来の POSITION セマンティクスを使ってもコンパイル失敗しないため要注意である。

また色情報については、SV_TARGET というものになっており、
従来の COLOR セマンティクスは有効でないため位置と同じ失敗はしない。

DirectX プログラミング
すらりんをフォローする
すらりん日記

コメント

タイトルとURLをコピーしました