【Unity-Shader】#12 Unity道場「Shader Graph はじめてみよう」の表現目指してshader書いた。

今までやってきたいくつかのエフェクト組み合わせた :)

f:id:snoopopo:20200915151210g:plain


youtu.be

最近の記事は↑のShader Graphの動画の内容をコードで書いてみよう!ってことでやってました。

shader

Shader "Custom/Warp"
{
    Properties
    {
        _MainTex("MainTexture", 2D) = "white" {}
        _NoiseTex("NoiseTexture", 2D) = "white" {}
        _PerlinNoiseTex("PerlinNoiseTexture", 2D) = "white" {}
        [HDR] _Color("Color", Color) = (1, 1, 1)
        _ColorVolume("ColorVolume", Range(0,1)) = 0
        _Border("Border", Range(0,1)) = 0
    }

    SubShader
    {
        Cull Off
        AlphaToMask On

        Tags
        {
            "Queue" = "AlphaTest"
            "RenderType" = "AlphaTest"
        }

        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD;
            };

            sampler2D _MainTex;
            sampler2D _PerlinNoiseTex;
            sampler2D _NoiseTex;
            float4 _Color;
            float _ColorVolume;
            float _Border;

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

            fixed4 frag(v2f i) : SV_Target
            {

                {//ブレるような動き
                    fixed2 noiseUv = fixed2(i.uv.x + cos(_Time.y * 0.5), i.uv.y);
                    fixed4 noiseColor = tex2D(_PerlinNoiseTex, noiseUv) * 0.05;

                    i.uv.x += noiseColor.r;
                }

                fixed4 color = tex2D(_MainTex, i.uv); //最終的に出力する色

                {//カラーの変更
                    fixed gray = dot(color.rgb, fixed3(0.299, 0.587, 0.114));
                    fixed4 targetColor = _Color * gray;

                    fixed4 lerpColor = lerp(color, targetColor, _ColorVolume);
                    color = fixed4(lerpColor.r, lerpColor.g, lerpColor.b, tex2D(_MainTex, i.uv).a);
                }


                {//帯電

                    fixed2 noiseUv1 = fixed2(i.uv.x + _Time.y * 1.2, i.uv.y);
                    fixed4 noise1 = tex2D(_NoiseTex, noiseUv1 * 0.005); //画像を拡大

                    fixed2 noiseUv2 = fixed2(i.uv.x + _Time.y * -1.5, i.uv.y);
                    fixed4 noise2 = tex2D(_NoiseTex, noiseUv2 * 0.005); //画像を拡大

                    fixed4 noise = noise1 + noise2;

                    noise = noise * 10 - 15; //remap 0~2の範囲を -5~5の範囲にremap
                    noise = abs(noise); //絶対値をとり、マイナス値だったものプラスに変化 0~5の値に変換
                    noise = 1 - noise; //黒白を反転させる -4~1の値に
                    noise = saturate(noise); //-4~1だとで加算したときに変な値になるので 0~1に絞る clamp01と同じ

                    color += noise; //帯電と元の画像を加算
                }

                {//scanline
                    color *= (1 - step(0.8, sin((i.uv.y - _Time.y * 0.2) * 50)));
                }

                {//border
                    color *= 1 - (step(_Border, i.uv.y));
                    fixed borderSize = 0.05;
                    fixed4 borderLine = (step(_Border, i.uv.y + borderSize) * step(i.uv.y + borderSize, _Border + borderSize)) *_Color;
                    borderLine.a = color.a;
                    color += borderLine;
                }

                if (color.a <= 0) {
                    discard;
                }

                return color;
            }

            ENDCG
        }
    }
}

これまでの記事

それぞれの動作は以下の記事に個別で作ったものがあります!

・色を変える www.snoopopo.com


