昔のマリオやペルソナ5でも使われている、だんだん視界が狭くなるワイプエフェクトをUnityのシェーダで作ってみます。このエフェクト、ワイプエフェクトとかアイリスエフェクトとか、色々な呼ばれ方をしているようで正式名称がわかりませんが、下のようなやつです。
今回の記事のコンテンツは次の通りです。
カメラのメソッドをフックする
今回はポストエフェクトとしてワイプエフェクトをかけるシェーダで実装します。ポストエフェクトについては↓の記事で詳しく説明しています。
今回も雰囲気を出すために、ユニティちゃんを配置しておきました。
プロジェクトビューで「PostEffect.cs」というファイルを作成し、次のプログラムを入力してください。このスクリプトの説明は上の記事で説明しています。
using UnityEngine; using System.Collections; public class PostEffect : MonoBehaviour { public Material wipeCircle; void OnRenderImage(RenderTexture src, RenderTexture dest) { Graphics.Blit (src, dest, wipeCircle); } }
スクリプトが保存できたら、PostEffect.csをMainCameraにドラッグ&ドロップしてアタッチしておきます。
Unityシェーダとマテリアルを作る
つづいて、ワイプエフェクトを表示するためのシェーダを作ります。プロジェクトビューで「右クリック」→「Create」→「Shader」→「Standard Surface Shader」を選択し、作成したファイル名をwipeCircleに変更します。続いてこのシェーダファイルをアタッチするマテリアルも作成しましょう。wipeCircleのシェーダをを選択した状態で「右クリック」→「Create」→「Material」を選択すると、wipeCircleというマテリアルが作成されます。
wipeCircle.shaderを開いて次のスクリプトを入力してください。
Shader "Custom/wipeCircle" { Properties{ _Radius("Radius", Range(0,2))=2 } SubShader { Pass { CGPROGRAM #include "UnityCG.cginc" #pragma vertex vert_img #pragma fragment frag float _Radius; fixed4 frag(v2f_img i) : COLOR { i.uv -= fixed2(0.5, 0.5); i.uv.x *= 16.0/9.0; if( distance(i.uv, fixed2(0,0)) < _Radius ){ discard; } return fixed4(0.0,0.0,0.0,1.0); } ENDCG } } }
今回作るワイプエフェクトはポストエフェクトなので、フラグメントシェーダで処理しています。やっていることは、原点からの値を見て黒く塗りつぶすかを決めているだけです。ただ、次の2点を補正するための処理が必要になります。
- 原点が左下にある
- 画面のアスペクトが影響する
画面の左下が原点になるため、画面の中央からの距離を見たい場合には次のようにu方向、v方向ともに0.5ずつ座標をずらす必要があります。
i.uv -= fixed2(0.5, 0.5);
また、入力される座標系は、画面の左下が(0, 0)、右上が(1, 1)になり、アスペクト比は考慮されていません。そこで正円をかくために、次のようにu方向にアスペクト比の補正をかけています。
i.uv.x *= 16.0/9.0;
最後に、原点からの距離が_Radius以下の場合にはワイプエフェクトをかけずに元の色を出力します。それ以外の場合には黒色で塗りつぶしています。_Radiusはインスペクタから変更できるように、Propertiesブロックで宣言しています。
シェーダで円を書く方法はこちらの記事でも紹介しています。
カメラにマテリアルをセットして実行する
作成したマテリアルをPostEffectスクリプトにセットします。ヒエラルキービューから「Main Camera」を選択し、インスペクタのPostEffectスクリプトのwipeCircle欄に、プロジェクトビューのwipeCircleマテリアルをドラッグ&ドロップします。
プロジェクトビューにあるwipeCircleのマテリアルを選択して、インスペクタからスライダを移動させるとワイプエフェクトが表示されます。
作成したワイプエフェクトはの実行結果は次のようになります。