[Unity初心者向け]画像を使ってシーン移動の演出をつくろう(トランジション)

##今回やること
- UnityのuGUI(UI)の機能を使って、フェードイン・フェードアウトの演出を作る。
- そのためにシェーダーを自作する。

トランジションって調べるとよく出てくる**uGUI**とは？　→　UnityのUI機能のこと(Canvasなど)。
この機能を応用することで、トランジション(シーン遷移のときの画面演出)が実装できる[^1]。
[^1]: uGUI (UnityのUI機能) の使い方まとめ, 2016, http://mikan-daisuki.hatenablog.com/entry/2016/01/11/175010

全体として以下[^2]の記事を参考にした。
[^2]: Unityでトランジション演出を実装する,2019, https://blog.cfm-art.net/archives/963


##1. ルール画像の作成
Unityでは、画像素材に対して設定を行うことで黒部分の透明化を行うことができる。α値を操作すれば、グラデーションのように画面が動いて切り替わる効果のトランジション(画面遷移)を作成できる。
今回は以下のような画像（透過なしPNGファイル）をPhotoshopで作成し、Rule01として使用した。

以下の画像(Rule01.png)は自作のため使用自由とする。
![Rule01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701407/5361a7bc-4758-6b29-0e37-0a71a32c4219.png)


##2. Spriteとしての調整
Assetに入れた状態から、素材をダブルクリックしてInspectorを開く。設定は以下の通り行った。
- `Texture Type`を`Sprite(2D and UI)`
- `sRGB`のチェックボックスをオフ
- `Alpha Source`を`From Gray Scale`に設定

![スクリーンショット 2021-02-20 19.09.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701407/c82b25c5-7fe3-987c-9078-896116b2c3e8.png)


##3. Imageの設定
- `Hierarchy`から`Create > UI > Image`を選んでオブジェクトを作る
- ポジションを(0,0,0)に変更（カメラの中心位置に置かれる）  
- Source Imageの中にSprite設定を行った画像をいれる
- Preserve Aspectにチェックを入れ(縦横比を固定できる)、画面におさまるサイズにWidthを変更


![スクリーンショット 2021-02-20 19.07.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701407/b2be1616-fbd7-11e8-af41-8841b2449e59.png)

参考：Unity Imageに表示する方法： https://www.sejuku.net/blog/56133

##4. シェーダーの作成
参考： 【Unity入門】Shaderってなんだ?誰でもわかるシェーダー解説!, 2018, https://www.sejuku.net/blog/66319

