maxp0wer789

UILineRenderer

Jan 20th, 2021
826
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //CREDITS TO FIRAGON @ https://forum.unity3d.com/threads/new-ui-and-line-drawing.253772/
  2. using System.Collections.Generic;
  3.  
  4. namespace UnityEngine.UI.Extensions
  5. {
  6.     /// <summary>
  7.     /// allows a ui line renderer
  8.     /// </summary>
  9.     [AddComponentMenu("UI/Extensions/Primitives/UILineRenderer")]
  10.     public class UILineRenderer : MaskableGraphic
  11.     {
  12.         private enum SegmentType
  13.         {
  14.             Start,
  15.             Middle,
  16.             End,
  17.         }
  18.  
  19.         /// <summary>
  20.         /// join between two nodes
  21.         /// </summary>
  22.         public enum JoinType
  23.         {
  24.             /// <summary>
  25.             /// Bevel
  26.             /// </summary>
  27.             Bevel,
  28.             /// <summary>
  29.             /// Miter
  30.             /// </summary>
  31.             Miter
  32.         }
  33.  
  34.         private const float MIN_MITER_JOIN = 15 * Mathf.Deg2Rad;
  35.  
  36.         // A bevel 'nice' join displaces the vertices of the line segment instead of simply rendering a
  37.         // quad to connect the endpoints. This improves the look of textured and transparent lines, since
  38.         // there is no overlapping.
  39.         private const float MIN_BEVEL_NICE_JOIN = 30 * Mathf.Deg2Rad;
  40.  
  41.         private static readonly Vector2 UV_TOP_LEFT = Vector2.zero;
  42.         private static readonly Vector2 UV_BOTTOM_LEFT = new Vector2(0, 1);
  43.         private static readonly Vector2 UV_TOP_CENTER = new Vector2(0.5f, 0);
  44.         private static readonly Vector2 UV_BOTTOM_CENTER = new Vector2(0.5f, 1);
  45.         private static readonly Vector2 UV_TOP_RIGHT = new Vector2(1, 0);
  46.         private static readonly Vector2 UV_BOTTOM_RIGHT = new Vector2(1, 1);
  47.  
  48.         private static readonly Vector2[] startUvs = new[] { UV_TOP_LEFT, UV_BOTTOM_LEFT, UV_BOTTOM_CENTER, UV_TOP_CENTER };
  49.         private static readonly Vector2[] middleUvs = new[] { UV_TOP_CENTER, UV_BOTTOM_CENTER, UV_BOTTOM_CENTER, UV_TOP_CENTER };
  50.         private static readonly Vector2[] endUvs = new[] { UV_TOP_CENTER, UV_BOTTOM_CENTER, UV_BOTTOM_RIGHT, UV_TOP_RIGHT };
  51.  
  52.  
  53.         [SerializeField]
  54.         Texture m_Texture;
  55.         [SerializeField]
  56.         Rect m_UVRect = new Rect(0f, 0f, 1f, 1f);
  57.  
  58.         /// <summary>
  59.         /// Thickness of line
  60.         /// </summary>
  61.         [Tooltip("Thickness of line")]
  62.         public float LineThickness = 2;
  63.         /// <summary>
  64.         /// Usa a margin
  65.         /// </summary>
  66.         [Tooltip("Usa a margin")]
  67.         public bool UseMargins;
  68.         /// <summary>
  69.         /// margin size
  70.         /// </summary>
  71.         [Tooltip("margin size")]
  72.         public Vector2 Margin;
  73.         /// <summary>
  74.         /// points of this line renderer
  75.         /// </summary>
  76.         [Tooltip("points of this line renderer")]
  77.         public Vector2[] Points;
  78.         /// <summary>
  79.         /// relative size of this line renderer
  80.         /// </summary>
  81.         [Tooltip("relative size of this line renderer")]
  82.         public bool relativeSize;
  83.  
  84.         /// <summary>
  85.         /// Use LineList
  86.         /// </summary>
  87.         public bool LineList = false;
  88.         /// <summary>
  89.         /// Use Line Caps
  90.         /// </summary>
  91.         public bool LineCaps = false;
  92.         /// <summary>
  93.         /// Join List type
  94.         /// </summary>
  95.         public JoinType LineJoins = JoinType.Bevel;
  96.  
  97.         /// <summary>
  98.         /// main texture from unity
  99.         /// </summary>
  100.         public override Texture mainTexture
  101.         {
  102.             get
  103.             {
  104.                 return m_Texture == null ? s_WhiteTexture : m_Texture;
  105.             }
  106.         }
  107.  
  108.         /// <summary>
  109.         /// Texture to be used.
  110.         /// </summary>
  111.         public Texture texture
  112.         {
  113.             get
  114.             {
  115.                 return m_Texture;
  116.             }
  117.             set
  118.             {
  119.                 if (m_Texture == value)
  120.                     return;
  121.  
  122.                 m_Texture = value;
  123.                 SetVerticesDirty();
  124.                 SetMaterialDirty();
  125.             }
  126.         }
  127.  
  128.         /// <summary>
  129.         /// UV rectangle used by the texture.
  130.         /// </summary>
  131.         public Rect uvRect
  132.         {
  133.             get
  134.             {
  135.                 return m_UVRect;
  136.             }
  137.             set
  138.             {
  139.                 if (m_UVRect == value)
  140.                     return;
  141.                 m_UVRect = value;
  142.                 SetVerticesDirty();
  143.             }
  144.         }
  145.  
  146.         /// <summary>
  147.         /// Unity callback
  148.         /// </summary>
  149.         /// <param name="vh"></param>
  150.         protected override void OnPopulateMesh(VertexHelper vh)
  151.         {
  152.             if (Points == null || Points.Length <= 0)
  153.                 return;
  154.  
  155.             var sizeX = rectTransform.rect.width;
  156.             var sizeY = rectTransform.rect.height;
  157.             var offsetX = -rectTransform.pivot.x * rectTransform.rect.width;
  158.             var offsetY = -rectTransform.pivot.y * rectTransform.rect.height;
  159.  
  160.             // don't want to scale based on the size of the rect, so this is switchable now
  161.             if (!relativeSize)
  162.             {
  163.                 sizeX = 1;
  164.                 sizeY = 1;
  165.             }
  166.  
  167.             if (UseMargins)
  168.             {
  169.                 sizeX -= Margin.x;
  170.                 sizeY -= Margin.y;
  171.                 offsetX += Margin.x / 2f;
  172.                 offsetY += Margin.y / 2f;
  173.             }
  174.  
  175.             vh.Clear();
  176.  
  177.             // Generate the quads that make up the wide line
  178.             var segments = new List<UIVertex[]>();
  179.             if (LineList)
  180.             {
  181.                 for (var i = 1; i < Points.Length; i += 2)
  182.                 {
  183.                     var start = Points[i - 1];
  184.                     var end = Points[i];
  185.                     start = new Vector2(start.x, start.y);
  186.                     end = new Vector2(end.x, end.y);
  187.  
  188.                     if (LineCaps)
  189.                     {
  190.                         segments.Add(CreateLineCap(start, end, SegmentType.Start));
  191.                     }
  192.  
  193.                     segments.Add(CreateLineSegment(start, end, SegmentType.Middle));
  194.  
  195.                     if (LineCaps)
  196.                     {
  197.                         segments.Add(CreateLineCap(start, end, SegmentType.End));
  198.                     }
  199.                 }
  200.             }
  201.             else
  202.             {
  203.                 for (var i = 1; i < Points.Length; i++)
  204.                 {
  205.                     var start = Points[i - 1];
  206.                     var end = Points[i];
  207.                     start = new Vector2(start.x, start.y);
  208.                     end = new Vector2(end.x, end.y);
  209.  
  210.                     if (LineCaps && i == 1)
  211.                     {
  212.                         segments.Add(CreateLineCap(start, end, SegmentType.Start));
  213.                     }
  214.  
  215.                     segments.Add(CreateLineSegment(start, end, SegmentType.Middle));
  216.  
  217.                     if (LineCaps && i == Points.Length - 1)
  218.                     {
  219.                         segments.Add(CreateLineCap(start, end, SegmentType.End));
  220.                     }
  221.                 }
  222.             }
  223.  
  224.             // Add the line segments to the vertex helper, creating any joins as needed
  225.             for (var i = 0; i < segments.Count; i++)
  226.             {
  227.                 if (!LineList && i < segments.Count - 1)
  228.                 {
  229.                     var vec1 = segments[i][1].position - segments[i][2].position;
  230.                     var vec2 = segments[i + 1][2].position - segments[i + 1][1].position;
  231.                     var angle = Vector2.Angle(vec1, vec2) * Mathf.Deg2Rad;
  232.  
  233.                     // Positive sign means the line is turning in a 'clockwise' direction
  234.                     var sign = Mathf.Sign(Vector3.Cross(vec1.normalized, vec2.normalized).z);
  235.  
  236.                     // Calculate the miter point
  237.                     var miterDistance = LineThickness / (2 * Mathf.Tan(angle / 2));
  238.                     var miterPointA = segments[i][2].position - vec1.normalized * miterDistance * sign;
  239.                     var miterPointB = segments[i][3].position + vec1.normalized * miterDistance * sign;
  240.  
  241.                     var joinType = LineJoins;
  242.                     if (joinType == JoinType.Miter)
  243.                     {
  244.                         // Make sure we can make a miter join without too many artifacts.
  245.                         if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_MITER_JOIN)
  246.                         {
  247.                             segments[i][2].position = miterPointA;
  248.                             segments[i][3].position = miterPointB;
  249.                             segments[i + 1][0].position = miterPointB;
  250.                             segments[i + 1][1].position = miterPointA;
  251.                         }
  252.                         else
  253.                         {
  254.                             joinType = JoinType.Bevel;
  255.                         }
  256.                     }
  257.  
  258.                     if (joinType == JoinType.Bevel)
  259.                     {
  260.                         if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_BEVEL_NICE_JOIN)
  261.                         {
  262.                             if (sign < 0)
  263.                             {
  264.                                 segments[i][2].position = miterPointA;
  265.                                 segments[i + 1][1].position = miterPointA;
  266.                             }
  267.                             else
  268.                             {
  269.                                 segments[i][3].position = miterPointB;
  270.                                 segments[i + 1][0].position = miterPointB;
  271.                             }
  272.                         }
  273.  
  274.                         var join = new UIVertex[] { segments[i][2], segments[i][3], segments[i + 1][0], segments[i + 1][1] };
  275.                         vh.AddUIVertexQuad(join);
  276.                     }
  277.                 }
  278.                 vh.AddUIVertexQuad(segments[i]);
  279.             }
  280.         }
  281.  
  282.         private UIVertex[] CreateLineCap(Vector2 start, Vector2 end, SegmentType type)
  283.         {
  284.             if (type == SegmentType.Start)
  285.             {
  286.                 var capStart = start - ((end - start).normalized * LineThickness / 2);
  287.                 return CreateLineSegment(capStart, start, SegmentType.Start);
  288.             }
  289.             else if (type == SegmentType.End)
  290.             {
  291.                 var capEnd = end + ((end - start).normalized * LineThickness / 2);
  292.                 return CreateLineSegment(end, capEnd, SegmentType.End);
  293.             }
  294.  
  295.             Debug.LogError("Bad SegmentType passed in to CreateLineCap. Must be SegmentType.Start or SegmentType.End");
  296.             return null;
  297.         }
  298.  
  299.         private UIVertex[] CreateLineSegment(Vector2 start, Vector2 end, SegmentType type)
  300.         {
  301.             var uvs = middleUvs;
  302.             if (type == SegmentType.Start)
  303.                 uvs = startUvs;
  304.             else if (type == SegmentType.End)
  305.                 uvs = endUvs;
  306.  
  307.             Vector2 offset = new Vector2(start.y - end.y, end.x - start.x).normalized * LineThickness / 2;
  308.             var v1 = start - offset;
  309.             var v2 = start + offset;
  310.             var v3 = end + offset;
  311.             var v4 = end - offset;
  312.             return SetVbo(new[] { v1, v2, v3, v4 }, uvs);
  313.         }
  314.  
  315.         /// <summary>
  316.         /// Helper function to create Axis
  317.         /// </summary>
  318.         /// <param name="vertices"></param>
  319.         /// <param name="uvs"></param>
  320.         /// <returns></returns>
  321.         protected UIVertex[] SetVbo(Vector2[] vertices, Vector2[] uvs)
  322.         {
  323.             UIVertex[] vbo = new UIVertex[4];
  324.             for (int i = 0; i < vertices.Length; i++)
  325.             {
  326.                 var vert = UIVertex.simpleVert;
  327.                 vert.color = color;
  328.                 vert.position = vertices[i];
  329.                 vert.uv0 = uvs[i];
  330.                 vbo[i] = vert;
  331.             }
  332.             return vbo;
  333.         }
  334.     }
  335. }
RAW Paste Data