日別アーカイブ: 2008年11月25日

Direct3D11/DirectX11 (13) TessFactor とシェーダーリンクの補足など

●TessFactor と方向の対応

テセレータによる分割数は Hull Shader で指定します。

float	Edge[4]  : SV_TessFactor;
float	Index[2] : SV_InsideTessFactor;

quad の場合上記 6パラメータで指定します。このとき各 TessFactor とテセレータ
出力の uv 値との対応は下記の通り。

                    u          v
SV_TessFactor[0]    0.0        0~1.0
SV_TessFactor[1]    0~1.0     0.0
SV_TessFactor[2]    1.0        0~1.0
SV_TessFactor[3]    0~1.0     1.0

例えば u方向を右向き → 、v方向を上向き ↑ として 2D でレンダリングすると
TessFactor[0][1][2][3] は 左、下、右、上 の順番となります。

 (0,1)  [3]   (1,1)
  ┌─────┐
  │     │
  │     │
 [0]│     │[2]
  │     │
  │     │
  └─────┘
 (0,0)  [1]   (1,0)

InsideTessFactor は下記の通り。

SV_InsideTessFactor[0] uの分割 (u=0~1.0)
SV_InsideTessFactor[1] vの分割 (v=0~1.0)

● Dynamic Shader Linkage の補足

Dynamic Shader Linkage には 2つの大きな変更があります。

(1) シェーダー内の命令の分岐先を外部から切換えられるようになった
(2) HLSL の記述で java 風の class 定義ができるようになった

表面的には (2) の方が大きいように見えますが、本来の目的は動的シェーダーリンク
という名前の通り (1) の方です。
むしろ (1) を実現するために、さまざまな候補の中から (2) の実装方法を選択した
だけだといえるかもしれません。
(詳しくはこちら Direct3D11/DirectX11 (5) WARP の試し方、Dynamic Shader Linkage)

シェーダーによって、ハードウエアのレンダリング動作を自分で記述することが
できるようになりました。
自由度が高まる反面、動作の種類毎に個別の異なるシェーダープログラムを用意
しなければならないという問題も生じました。

例えばライティングアルゴリズムによって数種類。基本的なものだけでも

・環境光源
・スカイライト
・平行光源
・点光源
・スポットライト

等複数存在します。
複数光源を照射する場合、オブジェクトの配置位置によって光源の組み合わせが変わる
かもしれません。例えば屋外だと平行光源が必要ですが屋内だと必要なかったりします。

・屋外用光源シェーダー
 太陽平行光源+環境スカイライト+エフェクト点光源

・屋内用光源シェーダー
 環境光源+点光源×1~4

など。

マテリアルによってはテクスチャをレイヤーで複数重ねたり、それぞれのブレンド式
を変えるかもしれません。
ノーマルマップやレリーフマップを持つ場合、付随して頂点に必要な情報も増えます。

他にも各レイヤー毎に独立した Texcoord (uv) を持たせるのか、テクスチャによって
は共有するのか、パラメータで生成するのかなど。

ゲームで実際に使うことを考えると、法線マップを圧縮したり、アルファチャンネルの
用途をマテリアルによって使い分けたり、場面によって精度を落としたり復号したり、
半透明やテクスチャアルファによる抜きの扱いでシェーダーを分けたり。
影のレンダリングのありなしや、ライトスペースの求め方の違い、フィルタリングの
種類による変更など。

VertexShader でもアニメーションによって、頂点ウエイトの個数、ビルボード化、
ジオメトリインスタンシングへの対応など種類が必要です。

これらをすべて自由に組み合わせられるような汎用的な描画の仕組みを作ると
シェーダーの数は爆発的に増えます。

もちろんシェーダープログラムも外部の情報へアクセスはできますし、分岐やループ
命令もありました。しかしながらシェーダーの組み合わせをによるバリエーション数を
減らすために用意された機能ではなかったことが問題でした。

マテリアル(描画命令)単位で大きな処理の切換えをしたいだけなのに、コード内で
分岐を行うのは少々大げさでです。
最適化の妨げになるし条件判断コードの実行によるパフォーマンスへの影響もあった
ので、どちらを取るか選択を迫られます。
(シェーダーを切換えるための負荷が減るメリットはあります)

Direct3D 11 (Shader Model 5.0) の Dynamic Shader Linkage の導入は
これらの問題を解決するために設けられたものです。
シェーダーのバリエーションを減らして管理しやすくすることが目的で、プログラム内
の命令ジャンプの飛び先を外部から切換えることが可能になりました。

分岐切り替えの粒度も不必要に細かくなく適切で、レンダリング命令単位(マテリアル単位)
で決められるし、その条件判断もシェーダーの外部で一度だけやればいいわけです。

期待が大きい反面、気になる点もあります。

・動的リンクで切換え可能なコードは予め 1つのシェーダーにコンパイルされている必要がある
・最適化への影響

オブジェクトのインスタンスも単なる Buffer へのマッピングに過ぎず、すべて静的に
決まってなければなりません。
非常に巨大な単一のシェーダープログラムができあがる可能性があります。

分岐先の決定は描画時まで遅延されるため、その分 HLSL コンパイラでできる最適化は
減少します。間接ジャンプはインライン化を阻害しますし、結局サブルーチン分の
消費レジスタも予めアロケートしておかなければならないのではないか、との疑問も
生じます。

シェーダーの単なる分岐と本当に違うのか、効果があるのかどうか、
動的リンクによるパフォーマンスの影響はどの程度なのか、
実ハードが出てからあらためて検証する必要がありそうです。

ちなみに D3D11 付属の HLSL コンパイラでは、class 定義だけなら ShaderModel 4.0
以前をターゲットにしても使えます。あくまで表記上の違いだけなので、できることは
今までと変わりません。
動的な飛び先の切り替え (interface 経由の呼び出し) は ShaderModel 5.0 以降のみ
となります。

関連エントリ
Direct3D11/DirectX11 (12) テセレータのレンダーステート他
Direct3D11/DirectX11 (11) 互換性とシェーダーの対応表など
Direct3D11/DirectX11 (10) テセレータの補間
Direct3D11/DirectX11 (9) テセレータによるアウトラインフォントの描画など
Direct3D11/DirectX11 (8) テセレータの動作
Direct3D11/DirectX11 (7) テセレータの流れの基本部分
Direct3D11/DirectX11 (6) D3D11 の ComputeShader を使ってみる
Direct3D11/DirectX11 (5) WARP の試し方、Dynamic Shader Linkage
Direct3D11/DirectX11 (4) FeatureLevel と旧 GPU の互換性、テクスチャ形式など
Direct3D11 (DirectX11) シェーダーの書き込み RWBuffer 他
Direct3D11 の遅延描画、スレッド対応機能、シェーダー命令
Direct3D11 Technical Preview D3D11の互換性、WARP Driver