・直線(スキャンラインwww.snoopopo.com


・上下で消えたり表示したりするやつ(ボーダーライン) www.snoopopo.com


・ぶらぶら歪み www.snoopopo.com


・雷 www.snoopopo.com

なんか今思ってること

今みると見本と違うところあるけど、それがなんなのかわからんw
なんかもっと光がぼわ~としているような? 
あともっとスキャンラインの間隔短いか? ボーダーラインが頭のちょっと上に残ってしまってるな? 

とかとかあるけど

shader 勉強としてやったので課題としてよかった^^ 
なんか知識も足りてないと思うけど手を動かす量がもっと足りてないと思っているので、
shaderのいい問題集・課題集? 的なものがあったら教えてくださいー :D~♪

【Unity-Shader】#11 ノイズ画像を使って雷っぽい表現

ノイズ画像をつかって雷っぽい表現を作った

f:id:snoopopo:20200914133303g:plain


youtu.be

今回はこの動画を元にしています。shader Graph の解説動画なので、これをshaderのコードにしたかんじ。

使った画像

【電撃走らせたい画像】
f:id:snoopopo:20200911112928p:plain

【ノイズ画像】
f:id:snoopopo:20200914134235p:plain

こちらより素材をおかりしました:https://ai-catcher.com/

shader

今回は前回の記事*1からフラグメントシェーダしか触っていないので、 フラグメントシェーダのみ抜粋

fixed4 frag(v2f i) : SV_Target
{
    fixed2 noiseUv1 = fixed2(i.uv.x + _Time.y * 1.2, i.uv.y);
    fixed4 noise1 = tex2D(_NoiseTex, noiseUv1 * 0.005); //画像を拡大

    fixed2 noiseUv2 = fixed2(i.uv.x + _Time.y * -1.5, i.uv.y);
    fixed4 noise2 = tex2D(_NoiseTex, noiseUv2 * 0.005); //画像を拡大

    fixed4 noise = noise1 + noise2;

    //noise = noise * 10 - 5; //remap 0~1の範囲を -5~5の範囲にremap
    noise = noise * 10 - 15; //remap 0~2の範囲を -5~5の範囲にremap
    noise = abs(noise); //絶対値をとり、マイナス値だったものプラスに変化 0~5の値に変換
    noise = 1 - noise; //黒白を反転させる -4~1の値に
    noise = saturate(noise); //-4~1だとで加算したときに変な値になるので 0~1に絞る clamp01と同じ

    fixed4 color = tex2D(_MainTex, i.uv) + noise; //帯電と元の画像を加算

    if (color.a <= 0) {
        discard;
    }

    return color;
}

【Unity-Shader】#10 ノイズ画像を使って絵をぶるぶるブレさせる

今回記事は、ノイズ画像を使って絵を歪ませてこんなかんじにぶるぶる横にブレるような動きを作ってみました。

f:id:snoopopo:20200911112829g:plain

▼今回の記事は前回の記事の続きっぽいかも。前回の記事はこちらです。

www.snoopopo.com

用意する画像

【歪ませたい画像】
f:id:snoopopo:20200911112928p:plain

【歪み情報として使うノイズ画像】
f:id:snoopopo:20200911112935p:plain

ノイズ画像自体もプログラムで作成することができますが、今回はその工程はすっ飛ばして既存の画像をつかいます。
このような画像のノイズのことを「パーリンノイズ(PerlinNoise)」または「GradientNoise」というらしい。

↓画像引用元、およびノイズ画像の作り方が書いてあるUnityのリファレンス。
Mathf-PerlinNoise - Unity スクリプトリファレンス

shader全文

Shader "Custom/NoiseDistortion"
{
    Properties
    {
        _MainTex("MainTexture", 2D) = "white" {}
        _NoiseTex("NoiseTexture", 2D) = "white" {}
    }

    SubShader
    {
        Cull Off

        Tags
        {
            "Queue" = "AlphaTest"
            "RenderType" = "AlphaTest"
        }

        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD;
            };

            sampler2D _MainTex;
            sampler2D _NoiseTex;

            float _Border;
            float4 _Color;

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

            fixed4 frag(v2f i) : SV_Target
            {
                fixed2 noiseUv = fixed2(i.uv.x + cos(_Time.y * 0.5), i.uv.y);
                fixed4 noiseColor = tex2D(_NoiseTex, noiseUv) * 0.05;

                i.uv.x += noiseColor.r;
                fixed4 color = tex2D(_MainTex, i.uv);

                if (color.a <= 0) {
                    discard;
                }

                return color;
            }

            ENDCG
        }
    }
}

今回も、フラグメントシェーダのみです。

前回の記事で、画像を歪ませるにはUV座標をずらせばよいことがわかりました。 今回は横ブレさせたいので、UV座標のX座標に手を加えることになりますが、これにノイズ画像を使います。

ノイズ画像は白黒の画像なので、色の範囲は(0,0,0)~(1,1,1)になっています。 この0~1の値をUV座標に加算することでUV座標をずらしこのような処理を実現しています。

解説

ノイズ画像をスクロールさせる

まずはじめにノイズ画像をUVスクロールさせます。
なんでかというと、さきほどノイズ画像の色0~1を使うと書いたが、この値は動かさないと変動しないからです。

