LoginSignup
6
3

More than 3 years have passed since last update.

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

Last updated at Posted at 2018-06-08

はじめに

スライドのトランジションの中に、本をめくるような形で次に進めるような奴ありますよね?
今回は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を入れます。
スクリーンショット 2018-06-08 21.49.05.png
スクリーンショット 2018-06-08 21.49.05 1.png

そして、imageのmaterialに入れます!!
スクリーンショット 2018-06-08 22.15.57.png

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

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

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

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

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

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

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);
    }

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

スクリーンショット 2018-06-08 21.11.44.png

ボタンスクリプトにimageを入れておくのもお忘れなく!
スクリーンショット 2018-06-08 21.11.05.png

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

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

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

ButtonScript.cs
public bool DontDestroyEnabled = true;

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

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

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);
        }
    }
}

参考サイト

紙をめくるアニメーションをするシェーダー作ってみた
【Unity】画面キャプチャ
Unityで画面のスクリーンショットを撮る(Application.CaptureScreenshotじゃない方法)

6
3
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
6
3