I haven’t found a way to do it directly from the shader, so I’m simply extending the LineRenderer to a predetermined maximum, and scripting _MaxDistance and _CutoffDistance values to the shader, so when the tracer needs to stop because it hit a wall, the _CutoffDistance will stop it, as well as _MaxDistance lending itself pretty well towards fixed speed calculations. Here’s the shader if anyone wants it. It has controls to set base transparency and fade duration as well as things like length, color, speed, etc. Please note that the speed is partially tied to the length; if you make it longer, you should turn down the speed if you want it to move the same speed as a shorter tracer. And here’s a super-professional, Grade-A tracer texture to use.
Shader "Custom/TracerShader"
{
Properties
{
_MainTex("Tracer Texture", 2D) = "white" {}
_Color("Color", Color) = (1, 1, 1, 1)
_Length("Length", Range(0.1, 1000)) = 1
_Speed("Speed", Range(0, 15)) = 2.0
_StartTime("Start Time", Float) = 0.0
_Offset("Offset", Range(1, 5)) = 0
_Fade("Fade time", Range(0, 5)) = 0
_Transparency("Transparency", Range(0, 1)) = 0
_TailBlendCutoff("Tail Blending Cutoff", Range(0, 1)) = 0.0
_Width("Tracer Texture Width", Float) = 0.0
_MaxDistance("Max Distance", Float) = 1000.0
_CutoffDistance("Cutoff Distance", Float) = 0.0
_AlphaClamp("Alpha Clamp", Range(0, 1)) = 0.0
_Debug("Debug", int) = 1
_DebugColorPre("DebugColorPre", Color) = (1, 1, 1, 1)
_DebugColorPost("DebugColorPost", Color) = (1, 1, 1, 1)
}
SubShader
{
Tags
{
"RenderType" = "Transparent"
"Queue" = "Transparent"
}
Pass
{
BlendOp Add
Blend SrcAlpha SrcAlpha
ZTest LEqual
ZWrite Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
fixed4 _Color;
float _Length;
float _StartTime;
float _Speed;
float _Width;
float _Offset;
float _Fade;
float _Transparency;
float _TailBlendCutoff;
float _MaxDistance;
float _CutoffDistance;
float _AlphaClamp;
int _Debug;
fixed4 _DebugColorPre;
fixed4 _DebugColorPost;
fixed alpha(fixed4 col)
{
fixed total = max(col.r, max(col.g, col.b));
if (total < _AlphaClamp) //if the color is too dark, clamp to transparent
return 1;
return total;
}
v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
//if debugging is off, make the colors transparent
if (_Debug == 0)
{
_DebugColorPre = fixed4(0, 0, 0, 1);
_DebugColorPost = fixed4(0, 0, 0, 1);
}
//if we've passed the cutoff distance, don't sample the tracer
float cutoff = _CutoffDistance / _MaxDistance;
if (i.uv.x > cutoff || i.uv.x < (_Offset / _MaxDistance))
{
return _DebugColorPost;
}
//calculate the difference between the current time and the start time
//if the uv.x coordinate is past it, don't sample the tracer
float timeDiff = (_Time.y - _StartTime) * ((_Speed / 10) * _Length); //divided by 10 to give reasonable speed values
if (i.uv.x > timeDiff)
{
return _DebugColorPost;
}
//calculate the length of the tracer by dividing the _Length parameter by the _MaxDistance parameter and multiplying by the texture width
//NOTE: this does make tracer lengths dependent on both the _MaxDistance used and the width of the texture
float tracerLength = (_Length / _MaxDistance) * _Width;
//get the uv coordinate of the start of the tracer
float tracerStart = timeDiff - tracerLength;
if (i.uv.x > tracerStart) //if we're inside the tracer's area...
{
float tracerOffset = (i.uv.x - tracerStart) / tracerLength;
float2 samp = i.uv;
samp.x = tracerOffset; //calculate the uv coordinate relative to the tracer that we need to sample
fixed4 col = tex2D(_MainTex, samp);
col = (col * _Color * (1 - _Transparency)); //calculate _Color and _Transparency
if (_Fade > 0)
col = col * (1 - timeDiff / _Fade); //calulate _Fade
float tailBlendUV = _TailBlendCutoff / (_MaxDistance / 10);
if (i.uv.x < tailBlendUV)
{
float blendVal = (i.uv.x / tailBlendUV) - 0.3; //calculate tail blend
col = col * min(1, blendVal);
}
col.a = alpha(col);
return col;
}
else //don't sample the tracer
{
return _DebugColorPre;
}
}
ENDCG
}
}
}