fixed4 frag(v2f i) : SV_Target
{
    fixed2 noiseUv = fixed2(i.uv.x + cos(_Time.y * 0.5), i.uv.y);
    fixed4 noiseColor = tex2D(_NoiseTex, noiseUv);

    return noiseColor;
}

f:id:snoopopo:20200911115821g:plain

cosを使って移動速度を滑らかにしていますが、時間経過で変わるなら _Time だけでもOK。


ノイズ画像の色をUV座標に使う

ノイズ画像をUVスクロールさせているので、noiseColorの色はノイズ画像の0~1の間の変動値となっています。
それを歪ませたい画像のUV座標に使います。

今回は横ゆれだけさせたいので、
UV座標のX座標の値にノイズ画像から取得した値noiseColorの値を入れています。
noiseColor.r を加算しているけどgでもbでもいい。なぜなら白黒画像なのでrgbの値はすべて同じのはずだから)

fixed4 frag(v2f i) : SV_Target
{
    fixed2 noiseUv = fixed2(i.uv.x + cos(_Time.y * 0.5), i.uv.y);
    fixed4 noiseColor = tex2D(_NoiseTex, noiseUv) * 0.05;

    i.uv.x += noiseColor.r;
    fixed4 color = tex2D(_MainTex, i.uv);

    if (color.a <= 0) {
        discard;
    }

    return color;
}

先程のノイズ画像をスクロールしたコードと違ってnoiseColorに* 0.05かけているのは、
0~1の値を単純に加算するとブレ幅が大きいから微調整しただけです。

参考にさせて頂きました☆

qiita.com

【Unity-Shader】#09 UV座標を使って絵を歪ませる

docs.google.com

今回の記事は上記の「歪み」部分を参考にさせて頂きました。

簡単な図形を歪ませる

絵を歪ませる前に、_Time を使って時間経過で円を歪ませてみます。

f:id:snoopopo:20200910100846g:plain

fixed4 frag(v2f i) : SV_Target
{
    i.uv.x += sin(i.uv.y * _Time.y * 10) * 0.05; //歪み
    return step(0.3, distance(0.5, i.uv)); //円
}

UV座標をずらすことで歪ませることができる!

絵を歪ませる

円で使った歪みの式をそのまま使います。

f:id:snoopopo:20200910101350g:plain

fixed4 frag(v2f i) : SV_Target
{
    i.uv.x += sin(i.uv.y * _Time.y * 10) * 0.05;

    if (i.uv.x < 0 || 1 < i.uv.x) {
        discard;
    }

    fixed4 color = tex2D(_MainTex, i.uv);

    if (color.a <= 0) {
        discard;
    }
                
    return color;
}

tex2Dに歪んだUV座標を渡すことでいいかんじになりました。


   if (i.uv.x < 0 || 1 < i.uv.x) {
        discard;
    }

コード内の上の部分ですが、歪ませて右にはみ出た(みきれた)部分が左側に表示されて不自然だったので、discardしています。

f:id:snoopopo:20200910101813p:plain
▲このコードがないとこんな風になっちゃってた

【Unity-Shader】#08 直線に沿って消えたり出てきたりさせる

上から消えたり下からでてきたり

f:id:snoopopo:20200906104522g:plain

fixed4 frag(v2f i) : SV_Target
{
    fixed4 color = tex2D(_MainTex, i.uv);
    color *= step(_Border, 1-i.uv.y);
    if (color.a <= 0) {
        discard;
    }
    return color;
}

前回▼の記事でやったstep を使い、 閾値(_Border という名前の変数となっている部分) を動的に変えることで、上から消えたり下からでてきたりするアニメが作れそうです。

www.snoopopo.com


ただこれだけだと少し物足りないので今回は直線を表示してそれに沿って消えたり出てきたりさせたいと思います。

直線に沿って表示したり消えたり…

f:id:snoopopo:20200906112806g:plain

fixed4 frag(v2f i) : SV_Target
{
    fixed4 color = tex2D(_MainTex, i.uv);
    color *= 1-(step(_Border, i.uv.y));

    fixed borderSize = 0.05;
    fixed4 borderLine = (step(_Border, i.uv.y + borderSize) * step(i.uv.y + borderSize, _Border + borderSize)) *_Color;

    borderLine.a = color.a;             
    color += borderLine;

    if (color.a <= 0) {
        discard;
    }

    return color;
}

【Unity-Shader】#07 直線を描く

今回は、線をフラグメントシェーダで描画します。「スキャンライン」というらしい。

線を描く

f:id:snoopopo:20200904083731p:plain

