[PostEffect]ワイプエフェクトのImageEffect

# 環境
- Unity5.5
- DOTween

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">わーい！Shaderたのーしー！ <a href="https://t.co/zMBwzZZF9l">pic.twitter.com/zMBwzZZF9l</a></p>&mdash; KUZ＊UKS (@superDebu12) <a href="https://twitter.com/superDebu12/status/834064760152797184">2017年2月21日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

(これワイプエフェクトっていうんだろうか・・？？)

# Shader側

Shader側のPropertyには

- 円の中心となるスクリーン座標 : (_HoleCenterX, _HoleCenterY)
- 円の半径 : _Radius

を定義します。

fragmentShaderの中で指定された円の中心とピクセルとの距離を計算します。
距離が_Radius未満の場合はそのままの色のままとし、_Radisu以上の場合は黒く塗りつぶします。

```glsl:WipeEffect.shader
Shader "Custom/WipeEffect"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
        _HoleCenterX ("HoleCenterX", float) = 0.5
        _HoleCenterY ("HoleCenterY", float) = 0.5
        _Radius ("Radius", float) = 0.5
	}
	SubShader
	{
		// No culling or depth
		Cull Off ZWrite Off ZTest Always

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				float4 vertex : SV_POSITION;
			};

			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
				o.uv = v.uv;
				return o;
			}
			
			sampler2D _MainTex;
            float _HoleCenterX;
            float _HoleCenterY;
            float _Radius;

			fixed4 frag (v2f i) : SV_Target
			{
                float2 pos = i.uv * _ScreenParams.xy;

                if( distance(pos.xy, fixed2(_HoleCenterX, _HoleCenterY)) < _Radius ){
                    discard;
                }
                return fixed4(0, 0, 0, 1);
			}
			ENDCG
		}
	}
}
```

#　Script側

Script側では円の中心となるスクリーン座標をshader側に渡しています。
今回は指定されたGameObjectを中心にワイプエフェクトをかけたいので、**WorldToScreenPoint"**関数でmyCameraから見たGameObjectのスクリーン座標を取得してshader側に渡しています。

```csharp:CircleEffect.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;

public class CircleEffect : MonoBehaviour
{
    [SerializeField]
    private Camera myCamera;
    private Material material;

    /// <summary>
    /// シーン上の覗き穴Effect対象のGameObjectの配列
    /// </summary>
    [SerializeField]
    private GameObject[] cubeArray;

    /// <summary>
    /// 処理中フラグ
    /// </summary>
    private bool isProcess;

    /// <summary>
    /// 最終的な半径の大きさ
    /// </summary>
    [SerializeField, Range (0.1f, 1.0f)]
    private float destinationRadius;

    /// <summary>
    /// 半径の一時変数
    /// </summary>
    private float _radius;

    GameObject currentTarget;
    int index = 0;

    void Start ()
    {
        material = new Material (Shader.Find ("Custom/CircleFadeOut"));
    }

    void OnRenderImage (RenderTexture source, RenderTexture destination)
    {
        if (isProcess) {
            UpdateMaterial ();
            Graphics.Blit (source, destination, material);
        }
    }

    void UpdateMaterial ()
    {
        Vector3 screenPoint = myCamera.WorldToScreenPoint (currentTarget.transform.position);

        float currentRadius = Screen.height * _radius;
        material.SetFloat ("_HoleCenterX", screenPoint.x);
        material.SetFloat ("_HoleCenterY", screenPoint.y);
        material.SetFloat ("_Radius", currentRadius);
    }

    /// <summary>
    /// 指定されたGameObjectのスクリーン上の座標の周りを黒塗りにする
    /// </summary>
    /// <param name="target">Target.</param>
    void StartTargetWipeEffect (GameObject target)
    {
        isProcess = true;
        _radius = 2.0f;
        currentTarget = target;
        DOTween.To (r => _radius = r, _radius, destinationRadius, 1.0f)
            .OnComplete (() => {
                Debug.Log("WipeEffect Process End!");
        });
    }

    void Update ()
    {
        if (Input.GetKeyDown (KeyCode.A)) {
            StartTargetWipeEffect (cubeArray[index%cubeArray.Length]);
            index++;
        }
    }
}
```