うにてぃブログ

UnityやUnreal Engineの記事を書いていきます

【Unity】Grid Shader

Shader でグリッドを表示させる方法について考える

画像を n分割する

グリッドを作成する前に 画像を n分割する方法を考える
画像を分割するためには frac 関数を利用する
frac 関数は「小数値の小数部分を返す」関数なので uv に 5を掛けた場合、下図のように 0 ~ 1 を5回繰り返す

f:id:hacchi_man:20200118220226p:plain:w400

fixed4 frag (v2f i) : SV_Target
{
     return fixed4(frac(i.uv * 5), 1, 1);
}

なのでフラグメント処理を上記のようにすることで下図のように5 ✕ 5 分割することができる

f:id:hacchi_man:20200118220320p:plain:w400

グリッドを表示する

先程利用した分割数に グリッドの幅 (0.1) を追加したものの結果を見てみると
※図の作成が面倒だったので分割数を2にしている

frac(i.uv * (2 + 0.1)) 

f:id:hacchi_man:20200118222050p:plain:w400

となりグリッドの幅 以下のところを別色で描画してやるといい感じでグリッドが表示できそう

fixed4 frag (v2f i) : SV_Target
{
     if (frac(i.uv.x * (2 + 0.1)) < 0.1 || frac(i.uv.y * (2 + 0.1)) < 0.1)
     {
           return fixed4(0.5, 0.5, 0.5, 1);
     }
     return fixed4(1, 1, 1, 1);
}

上記のフラグメント処理にすると下図のようになりグリッドが表示された

f:id:hacchi_man:20200118222958p:plain:w400

最終的なシェーダー

if文が利用されていたり、分割数やグリッドの幅固定値だったのを書き換えた最終的なシェーダが以下になります

f:id:hacchi_man:20200118223354p:plain:w400

Shader "Custom/Unlit/Grid" {
    Properties {
        _LineColor ("Line Color", Color) = (1,1,1,1)
        [NoScaleOffset] _MainTex ("Texture", 2D) = "white" {}
        [IntRange] _SplitCount("Split Count", Range(1, 30)) = 10
        _LineSize("Line Size", Range(0.01, 1)) = 0.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;
            };
            
            sampler2D _MainTex;
    
            fixed4 _LineColor;
            float _SplitCount;
            float _LineSize;
            
            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(
                    tex2D(_MainTex, i.uv),
                    _LineColor, 
                    saturate(
                        (frac(i.uv.x * (_SplitCount + _LineSize)) < _LineSize) + 
                        (frac(i.uv.y * (_SplitCount + _LineSize)) < _LineSize)
                    )
                );
            }
            ENDCG
        }
    }
}