放射状の模様を描画するシェーダ（くり抜き有り）

twitterで貼った、放射状エフェクトを描画するシェーダのコードを貼っておきます
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">演出用に放射シェーダ書いた。<br>u1w終わったらqiita書きます。<a href="https://twitter.com/hashtag/unity1week?src=hash&amp;ref_src=twsrc%5Etfw">#unity1week</a> <a href="https://t.co/ERnMK6oIsO">pic.twitter.com/ERnMK6oIsO</a></p>&mdash; MIYAKE (@ScreenPocket) <a href="https://twitter.com/ScreenPocket/status/1364530533087158276?ref_src=twsrc%5Etfw">February 24, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#コード
今回のシェーダはBuiltInShaderのUI-Defaultをベースに作成しています。UI用です。

```glsl:UiRadiation.shader
Shader "ScreenPocket/UI/Radiation"
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
        _Color ("Color", Color) = (1,1,1,1)
        _Angle ("Angle", Float) = 0
        _LineCount ("Line Count", Float) = 32
        _LineRate ("Line Rate", Range(-1,1)) = 0
        
        [Header(Clipping)]
        _Radius ("Radius", Range(0,1)) = 1
        
        [Header(UI Default Parameter)]
        _StencilComp ("Stencil Comparison", Float) = 8
        _Stencil ("Stencil ID", Float) = 0
        _StencilOp ("Stencil Operation", Float) = 0
        _StencilWriteMask ("Stencil Write Mask", Float) = 255
        _StencilReadMask ("Stencil Read Mask", Float) = 255

        _ColorMask ("Color Mask", Float) = 15

        [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
    }

    SubShader
    {
        Tags
        {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }

        Stencil
        {
            Ref [_Stencil]
            Comp [_StencilComp]
            Pass [_StencilOp]
            ReadMask [_StencilReadMask]
            WriteMask [_StencilWriteMask]
        }

        Cull Off
        Lighting Off
        ZWrite Off
        ZTest [unity_GUIZTestMode]
        Blend One OneMinusSrcAlpha
        ColorMask [_ColorMask]

        Pass
        {
            Name "Default"
        CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 2.0

            #include "UnityCG.cginc"

            #pragma multi_compile_local _ UNITY_UI_CLIP_RECT
            #pragma multi_compile_local _ UNITY_UI_ALPHACLIP

            struct appdata_t
            {
                float4 vertex   : POSITION;
                float4 color    : COLOR;
                float2 texcoord : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
                float4 vertex   : SV_POSITION;
                fixed4 color    : COLOR;
                float2 texcoord  : TEXCOORD0;
                float4 worldPosition : TEXCOORD1;
                half4  mask : TEXCOORD2;
                UNITY_VERTEX_OUTPUT_STEREO
            };

            sampler2D _MainTex;
            half4 _Color;
            half4 _TextureSampleAdd;
            float4 _ClipRect;
            float4 _MainTex_ST;
            float _MaskSoftnessX;
            float _MaskSoftnessY;
            float _Angle;
            float _Radius;
            float _LineCount;
            float _LineRate;

            v2f vert(appdata_t v)
            {
                v2f OUT;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
                float4 vPosition = UnityObjectToClipPos(v.vertex);
                OUT.worldPosition = v.vertex;
                OUT.vertex = vPosition;

                float2 pixelSize = vPosition.w;
                pixelSize /= float2(1, 1) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy));

                float4 clampedRect = clamp(_ClipRect, -2e10, 2e10);
                float2 maskUV = (v.vertex.xy - clampedRect.xy) / (clampedRect.zw - clampedRect.xy);
                OUT.texcoord = float4(v.texcoord.x, v.texcoord.y, maskUV.x, maskUV.y);
                OUT.mask = half4(v.vertex.xy * 2 - clampedRect.xy - clampedRect.zw, 0.25 / (0.25 * half2(_MaskSoftnessX, _MaskSoftnessY) + abs(pixelSize.xy)));

                OUT.color = v.color;
                return OUT;
            }

            half4 frag(v2f IN) : SV_Target
            {
                half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd);

                //座標を円周角度に変換
                float2 uv = float2(IN.texcoord.x-0.5, -IN.texcoord.y+0.5);
                float radian = atan2(uv.x, uv.y);
                //円周角度の繰り返し数とズラし角度を加味してsinにする
                float sinRate = sin(radian * _LineCount + _Angle);
                //sin波を0,1に切り分ける（パキッと切りたくないならceil()を止める）
                sinRate = ceil( saturate(sinRate + _LineRate) );
                color *= lerp( _Color, IN.color, sinRate);

                #ifdef UNITY_UI_CLIP_RECT
                half2 m = saturate((_ClipRect.zw - _ClipRect.xy - abs(IN.mask.xy)) * IN.mask.zw);
                color.a *= m.x * m.y;
                #endif

                //円形にくり抜く
                float l = length(uv);
                color.a = saturate(color.a * floor(l*2+(1 - _Radius)));
                
                #ifdef UNITY_UI_ALPHACLIP
                clip (color.a - 0.001);
                #endif

                color.rgb *= color.a;

                return color;
            }
        ENDCG
        }
    }
}

```

#使い方
使い方としては、上記のシェーダを充てたマテリアルをUIのImageかRawImageに設定する事で放射を表示する事が出来ます。
![スクリーンショット 2021-03-07 205609.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61266/724a04fb-197a-72c3-16fe-782ad0a28aed.png)
各パラメータの用法は下記の感じです

| パラメータ名 |用法|
|:--|:--|
|_Color|放射の帯の色を決めます。この色とアタッチしたGraphic（Image、RawImage）のColorを繰り返した放射模様となります|
|_Angle|放射の帯の角度をズラせます。加算し続ける事で放射が回転します|
|_LineCount|放射の帯の数を指定出来ます。少数を指定すると帯の境目が見えてしまうので整数指定の方が良いです|
|_LineRate|放射の帯とそうでない分の塗りつぶし割合を指定できます。０でどちらも同じ幅です|
|_Radius|中心をくり抜く際の割合を指定できます|
_Radiusは放射描画とは無関係な処理ではありますが、せっかくなので残しておきます。
下記の用例キャプチャの様に、トランジション表現でくり抜きたい場合などでご利用ください。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">unity1week3日目（※音出ます）<br>・ステージ選択追加<br>・とりあえずゲームループ完成<br>・場面遷移用のシェーダ2つ書いた（放射とストライプ）<br>・やりなおしボタン追加<br><br>あと結果画面作ったらステージ量産できるかな？<a href="https://twitter.com/hashtag/unity1week?src=hash&amp;ref_src=twsrc%5Etfw">#unity1week</a> <a href="https://t.co/n0WC93uRpC">pic.twitter.com/n0WC93uRpC</a></p>&mdash; MIYAKE (@ScreenPocket) <a href="https://twitter.com/ScreenPocket/status/1364610152947736576?ref_src=twsrc%5Etfw">February 24, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 使用上の注意
使用の際は、諸外国で怒られないようにお気を付けください。
※本記事のシェーダによる表現で政治的な意図を見出されて使用者が不利益を被ったとしても、作者は責任を負わない物とさせて頂きますので了承した上でご利用ください。