LoginSignup
5
7

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-02-27

環境

  • Unity5.5
  • DOTween

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

Shader側

Shader側のPropertyには

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

を定義します。

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

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側に渡しています。

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++;
        }
    }
}
5
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7