Unity:SLG游戏画线模块

最近学Shader有点心得,作了一个SLG画线模块。github地址:https://github.com/871041532/SLGDrawLinegit

性能有能再提升的地方,欢迎大佬指点。大笑github

1.介绍

  • 画线模块,可用于SLG游戏行军线。
  • 多个不一样速度、颜色、长度的线在一个DrawCall中实现。
  • 材质中ShowLength控制两端显示的长度,AlphaLength控制渐隐长度,AllShowLength是一个临界值,长度小于它的线所有显示,长度大于它的线出现中间渐隐消失效果。(ShowLength、AlphaLength控制这两个效果)
  • 只有一个C#脚本文件和一个Shader,100多行代码。

2.使用demo

外部接口,只有两个:app

  • 画线:int handle=LineManager.Instance.DrawLine(Vector3 start,Vector3 end,Color color,float speed);
  • 回收线:LineManager.Instance.BackLine(int handle);

屡次调用画线效果:性能

  • 线中间不显示,两端渐隐

image

  • 线所有显示 



3.C#代码部分

using System.Collections.Generic;
using UnityEngine;
using LineHandle = System.Int32;

class LineManager
{
    private GameObject m_root = null; 
    private GameObject m_origin = null;
    private Stack<GameObject> m_linePool = null;
    private Dictionary<int, GameObject> m_drawLines = null;
    private int m_index = 0;

    #region 外部接口
    //参数:起始点、终止点、颜色、速度
    public LineHandle DrawLine(Vector3 start,Vector3 end,Color color,float speed)
    {
        //从池中拿出
        GameObject line = getFromPool();
        Transform lineTransform = line.transform;
        Transform childTransform = lineTransform.GetChild(0);

        Mesh mesh = childTransform.GetComponent<MeshFilter>().mesh;
        var vertices = mesh.vertices;
        
        //设置颜色
        var colors = new Color[vertices.Length];
        for (int i = 0; i < colors.Length; i++)
        {
            colors[i] = color;
        }
        mesh.colors = colors;

        //设置父transform位置朝向,子transform缩放
        Vector3 position = new Vector3((start.x+end.x)/2,(start.y+end.y)/2,(start.z+end.z)/2);
        Vector3 scale =new Vector3(1,Vector3.Distance(start,end),1);
        Vector3 direction = (end - start).normalized;
        lineTransform.localPosition = position;
        childTransform.localScale = scale;
        lineTransform.localRotation = Quaternion.LookRotation(direction);

        //设置Y轴缩放,速度值
        var uv2 = new Vector2[vertices.Length];
        for (int i = 0; i < uv2.Length; i++)
        {
            uv2[i] = new Vector2(childTransform.localScale.y / childTransform.localScale.x, speed);
        }
        mesh.uv2 = uv2;

        //放入字典
        m_drawLines.Add(++m_index, line);

        return m_index;
    }
    //参数:索引
    public void BackLine(LineHandle handle)
    {
        if(m_drawLines.ContainsKey(handle))
        {
            GameObject line = m_drawLines[handle];
            m_drawLines.Remove(handle);
            backToPool(line);
        }
    }
    #endregion

    #region 内部实现
    private void Init()
    {
        m_origin = Resources.Load("DrawLine/Line") as GameObject;
        m_linePool = new Stack<GameObject>(23);
        m_root = new GameObject("LineRoot");
        m_drawLines = new Dictionary<int, GameObject>(23);
        m_index = 0;
    }

    private GameObject getFromPool()
    {
        if (m_linePool.Count==0)
        {
            GameObject gameObject = GameObject.Instantiate(m_origin);
            gameObject.transform.parent = m_root.transform;
            return gameObject;
        }
        else
        {
            return m_linePool.Pop();
        }
    }

    private void backToPool(GameObject line)
    {
        line.transform.localPosition = new Vector3(1000,1000,1000);
        m_linePool.Push(line);
    }
    #endregion

    #region singleton
    private static LineManager _instance = null;
    private LineManager() { Init(); }
    public static LineManager Instance
    {
        get {
            if (_instance==null)
            {
                _instance = new LineManager();
            }
            return _instance;
        }
        private set { }
    }
    #endregion
}

4.Shader代码部分

Shader "lineShader"{
        Properties
        {
            _MainTex("Line Texture",2D) = "white"{}
	    _ShowLength("Show Length",Float)=6.0 //展示的长度
	    _AlphaLength("Alpha Length",Float)=5.0 //有透明效果的长度
	    _AllShowLength("AllShow Length",Float)=10 //临界值,若是线比它短,那么全都显示
        }
         SubShader{
	   Tags{ "Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout" }
	Pass
	{
           Tags{ "LightMode" = "ForwardBase" }
           ZWrite Off
           Blend SrcAlpha OneMinusSrcAlpha


        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag

        #include "Lighting.cginc"

        sampler2D _MainTex;
        float4 _MainTex_ST;
	float _ShowLength;
	float _AlphaLength;
	float _AllShowLength;

        struct a2v
        {
            float4 vertex:POSITION;
            float4 texcoord:TEXCOORD0;
            fixed4 color:COLOR0;
	    float2 uv2 : TEXCOORD1; //第二套UV:x份量存储y轴缩放,y份量存储滚动速度				
        };

        struct v2f
        {
            float4 pos:SV_POSITION;
            float2 uv:TEXCOORD1;
	    fixed4 color:COLOR1;
	    float2 uv2:TEXCOORD2; //x份量存储Y轴缩放固定值,y份量存储滚动前uv.y
        };

        v2f vert(a2v v)
        {
            v2f o;
            o.pos = UnityObjectToClipPos(v.vertex);
            o.uv.xy = TRANSFORM_TEX(v.texcoord,_MainTex);
            o.uv.y *=v.uv2.x;//Y轴缩放
            o.color=v.color;
				
	    o.uv2=o.uv;
	    o.uv2.x=v.uv2.x; //o.uv2.x存储Y轴缩放固定值,y轴当前uv.y
            o.uv.y -=v.uv2.y* _Time.z; //Y轴随时间偏移
            return o;
        }

        fixed4 frag(v2f i) :SV_Target
        {
            fixed4 color = tex2D(_MainTex,i.uv.xy);
            //后半段透明值与前半段透明值,取最大值
	    i.color.a=max(clamp((_ShowLength-(i.uv2.x-i.uv2.y))/_AlphaLength,0,1),clamp((_ShowLength-i.uv2.y)/_AlphaLength,0,1)); //i.uv2.y存储此片元的UV.y
            //当比_AllShowLength小的时候所有显示
            i.color.a+=clamp(_AllShowLength-i.uv2.x,0,1); //大于0
	    i.color.a *= color.a;
            return i.color;
        }

        ENDCG
        }
        }
        //Fallback "VertexLit"
}