ResponsiveAAの挙動

先日の勉強会にて、ある人物からResponsive AAの挙動がどうにもドキュメントに書いてあることと違う気がする、と言われました。

Responsive AAについて最も詳しく書いてあるドキュメントは、以下の雪のシーンに関するものでしょう。

https://docs.unrealengine.com/latest/JPN/Resources/Showcases/Effects/SnowExamples/index.html

また、こちらのマテリアルプロパティに関するページも有用です。

https://docs.unrealengine.com/latest/JPN/Engine/Rendering/Materials/MaterialProperties/index.html

これらのドキュメントから察するに、小さな雪のようなパーティクルではTemporal AAによって輪郭が崩れ、存在が認識されづらくなってしまうので、それを回避するためにResponsive AAを有効にするべきという感じに読み取れます。

しかし、Responsive AAを有効にしても透過された部分で普通にTemporal AAが有効になっているようにも見えるし、そうするとそもそもResponsive AAってなんなのよ?という疑問が上がったわけです。

勉強会ではこの部分を調べましたので、知識共有としてブログにまとめようと思った次第です。

その前に、Temporal AAについて簡単に解説します。

先日の勉強会でもわからないという方がそれなりにいましたし、描画担当でもなければわからない部分でもありそうですので。

ポリゴン描画によって塗りつぶされるピクセルはどのように決定されるかというと、ピクセル中にあるサンプリングポイントという点がポリゴン内部にあるかどうかで決まります。

通常、このサンプリングポイントはピクセル中心なのですが、最近の大半のハードウェアで実装されているMSAAではこのサンプリングポイントが複数定義されます。

4xMSAAなどの言葉を聞いたことがある方もおられると思いますが、この場合はサンプリングポイントが4つになります。

この複数のサンプリングポイントの内いくつのポイントをポリゴンが内包するかどうかによってそのピクセルの色が決定されるのがMSAAという技術です。

例えば4xMSAAで、赤い色のポリゴン(R:1, G:0, B:0)が4つのポイントの内2つを内包していると仮定します。

また、残りの2点は一切何も描画されず、背景のクリアカラーとして設定されている青(R:0, G:0, B:1)色が設定されているものとします。

この場合、(赤 + 赤 + 青 + 青) / 4という計算が行われ、結果は (R:0.5, G:0, B:0.5)というカラーになる、という寸法です。

ue278.jpg

しかしこのMSAAはDeferred Renderingで特に弱いですし、バッファ量が増えるなどの弱点も多いため、UE4ではゲーム中のAA手法としてMSAAは採用していません。

その代わりに推奨されているのがTemporal AAです。

MSAAが1回の描画でピクセル内の複数のサンプリングポイント(サブピクセルと呼ばれる)を調べているのに対して、Temporal AAでは1回の描画では1つのサンプリングポイントしか計算しません。

ただし、毎フレーム、サンプリングポイントがずれるようにスクリーンを微妙に動かしています。

これによって時間軸方向にサブピクセルをサンプリングしてブレンドし、結果としてアンチエイリアスを実現するのがTemporal AAというわけです。

しかし、小さくて動くものは同じ場所にとどまることがほとんどないです。

まさにドキュメントにあるような雪片などはTemporal AAの効果で消えてしまうこともあります。

これを避けるのがResponsive AAなのですが、そもそもどういう原理で動いているのか疑問もありました。

というわけで、続きからこの原理を解説します。

まず、Responsive AAの設定ですが、これはマテリアルの詳細パネルから行います。

詳細パネルの[Translucency]→[Responsive AA]をONにすると有効になります。

デフォルトはOFFです。

ue279.jpg

これがONになると何が行われるのか、それを描画の順序に合わせて説明していきます。

まず、半透明マテリアルを描画するときに通常とは別の処理が走ります。

カラーの描画やライティングについては同一なのですが、唯一ステンシルバッファの処理が異なります。

ステンシルバッファとはカラーバッファやGBuffer、深度バッファとも異なるバッファですが、基本的に深度バッファにくっついているバッファです。

このバッファは8ビットの整数値を格納するバッファで、モデルを描画する際に描画されたピクセルに対して一律の処理を行うことが出来ます。

