この記事はポストプロセスをエンジン改造で実装する際にハマった罠について書いています。
エンジン改造してまでポストプロセスの実装なんてしないよ、という方には不要かもしれません。
コンソールゲーム機ではフレームバッファの解像度をユーザが変更できる機能は通常存在しません。
処理落ち回避のために動的にフレームバッファの解像度を変更するゲームがあったりはしましたが、あまり存在していません。
しかし、PCゲームでは解像度を変更する機能は普通に存在しています。
ましてやUE4やUnityのようなゲームエンジンはエディタ上でゲームを動かせるため、エディタ上のゲームViewのサイズが変更されることも多くあります。
解像度が変更された場合、通常であればフレームバッファや、ポストプロセスなどで処理を行うためのオフスクリーンバッファは解像度に合わせて作り直されるのが一般的です。
UE4でも基本はそうなのですが、ある状態変化の場合はフレームバッファが作り直されません。
その状態というのは、解像度が小さくなった場合です。
まずはこの画像をご覧ください。
これはUE4のエディタを小さめにして使っていた場合の途中のレンダーターゲットです。
では次。
こちらはエディタを最大化した際のレンダーターゲットです。
当然ですが解像度は縦も横も上がっているので、フレームバッファやオフスクリーンバッファは作り直されています。
では最後。
エディタの最大化を解除して、最初と同じウィンドウサイズに変更した場合のレンダーターゲットです。
見ての通り、最大化したサイズのまま、描画される範囲だけが小さくなっています。
この動作はシッピングされたゲームでも同様の動作をするのかは不明ですが、少なくともエディタ上ではこのように動作します。
ポストプロセスを実装する際、フレームバッファとサイズの異なるバッファを使用することはよくあります。主に縮小バッファとして。
しかし、単純にバッファサイズのポリゴンを描画するような方法を取ってしまうと正常に描画されなかったり無駄なピクセルシェーダが動いてしまったりします。
なので、正しいサイズで、正しい範囲に描画を行わなければなりません。
今回ピクセルシェーダで実装したディフュージョンフィルタでは他のポストプロセスに習って DrawPostProcessPass() という命令を使用しています。
この命令は出力先のレンダーターゲットに対して適切なUV座標を持った板を描画してくれる命令です。
ここに適切な値を渡してやればバッファサイズがどんなに変わってもちゃんと描画されますが、適切でないとうまくいきません。
なので必要なパラメータを少し紹介します。
float X, Y, SizeX, SizeY
これはレンダーターゲットに対するViewportの左上座標とサイズです。単位はピクセル。
float U, V, SizeU, SizeV
これはポストプロセスを適用する元のバッファのUV値の左上座標とサイズです。こちらも単位はピクセル。
FIntPoint TargetSize
これはレンダーターゲットのバッファの縦横のサイズです。単位はピクセルで、与えるのは整数値です。
FIntPoint TextureSize
これは元のバッファの縦横のサイズです。単位はピクセル、整数値で与えます。
この関数は簡単なポストプロセスには比較的簡単に適用できるのですが、複数のサイズが異るバッファを使った場合はうまくいかない可能性も出てきます。
複数のテクスチャにおいて使用する正規化されたUV値が同一でOKならさほど問題はないです。ちなみに、ディフュージョンフィルタでは同一UV値でOKだったので正常動作しています。
比率がぜんぜん違うテクスチャを複数枚使う場合はこの命令を参考に自分たちの用途に見合った命令を作成しましょう。
というわけで、ちょっとしたおまけでした。