🌟

Unityシェーダー超入門③ グラデーションを作ろう

2023/04/02に公開

今回はグラデーションを作ります

とりあえず結果とコードです。
Color_1とColor_2で指定した色味でグラデーションが出来ています。

Gradation
Shader "Unlit/Gradation"
{
    Properties
    {
        _Color1("Color_1" , Color) = (1,1,1,1)
        _Color2("Color_2" , Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        
        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;
            };

            float4 _Color1;
            float4 _Color2;

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

            fixed4 frag (v2f i) : SV_Target
            {
                return lerp(_Color1,_Color2,i.uv.y);
            }
            ENDCG
        }
    }
}

中身の解説

注目すべきは以下のvert関数とfrag関数の中身です。

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

            fixed4 frag (v2f i) : SV_Target
            {
                return lerp(_Color1,_Color2,i.uv.y);
            }

UVとは

下記のコードの説明から、といっても一行です。
そもそもUVとは何なのか?という方もいらっしゃるかと思います。
UVとは頂点データから取得出来るテクスチャの座標情報です。
(ネットの海にUVの解説は沢山あるので色々見てみましょう)
今回の色味に合わせて分かりやすく図にしてみました。
座標は基本的に正規化(0~1)して使います。

Gradation
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
		//頂点からUVの情報を取得
                o.uv = v.uv;
                return o;
            }

上記で行われたことは以下の通りです。
v2f構造体「o」のuv情報を、appdata構造体「v」のuv情報にコピーしています。
一見面倒なことしてるなと思いますが、これにより「vert(頂点シェーダー)」で計算されたUV座標が「frag(フラグメントシェーダー)」に渡され、フラグメントシェーダーで色やテクスチャの計算に使用ができます。

Lerpについて

残す所はfragの処理だけになります。
ここではlerpという関数を使用しています。
lerpは2つの値の間の中間値を計算する関数です。線形補間とも言うようです。
数学的な部分はまだ理解に及んでいませんが、挙動としては以下の通りです。
lerp(value1,value2,x)
・xが0の場合「value1」が返ってきます
・xが1の場合「value2」が返ってきます
2つの値の間の中間値を計算する関数で、第三引数の値により割合が変化するということです。
では改めてコードを見てましょう。

Gradation
            fixed4 frag (v2f i) : SV_Target
            {
                return lerp(_Color1,_Color2,i.uv.y);
            }

第1、第2引数に設定したカラーの値が入っています。
第3引数にはuv情報のy軸の座標情報が格納されています。

Fragmentは描画するピクセルの数だけ繰り返されます。
256pxだったら256回分処理が走るという感じです。
そして先程のuv座標のことを思い出してください。
i.uv.yでy軸の座標を引っ張ってきました。
そして下記の画像のようにピクセルをブロックでイメージしてみてください。

(0,0)の時は緑(0,0.5)の時は緑と青の中間という感じに1ピクセルずつ塗りつぶしているのです。
試しに以下のようにコードを打ってみましょう

Gradation
            fixed4 frag (v2f i) : SV_Target
            {
                return lerp(_Color1,_Color2,0.5);
            }


(0,0.5)の時と同じ色味になっています。
このことから1ピクセルずつ塗りつぶしているのが良くわかります。
この細かく区切られたブロックを一つ一つ塗りつぶすことでグラデーションを表現しています。
そうすると、今回使われているlerpの処理も理解が進みます。

第1引数、第2引数

任意のカラーを指定

第3引数

UV座標のY軸

具体的な処理

Y軸の座標(0-1)を引数にして第1引数、第2引数の割合を決める

という感じです。
そして勘違いしないで欲しいのが、Lerpはグラデーションを作る関数ではないということです。
僕も最初同じことを思っていたのですが、移動やアニメーションなど様々なことに使えます。
それらに関してはまた別の機会に触れようと思います!

それでは、良きシェーダーライフを!

Discussion