-100p

-10p

+10p

+100p

Unity松明シェーダー

Unity uGUI用、松明シェーダー。昔のRPGの洞窟内のような表現。
(Torch Shader for Unity uGUI)

関連ページ
昔のRPGでは、洞窟に入ると自分を中心に周囲が明るく、外側が真っ暗になる演出がよくあった。
今の自分ならこのシェーダーを作れるのではと思い、試してみて出来たので共有。

松明シェーダー、コード全文

下は松明シェーダーを使ったサンプル動画。



以下コード全文。uGUI Imageへの反映方法は こちらの記事 参照。
今回の場合GrabPassを使っているので、 こちら の知識も必要になる。
Shader "UI/Torch"
{
    Properties
    {
        [HideInInspector]_MainTex("-",2D)="white"{} 
        _OverlapColor("OverlapsColor", Color) = (0.35,0.5,1,1)

        [Space(10)]
        _TorchRange("TorchRange", Range(0, 1)) = 0.4
        _FadeRange("FadeRange", Range(0.001, 1)) = 0.3
        _DarknessColor("DarknessColor", Color) = (0,0,0,1)

        [Space(10)]
        _GlowRange("GlowRange", Range(0.001, 1)) = 1
        _GlowPower("GlowPow", Range(0, 1)) = 0.8
        _GlowColor("GlowColor", Color) = (1,0.55,0.3,1)
    }

    SubShader
    {
        Tags { "Queue" = "Transparent" }
        Cull Off
        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha

        GrabPass{}

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

            struct appdata
            {
                fixed2 uv : TEXCOORD0;
                fixed4 vertex : POSITION;
                fixed4 color : COLOR;
            };

            struct v2f
            {
                fixed2 uv : TEXCOORD0;
                fixed4 vertex : POSITION;
                fixed4 color : COLOR;
            };
            
            sampler2D _GrabTexture;
            float4 _GrabTexture_TexelSize;

            fixed4 _OverlapColor;

            fixed _TorchRange;
            fixed _FadeRange;
            fixed4 _DarknessColor;

            fixed _GlowPower;
            fixed _GlowRange;
            fixed4 _GlowColor;

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

            fixed getDistance(v2f i)
            {
                fixed2 centerPos = fixed2(0.5, 0.5);

                
//スクリーンの縦横の短い方を取得

                fixed minScreen = min(_ScreenParams.x, _ScreenParams.y);
                
//x軸とy軸のuv座標を補正、スクリーンの縦横比を適切に掛けることで正円にする

                fixed fixX = centerPos.x + (i.uv.x - centerPos.x) * (minScreen / _ScreenParams.y);
                fixed fixY = centerPos.y + (i.uv.y - centerPos.y) * (minScreen / _ScreenParams.x);
                
//x軸とy軸の中心からの距離を取得

                fixed diffX = abs(fixX - centerPos.x);
                fixed diffY = abs(fixY - centerPos.y);

                
//中心からの直線距離*2を返す

                return sqrt(pow(diffX, 2) + pow(diffY, 2)) * 2;
            }

            fixed4 getInTorchColor(fixed4 col, fixed distance)
            {
                
//glowRate=1で最大級の明るさ、glowRate=0でglow処理を行わない

                fixed glowRate = 1 - (saturate(distance / (_TorchRange * _GlowRange)));
                
//加算合成でピクセル色を1~4倍に明るくした上で、_GlowColorを掛け合わせる

                fixed4 maxGlowColor = col * (1 + _GlowPower)* (1 + _GlowPower) * _GlowColor;

                
//TorchRangeの内側の色を返す

                
//中心に近いほどmaxGlowColorの割合が強くなり、TorchRangeのエッジに近づくほどオリジナル色に近くなる

                return (1 - glowRate) * col + glowRate * maxGlowColor;
            }

            fixed4 getOutTorchColor(fixed4 col, fixed distance)
            {
                
//fadeRate=1で完全な暗闇、fadeRate=0で暗闇になし

                fixed fadeRate = 1 - (saturate(_FadeRange - (distance - _TorchRange)) / _FadeRange);

                
//TorchRangeの外側の色を返す

                
//TorchRangeのエッジ部分はオリジナル色、TorchRange+FadeRangeに近いほどDarknessColorの割合が強くなる

                return (1 - fadeRate) * col + fadeRate * _DarknessColor;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_GrabTexture, i.uv);
                
//最初に画面全体に_OverlapColorを掛ける

                col *= _OverlapColor;

                
//指定uv座標の中心からの直線距離を取得

                fixed distance = getDistance(i);

                
//TorchRangeの内側の色を取得

                fixed4 inTorchColor = getInTorchColor(col, distance);
                
//TorchRangeの外側の色を取得

                fixed4 outTorchColor = getOutTorchColor(col, distance);

                
//uv座標がTorchRangeの内側かどうか

                fixed isInTorchRange = step(distance, _TorchRange);
                
//TorchRangeの内側であればinTorchColorを選択、外側であればoutTorchColorを選択

                return isInTorchRange * inTorchColor + (1 - isInTorchRange) * outTorchColor;
            }
            ENDCG
        }
    }
}

プロパティを解説

用意してあるプロパティは7つ、結構多い。
松明シェーダーのプロパティ
 OverlapColor 
: 画面全体に一番最初に上掛けするベースの色設定。
 TorchRange 
: 松明の明かりの有効範囲、0~1まで設定できる。
 FadeRange 
: TorchRangeのエッジから、完全にDarknessColorに遷移するまでの距離。0~1まで設定できる。
 DarknessColor 
: 周囲の暗闇の色設定。暗闇と言ったが別に白色も設定できる。
 GlowRange 
: TorchRangeの内側で、明かりの色を上掛けする範囲。
 GlowPow 
: 上掛けする明かりの色の強さ。0~1まで設定でき、数値が上がるほど白っぽくなる。
 GlowColor 
: 上掛けする明かりの色設定。
ちょっと分かり辛いので以下動画で解説していく。

OverlapColorを弄ることで画面全体のベース色に変更を加える。
夜の暗闇を表現したいなら、青みがかった寒色がおすすめ。初期値から弄らない方がいいかも。


TorchRangeで明かりの有効範囲を拡大縮小できる。FadeRangeは暗闇に移行するまでのぼかし表現の程度を操作できる。


DarknessColorを弄ることで外側の暗闇の色を変更できる。暗闇と言ったが別に暗い色である必要はない。
明るい色を設定することで、松明感は無くなるが別の表現ができるかもしれない。


GlowRangeで中心の明かりの色の範囲を拡大縮小できる。GlowPowで明かりの強さを変更できる。


GlowColorを弄ることで中心の明かりの色を変更できる。

2
2

-100p

-10p

+10p

+100p