用Line Renderer和简单的uv动画Shader实现一个01数据流传输的效果,大致效果如图
步骤:
制作01纹理素材->编写shader->制作Line Renderer预制件->用脚本设置Line Renderer的节点位置
纹理素材
做一个大概这种感觉的透明背景图片就行,注意中间的间距和两边加起来的间距差不多,使得纹理位移时(边上的间距会连接起来)间距基本看着相同
白色可以方便后期在shader中调色
shader
只需要处理片元部分,在x方向上按时间移动uv值就可以(_Time*运动速度)
考虑到数据运动过于流畅,尝试通过floor函数离散化速度增量,实现数据跳跃性运动的效果(当然也可以不加)
Shader "Custom/DynamicDottedLineShader"
{
Properties
{
_Color ("Color", Color) = (1, 1, 1, 1)
// 运动速度
_Speed("Speed", Float) = 1.0
_MainTex("MainTex", 2D) = "white" {}
// 离散化步长,0.1代表uv运动一轮将包含10帧,1则整个图片会静止不动
// 不需要间断运动效果可以去掉
_Discrete ("Discrete", Range(0.01,1)) = 0.1
}
SubShader
{
// 透明效果默认相关设置
Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" "IgnoreProjector" = "True" }
Pass {
Tags { "LightMode"="ForwardBase" }
// 透明效果默认相关设置
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
fixed4 _Color;
float _Speed;
sampler2D _MainTex;
float4 _MainTex_ST;
float _Discrete;
struct a2v {
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
// 顶点函数无需修改
v2f vert (a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag(v2f i) : SV_Target {
// 偏移值为时间*速度
float delta = _Time.y * _Speed;
// 如果不需要间断运动效果可去掉这两行
// delta按_Discrete扩大,floor离散化后再缩小
delta = floor(delta / _Discrete);
delta = delta * _Discrete;
// 只在x方向移动uv
// 由于后续纹理会被设为Tile(堆叠),所以不需要控制uv在(0,1)内
half2 uv = i.uv + half2(delta, 0);
fixed4 c = tex2D(_MainTex, uv);
c.rgb *= _Color;
return c;
}
ENDCG
}
}
Fallback "Diffuse"
}
LineRenderer
新建一个空物体并加上LineRenderer组件,并将TextureMode设置为Tile(实现图案重复),Cast Shadows设为Off,其他保持默认设置即可,如图所示:
可以试着设置该组件节点(position)数为2,可以发现已经实现了数据流动效果,但是试着再添加多个点时,会发现纹理会被扭曲,所以要连接多个物体需要建立多个Line Renderer组件,每个组件仅包含两个position
现在先该物体拖到资产页中保存为prefab,便于编写脚本动态
编写脚本连接并跟随物体
在初始化中连接物体:
public class LineDrawer : MonoBehaviour
{
// 需要连接的物体位置列表
public Transform[] connectObjectsPos;
public List<LineRenderer> lines;
void Start()
{
for (int i = 0; i < connectObjectsPos.Length; i++ )
{
// 物体少于等于1个不连接
if (connectObjectsPos.Length <= 1)
break;
// 物体少于2个时只连接一根
if (connectObjectsPos.Length == 2 && i == 1) {
continue;
}
int p1 = i, p2 = (i + 1) % connectObjectsPos.Length;
Vector3 pos1 = connectObjectsPos[p1].position;
Vector3 pos2 = connectObjectsPos[p2].position;
LineRenderer line = Instantiate(linePrefab).GetComponent<LineRenderer>();
// 保存该组件,便于后续做跟随
lines.Add(line);
line.positionCount = 2;
line.SetPosition(0, pos1);
line.SetPosition(1, pos2);
}
}
}
这种方式可以实现n个物体的首尾连接(这样n个物体需要n个lineRenderer组件),如果需要连接方式可按情况修改
需要跟随的场合,同样只需要在Update中循环connectObjectsPos,赋值新的位置给每个line的2个position即可