シェーダでトランジション(ノイズ)

シェーダでトランジション(ノイズ)

 トランジションとは場面転換をする際に使用される演出効果のことです。このトランジションはグレースケールのルール画像からアルファ値を決定することで作成できます。この記事ではルール画像を使用せずに、シェーダによりアルファ値を決定し、UIのPanelにトランジション用のシェーダを設定したマテリアルをアタッチすることでトランジションを行います。このトランジションシェーダにシェーダでノイズ1シェーダでノイズ2(パーリンノイズ)シェーダでノイズ3(セルノイズ)で紹介したノイズを利用しました。

ブロックノイズ

 ブロックノイズを利用したトランジションです。ブロックノイズについてはここに掲載しています。

shader

 ブロックノイズを利用したトランジションのシェーダは以下の通りです。ブッロックノイズによって得られる値を利用し、アルファ値を決定しています。_Valueを大きくするとランダムな位置の四角い領域が透明になります。また、_Smoothingを大きくすると徐々に消えるようになります。_Smoothingの下限値が0ではありませんが、これはrandom(i_st, _Seed)=0でval=0、sm=0とした場合にc=0となるため、これを回避するために小さな値を下限値としています。さらに、_Valueの最大値が_Smoothingの値によって変わらないように処理をしています。

Shader "Transition/Transition_BlockNoise"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color ("Color", Color) = (1, 1, 1, 1)
		_Size ("Size", Vector) = (1, 1, 0, 0)
		_Seed ("Seed", Int) = 0
		_Value ("Value", Range(0, 1)) = 0
		_Smoothing ("Smoothing", Range(0.00001, 0.5)) = 0
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "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;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

			float4 _Color;
            int2 _Size;
            float _Seed;
            float _Value;
			float _Smoothing;

			float random(float2 st, int seed)
			{
				return frac(sin(dot(st.xy, float2(12.9898, 78.233)) + seed) * 43758.5453123);
			}

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
				float2 st = i.uv * _Size;
				float2 i_st = floor(st);
				
				float sm = _Smoothing;
				float val = _Value * (1 + sm);
				float a = smoothstep(val - sm, val, random(i_st, _Seed));

                fixed4 col = _Color;
				col.a = a;
                return col;
            }
            ENDCG
        }
    }
}

実行結果

 上記シェーダの実行結果は以下の通りです。scriptによって_Valueを変更しています。

また、以下の画像は_Smoothing=0.5のときの実行結果です。

パーリンノイズ

 パーリンノイズを利用したトランジションです。パーリンノイズについてはに掲載しています。

shader

 先ほどのブロックノイズを利用したトランジションシェーダのブロックノイズを求める箇所をパーリンノイズへ変更しています。画面は正方形ではないのでuv座標値をそのまま利用すると横に伸びてしまいます。そこで、_ScreenParamsによってアスペクト比を求め、uv座標値を調整しています。

Shader "Transition/Transition_ParlinNoise"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color ("Color", Color) = (1, 1, 1, 1)
		_Size ("Size", Float) = 0
		_Seed ("Seed", Int) = 0
		_Value ("Value", Range(0, 1)) = 0
		_Smoothing ("Smoothing", Range(0.00001, 0.5)) = 0
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "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;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

			float4 _Color;
            float _Size;
            float _Seed;
            float _Value;
			float _Smoothing;

			float2 rand(float2 st, int seed)
			{
				float2 s = float2(dot(st, float2(127.1, 311.7)) + seed, dot(st, float2(269.5, 183.3)) + seed);
				return -1 + 2 * frac(sin(s) * 43758.5453123);
			}

			float noise(float2 st, int seed)
			{
				float2 p = floor(st);
				float2 f = frac(st);

				float w00 = dot(rand(p, seed), f);
				float w10 = dot(rand(p + float2(1, 0), seed), f - float2(1, 0));
				float w01 = dot(rand(p + float2(0, 1), seed), f - float2(0, 1));
				float w11 = dot(rand(p + float2(1, 1), seed), f - float2(1, 1));
				
				float2 u = f * f * (3 - 2 * f);

				return lerp(lerp(w00, w10, u.x), lerp(w01, w11, u.x), u.y);
			}

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
				float2 st = float2(i.uv.x, i.uv.y * _ScreenParams.y / _ScreenParams.x) * _Size;
				
				float sm = _Smoothing;
				float val = _Value * (1 + sm);
				float a = smoothstep(val - sm, val, noise(st, _Seed) * 0.5 + 0.5);

                fixed4 col = _Color;
				col.a = a;
                return col;
            }
            ENDCG
        }
    }
}

