【Unity】残像を残しながらオブジェクトを拡大・縮小する

#はじめに
タイトルの通りです。
アントマン＆ワスプの大きさが変わるラボ(https://youtu.be/8_rTIAOohas の30秒あたり)に衝撃を受けたので再現してみました。

#できたもの
###縮小
![5a28b8d38073102f667c200d164f3ae4 (1).gif](https://qiita-image-store.s3.amazonaws.com/0/378758/912eb86c-7459-ca5f-bc06-272f1396beaf.gif)
これでゴーストに襲撃されても安心

###拡大
![be976b87425f23119b10b77ee202ef23.gif](https://qiita-image-store.s3.amazonaws.com/0/378758/556c63bd-f38d-151d-741e-79c987555e35.gif)
うーん（微妙）

#方針
+ 拡大・縮小したいオブジェクトのPrefabを作る
+ 残像分（5個くらい）配列を作り、少しずつサイズとアルファ値を変化させる
+ Updateにぶっこむと処理が速すぎて残像が残らないので、コルーチンを使って遅延させる

#コード
C#

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Shrink : MonoBehaviour
{
    public GameObject objPrefab;
    GameObject[] obj = new GameObject[5];
    //float TimeCount = 0;
    bool small = false;
    bool big = false;
    int count = 4;
    float a = 0.6f;
    float size;
    private Material material;

    void Start()
    {
        obj[0] = Instantiate(objPrefab) as GameObject;
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            small = true;
        }

            if (small == true)
        {
            Coroutine coroutine = StartCoroutine("SizeGenerator", 0.05f);
            small = false;
        }

        if (Input.GetMouseButtonDown(1))
        {
            big = true;
        }

        if (big == true)
        {
            Coroutine coroutine = StartCoroutine("SizeGenerator", 0.05f);
            big = false;
        }
    }

    private IEnumerator SizeGenerator(float waitTime)
    {
        if (small == true)
        {
          size = 0.5f;
        }

        if (big == true)
        {
            size = 2.0f;
        }

        for (int i = 1; i <= count; i++)
        {
            for (int j = i; j >= 0; j--)
            {
                if (i == j)
                {
                    obj[i] = Instantiate(objPrefab) as GameObject;
                    float alpha = Mathf.Pow(a, j);
                    obj[j].GetComponent<Renderer>().material.SetFloat("_Alpha", alpha);
                }
                else
                {
                    obj[j].transform.localScale = obj[j].transform.localScale * size;
                }    
            }
            yield return new WaitForSeconds(waitTime);
        }

        //destroyする用
        for(int k=0; k<8; k++)
        {
            //配列回すようループ
            for (int l = obj.Length-1; l > 0; l--)
            {
                float alpha = Mathf.Pow(a, l)* Mathf.Pow(a, k);
                if (obj[l] != null)
                {
                    obj[l].GetComponent<Renderer>().material.SetFloat("_Alpha", alpha/2);
                }
                if (alpha < 0.05)
                {
                    Destroy(obj[l]);
                }
            }
            yield return new WaitForSeconds(waitTime);
        }
    }
}
```
左クリックで縮小、右クリックで拡大

シェーダ

```
Shader "Custom/Custom"
{
	Properties{
	_MainTex("Water Texture", 2D) = "white" {}
	_Alpha("Alpha", Range(0,1)) = 1.0
	}

	SubShader{
		Tags { "Queue" = "Transparent" }
		LOD 200

		CGPROGRAM
		#pragma surface surf Standard alpha:fade 
		#pragma target 3.0

		struct Input {
			float2 uv_MainTex;
		};

	half _Alpha;
	sampler2D _MainTex;

		void surf(Input IN, inout SurfaceOutputStandard o) {
			fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
			o.Albedo = c.rgb;
			o.Alpha = _Alpha;
		}
		ENDCG
	}
		FallBack "Diffuse"
}

```
テクスチャとアルファ値のみのsurfaceシェーダ

#注意
+ 残像処理を行うために複製したオブジェクト同士の衝突判定を無くす必要あり
+ 拡大の場合、オブジェクトのRigidbody→is Kinematicにチェックを入れないとオブジェクトがふっ飛ぶ（なぜ...?）

#参考
+ https://12px.com/blog/2016/11/unity-delay/
 　遅延処理
+  https://gomafrontier.com/unity/1189
　layerを使ってオブジェクト同士の衝突判定を無くす
+ http://kan-kikuchi.hatenablog.com/entry/Material 　スクリプトからshaderの値をいじる