元記事:
blender.org - Irregular Shadow Buffer
イレギュラーシャドウバッファ
旧来(Classical)のシャドウバッファ、5秒でレンダリング。影との境界にジャギーやぼやけがある(クリックで拡大)。
イレギュラーシャドウバッファ。15秒でレンダリング。レイトレース品質の影になっている
今まで Blender でサポートされていた旧来(Classical)のシャドウバッファ(Shadow Buffer)は、Spot Lamp を視点とした Z 値付きの画像を作成し、その Z 値を影を受け取るかどうかを決めるのに使用します。バッファの解像度(Resolution)とクリッピング情報(Clip Sta, End)を丹念に調整することで、影の品質をコントロールできます。
しかし、このシステムは常にバッファサイズの限界に悩むことになり、更にスレッドタイルレンダリングシステムの一部にできず、Scene 全体のためにあらかじめ計算する必要がありました。
最近、いい代替方法の論文がいくつか公開されました。それは、Lamp 視点の正方形の画像を作成する代わりに、レンダリングされたサンプル(画像のピクセル)を "Lamp スペース" にマップし、これらのサンプルを利用して Scene 内の Face に影を投影するかどうか決定します。
この方法は、すべてのサンプルを単純に Lamp スペース内の正方形の X - Y グリッドに格納できないことから、「イレギュラー Z バッファリング(Irregular Z buffering)」と呼ばれています。
(訳注:最後まで Regular をどう訳すか悩みました。現在は正方形ですが、「規則的な」などでもよかったかもしれません)
それぞれのサンプルで影のテストを独立して行うため、その結果は鮮明で、レイトレースシャドウのようにシャープです。この方法が Blender で使用できるようになりました。
これらのイレギュラーサンプルを格納するため、二つの方法が検討されました。一つめの方法は Lamp 毎に固定サイズの X-Y ルックアップテーブルを使用するもので、これには現存のZバッファのスキャンコンバートが再利用できるという利点があります。
二つめの方法は、サンプルをKd木(軸に平行に空間分割した BSP 木)に格納する方法です。
両方法をテストしてみたところ、一つめの方法は簡単に実装でき、比較的早いのですが、固定サイズのテーブルを持つことにより、大きな問題に悩まされます。それは、今後もレンダリング用のテーブルサイズの調整に依存することになることと、極端なケース(ひとつの Lamp で大都市をライティングするなど)で非常にレンダリングが遅くなることです。
二つめの Kd 木を使用する方法は、最速のケースでも若干速度が遅くなることが判明していますが、極端なケースでも速度低下に悩まされることは全くありません。
参照した論文(pdf):
Gregory Johnson et al, University of Texas, Austin.(通常のグリッド方式)
Timo Aila and Samuli Laine, Helsinki University of Technology.(BSP 方式).
イレギュラーバッファの使用
"Shadow and Spot" パネルに、バッファタイプを選択するメニューがつきました。ここでバッファを "Irregular" に設定できます。
通常どおり、クリッピングの開始・終了範囲を指定する必要があります(Clip Sta, End)。ただし、これは Classical バッファタイプほど、影の品質に影響しません。
Biasいまだにこれらの値を設定する主な理由は、"Bias" です。この手のバッファでは Classical シャドウバッファに比べ、バイアスはほんの一部だけなのですが、まだ浮動小数点数の精度の問題を防ぐため、十分大きな値にする必要があります。
デフォルトの Bias 値は '1.0' で、イレギュラーシャドウバッファでは、全深度範囲(Clip Sta から End まで)の0.0005に相当します。Classical シャドウバッファでは、これは0.01にあたります。
注意:この Bias の実装は、改良の候補のひとつであり、状況に依存しない定数になる可能性があります。
スレッディングとメモリ使用この新しいバッファの一番の特長は、タイルがレンダリングされるそれぞれのスレッド内で完全に作成できることです。メモリの確保と解放もスレッド自身の中だけで行えます。特に非常に大きなシーンでは大きなメリットとなります。
実際のシェーディングが発生する前に、影は前の段階で計算されます。Lamp 毎にすべてのサンプルが Kd 木に変換・挿入され、影がチェックされます。最終結果(ピクセル毎の影の値)のみが、シェーディング時に使用するために格納されます。
一つのイレギュラーシャドウバッファに対するメモリのオーバーヘッドは以下の通りです。(1920x1024 HDフレーム、OSA 8、6×4タイル):
- Scene レンダリング毎に通しで使用されるストレージ:0.0 MB
- シャドウバッファ生成:すべてのサンプルのストレージ。
8(OSA)×24(sample size)×81920(タイル毎のピクセル数)=15MB+0.5MB (Kd 木)
- 結果シャドウのストレージ(Lamp毎):4(float)×81920(タイル毎のピクセル)=320KB
シャドウバッファを作成している間のみ、最大量が必要になります。この最大量は Lamp 毎に完全に解放されるため、イレギュラーバッファ量は、結果の影のストレージ量にのみ依存します。
レンダリング時に分割しない場合、この最大量はHD フレームでは簡単に380MBまでいってしまう可能性があることに注意して下さい。
また、イレギュラーシャドウは、それぞれの Render Layer でも再び作成されます。しかし、Classical シャドウバッファの様に、Lamp "Lay" オプションが使用されていない限り、Face に投影されるのはすべての可視 Scene Layer です。このケースでは、可視 Lamp レイヤ内の Face を使用します。
動作しない物…この方法はスキャンラインレンダーシステムのサンプルに直接働くため、イレギュラーバッファによる影の投影は、レイトレースミラー(Raymiror)や、レイトレース透明度(RayTransp)、Solid Halo では視覚化されません。
ソフトシャドウも不可能で、'Halo Step' も動作しません。
デモファイルテスト用の二つのサンプルファイルがダウンロードできます。
download.blender.org/demo/test/2.43/Transparency(半透明)
イレギュラーバッファ作業のおかげで、半透明影の投影サポートが非常に簡単に追加できました。レンダリング時間もほとんど増えません。
現在の実装は、Face 毎に固定の透明度のみサポートしており、テクスチャは評価されません。透明度は "Material" パネル内の新しい Material オプション、"Shad A"(Shadow Alpha)でコントロールできます。
この Monkey の頭部画像は普通の Solid な Mateiral に、Shadow Alpha を0.4にしたものです。
この窓の画像は、ZTransp の Face により半透明の影が落ちている様子を示しています。
一番恩恵がはっきりと判るのは、ZTransp のピクセルがイレギュラーバッファによる影を受ける時です。しかしこれは、レンダリングされるすべてのサンプルが Kd 木 に存在していなければならないことを意味します。複数の半透明レイヤがオーバーラップしているケース(髪の毛の Strand では、100にもなる場合があります)では、メモリのオーバーヘッドが大きくなります。
Solid な Face では、これはシャドウバッファを作成している間だけであり、実際にシェーディングされる前には、メモリはすべて解放されます。
最後の二つの画像は ZTransp Face と半透明の影の様子です。
StrandStrand がイレギュラーバッファ内で正確な幅で影を投影してレンダリングされるかどうかのテスト。短い距離では許容できる影になりますが、Strand が影を投影する場所から遠く離れている場合は、エリアシングが発生します。
Strand に対するイレギュラーバッファシャドウのテストは良好だったのですが、Ztransp Strand のレンダリング時間が、特に100以上の Strand が一つのピクセルに重なる場合、非常に長くなります。このケースでは、これらすべてのサンプルが見えていなくても、Kd 木 に挿入し影の判定を行う必要があります。
Strand の影には、通常のシャドウバッファを使用した方がいいでしょう。シャドウバッファシステムを詳しく調査する時かもしれません…。
実装について
イレギュラーバッファシャドウのメイン関数は以下のとおりです。
void ISB_create(RenderPart *pa, struct APixstr *apixbuf);
void ISB_free(RenderPart *pa);
float ISB_getshadow(ShadeInput *shi, ShadBuf *shb);
'create' と 'free' 関数は部分レンダリング中で、実際の Solid と Z-Transparent レイヤのシェーディング前と後にのみ呼ばれます。これらの関数はすべての Lamp を反復し、必要に応じてバッファを作成します。
バッファの作成は以下のステップからなります。
- サンプルバッファ作成。OSA パス毎とピクセル毎に、1サンプルの構造体のメモリが確保されます。これらのサンプルは Lamp バッファ内で可視かどうか判定されます。
- サンプルを Kd 木 へ追加。可視サンプルのみを追加します。Kd 木の挿入は再帰的に行われ、そしてサンプル数が閾値(現在は128)に達すると別のノードに分離されます。確実にバランスのいい木にするため、この Kd 木をまず16×16に均等に分割し、その後サンプルを擬似乱数の順序で追加します。
- Face の判定。Face は Lamp スペースに変換され、まず範囲内かを調べ、そして再帰的に Kd 木に接触しているかをテストします。四角形、三角形、Strand は各々別々に処理されます。すべての Face が常にすべてのサンプルについて判定を行っているため、 "Shadow Alpha" の判定はすぐです。
元記事:
blender.org - Irregular Shadow Buffer