概要
以下のように丸を並べた点線をLineRendererで描画します。ついでにアニメーションもつけました。
プロジェクトのソースはこちら
https://github.com/Arihide/unity-dotted-line
解説
LineRendererをアタッチする
まず、適当なGameObjectにLineRendererをアタッチします。
その後、下のように[Texture Mode]を[Tile]に設定します。
シェーダーを書く
次に、LineRendererに設定する点線のマテリアルのためのシェーダーを書いていきます。
1.丸を並べる
まずは下図のように、丸を隙間なく敷き詰めるLineRenderer用のシェーダーを書きます。
どのようなロジックでこれを実現するかというと、
先程のTextureMode:Tileの設定によって、以下のようなUV座標になるので、
以下のように0...1になるように座標を変更したあと、
中心:(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軸はアルファ値)
図を見てもらうとわかるように、円柱ではなく円錐台になっています。
このようにすることによって、円の境界線をぼかしてきれいに描画できるようになります。
円の隙間を開ける
隙間が詰まりすぎていて気になるので、次は間隔を少し開けてみます。
これは以下のように、_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のシェーダーで点線を描画する方法について説明しました。
シェーダーを工夫すれば、円ではなく楕円などの点線にすることもできると思うので、色々試してみるのも面白いかもしれません。