7080 + 1

ゲームプログラミングの記事を書いてます。

【Unity】ImageEffectを使わずにポストプロセス処理をする

始めに

ImageEffectを使うと、オリジナルのポストプロセスを書けるのはUnityの機能として以前からありました。私もポストプロセスでステンシルバッファを使った描画処理をやっていたのですが、Unity2017.3にアップデートした途端に挙動がおかしくなってしまったのです...。

色々と調べてみた結果、ImageEffectを使わずにポストプロセスをする方法を思い付いたので記事にします。

ちなみに、ステンシルバッファをImageEffectでは使えないのかというと、そんなことはないです。Unity2017上でもちゃんと動く方法はありますが、今回の本筋からは外れるので、別記事にします。そのうち書こうと思うで、少々お待ちください。

では、ImageEffectを使わずにどうやってポストプロセスをするのか、書いていきます。

実装

結論を言葉だけで説明すると、

  • uGUIのImageでカメラを覆って、GrabPassを使って描画する。(RenderQueueは一番最後になるように設定)

になります。具体的に説明します。

・用意するもの
ポストプロセスで使うシェーダ
uGUIのImage

以上になります。
まず、uGUIのImageをシーン内に置いてください。これ用のCanvasの設定が必要なので、新規Canvasの子で作ったほうがいいかもです。
で、Canvasの設定を以下のようにしてください。
f:id:atori708:20180325000903p:plain

RenderCameraはポストプロセスをかけたいカメラです。
PlaneDistanceは他のオブジェクトより絶対前になればどこでもいいですが、カメラのnearプレーンのすぐ近くにしておけば安心だと思います。今回はMainCameraのnearと同じ数値にしています。
これでカメラがImageを一番前面にして描画するようになります。
また、Imageはカメラを覆うようにWidth,Heightともにstreachにし、Materialにポストプロセス用の奴を適用します。
f:id:atori708:20180325001239p:plain

次にシェーダの方です。この記事を見ている皆さんには、恐らくImageEffectで適用していたシェーダがすでにあると思います。それを少し編集するだけでいいです。
編集するのは2箇所になります。

  • RenderQueueをとにかくでかい数値に
  • GrabPass{}を追加する

RenderQueueは大きいほど後に描画されます。とにかくでかくすることで、他の全ての描画が終わった後に描画を走らせます。
そしてGrabPassにより、_GrabTextureに描画後の結果が入ってきます。なので、_GrabTextureをシェーダでいじってやれば、ポストプロセスで処理することができる。というわけです。

一応ものすごくシンプルなシェーダを、ImageEffectと今回のパターンの両方載せておきます。
色を反転するポストプロセスシェーダです。変化している場所を見比べてください。


この方法だとImageEffectに比べて、カメラのMSAAをONにしててもステンシルバッファを取得出来るというメリットがあります。ただ、Unityが推奨しているポストプロセスのやり方ではないので、なにか予期せぬことが起きるかもしれません。実機等でちゃんとテストしてみてください。

なんかわからんけどImageEffectうまく動かねえって人は今回の方法を試してみてはいかがでしょうか。