月別アーカイブ: 2007年11月

Direct3D 10 ShaderModel4.0 Stencil Routed A-Buffer とお詫び

ここしばらく半透明描画などの方法についていくつか考えたことを紹介して
きました。
Direct3D 10 ShaderModel4.0 ピクセル単位の半透明ソートを行う
Direct3D 10 ShaderModel 4.0 半透明ソート補足

浮動少数への畳み込みは、丸め込みの桁上がりの解決が必要なこと、仮数部の
情報量が限られていて格納時の効率が悪いこと、レイヤー数に上限があること
演算に Blend 機能を使うためRead 帯域をかなり消費するなどろいろと制限が
あります。
ところがドキュメントを調べていて非常良い方法があることがわかりました。

NVIDIA SIGGRAPH 2007 Stencil Routed A-Buffer

Multisample のハードウエアの機能を、非常に効率よく使った手法です。

最初説明でも書いたとおり、フレームバッファに値を蓄積するためには
直前の出力を受け取る必要があります。現状これが可能なのは

・RenderTarget Blend
・DepthStencil

の2つだけです。Blend の場合は値の演算ができるものの、Depth や Stencil
はテストと更新だけに限られます。またテストの結果は描画するしないの
bool 判定であり、MRT 等で複数の出力を持っていても同じ結果が反映されます。
MRT すべて書くか、すべて書かないかの二通りしかできません。

もし MRT 毎にそれぞれ異なる Stencil Test や Stencil Operation が設定
できれば、かなりできることが広がるでしょう。無理やり浮動少数の演算に
押し込めていた履歴による値の選択と切り捨てが、もっときれいに実装できる
ようになるはずです。

Stencil Routed A-Bufferはまさにこの、複数の出力に対する異なる
Stencil Test を実現可能にします。

Multisample anti-aliasing は数倍の解像度のフレームバッファにレンダ
リングします。このとき Shader 自体の pixel 出力は同一の値が用いられる
点が Supersample と異なります。
これを利用すると、同じ値を一度に複数書き込む手段として活用することが
できるわけです。

Multisample で8倍などの高解像度 RenderTarget を実現するには、
同じように Zバッファも必要です。付随して Stencil も同じ分だけ持っている
ことになります。
Stencil Test や Stencil Operation は全 pixel 同じ操作となりますが、
Stencil の初期値をずらすことで各ピクセル個別に操作することができる
ようになります。
これでピクセルごとに描画回数の保存と、回数に依存した書き込むピクセルの
選択が可能となりました。

あとは書き込まれた値に個別にアクセスする手段があれば十分です。
アクセス手法は後ほどもう少し調べます。

この辺の機能もやはり Direct3D 10.1 では Multisample 周りの機能が拡張
されていくようです。Programmable AA sample Pattern にしても、この辺を
踏まえての機能拡張だったのかもしれません。

とにかく GPU のハードウエア機能を活用するだけで、ほぼ要求を満たして
いることになるので非常にすばらしいです。まだ試していませんが、
かなり使える手法です。いろいろ実験してみたいと思ってます。

というか今更ですが、全くこれらのメジャーな文献を読んでいなかったことが
本当に信じられないくらい恥ずかしい限りです。

全くの無知のまま、いろいろ書いていた説明の数々、一応読んでくださった方
親切に無視してくださった方、
そしてこれら Realtime Graphics の研究に携わっている先人の方々に深く
お詫び申し上げます。

ごめんなさい。

Direct3D 10 ShaderModel4.0 偏光板シェーダー

前回ピクセル単位で、半透明のソートを行うシェーダーを作成しました。
Direct3D 10 ShaderModel4.0 ピクセル単位の半透明ソートを行う
Direct3D 10 ShaderModel 4.0 半透明ソート補足

レンダリング時にはカラー値をためておくだけにして、最後にシェーダーで
一気に Z ソートして合成をかけます。

そのため常に順番が正しく描画されることと、ピクセル単位なので交差
しようが自分自身と重なろうが、描画が矛盾しないという特徴があります。

他にも、最後の Blend をシェーダーで求めているため、通常のハードウエア
Blend だけでは表現できない複雑かつ高度な半透明合成ができるという利点も
あります。

今回はその点に着目して偏光板を作ってみました。

polarization shader

単純な板なので、実際に走らせて動いているところを見ないと少々わかり
にくいかもしれません。ダウンロードは下記からどうぞ。

wheelhandle_ss11t.zip

[SPACE]    pauge 一時停止
[U]        + Plane 追加
[D]        - Plane 削除
[Up]       camera up
[Down]     camera down
[Left]     rotate
[Right]    rotate

今回シミュレートしているのはあくまで偏光板同士の透過率の変化です。
背景画像など、一般の映像をカメラなどの偏光フィルターを通した場合の
表現ではない点にご注意ください。

この偏光板シェーダーは、透明度として Alpha の代わりに Tangent Vector を
用います。
ソートのあと、順番に Blend 合成するときに 2枚の偏光板同士の位相に応じて
透明度が変化します。

  TV  = Tangent Vector
  Tr  = Transparency

  blendf= saturate( 1.0f - abs( dot( TV[i-1], TV[i] ) ) * Tr )

透過度の最大値を Tr で与えています。0 または 180度で透過度が最大と
なり、90度ずれると 0% になります。

上記のように、2ピクセル間の関連性でのみ透過度を求めます。そのため、
2枚重なったエリアよりも 3枚以上重なったエリアの方が透過度が上がる
(明るくなる)ことがあります。

例えば A と C が 90度ずれている場合透明度は 0% で真っ黒になります。
ところが間に 45度ずれた B を挿入すると透過度が上がります。

A --------90--------- C   0%

A ---45--- B ---45--- C   50%

A と C の間は真っ黒なのに、B など斜めの板が重なってるエリアは
明るくなっているのがわかるでしょうか。(Aが手前、Cが奥です)

polarization shader

これは現実の偏光板でも起こる正しい現象のようです。

パラメターが増えたために、MRT は 6 枚使っています。
フレームバッファ 1pixel 96byte もあります。

データがただの板でわかりにくいですが、ソートされているのでカーソルキー
左右で回転などしても大丈夫です。ちなみに板の裏面は色つきです。