本のようにシーン移動する

#はじめに
スライドのトランジションの中に、本をめくるような形で次に進めるような奴ありますよね？
今回はunityでそれを表現するためにコルーチンとシェーダーをいじっていきます。

流れとしては

1. めくる動作ができるようシェーダーを調節したimageを用意する。
2. 移動前のシーンのスクリーンをReadPicxelsで取得する。
3. imageに取得したものを入れる。
4. imageは残したまま、シーンを移動させる。
5. imageをめくる！

という形で進めていきます。

#開発
##シェーダーをいじる
こちらの記事のシェーダーコードを使わせていただいています。
http://esprog.hatenablog.com/entry/2016/03/13/130506

CreatでShaderを作り、中身を以下に差し替えます。

```NextPage.shader
Shader "MBL/NextPage"
{
	Properties
	{
		_MainTex("Texture", 2D) = "white" {}
		_PageTex("PageTexture", 2D) = "white" {}
		_AlphaMask("AlphaMask", Range(0, 1)) = 0.1
		_Flip("Flip",Range(-1, 1)) = 0
	}
	SubShader
	{
		Tags { "RenderType" = "Transparent" }
		Blend SrcAlpha OneMinusSrcAlpha

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"

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

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

			sampler2D _MainTex;
			float4 _MainTex_ST;
			sampler2D _PageTex;
			float4 _PageTex_ST;
			float _AlphaMask;
			float _Flip;

			float l2(float x)
			{
				return 1 - _Flip + 0.1 * cos(x * 2);
			}

			float l1(float y)
			{
				return _Flip + 0.1 * sin(y * 3);
			}

			float l0(float x)
			{
				return x - _Flip;
			}

			v2f vert(appdata v)
			{
				v2f o;
				o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				o.puv = TRANSFORM_TEX(v.uv, _PageTex);
				return o;
			}

			fixed4 frag(v2f i) : SV_Target
			{
				//コンテンツとページテクスチャ色取得
				float4 content_col = tex2D(_MainTex, i.uv);
				float4 page_col = tex2D(_PageTex, i.puv);

				//L0より右の描画を無視
				float l0_y = l0(i.uv.x);
				clip(i.uv.y - l0_y);

				//範囲内ならば暗い色に
				if (i.uv.x > l1(i.uv.y) && i.uv.y < l2(i.uv.x))
					content_col = float4(0.5, 0.5, 0.5, 1);

				//ページ内容のうち一定の値より透明なものはページの色にすり替える
				if (content_col.a < _AlphaMask)
					return page_col;

				return content_col * page_col;
			}
			ENDCG
		}
	}
}
```

新しいマテリアルを作り、その中に作ったShaderを入れます。
<img width="234" alt="スクリーンショット 2018-06-08 21.49.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/251744/56f8fcce-fca7-b69c-ceb1-a8f7a4f4d23b.png">
<img width="276" alt="スクリーンショット 2018-06-08 21.49.05 1.png" src="https://qiita-image-store.s3.amazonaws.com/0/251744/90227c44-4a8c-0ba1-8643-57dae1653bc4.png">

そして、imageのmaterialに入れます！！
<img width="276" alt="スクリーンショット 2018-06-08 22.15.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/251744/d6470969-9e40-9da3-dbf0-84becf26c25e.png">

めくれるようになりました！！！！！
Shaderの中のFlipのスライダーをずらすとよくわかります。
これで画像を入れる土台は整いました。

imageは非アクティブにしておきしょう！。

##スクリーンを取得してimageに入れる

スクリーンを取得するためにはReadPicxelsというメソッドを使っていきます。

はじめに、imageつけるスクリプトをかきます。（今回はButtonでシーン移動させます）

UIに関するスクリプトを動かすので以下を追記します。
`using UnityEngine.UI;`
`using UnityEngine.SceneManagement;`


```C#:ButtonScript.cs


public Image m_DrawTex;

public void Botton(){
		StartCoroutine ("Capture");
	}

IEnumerator Capture()
	{
		//ReadPicxelsがこの後でないと使えないので必ず書く
		yield return new WaitForEndOfFrame();
		
		//スクリーンの大きさのSpriteを作る
		var texture = new Texture2D(Screen.width, Screen.height);

		//スクリーンを取得する
		texture.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
		//適応する
		texture.Apply();
		
		//取得した画像をSpriteに入るように変換する
		byte[] pngdata = texture.EncodeToPNG();
		texture.LoadImage(pngdata);

		//先ほど作ったSpriteに画像をいれる
		Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
		Debug.Log ("c");

		//Spriteを使用するオブジェクトに指定する
		//     今回はUIのImage
		m_DrawTex.GetComponent<Image>().sprite = sprite;

		// サイズ変更
		m_DrawTex.GetComponent<RectTransform>().sizeDelta = new Vector2(texture.width, texture.height);

		//imageをアクティブにする
		image.SetActive (true);
	}
```

ボタンを押したときにメソッドが呼ばれるように設定しましょう

<img width="384" alt="スクリーンショット 2018-06-08 21.11.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/251744/16a4a038-f0de-f1b5-4886-2825e5ec68d0.png">

ボタンスクリプトにimageを入れておくのもお忘れなく！
<img width="275" alt="スクリーンショット 2018-06-08 21.11.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/251744/2db0d1ab-e754-7bdb-816d-42647af6eb39.png">


これで、シーン移動の直前画面をimageで写すことができるようになりました。
次にこのimageを消さないままシーン移動する方法を説明します。

##imageを残したままシーン移動

imageが消えないようにするにはDontDestroyOnLoadを使います。
bool値の宣言とstart()の中に以下を追記してください。

```C#:ButtonScript.cs
public bool DontDestroyEnabled = true;

	void Start () {
		if (DontDestroyEnabled) {
			// Sceneを遷移してもオブジェクトが消えないようにする
			DontDestroyOnLoad (this);
		}
	}
```

更に別のメソッドを作りシーン移動ができるようにする。

```C#:Button.cs
public void nextScene(){
	//任意のシーンへ移動する
	SceneManager.LoadScene ("シーンの名前");

	//destroyできるようにする
	DontDestroyEnabled = false;
}
```
最後にCapture()の最後に以下を追記して移動できるようになります！

```ButtonScript.cs
nextScene();
```

##imageをめくる
imageにそのままつけて実行すると自動でめくるモーションが再生される
サンプルを貼っておきます。参考までに！！

```flipTest.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class flipTest : MonoBehaviour
{

	// Start is called before the first frame update
	void Start()
	{
		this.GetComponent<Image>().material.SetFloat("_Flip", 1.0f);
	}

	// Update is called once per frame
	void Update()
	{
		float flipValue = this.GetComponent<Image>().material.GetFloat("_Flip");

		if (flipValue > -1.0f)
		{
			flipValue -= 1f * Time.deltaTime;
			this.GetComponent<Image>().material.SetFloat("_Flip", flipValue);
		}
	}
}
```


##参考サイト
[紙をめくるアニメーションをするシェーダー作ってみた](http://esprog.hatenablog.com/entry/2016/03/13/130506)
[【Unity】画面キャプチャ](http://yttm-work.jp/unity/unity_0030.html)
[Unityで画面のスクリーンショットを撮る(Application.CaptureScreenshotじゃない方法)](https://qiita.com/tempura/items/e8f4bbb4419407916d12)