おもちゃラボ

Unityで遊びを作ってます

【Unityシェーダ入門】シェーダでワイプエフェクトを作る

 昔のマリオやペルソナ5でも使われている、だんだん視界が狭くなるワイプエフェクトをUnityのシェーダで作ってみます。このエフェクト、ワイプエフェクトとかアイリスエフェクトとか、色々な呼ばれ方をしているようで正式名称がわかりませんが、下のようなやつです。

f:id:nn_hokuson:20161128200019p:plain

今回の記事のコンテンツは次の通りです。

カメラのメソッドをフックする

今回はポストエフェクトとしてワイプエフェクトをかけるシェーダで実装します。ポストエフェクトについては↓の記事で詳しく説明しています。

nn-hokuson.hatenablog.com

今回も雰囲気を出すために、ユニティちゃんを配置しておきました。

f:id:nn_hokuson:20161128201032p:plain

プロジェクトビューで「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にドラッグ&ドロップしてアタッチしておきます。

f:id:nn_hokuson:20161128201313p:plain

Unityシェーダとマテリアルを作る

つづいて、ワイプエフェクトを表示するためのシェーダを作ります。プロジェクトビューで「右クリック」→「Create」→「Shader」→「Standard Surface Shader」を選択し、作成したファイル名をwipeCircleに変更します。続いてこのシェーダファイルをアタッチするマテリアルも作成しましょう。wipeCircleのシェーダをを選択した状態で「右クリック」→「Create」→「Material」を選択すると、wipeCircleというマテリアルが作成されます。

f:id:nn_hokuson:20161128203726p:plain

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);

f:id:nn_hokuson:20161128203455j:plain

また、入力される座標系は、画面の左下が(0, 0)、右上が(1, 1)になり、アスペクト比は考慮されていません。そこで正円をかくために、次のようにu方向にアスペクト比の補正をかけています。

i.uv.x *= 16.0/9.0;

f:id:nn_hokuson:20161128203956j:plain

最後に、原点からの距離が_Radius以下の場合にはワイプエフェクトをかけずに元の色を出力します。それ以外の場合には黒色で塗りつぶしています。_Radiusはインスペクタから変更できるように、Propertiesブロックで宣言しています。

シェーダで円を書く方法はこちらの記事でも紹介しています。

nn-hokuson.hatenablog.com

カメラにマテリアルをセットして実行する

作成したマテリアルをPostEffectスクリプトにセットします。ヒエラルキービューから「Main Camera」を選択し、インスペクタのPostEffectスクリプトのwipeCircle欄に、プロジェクトビューのwipeCircleマテリアルをドラッグ&ドロップします。

f:id:nn_hokuson:20161128204743p:plain

プロジェクトビューにあるwipeCircleのマテリアルを選択して、インスペクタからスライダを移動させるとワイプエフェクトが表示されます。

f:id:nn_hokuson:20161128205009p:plain

作成したワイプエフェクトはの実行結果は次のようになります。

f:id:nn_hokuson:20161128205425g:plain