Unity

【Unity】Skyboxシェーダーの書き方

UnityのSkyboxはシェーダーを書くことで自作できるのですが、あまり情報がなかったのでまとめてみました。

まず、次のようなy軸方向で色がグラデーションするシンプルな例を見てみましょう。

vertical.gif

このSkyboxを実現しているシェーダーは以下のようになります。
Skyboxシェーダーの特徴は頂点データとして渡されるTEXCOORD0です。ここには視線方向の三次元の値が[-1, 1]の範囲で入っています。例えば、デフォルトのカメラは+z軸方向を向いているので、画面の真ん中でのtexcoordの値は[0, 0, 1]になります。
また、背景として描画するので、RenderTypeQueueBackgroundにして、ZWriteOffにしておきます。"PreviewType"="SkyBox"は必須ではないですが、設定するとマテリアルのプレビューがSkybox用のものになります。

Vertical.shader
Shader "CustomSkybox/Vertical"
{
    SubShader
    {
        Tags
        {
            "RenderType"="Background"
            "Queue"="Background"
            "PreviewType"="SkyBox"
        }

        Pass
        {
            ZWrite Off
            Cull Off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct appdata
            {
                float4 vertex : POSITION;
                float3 texcoord : TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 texcoord : TEXCOORD0;
            };

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

            fixed4 frag (v2f i) : SV_Target
            {
                return fixed4(lerp(fixed3(1, 0, 0), fixed3(0, 0, 1), i.texcoord.y * 0.5 + 0.5), 1.0);
            }
            ENDCG
        }
    }
}

このシェーダーでマテリアルを作成して、Window > Lighting > Settings > Scene > Environment > Skybox Materialにセットすることで、Skyboxとして適用することができます。

frag関数を以下のようにすると+x軸方向が赤、+y軸方向が緑、+z軸方向が青となるようなSkyboxとなります。

RGB.shader
fixed4 frag (v2f i) : SV_Target
{
    return fixed4(i.texcoord * 0.5 + 0.5, 1.0);
}

rgb.gif

最後にせっかくなので太陽を書いてみました。

sun.gif

このシェーダーでは太陽の方向_SunDirと視線方向texcoordの内積をとることで、どれぐらい太陽の方向を向いているかを計算しています。この値を適当な値で累乗することで太陽の強さを設定しています。

Sun.shader
Shader "CustomSkybox/Sun"
{
    Properties {
        _BGColor ("Background Color", Color) = (0.7, 0.7, 1, 1)
        _SunColor ("Color", Color) = (1, 0.8, 0.5, 1)
        _SunDir ("Sun Direction", Vector) = (0, 0.5, 1, 0)
        _SunStrength("Sun Strengh", Range(0, 30)) = 12
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Background"
            "Queue"="Background"
            "PreviewType"="SkyBox"
        }

        Pass
        {
            ZWrite Off
            Cull Off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            fixed3 _BGColor;
            fixed3 _SunColor;
            float3 _SunDir;
            float _SunStrength;

            struct appdata
            {
                float4 vertex : POSITION;
                float3 texcoord : TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 texcoord : TEXCOORD0;
            };

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

            fixed4 frag (v2f i) : SV_Target
            {
                float3 dir = normalize(_SunDir);
                float angle = dot(dir, i.texcoord);
                fixed3 c = _BGColor + _SunColor * pow(max(0.0, angle), _SunStrength);
                return fixed4(c, 1.0);
            }
            ENDCG
        }
    }
}

参考