**シェーダーとは？**　→　テクスチャをどのように表示するかをきめるプログラム
Unityでは、シェーダーはHLSL言語で記述され、UnityのScriptの書き方(C#)とは異なる言語である[^3]。



[^3]: Unityリファレンス(Unityで使用するシェーダー言語), https://docs.unity3d.com/ja/2018.4/Manual/SL-ShadingLanguage.html

表示させたルール画像をつかってテクスチャの表示方法を決めたいので、シェーダーのプログラム(スクリプト)を書いてImageに反映させます。

###4.1 マテリアルの作成
シェーダースクリプトをアタッチするためにはマテリアルが必要なので、トランジション用マテリアルを作成してからImageにアタッチする。
![スクリーンショット 2021-02-20 20.17.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701407/93a20741-628e-3c83-3dc5-0be6dd94b6dd.png)


###4.2 シェーダースクリプトを作成する
`Create`>`Shader`>`UnlitShader`でShaderを作成する。※名前注意！
![スクリーンショット 2021-02-20 20.37.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701407/d89ed4b9-eb4e-7011-bce6-7c5556393c44.png)

####▼注意！ shaderの名前を後から変更すると…（間違い探し）
![スクリーンショット 2021-02-20 20.27.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701407/7312e2ce-65b8-c5b4-2d0c-a94d96343630.png)
右側に注目。名前が`Unlit/NewUnlitShader`になってしまうので、アタッチしようとするときに名前がわかりづらい。作成直後に名前が変更できるときがあるので、ここで変更しておくとよい。
なお、Shaderのスクリプトを変更する際にスクリプト内で名前を変更すれば、こちらのInspector表示上の名前も変わる。名前の不一致に注意。


###4.3 シェーダースクリプトをアタッチする
マテリアルをInspector画面に表示する。`Shader`>`Unlit`>`"Shaderの名前"`からアタッチできる。
![スクリーンショット 2021-02-20 20.31.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701407/dc6c9612-597c-34f2-5c70-4da1c22b74ef.png)

▼アタッチしたところ。シェーダースクリプトの中身がまだ空なのでただの画像が表示されている。
![スクリーンショット 2021-02-20 20.44.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701407/273e37cc-daa2-acf5-2934-7c93c09e1eef.png)

###4.4 シェーダースクリプトの中身(HLSL)の作成
エディタでShaderを表示し、コードを変更して保存する。
UnityのScriptを作ったときと同様に、あらかじめ書き込まれている文章があるが、特にこだわりがなければ以下のコードのコピペで構わない。

スクリプトは[Unityでトランジション演出を実装する](https://blog.cfm-art.net/archives/963) の記事から、**`時間によって画像のα値を増減する`**の項目より引用。※Unityのスクリプト同様、名前に注意すること！

```HLSL:"Shaderの名前"
Shader "Unlit/Shaderの名前"  //ここの名前を変えるのを忘れずに！
{
	Properties
	{
		[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
		_Color("Tint", Color) = (1,1,1,1)
		_Alpha ("Time", Range(0, 1)) = 0
	}

	SubShader
	{
		Tags
		{
			"Queue" = "Transparent"
			"IgnoreProjector" = "True"
			"RenderType" = "Transparent"
			"PreviewType" = "Plane"
			"CanUseSpriteAtlas" = "True"
		}

		Cull Off
		Lighting Off
		ZWrite Off
		ZTest[unity_GUIZTestMode]
		Fog{ Mode Off }
		Blend SrcAlpha OneMinusSrcAlpha

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

			struct appdata_t
			{
				float4 vertex   : POSITION;
				float2 texcoord : TEXCOORD0;
			};

			struct v2f
			{
				float4 vertex   : SV_POSITION;
				half2 texcoord  : TEXCOORD0;
			};

			fixed4 _Color;
			fixed _Alpha;
			sampler2D _MainTex;

			// 頂点シェーダーの基本
			v2f vert(appdata_t IN)
			{
				v2f OUT;
				OUT.vertex = UnityObjectToClipPos(IN.vertex);
				OUT.texcoord = IN.texcoord;
#ifdef UNITY_HALF_TEXEL_OFFSET
				OUT.vertex.xy += (_ScreenParams.zw - 1.0) * float2(-1,1);
#endif
				return OUT;
			}

			// 通常のフラグメントシェーダー
			fixed4 frag(v2f IN) : SV_Target
			{
				half alpha = tex2D(_MainTex, IN.texcoord).a;
				alpha = saturate(alpha + (_Alpha * 2 - 1));
				return fixed4(_Color.r, _Color.g, _Color.b, alpha);
			}
			ENDCG
		}
	}

	FallBack "UI/Default"
}
```


▼スクリプトを入力したところ。
![スクリーンショット 2021-02-20 20.47.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701407/8725fc25-32f0-c34b-ac96-69c16c00d659.png)


##5. Shaderを動かすスクリプト(C#)の作成
C#スクリプトを作成。

スクリプトは[Unityでトランジション演出を実装する](https://blog.cfm-art.net/archives/963) の記事から、**`時間を制御するスクリプト`**の項目より引用。

####▼暗転用C#スクリプト
```C#:Transition.cs
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

public class Transition : MonoBehaviour
{
    [SerializeField]
    private Material _transitionIn;

    void Start()
    {
        StartCoroutine( BeginTransition() );
    }

    IEnumerator BeginTransition()
    {
        yield return Animate( _transitionIn, 1 );
    }

    /// <summary>
    /// time秒かけてトランジションを行う
    /// </summary>
    /// <param name="time"></param>
    /// <returns></returns>
    IEnumerator Animate(Material material, float time)
    {
        GetComponent<Image>().material = material;
        float current = 0;
        while (current < time) {
            material.SetFloat( "_Alpha", current / time );
            yield return new WaitForEndOfFrame();
            current += Time.deltaTime;
        }
        material.SetFloat( "_Alpha", 1 );
    }
}
```

コピペそのままでは**:warning:エラー**が出るので、まずオブジェクト(Image)にアタッチしてから、Noneになっている`Transition In`変数に、マテリアルをアタッチする。

▼スクリプトを入力し、`Transition In`にマテリアルをアタッチしたところ。
![スクリーンショット 2021-02-20 21.07.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701407/28ac6257-7fd4-d5dc-ba14-8bc62079b31d.png)

動かしてみると→
![2021-02-20 21.13.31.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701407/9e7e8219-cd50-ed04-4360-83e0ec776e8e.gif)
マテリアルの色で暗転するようになりました。

####▼明転用C#スクリプト(暗転用と同様に設定)
スクリプトは[Unityでトランジション演出を実装する](https://blog.cfm-art.net/archives/963) の記事から、**`時間を制御するスクリプト`**の項目を一部改変。

```C#:Transition02.cs
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

public class Transition02 : MonoBehaviour
{
    [SerializeField]
    private Material _transitionIn;

    void Start()
    {
        StartCoroutine( BeginTransition() );
    }

    IEnumerator BeginTransition()
    {
        yield return Animate( _transitionIn, 1 );
    }

    /// <summary>
    /// time秒かけてトランジションを行う
    /// </summary>
    /// <param name="time"></param>
    /// <returns></returns>


    IEnumerator Animate(Material material, float time)
    {
        GetComponent<Image>().material = material;
        float current = 0;
        while (current < time) {
            material.SetFloat( "_Alpha", 1 - current / time );
            yield return new WaitForEndOfFrame();
            current += Time.deltaTime;
        }
        material.SetFloat( "_Alpha", 0 );
    }
}
```
動かしてみると→
![gif02.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701407/44959a8f-edda-888d-697a-327121c063cd.gif)



##6. 完成・アレンジ
####★`マテリアルの色(Tint)`を変更すると、明転・暗転の色が変わる。![gif03.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701407/e02e81d5-1c95-f2a3-60ed-b2f2641aecb1.gif)
####★ルール画像を変更[^4]すれば、いろいろな模様で暗転・明転させることができる。![gif04.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701407/8ddae89a-46fa-3f48-47c1-27deec6375d7.gif)
[^4]: このルール画像を使っています(自作のため使用自由)![Rule2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701407/d4c288e4-1951-bafc-3542-ffa199239335.png)
####★このスクリプトのままではStart時にCoroutineが始まってしまうので、Coroutineの開始を適宜調整する。

***

##補記
途中でトランジションのスペル(綴り)がTransitionであることを知りました。やっちまった…