実行結果

 上記シェーダの実行結果は以下の通りです。scriptによって_Valueを変更しています。

また、以下の画像は_Smoothing=0.5のときの実行結果です。

セルラーノイズ

 セルラーノイズを利用したトランジションです。 セルラー ノイズについてはここに掲載しています。

shader

  セルラーノイズを利用したトランジションのシェーダは以下の通りです。 セルラーノイズによって得られる値をアルファ値を求めるために使用しています。その他の部分はブロックノイズやパーリンノイズの場合と同様です。

Shader "Transition/Transition_CellularNoise"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color ("Color", Color) = (1, 1, 1, 1)
		_Size ("Size", Float) = 0
		_Seed ("Seed", Int) = 0
		_Value ("Value", Range(0, 1)) = 0
		_Smoothing ("Smoothing", Range(0.00001, 0.5)) = 0
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "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;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

			float4 _Color;
            float _Size;
            float _Seed;
            float _Value;
			float _Smoothing;

			float2 rand(float2 st, int seed)
			{
				float2 s = float2(dot(st, float2(127.1, 311.7)) + seed, dot(st, float2(269.5, 183.3)) + seed);
				return frac(sin(s) * 43758.5453123);
			}

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
				int seed = _Seed;
				float2 st = float2(i.uv.x, i.uv.y * _ScreenParams.y / _ScreenParams.x) * _Size;
				float2 i_st = floor(st);
				float2 f_st = frac(st);

				float min_dist = 1;
				for(int j = -1; j <= 1; j++){
					for(int k = -1; k <= 1; k++){
						float2 n = float2(j, k);
						float2 p = rand(i_st + n, seed) + n;
						float dist = distance(f_st, p);
						min_dist = min(min_dist, dist);
					}
				}

				float sm = _Smoothing;
				float val = _Value * (1 + sm);
				float a = smoothstep(val - sm, val, min_dist);

                fixed4 col = _Color;
				col.a = a;
                return col;
            }
            ENDCG
        }
    }
}

実行結果

 上記シェーダの実行結果は以下の通りです。scriptによって_Valueを変更しています。

また、以下の画像は_Smoothing=0.5のときの実行結果です。

ボロノイ図

 ボロノイ図を利用したトランジションです。 ボロノイ図についてはここに掲載しています。

shader

  ボロノイ図をノイズを利用したトランジションのシェーダは以下の通りです。 ボロノイ図を利用して得られる値をアルファ値を求めるために使用しています。
その他の部分は以上のシェーダと同様です。

Shader "Transition/Transition_Crystal"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color ("Color", Color) = (1, 1, 1, 1)
		_Size ("Size", Float) = 0
		_Seed ("Seed", Int) = 0
		_Value ("Value", Range(0, 1)) = 0
		_Smoothing ("Smoothing", Range(0.00001, 0.5)) = 0
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "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;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

			float4 _Color;
            float _Size;
            float _Seed;
            float _Value;
			float _Smoothing;

			float2 rand(float2 st, int seed)
			{
				float2 s = float2(dot(st, float2(127.1, 311.7)) + seed, dot(st, float2(269.5, 183.3)) + seed);
				return frac(sin(s) * 43758.5453123);
			}

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
				int seed = _Seed;
				float2 st = float2(i.uv.x, i.uv.y * _ScreenParams.y / _ScreenParams.x) * _Size;
				float2 i_st = floor(st);
				float2 f_st = frac(st);

				float min_dist = 1;
				float2 min_p;
				for(int j = -1; j <= 1; j++){
					for(int k = -1; k <= 1; k++){
						float2 n = float2(j, k);
						float2 p = rand(i_st + n, seed);
						float dist = distance(f_st, p + n);
						if(dist < min_dist){
							min_dist = dist;
							min_p = p;
						}
					}
				}

				float sm = _Smoothing;
				float val = _Value * (1 + sm);
				float a = smoothstep(val - sm, val, dot(min_p, float2(0.3, 0.2)));

                fixed4 col = _Color;
				col.a = a;
                return col;
            }
            ENDCG
        }
    }
}

実行結果

 上記シェーダの実行結果は以下の通りです。 scriptによって_Valueを変更しています。

また、以下の画像は_Smoothing=0.5のときの実行結果です。