bate's blog

調べたこと実装したことなどを取りとめもなく書きます。

tutorial02

三角形の描画サンプルでした。
誤魔化しつつ日本語にした。



Tutorial 2: Renderaing a Triangle


前のチュートリアルで単色ウィンドウの最小のDX11アプリを作った。
ここでは、画面に一つの三角形を描画するためにアプリケーションを拡張する。
三角形と関係するデータ構造を準備するプロセスを体験する。


このチュートリアルの結果は、ウィンドウの中心に三角形を表示したウィンドウだ。


三角形の要素
三角形は、頂点と呼ばれる3つの点で定義される。
固有の位置を持つ3つの頂点セットは、固有の三角形を定義する。
2次元を例にすると、(0,0),(0,1)そして(1,0)の位置を持つ3つの頂点をGPUに渡すと、
GPUは、三角形を表示するのに十分な情報を得る。


そして今、三角形を表示するために3つの位置をGPUに渡す。
どうやってこの情報をGPUに渡すか?
DX11では、位置のような頂点情報はバッファリソースに格納される。
頂点情報を格納するのに使われるバッファは単に頂点バッファと呼ばれる。
3つの頂点に十分な大きなの頂点バッファを作り、頂点位置を詰めなければならない。
DX11では、バッファリソースを作る時、バイト単位でバッファサイズを明確にしなければならない。
3つの頂点に十分な大きなでなければならないことが分かったが、
各頂点は何バイト必要なのか?
この質問に答えるには、頂点レイアウトを理解する必要がある。


入力レイアウト
頂点は位置を持つ。
しばしば、法線や色、テクスチャマッピングに使うテクスチャ座標などのその他の属性を持つこともある。
頂点レイアウトは、これらの属性をどのようにメモリに配置するかを定義する。
各属性が使うデータタイプは何か、各属性がもつサイズはいくつか、メモリでの属性の並びなど。
なぜなら属性は普通、異なる型を持つからだ。それは、C言語の構造体に似ている。
頂点は通常、構造体で表現される。
頂点のサイズは便利なことに構造体のサイズから得られる。


ここでは、頂点の位置だけを見る。
それゆえ、XMFLOAT3という型の単一フィールドの頂点構造を定義する。
この型は、3つのfloat-pointという構成要素の頂点で、3Dでの位置に使われる典型的なデータタイプです。


今、頂点を表す構造体を得た。
アプリケーションのシステムメモリに頂点情報格納を管理する。
しかし、頂点を構成する頂点バッファをGPUに渡す時、メモリの塊を渡しているに過ぎない。
GPUはバッファから正しく入力レイアウトを展開するために頂点レイアウトを知らなければならない。
これを達成するには、入力レイアウトを使う必要がある。


DX11では、入力レイアウトはGPUがある程度頂点構造を理解できるように記述されたDirect3Dオブジェクトである。
各頂点属性は、D3D11_INPUT_ELEMENT_DESC構造で記述されている。
アプリケーションは1つかそれ以上のD3D11_INPUT_ELEMENT_DESCの配列を定義し、
全体として頂点を記述する入力レイアウトオブジェクトを作るために配列を使う。
D3D11_INPUT_ELEMENT_DESCのフィールドを詳細に見る。


SemanticName
セマンティック名はこの要素の目的か本質を表す言葉を含む文字


SemanticIndex
セマンティック名の補完。同じセマンティック名の場合に対応するために番号を振る
COLOR0, COLOR1とか


Format
この要素で使われるデータタイプを定義する
DXGI_FORMAT_R32G32B32_FLOATとか


InputSlot
この要素にフェッチするべき頂点バッファをGPUに教える


AlignedByteOffset
GPUにこの要素のデータをフェッチするメモリの開始点を教える


InputSlotClass
Instancingに使う


InstanceDataStepRate
Instanceingに使う。


