🌈

そろそろShaderをやるパート95 -URP編- グリッドで区切ってランダム風に塗り分ける

に公開

そろそろShaderをやります

そろそろShaderをやります。そろそろShaderをやりたいからです。
パート100までダラダラ頑張ります。10年かかってもいいのでやります。
100記事分くらい学べば私レベルの初心者でもまあまあ理解できるかなと思っています。

という感じでやってます。

※初心者がメモレベルで記録するので
 技術記事としてはお力になれないかもしれません。

下準備

下記参考
そろそろShaderをやるパート1 Unite 2017の動画を見る(基礎知識~フラグメントシェーダーで色を変える)

URP対応のためにUnityHubからプロジェクトテンプレート選択画面でURPを選択しました。

バージョン

Unity 2021.2.12f1
Universal RP 12.1.4

デモ

UVをグリッドで区切ってランダムに色が移り変わる雰囲気のデモです。

ゲームジャム参加時にDeepSeekの応答待機画面として利用しました。

参考リンク:日本経済救済シミュレーター

Shaderサンプル

Shader "Custom/GridEffect"
{
    Properties
    {
        _BaseColor ("Grid Color", Color) = (1,1,1,1)
        _GridColor ("Grid Color", Color) = (0,0,0,1)
        _GridCount ("Grid Count", Range(1, 100)) = 10
        _Speed ("Speed", Range(0, 100)) = 1
    }
    SubShader
    {
         Tags
        {
            "RenderType" = "Opaque"
            "RenderPipeline" = "UniversalPipeline"
        }
         
        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

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

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

            float4 _BaseColor;
            float4 _GridColor;
            float _GridCount;
            float _Speed;

            // 0~1の疑似ランダムな値を返す関数。
            float rand(float2 co) 
            {
                return frac(sin(dot(co.xy, float2(12.9898, 78.233))) * 43758.5453);
            }
           
            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = TransformObjectToHClip(v.vertex);
                o.uv = v.uv;
                return o;
            }

            float4 frag(v2f i) : SV_Target
            {
                // fracで連続する0~1の値を計算。
                float2 gridUV = i.uv * _GridCount;

                // グリッドIDを計算し、グリッドごとに時間変化するハッシュ値を作成。
                int2 gridID = int2(floor(gridUV));
                float random = rand(float2(gridID));
                float hash = frac(random + _Time.x * _Speed);

                // ハッシュ値に応じてセルの色を決定。
                float interpolation = step(0.5, hash);
                float4 cellColor = lerp(_BaseColor, _GridColor, interpolation);
                return cellColor;
            }
            ENDHLSL
        }
    }
}

int2 gridID = int2(floor(gridUV));
この処理が決め手です。uvをfloorで切り捨てることで、各ピクセルが属するグリッドの2次元座標を計算できます。

floorで切り捨てた後の値が切り替わるまではグリッド単位で数値が変わらないため、ピクセルがどのグリッドに所属するかを二次元座標で表現可能となります。

注意点として、randは疑似乱数であるため、色の切り替わり方はグリッドごとに一定となり、あくまで"ランダム風"となります。ちゃんとランダムにしたい場合はC#から乱数を受け取るとできると思います。

参考リンク:そろそろShaderをやるパート13 マウスのRayの座標をC#からShaderで受け取る

Discussion