Multi-Layer Weighted Blended Order-Independent Transparency

前回紹介したWeighted Blended OITは、ポリゴンの距離が離れすぎると半透明の重ね合わせが不自然になる問題があるため、それを解決する方法を考えてみました。
カメラからの距離でポリゴン(ピクセル)をレイヤ分けして描画、最後に遠くのレイヤから合成していくことで問題を解決します。同一レイヤ内にポリゴンが複数存在した場合は、Weighted Blended OITを利用してレイヤの代表値を1つ求めて、その値でレイヤ合成を行います。
レイヤ分けするためにはレイヤ数だけ繰り返し描画する必要がありますが、MSAAの機能を利用して1回の描画で行う方法を考案できたため、比較的簡単に実装できるようになっています(裏技的な使い方です)。


描画結果比較

ソート有無、Weighted Blended OITとの描画結果比較画像です。
ポリゴンが疎らという事もありますがソートした場合とほぼ同じ結果です。ポリゴンが密集した部分が少し違う程度です。Weighted Blended OITは手前の白ポリゴンの影響が強すぎて遠くのポリゴンが白くなりすぎています。

Multi-Layer Weighted Blended OIT

ポリゴン(ピクセル)をカメラからの距離でレイヤ分けすることで大まかなピクセルソートを行い、遠くのレイヤからブレンド合成していきます。レイヤには多数のポリゴンが存在するため、Weighted Blended OITを使用して1つの値にまとめます。各レイヤ境界からの距離でウエイト値を求めるため、狭い範囲での計算となりポリゴン間の距離が離れすぎる問題を回避できます。以下に概念図を示します。

実装

レイヤ分けを行うためには、ポリゴンをレイヤ毎に分割、レイヤ境界でクリップして描画する必要がありますが、処理が複雑になり既存の描画システムに組み込む事が困難です。レイヤ分けを簡単に行うために、マルチサンプルAAのサブピクセルへの書き込み制御機能を利用します。この機能により1回の描画でレイヤ分けを行うことが可能になります(本来の使い方ではありません)。元々は、AlphaToCoverageやポリゴンエッジのマルチサンプル処理を自分で実装するための機能です。
ピクセルシェーダーのSV_Coverageシステム値セマンティクスのビット値で、出力するサブピクセルを指定します。

レイヤ境界での問題

レイヤ境界とポリゴンが重なる部分で下図のような色の境界線ができてしまいます。右側は白ポリゴンと同一レイヤのためWeighted Blended OITで合成、左側は別レイヤのためソート合成となり描画結果に違いが発生します(わざと目立つように重み関数のパラメータを調整)。

レイヤ境界の重ね合わせ

レイヤ境界での問題を解決する(というよりごまかす)ために、レイヤを一部重ね合わせて境界線を目立たないようにします。レイヤ境界付近のポリゴン(ピクセル)を前後2つのレイヤに所属させ境界面からの距離で影響度を求めます。その影響度をα値に掛け算することで境界の色の変化を滑らかにします。

重ね合わせ処理の実装

MSAAでのサブピクセルは1つの値しか出力できないため、レイヤの重ね合わせのためにポリゴンを2回描画する必要があります。ジオメトリシェーダを使用すればシェーダのみで2回描画に対応できます。

重ね合わせ時のα値誤差

単純に重ね合わせると下図左のように元のα値より小さい部分が帯状に現れます。その部分の誤差を補正したものが下図右です。

重ね合わせα値補正

重ね合わせ部分のα値が小さくなるため、ある値nを影響度にかけて補正計算を行います。理論的な根拠はありませんが、うまくいっているようなので使用しています。

描画結果

以上の解決策と重なり幅を調整した描画結果です。境界が目立たなくなっています。

仮想カメラ

最後にWeighted Blended OITでの問題、カメラが移動すると描画結果が変わる問題を改善するために、レンダリングカメラとは別に重み計算専用の仮想カメラを配置します。下図のように仮想カメラをレイヤ境界上だけに配置することで重み計算で使用するレイヤ境界からの距離をレンダリングカメラの位置に関係なく一定にすることができます。ただし、この方法はカメラが前後に移動した場合のみ有効です。回転した場合、画面が大きく変化して描画結果の変化に気づき難いため、特に問題はなさそうです。

まとめ

以上、描画順序に依存しない半透明描画処理Multi-Layer Weighted Blended Order-Independent Transparencyについての説明でした。一応Weighted Blended OIT以外はオリジナルの技術ですが、もしかしたらすでにある技術かもしれません……。
もっと複雑なシーンでの検証が必要ですが、ポリゴンをソートした場合に似た描画結果が比較的低コストで得られるはずです。
MSAAの機能でレイヤ分けを1回の描画で実現できたところで「完成した!」と思ったのですが、そこからが長かった。苦労した分満足のいく結果が得られたと思います。

サンプルプログラム

数字キーの入力で描画方法を切り替え、マウスでカメラの移動ができます。
Multi-Layer Weighted Blended Order-Independent Transparency

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

認証:数字を入力してください(必須) * Time limit is exhausted. Please reload CAPTCHA.