知識0からのUnityShader勉強

知識0からのUnityShader勉強

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

【UnityShader】ノイズシェーダー拡張 【3】#47

前回の成果

ノイズを使用して着色した。

soramamenatan.hatenablog.com

今回やること

ノイズシェーダーを使用して、歪ませます。

sasanon.hatenablog.jp


事前準備

Scene上にPlaneを配置し、今回制作したMaterialをアタッチします。

f:id:soramamenatan:20200329114152p:plain


ソースコード

Shader "Unlit/DistortionNoise" {
    Properties {
        _MainTex ("Texture", 2D) = "white" {}
        _BaseColor ("Base Color", Color) = (1, 1, 1, 1)
        _AddAlphaColor ("Add Alpha Color", Color) = (0, 0, 0, 1)
    }
    SubShader {
        Tags { "RenderType"="Transparent" "Queue"="Transparent"}
        LOD 100
        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;
            fixed4 _BaseColor;
            fixed4 _AddAlphaColor;

            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 {
                fixed4 col = tex2D(_MainTex, i.uv);
                col *= _BaseColor;
                col.rgb += _AddAlphaColor * col.a;
                return col;
            }
            ENDCG
        }
    }
}

歪ませるために、まずはアルファブレンドソースコードです。
特に難しいことはしていません。


アルファブレンド

テクスチャと、2色の色を用いてアルファブレンドを行います。
そもそもアルファブレンドとは、

アルファブレンドとは、二つの画像を重ね合わせ、各画素ごとに設定された透過度(アルファ値)に基いて合成すること。

アルファブレンド(αブレンド)とは - IT用語辞典 e-Words:より引用

のことでエフェクト等を扱うのに使用されます。


結果

Main Textureには、Unityのデフォルトで存在するDefault-Particleを使用しています。

プロパティ

f:id:soramamenatan:20200405092812p:plain

描画結果

f:id:soramamenatan:20200405092807p:plain

このアルファブレンドしたものを歪ませていきます。


ソースコード

