Unity中画实线与虚线
发表于2018-06-28
本篇文章和大家介绍下在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]); } });
如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引