fixed4 frag(v2f i) : SV_Target
{
    return step(0.3, i.uv.y) * step(i.uv.y, 0.4);
}

step

step(閾値, x)

xが閾値以上なら1, 閾値未満なら0 を返す。


上記の例は、UV座標のY座標が0.3~0.4 の位置にあるときに1を返すので、1=白が表示されている。

sin波を使って複数線を描く

fixed4 frag(v2f i) : SV_Target
{
    return sin(i.uv.y * 50);
}

複数線を書くために 0→1→0→1→0・・・ となる値が必要なので、今回はsin波を使います。

f:id:snoopopo:20200904092449p:plain

sin でウェーブさせた値をそのまま色として出力すると、上記のようになり、0(黒)→1(白)→0(黒)→1(白)→0(黒)・・・ を繰り返していることがわかる。

sinでだした値はゆるやかに0から1をいききした値になっている 0→0.1→0.2→…→0.9→0.8…→1
のでぼやけた線みたいな表示になっている。

ここでstepを使い、閾値を元に0か1だけの値にしてはっきりした直線にする。

f:id:snoopopo:20200904093414p:plain

fixed4 frag(v2f i) : SV_Target
{
    return step(0.3, sin(i.uv.y * 50));
}

線を動かす

fixed4 frag(v2f i) : SV_Target
{
    return step(0.3, sin((i.uv.y - _Time.y * 0.2) * 50));
}

_Timeを使ってUV座標のyを下に時間経過で移動させて線が動いているようにみせる。

f:id:snoopopo:20200904094136g:plain

画像と組み合わせたり…

f:id:snoopopo:20200904095920g:plain

白と黒の線が引けたところで、画像の表示と組み合わせてみるとちょっとゲームで使えそうになってきました。

fixed4 frag(v2f i) : SV_Target
{
    fixed4 color = tex2D(_MainTex, i.uv);
    if (color.a <= 0) {
        discard;
    }

    return (1 - step(0.8, sin((i.uv.y - _Time.y * 0.2) * 50))) * color;
}

画像の色と乗算しているため、 黒(0)は黒いまま、白(1)はx1となるので画像の色がそのまま表示されます。


f:id:snoopopo:20200904100915g:plain

fixed4 frag(v2f i) : SV_Target
{
    fixed4 color = tex2D(_MainTex, i.uv);
    color *= (1 - step(0.8, sin((i.uv.y - _Time.y * 0.2) * 50)));
    if (color.a <= 0) {
        discard;
    }

    return color;
}

黒い線の部分は破棄 discard しちゃうのもよさげだ…

【Unity-Shader】#06 テクスチャの色を徐々に変える

テクスチャの色を徐々に変える f:id:snoopopo:20200903100912g:plain

▼ 前回の記事 www.snoopopo.com

全文

Shader "Custom/GrayScaleColor"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
        _Volume("Volume", Range(0,1)) = 0
        _Color("Color", Color) = (1, 1, 1)
    }

    SubShader
    {
        Cull Off
        AlphaToMask On

        Tags
        {
            "Queue" = "AlphaTest"
            "RenderType" = "AlphaTest"
        }

        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD;
            };

            sampler2D _MainTex;
            float _Volume;
            float4 _Color;

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

            fixed4 frag(v2f i) : SV_Target
            {
                fixed4 color = tex2D(_MainTex, i.uv);

                fixed gray = dot(color.rgb, fixed3(0.299, 0.587, 0.114));
                fixed4 targetColor = _Color * gray;

                fixed4 viewColor = lerp(color, targetColor, _Volume);
                return fixed4(viewColor.r, viewColor.g, viewColor.b, tex2D(_MainTex, i.uv).a);
            }

            ENDCG
        }
    }
}

一度グレースケール化させてから色を塗る

               fixed gray = dot(color.rgb, fixed3(0.299, 0.587, 0.114));
                fixed4 targetColor = _Color * gray;

上記のソースの通り、一度グレースケール化してから色を乗算しています。

www.snoopopo.com

こうすることによって、もともとの画像についている色味が消えてちょっとメタリック?なかんじになります。

(左)グレースケール化せずに乗算 (右)グレースケール化後、乗算 f:id:snoopopo:20200903102035p:plainf:id:snoopopo:20200903102042p:plain

lerp

               fixed4 viewColor = lerp(color, targetColor, _Volume);
                return fixed4(viewColor.r, viewColor.g, viewColor.b, tex2D(_MainTex, i.uv).a);

徐々に色を変えるには線形補完が使える。