知識0からのUnityShader勉強

知識0からのUnityShader勉強

UnityのShaderをメインとして、0から学んでいくブログです。

【UnityShader】ブロックノイズトランジション #29

前回の成果

ワイプエフェクトを実装しました。

soramamenatan.hatenablog.com


今回やること

トランジションをしていこうと思います。

karanokan.info


トランジションとは

ビデオ編集する際に、カットとカットの間に挿入する切り替え効果のこと。

フェードイン、フェードアウト、ワイプ、オーバーラップなど、さまざまな効果がある。

トランジション(とらんじしょん)とは - コトバンク:より引用

ゲームでのシーン切り替えとかによくあるものです。

まず初めにブロックノイズのトランジションをしていきます。

事前準備

Scene上にCanvasを置き、その下にImageを置いてください。
次に、そのImageのMaterialに今回制作したMaterialをアタッチしてください。
最後にRect Transformを画面全体にstretchしてください。

f:id:soramamenatan:20191110162746p:plain


ソースコード

Shader "Unlit/transitionBlockNoize" {
    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" "Quaue" = "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
        }
    }
}

以前やったブロックノイズに似ています。

soramamenatan.hatenablog.com


floor

これは小数値の整数を返す関数です。

// xに整数値が欲しい数値を入れる
floor(x);

// 例
float a = 1.0f;
float b = 3.5f;
// 1が返ってくる
floor(a);
// 3が返ってくる
floor(b);


smoothstep

これは指定した値を別の指定した値の範囲で収める関数です

// minに最小値、maxに最大値、xに収めたい値を入れる
//  x < minの場合は0、x > maxの場合は1、それ以外の場合は0から1の間で線形補間される
smoothstep(min, max, x);

// 例
float min = 0;
float max = 10;
float a = -3;
float b = 5;
float c = 12;
// 0が返ってくる
smoothstep(min, max, a);
// 0.5が返ってくる
smoothstep(min, max, b);
// 1が返ってくる
smoothstep(min, max, c);

smoothstepのイメージは下記の図です。

f:id:soramamenatan:20191110164030p:plain

【Unityシェーダ入門】シェーダだけで描く図形10選 - おもちゃラボ:より引用


_Smoothing ("Smoothing", Range(0.00001, 0.5)) = 0

このPropertyを0ではなく、0.000001にしています。
これは、

smoothstep(val - sm, val, random(i_st, _Seed));

このsmoothstepのmin、max、xが全て0だった場合に0が返ってきてしまうためです。
下記の図のように、Valueが0にも関わらず画面が真っ黒になっていない箇所が出てきてしまいます。

Rangeが0のとき

f:id:soramamenatan:20191110164536p:plain

Rangeが0.00001のとき

f:id:soramamenatan:20191110164612p:plain


float random(float2 st, int seed)

これは、ブロックノイズの記事で紹介したようにランダムな値を返す関数となっています。
詳しくはこちらのサイト様を参考にしてください。

qiita.com


fragの解説

frag関数でやっていることの解説をしていきます。

float2 st = i.uv * _Size

uv値にsizeをかけることにより、1画面に何個ブロックノイズを出すかを決めています。

float val = _Value * (1 + sm);

この下でsmを引いているので、その調整のために足しています。

float a = smoothstep(val - sm, val, random(i_st, _Seed));

smを引いてあげることにより、ブロックノイズのAlphaを調整しています。
smが0の場合は、smoothstepのminとmaxが等しくなるため、Alphaは0か1になります。


結果

Valueを変化させることによって、トランジションしています。

f:id:soramamenatan:20191119162336g:plain


ソースコードにコメントを付与

Shader "Unlit/transitionBlockNoize" {
    Properties {
        _MainTex("Texture", 2D) = "white" {}
        _Color("Color", Color) = (1, 1, 1, 1)
        // xとyにブロックノイズを表示する個数を入れる
        _Size("Size", Vector) = (1, 1, 0, 0)
        // シード値
        _Seed("Seed", int) = 0
        // ブロックノイズの値
        _Value("Value", Range(0, 1)) = 0
        // Alphaを許容する
        _Smoothing("Smoothing", Range(0.00001, 0.5)) = 0
    }
    SubShader {
        Tags { "RenderType" = "Transparent" "Quaue" = "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 {
                // size分ブロックノイズを出す
                float2 st = i.uv * _Size;
                // 整数値を取得
                float2 i_st = floor(st);

                float sm = _Smoothing;
                // 調整用
                float val = _Value * (1 + sm);
                // Alphaをsmの値によって変化させる
                float a = smoothstep(val - sm, val, random(i_st, _Seed));
                fixed4 col = _Color;
                col.a = a;
                return col;
            }
            ENDCG
        }
    }
}

今回は以上となります。
ここまでご視聴ありがとうございました。