頂点レイアウト
次のチュートリアルでは、テクニックオブジェクトとシェーダー関連を説明する。
今は、テクニックのためにDirect3D頂点レイアウトオブジェクトを作ることに集中する。
しかし、頂点レイアウトと密接に間益する頂点シェーダーを学ぶ。
理由としては、頂点レイアウトオブジェクトを作ることは頂点シェーダーの入力サインを必要とするからだ。
頂点シェーダーの入力サインを表現するバイナリデータを回収するD3DX11CompileFromFile()からの戻り値である
ID3DBlobオブジェクト使う。
このデータを得れば、頂点レイアウトオブジェクトを作るために、
ID3D11Device::CreateInputLayout()を呼べる。
そして、アクティブな頂点レイアウトとして設定するために、ID3D11DeviceContext::IASetInputLayout()を呼べる。


頂点バッファの作成
初期化中に必要なことの一つは、持っている頂点データから頂点バッファを作ること。
DX11で、頂点バッファを作るためには、D3D11_BUFFER_DESCとD3D11_SUBRESOURCE_DATAの2つの構造体を設定し、
それからID3D11Device::CreateBuffer()を呼ぶ。
D3D11_BUFFER_DESCは作られる頂点バッファを説明し、
D3D11_SUBRESOURCE_DATAは作成時に頂点バッファにコピーされる実際のデータを説明する。
頂点バッファの作成と初期化は、一度だけで済むので、以後バッファの初期は必要ない。
頂点バッファにコピーされるデータは頂点、自作の頂点構造体の配列です。
頂点配列の座標は選ばれる。シェーダーで描画した時にアプリケーションウィンドウの中央に三角形を見るために。
頂点バッファを作った後、デバイスにつなげるためにID3D11DeviceContext::IASetVertexBuffers()を呼べる。


プリミティブの接続形態
プリミティブ接続形態は、三角形の描画に必要な3つの頂点をGPUがどのように得るかを言及する。
1つの三角形を描画するために議論した。アプリケーションはGPUに3つ頂点を送る必要がある。
それゆえに、頂点バッファは3つの頂点を持つ。
三角形を2つ描画したい場合はどうか?
1つは、6つの頂点をGPUに送ることだ。
最初の3つの頂点が最初の三角形を定義し、次の3つの頂点が2つ目の三角形を定義する。
この接続形態を三角形リストという。
三角形リストは簡単に理解できる利点がるが、いくつかのケースで非効率だ。
頂点を共有した三角形を連続で描画するケースがそれにあたる。
2つ目の三角形を描画する時に、頂点バッファから3つの全頂点をフェッチする代わりに前の三角形から2つの頂点を使えば、
フェッチする頂点が1つだけになることをGPUに教えられれば頂点バッファはより小さくなる。
これを三角形ストライプという。
三角形ストライプを描画する時、一番最初の三角形は秒店バッファの最初の3つの頂点で定義される。
次の三角形は前の三角形の最後の2つの頂点に頂点バッファの次の頂点を足したもので定義される。


三角形描画
不足していた最後の項目は、実際の三角形を描画する処理のコードだ。
レンダリングのために頂点シェーダーとピクセルシェーダーの2つのシェーダーを作った。
頂点シェーダーは三角形の個別の頂点を正しい位置に変換することに責任を持つ。
ピクセルシェーダーは三角形の各ピクセルの最終出力の色を計算することに責任を持つ。
次のチュートリアルで詳細を述べる。
これらを使うために、ID3D11DeviceContext::VSSetShader()とID3D11DeviceContext::PSSetShader()を呼ばなければならない。
最後に、ID3D11DeviceContext::Draw()を呼び、
現在の頂点バッファ、頂点レイアウト、プリミティブ接続形態を使ってレンダリングするようにGPUに命令する。
Draw()の第一引数はGPUに送る頂点の数、第二引数は伝達が始まる最初の頂点のインデックス。
3と0をパラメータとして使うことで、1つの三角形をレンダリングし、それは頂点バッファの最初からレンガリングする。