💭

Unityシェーダー超入門⑦ 菱形のグリッド作成

2023/04/24に公開

今回もsmoothstepを使って図形を作ります。

ちょっとメタリックな質感なやつ

大元はGLSLのyoutubeでの解説をHLSLに変換をしているだけです。
参照元は以下の動画
https://www.youtube.com/watch?v=VmrIDyYiJBA&t=745s

コードはこんな感じ

05_Rhombus
Shader "Unlit/05_Rhombus"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            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
            {   
                float4 col = 0;
                float2 uv = i.uv * 6;
                uv = frac(uv - .5);
                float2 a = frac(uv) - .5;
                float2 b = frac(uv - .5) - .5;
                float2 gv = length(a) < length(b) ? a : b;
                float y = smoothstep(0, 0.98, length(gv.y));
                return float4(y,y,y,1.0)*.8;
            }
            ENDCG
        }
    }
}

今回もfragシェーダー内で完結しています。

05_Rhombus
            fixed4 frag (v2f i) : SV_Target
            {   
                float4 col = 0;
                float2 uv = i.uv * 6;
                uv = frac(uv - .5);
                float2 a = frac(uv) - .5;
                float2 b = frac(uv - .5) - .5;
                float2 gv = length(a) < length(b) ? a : b;
                float y = smoothstep(0, 0.98, length(gv.y));
                return float4(y,y,y,1.0)*.8;
            }

ほぼ、前回と同じような記述になっています。
計算しやすいようにuvの原点は(0,0)にずらしてあります。
今回ポイントとなるのは菱形の形成のされ方になります。

菱形パターンの作り方

以下のコードでほぼ完結しています。

05_Rhombus
                float2 a = frac(uv) - .5;
                float2 b = frac(uv - .5) - .5;
                float2 gv = length(a) < length(b) ? a : b;

言語化してみましょう。
aはfrac関数で引数uvの小数を-0.5をしています
bはfrac関数で引数uvを事前に-0.5し、結果として返ってきた小数を更に-0.5しています。
aとbの長さを比較してgvに代入しています。
流れとしてはこんな感じです。
frac関数はfrac(x)は引数xが1.2の場合、0.2を返すという単純なものです。
前回のUVの時にも使用していたものですね。
そして菱形が出来る要因はここです。

05_Rhombus
float2 a = frac(uv) - .5;
float2 b = frac(uv - .5) - .5;

ここで更にオフセットを加えることで実現してます。
-0.5の値を-0.48とか変えて見ると仕組みが見えてきます。
要は正方形での塗りは変わらないのですが、aとbでオフセットをかけた値を作り比較した
結果塗りのパターンを変えたという感じだと思われます。
理屈はわかってきたのですが、何故そうなっているか…を完全には答えれないかもです。
悔しいですがここをずっと考えるわけにもいかないので、後日また履修します。
後はy軸に向けたグラデーションをsmoothstepで作っているという感じです。
return float4(y,y,y,1.0)*.8;
ここで0.8かけているのは微妙に色の濃さを調整したかっただけです。

完全には理解出来なくても

考える時間を設けることとタイムリミットを設けることかなと…
シェーダーを書くのが目的ではなく、シェーダーを使った表現力をつけたいが
目的なのを忘れないように勉強を続けたいです。

4/24追記

オフセットを図にしたら自分の中で納得行く理解まで漕ぎ着けた。
正方形同士が重なり合う部分で元の位置で塗るか、オフセットされた位置で塗るかだけってシンプルに考えたら良き感じに理解出来てきた気がします

Discussion