この処理は基本的にステンシルバッファへの書き込みと比較によるマスクが主です。

例えば、書き込まれたステンシルバッファの値が一定値以上ならそのピクセルにはポリゴンが描画されなくなる、といった設定が可能になっています。

Responsive AAがOFFの場合はステンシルバッファへは何も書き込みませんし、比較も行いません。

しかしONの場合は別で、この場合は半透明マテリアルが描画できたピクセルのみ、ステンシルバッファの値を1に設定しています。

これにより、Responsive AAありのマテリアルが描画されなかった部分がステンシル0、描画された部分がステンシル1となります。

その後色々処理があった後、Temporal AAの描画が行われます。

通常であれば1回だけしか行われないTemporal AAは、Responsive AAが1回以上描画されるとTemporal AAの処理が2回走るようになります。

1回はステンシル0の部分、もう1回はステンシル1の部分に対して行われます。

下の図はTemporal AAが処理される直前のスクリーンショットです。

ue280.jpg 

赤い三角柱はResponsive AAがONの半透明マテリアルが適用されています。

次に1回目のTemporal AAが適用された直後のスクリーンショットです。

ue281.jpg

見事に半透明マテリアルの部分がくり抜かれています。

最後に2回目のTemporal AAが描画された直後のスクリーンショットを見てみましょう。

ue282.jpg

ご覧のように、くり抜かれた部分でTemporal AAが有効になって描画されました。

さて、Temporal AAを2回別々に適用することで何が起こるのでしょうか?

もちろん、この2回のTemporal AAがどちらも同じ処理を行っているのだとしたら、1回のTemporal AAをかけた場合と何ら変わりません。

実は2回目のTemporal AAは通常のものとは少し異なった処理が行われています。

具体的な違いは、現在フレームと前回までの結果のブレンド割合です。

通常のTemporal AAでは様々な要因から計算したブレンド値が用いられますが、基本的にそれほど大きな値にはなりません。

16フレームくらいですべてのサンプリングポイントを再現するのだとすると、現在フレームのブレンド値は当然”1/16”になります。

実際にはこの値にはならないものの、前回フレームとの間で大きな変化がない場合はほぼこの程度のブレンド値で処理されるはずです。

しかし、2回目のTemporal AAは、ブレンドの最小値を”1/4”に設定しています。

どのような計算式で処理されたとしてもこの数値未満のブレンド値にはなりません。

この値は前回フレームまでの描画結果を利用する処理においてはかなり大きめの値だと認識してください。

大きめのブレンド値が利用される場合、現在フレームのカラーの支配力が増します。

支配力が増すことにより、小さなものが輪郭を保ちやすくなります。

しかしこれは、ジャギーが目立つようになるという諸刃の剣でもあります。

カメラが大きく動くようなシーンでは問題にならないかもしれませんが、ゆっくりと動くシーン、停止しているシーンでは特にスペキュラエイリアスが問題になります。

今回、その問題がわかりやすいようなシーンをパッケージングしてみました。

http://1drv.ms/1EYLzjL

ResponsiveAA.zip

実行ファイルを実行するとカメラの手前に赤い壁がある状態で開始するはずです。

この赤い壁はResponsive AAがOFFのマテリアルが適用されています。

次にキーボードのZキーを押しっぱなしにしてみてください。押しっぱなしの時はResponsive AAがONのマテリアルに切り替わります。

どうでしょう?スペキュラがジラジラしませんか?

現在のフレームが支配的になってしまったために起こる現象です。

雪片のような小さなものであればこのような状態でも目立ちにくいはずですが、このサンプルのように大きなものに対して使用してしまうとスペキュラエイリアスが目立ちます。

というわけでまとめです。

  1. Responsive AAを利用するとTemporal AAの処理が2回走ります

    EarlyDepthStencilを使っていないようにも見えるので、この部分の処理速度が2倍になる恐れがあります

  2. Responsive AAの利用は小さなものに限定しましょう

    大きなものに利用するとスペキュラエイリアスが目立ちます

こんな感じでしょうか。

まあ、基本OFFで問題ない機能です。

特に困った場面に遭遇しない限り、わざわざONにする必要はないでしょうね。