LoginSignup
3
6

More than 3 years have passed since last update.

Unity LineRendererでシェーダーを用いて点線を描画する

Last updated at Posted at 2020-10-11

概要

以下のように丸を並べた点線をLineRendererで描画します。ついでにアニメーションもつけました。
dotted-line.gif

プロジェクトのソースはこちら
https://github.com/Arihide/unity-dotted-line

解説

LineRendererをアタッチする

まず、適当なGameObjectにLineRendererをアタッチします。
その後、下のように[Texture Mode]を[Tile]に設定します。
スクリーンショット_2020-10-12_0_03_03.png

シェーダーを書く

次に、LineRendererに設定する点線のマテリアルのためのシェーダーを書いていきます。

1.丸を並べる

まずは下図のように、丸を隙間なく敷き詰めるLineRenderer用のシェーダーを書きます。
スクリーンショット 2020-10-12 0.24.09.png

どのようなロジックでこれを実現するかというと、
先程のTextureMode:Tileの設定によって、以下のようなUV座標になるので、
dotted-line.png
以下のように0...1になるように座標を変更したあと、
dotted-line2.png
中心:(0.5, 0.5)、半径:0.5 の円を考えて、内側は不透明、外側は透明になるように描画してあげればよいです。
それを踏まえたシェーダーのコードは以下になります。

Shader "Custom/DottedLine"
{
    SubShader
    {
        Tags { "RenderType" = "Transparent" }
        Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                half2 texcoord : TEXCOORD0;
                half4 vertex : POSITION;
                fixed4 color : COLOR0;
            };

            struct v2f
            {
                half2 uv : TEXCOORD0;
                half4 pos : SV_POSITION;
                fixed4 color : COLOR0;
            };

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

            fixed4 frag (v2f i) : SV_TARGET
            {
                // 1の剰余をとることで、0と1の間を繰り返すようにする
                i.uv.x = i.uv.x % 1;

                fixed4 col = i.color;

                // 円の内側を不透明、外側を透明にする
                half s = length(i.uv - half2(1, 1) * 0.5);
                col.a = saturate((0.5 - s) * 100);

                return col;
            }
            ENDCG
        }
    }
}

上記のシェーダーを記述後、マテリアルを作成しLineRendererのマテリアルにアタッチすると、はじめの図のように線に沿って丸が描画されると思います。

ここで、以下のコード部分が若干複雑なので補足します。

// 円の内側を不透明、外側を透明にする
half s = length(i.uv - half2(1, 1) * 0.5);
col.a = saturate((0.5 - s) * 100);

この関数をプロットすると以下のようになります。(xy平面がそれぞれUV、z軸はアルファ値)
geogebra-export.png

図を見てもらうとわかるように、円柱ではなく円錐台になっています。
このようにすることによって、円の境界線をぼかしてきれいに描画できるようになります。

円の隙間を開ける

隙間が詰まりすぎていて気になるので、次は間隔を少し開けてみます。
スクリーンショット 2020-10-12 1.54.10.png
これは以下のように、_Spaceという変数を用意して、剰余と円の中心をずらせば実現できます。

Shader "Custom/DottedLine"
{
    Properties
    {
        _Space ("Space Between Dots", Range(1, 5)) = 1.2
    }
    SubShader
    {
        //...(中略)

            half _Space;

            fixed4 frag (v2f i) : SV_TARGET
            {
                i.uv.x = i.uv.x % _Space;

                fixed4 col = i.color;

                // 円の内側を不透明、外側を透明にする
                half s = length(i.uv - half2(_Space, 1) * 0.5);
                col.a = saturate((0.5 - s) * 100);

                return col;
            }
            ENDCG
        }
    }
}

変更後、マテリアルから[Space Between Dots]の値を調節することで隙間があくのを確認できます。

アニメーションさせる

これで完成でもよいのですが、せっかくなので冒頭のGifのように時間経過によって丸が動くようなアニメーションもつけたいと思います。これはとても簡単で、frag関数冒頭を

i.uv.x = (i.uv.x + _Time * 50) % _Space;

と置き換えることで実現できます。見ていただけばわかるように時間ごとに座標をずらしています。

まとめ

以上、LineRendererのシェーダーで点線を描画する方法について説明しました。
シェーダーを工夫すれば、円ではなく楕円などの点線にすることもできると思うので、色々試してみるのも面白いかもしれません。

3
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
6