Is it really so difficult to draw smooth lines in Unity?

后端 未结 6 992
醉话见心
醉话见心 2021-02-03 10:51

I been trying for a while to draw smooth lines in Unity but with Line Renderer I obtained only jagged lines with the corners not rounded, in particular when the angle of curvatu

6条回答
  •  礼貌的吻别
    2021-02-03 11:02

    I finally got this working thanks to @Iggy's excellent answer.

    Create a new Image on your canvas, delete the Image script and replace it with UICubicBezier.

    To give:

    using UnityEngine;
    using UnityEngine.UI;
    
    [ExecuteInEditMode]
    public class UiCubicBezier : MaskableGraphic
    {
        public float thickness = 2;
    
        public int anchors = 20;
    
        protected override void OnPopulateMesh(VertexHelper vh)
        {
            // draws a cubic bezier curve from the lower left hand corner (start)
            // to the upper right hand corner (end).
            vh.Clear();
    
            var rt = this.rectTransform;
            var rect = rt.rect;
    
            var start = new Vector2(-rect.width / 2, -rect.height / 2);
            var cp1 = new Vector2(-rect.width / 6, -rect.height / 2);
            var cp2 = new Vector2(rect.width / 6, rect.height / 2);
            var end = new Vector2(rect.width / 2, rect.height / 2);
            var data = new BezierData(start, cp1, cp2, end);
    
            // all you need to know is that data.GetPoint generates a sequence of points
            // between the start and end points.
            var points = new Vector2[this.anchors];
            for (var anchor = 0; anchor < points.Length; anchor++)
            {
                var t = (float)anchor / this.anchors;
                points[anchor] = data.GetPoint(t);
            }
    
            // because the normals are at the mid-points between vertexes the start and end
            // points don't touch the bounding box. to fix this some vertexes are added to
            // the start and end that touch the bounding box.
            this.DrawStartVertexes(vh, start);
    
            for (var anchor = 0; anchor < points.Length - 1; anchor++)
            {
                this.DrawVertexes(vh, points[anchor], points[anchor + 1]);
            }
    
            this.DrawEndVertexes(vh, end);
    
            for (var v = 0; v + 2 < vh.currentVertCount; v += 2)
            {
                vh.AddTriangle(v, v + 1, v + 2);
            }
    
            for (var v = 0; v + 3 < vh.currentVertCount; v += 2)
            {
                vh.AddTriangle(v + 1, v + 2, v + 3);
            }
        }
    
        private void DrawStartVertexes(VertexHelper vh, Vector2 start)
        {
            // d = thickness * \sqrt{2}, so the distance between the vertexes
            // is equal to the thickness (https://en.wikipedia.org/wiki/Triangle#Right_triangles)
            var d = this.thickness * 0.70710678118f;
    
            var vertex = UIVertex.simpleVert;
            vertex.color = this.color;
    
            vertex.position = new Vector2(start.x, start.y + d);
            vh.AddVert(vertex);
    
            vertex.position = new Vector2(start.x + d, start.y);
            vh.AddVert(vertex);
        }
    
        private void DrawEndVertexes(VertexHelper vh, Vector2 end)
        {
            // d = thickness * \sqrt{2}, so the distance between the vertexes
            // is equal to the thickness (https://en.wikipedia.org/wiki/Triangle#Right_triangles)
            var d = this.thickness * 0.70710678118f;
    
            var vertex = UIVertex.simpleVert;
            vertex.color = this.color;
    
            vertex.position = new Vector2(end.x - d, end.y);
            vh.AddVert(vertex);
    
            vertex.position = new Vector2(end.x, end.y - d);
            vh.AddVert(vertex);
        }
    
        private void DrawVertexes(VertexHelper vh, Vector2 start, Vector2 end)
        {
            var v = end - start;
            var mid = start + v / 2; // the mid-point between start and end.
            var perp = Vector2.Perpendicular(v.normalized); // vector of length 1 perpendicular to v.
    
            var vertex = UIVertex.simpleVert;
            vertex.color = this.color;
    
            // move half the thickness away from the mid-point.
            vertex.position = mid + (perp * this.thickness / 2); 
            vh.AddVert(vertex);
    
            // move half the thickness away from the mid-point in the opposite direction.
            vertex.position = mid - (perp * this.thickness / 2);
            vh.AddVert(vertex);
        }
    
        private struct BezierData
        {
            private readonly Vector2 start;
            private readonly float cx;
            private readonly float bx;
            private readonly float ax;
            private readonly float cy;
            private readonly float by;
            private readonly float ay;
    
            public BezierData(Vector2 start, Vector2 cp1, Vector2 cp2, Vector2 end)
            {
                // cribbed from here: https://www.codeproject.com/articles/25237/bezier-curves-made-simple
    
                this.start = start;
                this.cx = 3 * (cp1.x - start.x);
                this.bx = 3 * (cp2.x - cp1.x) - this.cx;
                this.ax = end.x - start.x - this.cx - this.bx;
    
                this.cy = 3 * (cp1.y - start.y);
                this.by = 3 * (cp2.y - cp1.y) - this.cy;
                this.ay = end.y - start.y - this.cy - this.by;
            }
    
            public Vector2 GetPoint(float t)
            {
                var tSquared = t * t;
                var tCubed = tSquared * t;
    
                return new Vector2(
                    (this.ax * tCubed) + (this.bx * tSquared) + (this.cx * t) + this.start.x,
                    (this.ay * tCubed) + (this.by * tSquared) + (this.cy * t) + this.start.y);
            }
        }
    }
    

提交回复
热议问题