Unity中画实线与虚线

发表于2018-06-28
评论1 3.4k浏览
本篇文章和大家介绍下在Unity中实现和虚线的代码实现,对于如何去划虚线,大多数人想到的肯定还是shader,这里也是如此,对于实线部分用的是GL。

代码如下:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public enum LineType
{
    Dashed,
    Line
}
public class VectorLines : MonoBehaviour
{
    private static VectorLines inst;
    public static VectorLines instance
    {
        get
        {
            if (inst == null)
            {
                inst = Camera.main.transform.gameObject.AddComponent<VectorLines>();
            }
            return inst;
        }
    }
    private Dictionary<Line, Callback0> lines;
    private Material lineMaterial;
    void Awake()
    {
        lines = new Dictionary<Line, Callback0>();
        lineMaterial = new Material("Shader \"Lines/Colored Blended\" {" +
                "SubShader { Pass {" +
            "   BindChannels { Bind \"Color\",color }" +
            "   Blend SrcAlpha OneMinusSrcAlpha" +
            "   ZWrite Off Cull Off Fog { Mode Off }" +
            "} } }");
        lineMaterial.hideFlags = HideFlags.HideAndDontSave;
        lineMaterial.shader.hideFlags = HideFlags.HideAndDontSave;
    }
    public void Draw(Line line, Callback0 draw)
    {
        if (lines.ContainsKey(line)) 
            lines.Remove(line);
        lines.Add(line, draw);
    }
    public void Cancel(Line line)
    {
        if (lines.ContainsKey(line))
            lines.Remove(line);
    }
    void OnPostRender()
    {
        if (lines.Count > 0)
        {
            lineMaterial.SetPass(0);
            GL.Begin(GL.LINES);
            GL.Color(Color.gray);
            foreach (var line in lines.Values)
            {
                line();
            }
            GL.End();
        }
    }
}
public class Line
{
    private LineType lineType;
    private Vector3[] vectors;
    private float length;
    private Vector3 dir;
    private Vector3 next;
    private Vector3 cur;
    public Line()
    {
        lineType = LineType.Line;
        vectors = new []{Vector3.zero, Vector3.left};
        length = 1;
        ReDraw();
    }
    public Line(LineType lt, Vector3[] vecs, float len = 0.2f)
    {
        lineType = lt;
        vectors = vecs;
        length = len;
        ReDraw();
    }
    public void SetType(LineType lt)
    {
        if(lineType == lt) return;
        lineType = lt;
        ReDraw();
    }
    public void SetVectors(Vector3[] vecs)
    {
        if(vectors == vecs) return;
        vectors = vecs;
        ReDraw();
    }
    /// <summary>
    /// Can use only in dashed mode
    /// </summary>
    public void SetLength(float len)
    {
        if(length == len) return;
        length = len;
        ReDraw();
    }
    public void Cancel()
    {
        VectorLines.instance.Cancel(this);
    }
    void ReDraw()
    {
        if(vectors.Length <= 1) {Debug.LogError("vectors' length canot less than 2!");return;}
        if (lineType == LineType.Line)
        {
            VectorLines.instance.Draw(this, () =>
            {
                for (int i = 0; i < vectors.Length -1; i++)
                {
                    GL.Vertex(vectors[i]);
                    GL.Vertex(vectors[i+1]);
                }
            });
        }
        else if(lineType == LineType.Dashed)
        {
            if (length <= 0) { Debug.LogError("Length canot less than 0 in dashed mode!"); return;}
            VectorLines.instance.Draw(this, () =>
            {
                for (int i = 0; i < vectors.Length - 1; i++)
                {
                    cur = vectors[i];
                    dir = (vectors[i + 1] - vectors[i]).normalized;
                    GL.Vertex(cur);
                    next = cur + dir*length;
                    while (Vector3.Distance(next, vectors[i]) < Vector3.Distance(vectors[i + 1], vectors[i]))
                    {
                        GL.Vertex(next);
                        cur = next;
                        next = cur + dir*length;
                    }
                    GL.Vertex(vectors[i+1]);
                }
            });
        }
    }
}

使用方法是:
new Line(LineType.Dashed, v, 0.2f);//画虚线
new Line();//画实线

具体效果:

该做法优点是画多条线只增加一个DC,缺点也很明显,颜色单一,线条宽度……试试其他有没有更好的方法吧。

发现一个bug:当画虚线时长度分割正好为单数的时候会和下一条线连在一起,做出修改:
if (length <= 0) { Debug.LogError("Length canot less than 0 in dashed mode!"); return;}
            VectorLines.instance.Draw(this, () =>
            {
                for (int i = 0; i < vectors.Length - 1; i++)
                {
                    cur = vectors[i];
                    dir = (vectors[i + 1] - vectors[i]).normalized;
                    GL.Vertex(cur);
                    flag = 1;
                    next = cur + dir*length;
                    while (Vector3.Distance(next, vectors[i]) < Vector3.Distance(vectors[i + 1], vectors[i]))
                    {
                        GL.Vertex(next);
                        flag++;
                        cur = next;
                        next = cur + dir*length;
                    }
                    GL.Vertex(vectors[i+1]);
                    flag++;
                    if(flag % 2 != 0)
                        GL.Vertex(vectors[i + 1]);
                }
            });

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

0个评论