連載 .NET&Windows Vistaへ広がるDirectXの世界 第7回 プログラマブル・シェーダによる積極的なGPUの活用 NyaRuRuMicrosoft MVP Windows - DirectX(Jan 2004 - Dec 2007) 2007/05/08 |
|
■頂点ストリーム→頂点インプット
頂点シェーダの入力に当たる頂点インプットのデータ構造は、ユーザー定義構造体のようにカスタマイズすることができる。具体例として、サンプル1で使用している頂点シェーダの頂点インプット構造体VertexInを見てみよう。この構造体定義は、C#のソース・コードではなくエフェクト・ファイルにHLSLを用いて記述されている。サンプル1のSimple.fxをご覧いただきたい。
|
|
頂点シェーダの頂点インプット構造体VertexIn(HLSLによる記述) | |
HLSLでの構造体定義はC言語とよく似ているが、フィールド名の後のコロン記号に続けてPOSITIONやTEXCOORD0という記述があるのが目新しい。 これはセマンティクスと呼ばれるメタデータの一種で、今回はフィールドのUsage(用途)を記述するために使用する。 |
先ほど頂点ストリームにセットした頂点バッファは、型情報の失われたBLOB(Binary Large OBject)である。このBLOBのデータ構造と、頂点インプット構造体の各フィールドの対応を記述するスキーマが、XNA FrameworkのVertexDeclarationクラスだ。
VertexDeclarationクラスのコンストラクタには、頂点の各要素の対応関係を表すVertexElementオブジェクトの配列を指定する。対応関係1つに付き、その情報を含んだVertexElementが1つ存在する。
// 作成 |
ここで、VertexElementコンストラクタ・パラメータは、次のような意味を持っている。
VertexElement( | |
ストリーム番号, 要素先頭からのバイト・オフセット, データ型, | |
テッセレーション属性, | |
用途, 同一用途の区別用ID) |
例えば、上の例で示したVertexDeclarationクラスは2つの要素のVertexElement配列をパラメータに取るが、その意味を図に表してみた。
VertexElement配列により表される対応関係 |
サンプル・コードで使用しているVertexElement配列の意味を説明すると、次のようになる。 ・ストリーム0番の頂点要素には、先頭から0bytes目にVector2型のデータが存在する。データの用途(Usage)は0番目のPosition。 ・ストリーム0番の頂点要素には、先頭から8bytes目にVector2型のデータが存在する。データの用途(Usage)は0番目のテクスチャ座標。 ストリーム番号に0以外を選ぶことで、複数の頂点ストリームのデータを集約することもできる。SQLでいえば、複数のテーブルを参照したときのSelect文に近いだろう。 最後のパラメータ(同一Usage区別用のID)は、マルチ・テクスチャでの複数のUV座標など、同じ用途で複数のデータを持つときに使用する。例えば頂点ごとにテクスチャUV座標を2セット持つとすれば、ここに0と1を指定することで、それぞれTEXCOORD0とTEXCOORD1に対応付けることができる。 なお、頂点バッファ上の要素のデータ型と、マッピングされたHLSL要素のデータ型は、必ずしも厳密に一致する必要はない。例えばVector2型からfloat3型に拡張したり、逆にVector4型からfloat2型へ縮小したりといった、いくつかの標準的なデータ変換がデフォルトでサポートされている。 |
頂点バッファ→頂点ストリーム→頂点インプットと、データがどのように転送されるかが分かったところで、いよいよ頂点シェーダの実装に移ろう。
■頂点インプット→頂点シェーダ→頂点アウトプット
頂点シェーダとは何かをひと言でいえば、ある頂点インプット構造体VertexOutから頂点アウトプット構造体VertexInへの変換を記述した関数ということになる。.NETの世界では、Converter<VertexOut, VertexIn>デリゲートに適合するメソッドといえばイメージが沸きやすいだろうか。
頂点インプット構造体VertexInがカスタマイズできたように、頂点アウトプット構造体VertexOutもユーザー定義構造体として定義できる。今回は、次のような頂点アウトプット構造体VertexOutを定義した。
|
|
頂点シェーダの頂点インプット構造体VertexOut(HLSLによる記述) |
頂点シェーダの最も重要な役割は、その頂点がスクリーン上のどこに出力されるかを決めることだ。頂点アウトプット構造体は、従って、スクリーン上の出力位置を表すフィールドを必ず含んでいなければならない。出力位置を表すフィールドは、POSITION Usageによってマークしておく。
UVフィールドにはTEXCOORD0 Usageが指定されているが、POSITION以外のUsageが設定された出力値は、ラスタライズ後のピクセル・インプットとの連結に使用する。これについては次の章で述べることにしよう。
さて、POSITION Usageによってスクリーン上の出力位置を指定すると述べたが、このときの座標系はやや特殊で、同次座標(X, Y, Z, W)というものを用いる。同次座標系の点(X, Y, Z, W)は、スクリーン座標系の点(x,y,z)と、
(x, y, z)=(X/W, Y/W, Z/W)
という関係で結ばれる。ただし今回のサンプルでは3Dを扱わないので、詳細については割愛させていただくことにしよう。今回の範囲内では、W=1で固定することで、スクリーン座標系の値を直接出力していると理解しておけばよい。
ビューポートとスクリーン空間の関係 |
W=1に固定したときは、左図のようなスクリーン座標系の値がそのままX,Y,Zに指定されると思えばよい。 ビューポートとはクライアント領域中の描画対象領域で、デフォルトではクライアント領域全体である。 左図の座標の範囲外に描画した場合は何も表示されない。また、ビューポートのサイズ・形状によらず、スクリーン空間の有効範囲は一定である。 深度バッファ(Zバッファ)が有効なときは、奥行きを考慮した塗りつぶしが行われる。 |
実際、今回作成した頂点シェーダは、インプットから渡されたXY座標に、Z=0とW=1を付け加えるだけという単純なものだ。
|
|
シンプルな頂点シェーダ |
なお、同次座標系が理解できないと3Dゲームが作れないかというと、そんなことはないので安心していただきたい。細かい数学的な計算を自分で行わなくても、必要な変換行列の作成はすべてライブラリに任せることができる。そのあともmul関数を用いてベクトルを行列で変換するだけなので、ほとんどの場合、出力座標の計算は1行で完了する。
一般に、頂点シェーダの実行順序は表示結果に影響を及ぼせないようになっている。そのおかげで、頂点シェーダを並列に実行し、複数の頂点を同時に処理することが可能なのだ。
INDEX | ||
.NET&Windows Vistaへ広がるDirectXの世界 | ||
第7回 プログラマブル・シェーダによる積極的なGPUの活用 | ||
1.トピックの由来とサンプル・コード | ||
2.描画の流れ(1) | ||
3.描画の流れ(2) | ||
4.描画の流れ(3) | ||
5.描画の実行 | ||
「.NET&Windows Vistaへ広がるDirectXの世界」 |
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|