Shader "Unlit/DistortionNoise" {
    Properties {
        _MainTex ("Texture", 2D) = "white" {}
        _BaseColor ("Base Color", Color) = (1, 1, 1, 1)
        _AddAlphaColor ("Add Alpha Color", Color) = (0, 0, 0, 1)
        _NoiseTilingOffset ("NoiseTex Tiling(x,y)/Offset(z,w)", Vector) = (0.1, 0.1, 0,0)
        _NoiseSizeScroll ("NoiseTex Size(x,y)/Scroll(z,w)", Vector) = (16, 16, 0, 0)
        _DistortionPower ("Distortion Power", Float) = 0
    }
    SubShader {
        Tags { "RenderType"="Transparent" "Queue"="Transparent"}
        LOD 100
        Blend SrcAlpha OneMinusSrcAlpha

        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "extensionNoiseUtil.cginc"

            struct appdata {
                float4 vertex : POSITION;
                float2 texuv : TEXCOORD0;
                float2 noiseuv : TEXCOORD1;
            };

            struct v2f {
                float2 texuv : TEXCOORD0;
                float2 noiseuv : TEXCOORD1;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed4 _BaseColor;
            fixed4 _AddAlphaColor;
            fixed4 _NoiseTilingOffset;
            fixed4 _NoiseSizeScroll;
            float _DistortionPower;

            v2f vert (appdata v) {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.texuv = TRANSFORM_TEX(v.texuv, _MainTex);
                o.noiseuv = TRANSFORM_NOISE_TEX(v.noiseuv, _NoiseTilingOffset, _NoiseSizeScroll);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target {
                fixed3 dist = normalNoise(i.noiseuv, _NoiseSizeScroll.xy);
                dist = dist * 2 - 1;
                dist *= _DistortionPower;
                i.texuv += dist.xy;
                fixed4 col = tex2D(_MainTex, i.texuv);
                col *= _BaseColor;
                col.rgb += _AddAlphaColor * col.a;
                return col;
            }
            ENDCG
        }
    }
}

extensionNoiseUtil.cgincを使用しています。
extensionNoiseUtil.cgincは以下にあります。

soramamenatan.hatenablog.com


テクスチャを歪ませる

考え方

考え方はフローマップと同じです。
フローマップは以前やったので、詳しくはそちらを参照してください。

soramamenatan.hatenablog.com

フローマップは以下の画像のように歪みます。

f:id:soramamenatan:20200405101200p:plain

ノイズでアルファ加算画像を歪ませるシェーダーをつくる - ささみ雑記帳:より引用

法線マップも傾きにより色が変わるので、これをフローマップのように扱うことによりノイズテクスチャを歪ませます

f:id:soramamenatan:20200405101157p:plain

ノイズでアルファ加算画像を歪ませるシェーダーをつくる - ささみ雑記帳:より引用


UV値から法線マップを出す

今回は法線マップをフローマップとして扱います。 なので、extensionNoiseUtil.cgincで定義したnormalNoise関数を使用します。

normalNoise

これはノイズで法線マップを生成する関数です。
定義は以下です。

fixed3 normalNoise(fixed2 uv, fixed2 size) {
    fixed3 result = fixed3(perlinNoise(uv.xy, size),
                           perlinNoise(uv.xy + fixed2(1, 1), size),
                           1.0);
    return result;
}

パーリンノイズ関数(疑似乱数)を使用し、法線マップを生成しています。
2回目のパーリンノイズにfixed2(1, 1)を加算している理由は、
法線マップ的にXYで異なる乱数でないと、常に斜め右上か左下方向の面の傾きベクトルになってしまうからです。
パーリンノイズ関数は疑似乱数のため、同じ値を引数に持たせると同じ結果が帰ってきてしまいます。
ですので、適当な値として1を加算しています。

fixed(1 ,1)を足さなかった場合

f:id:soramamenatan:20200405110833p:plain

fixed(1 ,1)を足した場合

f:id:soramamenatan:20200405110827p:plain


範囲を変える

パーリンノイズ関数は、0~1を返す関数なので、-1~1にするために以下を行っています。

dist = dist * 2 - 1;


結果

以下のようになれば成功です。

プロパティ

f:id:soramamenatan:20200405112658p:plain

結果

f:id:soramamenatan:20200405112653p:plain

また、プロパティの値を変更することによりエフェクトに幅を持たせることができます。
f:id:soramamenatan:20200405112644g:plain

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

Shader "Unlit/DistortionNoise" {
    Properties {
        _MainTex ("Texture", 2D) = "white" {}
        _BaseColor ("Base Color", Color) = (1, 1, 1, 1)
        _AddAlphaColor ("Add Alpha Color", Color) = (0, 0, 0, 1)
        _NoiseTilingOffset ("NoiseTex Tiling(x,y)/Offset(z,w)", Vector) = (0.1, 0.1, 0,0)
        _NoiseSizeScroll ("NoiseTex Size(x,y)/Scroll(z,w)", Vector) = (16, 16, 0, 0)
        _DistortionPower ("Distortion Power", Float) = 0
    }
    SubShader {
        Tags { "RenderType"="Transparent" "Queue"="Transparent"}
        LOD 100
        Blend SrcAlpha OneMinusSrcAlpha

        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "extensionNoiseUtil.cginc"

            struct appdata {
                float4 vertex : POSITION;
                // テクスチャ用UV
                float2 texuv : TEXCOORD0;
                // ノイズ用UV
                float2 noiseuv : TEXCOORD1;
            };

            struct v2f {
                float4 vertex : SV_POSITION;
                // テクスチャ用UV
                float2 texuv : TEXCOORD0;
                // ノイズ用UV
                float2 noiseuv : TEXCOORD1;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed4 _BaseColor;
            fixed4 _AddAlphaColor;
            fixed4 _NoiseTilingOffset;
            fixed4 _NoiseSizeScroll;
            float _DistortionPower;

            v2f vert (appdata v) {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.texuv = TRANSFORM_TEX(v.texuv, _MainTex);
                o.noiseuv = TRANSFORM_NOISE_TEX(v.noiseuv, _NoiseTilingOffset, _NoiseSizeScroll);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target {
                // パーリンノイズの疑似乱数からフローマップに見立てた法線マップを生成
                fixed3 dist = normalNoise(i.noiseuv, _NoiseSizeScroll.xy);
                // distを-1 ~ 1の範囲に
                dist = dist * 2 - 1;
                dist *= _DistortionPower;
                i.texuv += dist.xy;
                fixed4 col = tex2D(_MainTex, i.texuv);
                col *= _BaseColor;
                col.rgb += _AddAlphaColor * col.a;
                return col;
            }
            ENDCG
        }
    }
}

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