Search Unity

New UI and line drawing

Discussion in 'UGUI & TextMesh Pro' started by jctz, Jun 25, 2014.

  1. jctz

    jctz

    Joined:
    Aug 14, 2013
    Posts:
    47
    Hi, we'd like to do simple line drawing working within an NGUI panel, using Vectrosity. Apparently this is a popular request. Given how difficult it is to do with the source of both NGUI and Vectrosity available, how difficult will it be once NGUI is made native in Unity 4.6? Won't it be next to impossible?

    Will Unity 4.6 have a UI system that can do simple line drawing?
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    You seem to have some misconceptions about the new UI. First of all, uGUI is not "NGUI made native". It's not NGUI and it's not (all) native. Most of the UI elements have their source available. Second, you're trying to combine two systems (NGUI and Vectrosity) that were never designed for each other; why would you expect it to be easy?

    Now that we're past that, line drawing ought to be simple as pie in the new system... though not with Vectrosity, at least not with a current version of vectrosity; any line drawing system would have to have uGUI. Since it supports really simple 9-slicing and can therefore correctly stretch a line texture to any size, a DrawLine(a,b,someSprite) function only needs to set the position, rotation, and scale so that each end is at one of the points. (That's assuming that there isn't a native one)
     
  3. jack.sydorenko

    jack.sydorenko

    Joined:
    Dec 15, 2014
    Posts:
    1
    If you need to make UI Component that draws line, just use this one from me:


    Code (CSharp):
    1.  
    2. public class UILineRenderer : MaskableGraphic
    3.     {
    4.         public float LineThikness = 2;
    5.         public bool UseMargins;
    6.         public Vector2 Margin;
    7.         public Vector2[] Points;
    8.  
    9.         protected override void OnFillVBO(List<UIVertex> vbo)
    10.         {
    11.             if (Points == null || Points.Length < 2)
    12.                 Points = new[] { new Vector2(0, 0), new Vector2(1, 1) };
    13.  
    14.             var sizeX = rectTransform.rect.width;
    15.             var sizeY = rectTransform.rect.height;
    16.             var offsetX = -rectTransform.pivot.x * rectTransform.rect.width;
    17.             var offsetY = -rectTransform.pivot.y * rectTransform.rect.height;
    18.  
    19.             if (UseMargins)
    20.             {
    21.                 sizeX -= Margin.x;
    22.                 sizeY -= Margin.y;
    23.                 offsetX += Margin.x/2f;
    24.                 offsetY += Margin.y/2f;
    25.             }
    26.  
    27.             vbo.Clear();
    28.  
    29.             Vector2 prevV1 = Vector2.zero;
    30.             Vector2 prevV2 = Vector2.zero;
    31.  
    32.             for (int i = 1; i < Points.Length; i++)
    33.             {
    34.                 var prev = Points[i - 1];
    35.                 var cur = Points[i];
    36.                 prev = new Vector2(prev.x * sizeX + offsetX, prev.y * sizeY + offsetY);
    37.                 cur = new Vector2(cur.x * sizeX + offsetX, cur.y * sizeY + offsetY);
    38.  
    39.                 float angle = Mathf.Atan2(cur.y - prev.y, cur.x - prev.x) * 180f / Mathf.PI;
    40.  
    41.                 var v1 = prev + new Vector2(0, -LineThikness / 2);
    42.                 var v2 = prev + new Vector2(0, +LineThikness / 2);
    43.                 var v3 = cur + new Vector2(0, +LineThikness / 2);
    44.                 var v4 = cur + new Vector2(0, -LineThikness / 2);
    45.  
    46.                 v1 = RotatePointAroundPivot(v1, prev, new Vector3(0, 0, angle));
    47.                 v2 = RotatePointAroundPivot(v2, prev, new Vector3(0, 0, angle));
    48.                 v3 = RotatePointAroundPivot(v3, cur, new Vector3(0, 0, angle));
    49.                 v4 = RotatePointAroundPivot(v4, cur, new Vector3(0, 0, angle));
    50.  
    51.                 if (i > 1)
    52.                     SetVbo(vbo, new[] { prevV1, prevV2, v1, v2 });
    53.  
    54.                 SetVbo(vbo, new[] { v1, v2, v3, v4 });
    55.  
    56.                 prevV1 = v3;
    57.                 prevV2 = v4;
    58.             }
    59.         }
    60.  
    61.         protected void SetVbo(List<UIVertex> vbo, Vector2[] vertices)
    62.         {
    63.             for (int i = 0; i < vertices.Length; i++)
    64.             {
    65.                 var vert = UIVertex.simpleVert;
    66.                 vert.color = color;
    67.                 vert.position = vertices[i];
    68.                 vbo.Add(vert);
    69.             }
    70.         }
    71.  
    72.         public Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Vector3 angles)
    73.         {
    74.             Vector3 dir = point - pivot; // get point direction relative to pivot
    75.             dir = Quaternion.Euler(angles)*dir; // rotate it
    76.             point = dir + pivot; // calculate rotated point
    77.             return point; // return it
    78.         }
    79.     }
    80.  
     
    BryanSilva, vonSchlank, RaL and 4 others like this.
  4. R-Lindsay

    R-Lindsay

    Joined:
    Aug 9, 2014
    Posts:
    287
    Unity already has a simple line renderer (in case you aren't aware of it). For some more power in your line API, I understand the latest version of Vectrosity is designed specifically for the new Unity GUI. There is a new Vectrosity thready for this.

    I am currently working on this area myself. My approach so far has been to develop a 2D drawing API. I have mostly finished a lower level path style API (e.g. LineTo(), SmoothCurveTo() etc) and a higher level DisplayList style structure which can take dynamic transform lists and allows hierarchical display/ordering of paths. I'm also working on path renderers, e.g. stroking, filling, but also distributing objects along a path, like particle effects. I'm still some way off having it ready for the asset store though. I would love to know if this sort of thing is something people would want.
    /horn-tooting
     
    aliceeducationstudio likes this.
  5. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    The LineRenderer component is not suitable for drawing lines in the new UI, it's actually just irrelevant in this context.
     
    AlterMannn and YuHeLong like this.
  6. jonbro5556

    jonbro5556

    Joined:
    Jan 1, 2013
    Posts:
    24
    Hey, I was having some difficulty with this script, and I modded it to support using textures directly (so you can drop in sprites), to support non relative positioning (so it doesn't take in account the width/height of the rect it is in), and to support line capping (so the beginning and ends of the lines can be rounded based on a circle sprite image).
     

    Attached Files:

    DungDajHjep and PrimalCoder like this.
  7. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    Looks like an awesome effect, will need some work documenting it to make sense of its use.

    @jonbro5556 @jack.sydorenko You guys ok with this script being added to the UI extensions bitbucket repo? (link in sig)
     
  8. yoonitee

    yoonitee

    Joined:
    Jun 27, 2013
    Posts:
    2,363
    I might have a go at making something... I have a few ideas that might be quite cool.
     
  9. IsGreen

    IsGreen

    Joined:
    Jan 17, 2014
    Posts:
    206
    You can draw line scaling uImage.
     
  10. jonbro5556

    jonbro5556

    Joined:
    Jan 1, 2013
    Posts:
    24
  11. Fragfire

    Fragfire

    Joined:
    Apr 15, 2014
    Posts:
    9
    Is there any way to update the graphics (line) via script? My problem is, that when I set the points array via script the line isn't updated. If I change a point in the editor it updates just fine.

    Edit.: I just found the solution. After u set the points via script just call SetVerticesDirty() on the UILineRenderer-object.
     
    Last edited: Apr 29, 2015
    enriqueflores likes this.
  12. Kadaj

    Kadaj

    Joined:
    Jul 24, 2014
    Posts:
    19
    This script seems very interesting, thank you for sharing!

    However, as said SimonDarksideJ, is it possible to comment more the code to explain how it works in practice?

    Again, thank you.
     
    Last edited: Jun 26, 2015
  13. iivo_k

    iivo_k

    Joined:
    Jan 28, 2013
    Posts:
    314
    Thanks a lot for the script! The @jonbro5556 version seems to have broken the relative positioning, so I used the original by @jack.sydorenko .
     
  14. Vegeta_DTX

    Vegeta_DTX

    Joined:
    Aug 20, 2015
    Posts:
    3
    I'm sorry for posting in the old thread, but could someone explain me how to implement the above code? I need to draw a line between two gui elements and from what you people say this seems to be close to it, but for the life of mine I don't understand that piece of script and how it draws a line on gui elements?

    Should I mention that I am new to unity :D Though not new to C# and scripting...
     
  15. CarreraSilvio

    CarreraSilvio

    Joined:
    Jul 21, 2012
    Posts:
    31
    I'm trying to draw a line between two points that I selected via the UI. How do I set that up on @jack.sydorenko's code? o.o
     
  16. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    The script is now part of the UI extensions project along with many other great community controls.
    It is mainly for drawing lines within the bounds of the object or scene, not really for drawing a line between two RectTransforms.

    But you can use the line rendering code to create a new control that takes two RectTransforms to draw a line between them, I've seen various request for this so far. If I get time I'll add one to the project, or you can contribute and add your own version.
     
  17. andrii-shpak

    andrii-shpak

    Joined:
    Nov 27, 2014
    Posts:
    315
    StarManta likes this.
  18. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    557
    I mean, if we're plugging in a revived thread anyway... ;) Primitive UI is a similar package that supports a wide variety of shape and line drawing methods. Anyone reading this should of course pick the one they feel serves their purposes best; my asset seems to support some more primitives, but lacks rounded rectangles for instance.

    (Sorry Andy!)
     
    SimonDarksideJ likes this.
  19. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    Looks good @AndyFi although most seem to be based of the UI Extensions versions :D obviously with improvements :p
    Good luck with your asset.

    @Senshi How are you handling the 5.2.1 / 5.2.1P issues, or have you avoided controls that are affected?
     
  20. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    557
    From the asset description:
    I have uploaded a VBO version from 4.6.1 and a "toFill" version from 5.2.0. Once the new API is in and we get some sort of "yes, it's finalized" message from the devs I'll also upload a version from either P3 or 5.2.2 if the window between them is small enough.

    It's not the nicest solution, but it is the most managable.

    (Slighty off-topic: There were some editor changes as well between 5.0 and 5.1 or so iirc, which I just handled using an "IF UNITY_5_0" or some-such statement.)
     
    Last edited: Oct 14, 2015
  21. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    Ahh, good plan.
    I've avoided #IF's for the UI Extensions due to the complexity it would bring.
     
  22. andrii-shpak

    andrii-shpak

    Joined:
    Nov 27, 2014
    Posts:
    315
  23. yudixiaok

    yudixiaok

    Joined:
    Aug 29, 2014
    Posts:
    17
    hi @SimonDarksideJ,
    maybe you can make the solution more efficient. when i use the UILinerender at update. it perform bad.
     
  24. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    As with all the UI components @yudixiaok , you can only update in LateUpdate. In the Update loop, Unity is still doing "stuff" with the UI and changing it then causes issues.
    Also, if you are programatically updating the line, be sure to call "SetDirty" when you have finished. I believe their is a comment on the LineRenderer video on that.
     
  25. Kadaj

    Kadaj

    Joined:
    Jul 24, 2014
    Posts:
    19
    For those interested , I share my version of UILineRenderer code which works with the 5.2.
    Code (CSharp):
    1. // from http://forum.unity3d.com/threads/new-ui-and-line-drawing.253772/
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4. using System.Collections.Generic;
    5.  
    6. public class UILineRenderer : Graphic
    7. {
    8.     [SerializeField] Texture m_Texture;
    9.     [SerializeField] Rect m_UVRect = new Rect(0f, 0f, 1f, 1f);
    10.  
    11.     public float LineThickness = 2;
    12.     public bool UseMargins;
    13.     public Vector2 Margin;
    14.     public Vector2[] Points;
    15.     public bool relativeSize;
    16.  
    17.     public override Texture mainTexture
    18.     {
    19.         get
    20.         {
    21.             return m_Texture == null ? s_WhiteTexture : m_Texture;
    22.         }
    23.     }
    24.  
    25.     /// <summary>
    26.     /// Texture to be used.
    27.     /// </summary>
    28.     public Texture texture
    29.     {
    30.         get
    31.         {
    32.             return m_Texture;
    33.         }
    34.         set
    35.         {
    36.             if (m_Texture == value)
    37.                 return;
    38.  
    39.             m_Texture = value;
    40.             SetVerticesDirty();
    41.             SetMaterialDirty();
    42.         }
    43.     }
    44.  
    45.     /// <summary>
    46.     /// UV rectangle used by the texture.
    47.     /// </summary>
    48.     public Rect uvRect
    49.     {
    50.         get
    51.         {
    52.             return m_UVRect;
    53.         }
    54.         set
    55.         {
    56.             if (m_UVRect == value)
    57.                 return;
    58.             m_UVRect = value;
    59.             SetVerticesDirty();
    60.         }
    61.     }
    62.  
    63.     //protected override void OnFillVBO(List<UIVertex> vbo)
    64.     protected override void OnPopulateMesh(Mesh toFill)
    65.     {
    66.         // requires sets of quads
    67.         if (Points == null || Points.Length < 2)
    68.             Points = new[] { new Vector2(0, 0), new Vector2(1, 1) };
    69.         var capSize = 24;
    70.         var sizeX = rectTransform.rect.width;
    71.         var sizeY = rectTransform.rect.height;
    72.         var offsetX = -rectTransform.pivot.x * rectTransform.rect.width;
    73.         var offsetY = -rectTransform.pivot.y * rectTransform.rect.height;
    74.  
    75.         // don't want to scale based on the size of the rect, so this is switchable now
    76.         if (!relativeSize)
    77.         {
    78.             sizeX = 1;
    79.             sizeY = 1;
    80.         }
    81.         // build a new set of points taking into account the cap sizes.
    82.         // would be cool to support corners too, but that might be a bit tough :)
    83.         var pointList = new List<Vector2> ();
    84.         pointList.Add (Points [0]);
    85.         var capPoint = Points [0] + (Points [1] - Points [0]).normalized * capSize;
    86.         pointList.Add (capPoint);
    87.  
    88.         // should bail before the last point to add another cap point
    89.         for (int i = 1; i < Points.Length-1; i++)
    90.         {
    91.             pointList.Add (Points [i]);
    92.         }
    93.         capPoint = Points [Points.Length-1] - (Points [Points.Length-1] - Points [Points.Length-2]).normalized * capSize;
    94.         pointList.Add (capPoint);
    95.         pointList.Add (Points [Points.Length - 1]);
    96.  
    97.         var TempPoints = pointList.ToArray ();
    98.         if (UseMargins)
    99.         {
    100.             sizeX -= Margin.x;
    101.             sizeY -= Margin.y;
    102.             offsetX += Margin.x/2f;
    103.             offsetY += Margin.y/2f;
    104.         }
    105.  
    106.         toFill.Clear();
    107.         var vbo = new VertexHelper(toFill);
    108.  
    109.         Vector2 prevV1 = Vector2.zero;
    110.         Vector2 prevV2 = Vector2.zero;
    111.  
    112.         for (int i = 1; i < TempPoints.Length; i++)
    113.         {
    114.             var prev = TempPoints[i - 1];
    115.             var cur = TempPoints[i];
    116.             prev = new Vector2(prev.x * sizeX + offsetX, prev.y * sizeY + offsetY);
    117.             cur = new Vector2(cur.x * sizeX + offsetX, cur.y * sizeY + offsetY);
    118.  
    119.             float angle = Mathf.Atan2(cur.y - prev.y, cur.x - prev.x) * 180f / Mathf.PI;
    120.  
    121.             var v1 = prev + new Vector2(0, -LineThickness / 2);
    122.             var v2 = prev + new Vector2(0, +LineThickness / 2);
    123.             var v3 = cur + new Vector2(0, +LineThickness / 2);
    124.             var v4 = cur + new Vector2(0, -LineThickness / 2);
    125.  
    126.             v1 = RotatePointAroundPivot(v1, prev, new Vector3(0, 0, angle));
    127.             v2 = RotatePointAroundPivot(v2, prev, new Vector3(0, 0, angle));
    128.             v3 = RotatePointAroundPivot(v3, cur, new Vector3(0, 0, angle));
    129.             v4 = RotatePointAroundPivot(v4, cur, new Vector3(0, 0, angle));
    130.  
    131.             Vector2 uvTopLeft = Vector2.zero;
    132.             Vector2 uvBottomLeft = new Vector2(0, 1);
    133.  
    134.             Vector2 uvTopCenter = new Vector2(0.5f, 0);
    135.             Vector2 uvBottomCenter = new Vector2(0.5f, 1);
    136.  
    137.             Vector2 uvTopRight = new Vector2(1, 0);
    138.             Vector2 uvBottomRight = new Vector2(1, 1);
    139.  
    140.             Vector2[] uvs = new[]{ uvTopCenter,uvBottomCenter,uvBottomCenter,uvTopCenter };
    141.  
    142.             if (i > 1)
    143.                 SetVbo(vbo, new[] { prevV1, prevV2, v1, v2 }, uvs);
    144.  
    145.             if(i==1)
    146.                 uvs = new[]{ uvTopLeft,uvBottomLeft,uvBottomCenter,uvTopCenter };
    147.             else if(i==TempPoints.Length-1)
    148.                 uvs = new[]{uvTopCenter,uvBottomCenter, uvBottomRight, uvTopRight };
    149.  
    150.             //SetVbo(vbo, new[] { v1, v2, v3, v4 }, uvs, toFill);
    151.             vbo.AddUIVertexQuad(SetVbo(vbo, new[] { v1, v2, v3, v4 }, uvs));
    152.             vbo.FillMesh (toFill);
    153.  
    154.             prevV1 = v3;
    155.             prevV2 = v4;
    156.         }
    157.     }
    158.  
    159.     //protected void SetVbo(UIVertex vbo, Vector2[] vertices, Vector2[] uvs)
    160.     protected UIVertex[] SetVbo(VertexHelper vbo, Vector2[] vertices, Vector2[] uvs)
    161.     {
    162.         UIVertex[] VboVertices = new UIVertex[4];
    163.  
    164.         for (int i = 0; i < vertices.Length; i++)
    165.         {
    166.             var vert = UIVertex.simpleVert;
    167.             vert.color = color;
    168.             vert.position = vertices[i];
    169.             vert.uv0 = uvs [i];
    170.             VboVertices[i] = vert;
    171.         }
    172.  
    173.         return VboVertices;
    174.     }
    175.  
    176.     public Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Vector3 angles)
    177.     {
    178.         Vector3 dir = point - pivot; // get point direction relative to pivot
    179.         dir = Quaternion.Euler(angles)*dir; // rotate it
    180.         point = dir + pivot; // calculate rotated point
    181.         return point; // return it
    182.     }
    183. }
    For more details, check out this thread: http://forum.unity3d.com/threads/onfillvbo-to-onpopulatemesh-help.353977/
     
    DungDajHjep likes this.
  26. firagon

    firagon

    Joined:
    Feb 26, 2016
    Posts:
    3
    I downloaded the ui extensions, and heavily rewrote/refactored the UILineRenderer to suit my own needs. It's much more configurable now; the main new things are:

    - miter joins
    - toggleable line caps
    - option to render as line lists instead of a linestrip

    It also seems to fix some of the weirdness I was having with the original implementation (such as lines going to infinity), and I made textured lines look a little better in some cases by reducing the overlap. There's probably room for optimization, but I was primarily concerned with getting it to look correct and it's good enough for my use case for now.

    Code (CSharp):
    1. using System.Collections.Generic;
    2.  
    3. namespace UnityEngine.UI.Extensions {
    4.   [AddComponentMenu("UI/Extensions/Primitives/UILineRenderer")]
    5.   public class UILineRenderer : MaskableGraphic {
    6.     private enum SegmentType {
    7.       Start,
    8.       Middle,
    9.       End,
    10.     }
    11.  
    12.     public enum JoinType {
    13.       Bevel,
    14.       Miter
    15.     }
    16.  
    17.     private const float MIN_MITER_JOIN = 15 * Mathf.Deg2Rad;
    18.  
    19.     // A bevel 'nice' join displaces the vertices of the line segment instead of simply rendering a
    20.     // quad to connect the endpoints. This improves the look of textured and transparent lines, since
    21.     // there is no overlapping.
    22.     private const float MIN_BEVEL_NICE_JOIN = 30 * Mathf.Deg2Rad;
    23.  
    24.     private static readonly Vector2 UV_TOP_LEFT = Vector2.zero;
    25.     private static readonly Vector2 UV_BOTTOM_LEFT = new Vector2(0, 1);
    26.     private static readonly Vector2 UV_TOP_CENTER = new Vector2(0.5f, 0);
    27.     private static readonly Vector2 UV_BOTTOM_CENTER = new Vector2(0.5f, 1);
    28.     private static readonly Vector2 UV_TOP_RIGHT = new Vector2(1, 0);
    29.     private static readonly Vector2 UV_BOTTOM_RIGHT = new Vector2(1, 1);
    30.  
    31.     private static readonly Vector2[] startUvs = new[] { UV_TOP_LEFT, UV_BOTTOM_LEFT, UV_BOTTOM_CENTER, UV_TOP_CENTER };
    32.     private static readonly Vector2[] middleUvs = new[] { UV_TOP_CENTER, UV_BOTTOM_CENTER, UV_BOTTOM_CENTER, UV_TOP_CENTER };
    33.     private static readonly Vector2[] endUvs = new[] { UV_TOP_CENTER, UV_BOTTOM_CENTER, UV_BOTTOM_RIGHT, UV_TOP_RIGHT };
    34.  
    35.  
    36.     [SerializeField]
    37.     Texture m_Texture;
    38.     [SerializeField]
    39.     Rect m_UVRect = new Rect(0f, 0f, 1f, 1f);
    40.  
    41.     public float LineThickness = 2;
    42.     public bool UseMargins;
    43.     public Vector2 Margin;
    44.     public Vector2[] Points;
    45.     public bool relativeSize;
    46.  
    47.     public bool LineList = false;
    48.     public bool LineCaps = false;
    49.     public JoinType LineJoins = JoinType.Bevel;
    50.  
    51.     public override Texture mainTexture {
    52.       get {
    53.         return m_Texture == null ? s_WhiteTexture : m_Texture;
    54.       }
    55.     }
    56.  
    57.     /// <summary>
    58.     /// Texture to be used.
    59.     /// </summary>
    60.     public Texture texture {
    61.       get {
    62.         return m_Texture;
    63.       }
    64.       set {
    65.         if (m_Texture == value)
    66.           return;
    67.  
    68.         m_Texture = value;
    69.         SetVerticesDirty();
    70.         SetMaterialDirty();
    71.       }
    72.     }
    73.  
    74.     /// <summary>
    75.     /// UV rectangle used by the texture.
    76.     /// </summary>
    77.     public Rect uvRect {
    78.       get {
    79.         return m_UVRect;
    80.       }
    81.       set {
    82.         if (m_UVRect == value)
    83.           return;
    84.         m_UVRect = value;
    85.         SetVerticesDirty();
    86.       }
    87.     }
    88.  
    89.     protected override void OnPopulateMesh(VertexHelper vh) {
    90.       if (Points == null)
    91.         return;
    92.  
    93.       var sizeX = rectTransform.rect.width;
    94.       var sizeY = rectTransform.rect.height;
    95.       var offsetX = -rectTransform.pivot.x * rectTransform.rect.width;
    96.       var offsetY = -rectTransform.pivot.y * rectTransform.rect.height;
    97.  
    98.       // don't want to scale based on the size of the rect, so this is switchable now
    99.       if (!relativeSize) {
    100.         sizeX = 1;
    101.         sizeY = 1;
    102.       }
    103.  
    104.       if (UseMargins) {
    105.         sizeX -= Margin.x;
    106.         sizeY -= Margin.y;
    107.         offsetX += Margin.x / 2f;
    108.         offsetY += Margin.y / 2f;
    109.       }
    110.  
    111.       vh.Clear();
    112.  
    113.       // Generate the quads that make up the wide line
    114.       var segments = new List<UIVertex[]>();
    115.       if (LineList) {
    116.         for (var i = 1; i < Points.Length; i += 2) {
    117.           var start = Points[i - 1];
    118.           var end = Points[i];
    119.           start = new Vector2(start.x * sizeX + offsetX, start.y * sizeY + offsetY);
    120.           end = new Vector2(end.x * sizeX + offsetX, end.y * sizeY + offsetY);
    121.  
    122.           if (LineCaps) {
    123.             segments.Add(CreateLineCap(start, end, SegmentType.Start));
    124.           }
    125.  
    126.           segments.Add(CreateLineSegment(start, end, SegmentType.Middle));
    127.  
    128.           if (LineCaps) {
    129.             segments.Add(CreateLineCap(start, end, SegmentType.End));
    130.           }
    131.         }
    132.       } else {
    133.         for (var i = 1; i < Points.Length; i++) {
    134.           var start = Points[i - 1];
    135.           var end = Points[i];
    136.           start = new Vector2(start.x * sizeX + offsetX, start.y * sizeY + offsetY);
    137.           end = new Vector2(end.x * sizeX + offsetX, end.y * sizeY + offsetY);
    138.  
    139.           if (LineCaps && i == 1) {
    140.             segments.Add(CreateLineCap(start, end, SegmentType.Start));
    141.           }
    142.  
    143.           segments.Add(CreateLineSegment(start, end, SegmentType.Middle));
    144.  
    145.           if (LineCaps && i == Points.Length - 1) {
    146.             segments.Add(CreateLineCap(start, end, SegmentType.End));
    147.           }
    148.         }
    149.       }
    150.  
    151.       // Add the line segments to the vertex helper, creating any joins as needed
    152.       for (var i = 0; i < segments.Count; i++) {
    153.         if (!LineList && i < segments.Count - 1) {
    154.           var vec1 = segments[i][1].position - segments[i][2].position;
    155.           var vec2 = segments[i + 1][2].position - segments[i + 1][1].position;
    156.           var angle = Vector2.Angle(vec1, vec2) * Mathf.Deg2Rad;
    157.  
    158.           // Positive sign means the line is turning in a 'clockwise' direction
    159.           var sign = Mathf.Sign(Vector3.Cross(vec1.normalized, vec2.normalized).z);
    160.  
    161.           // Calculate the miter point
    162.           var miterDistance = LineThickness / (2 * Mathf.Tan(angle / 2));
    163.           var miterPointA = segments[i][2].position - vec1.normalized * miterDistance * sign;
    164.           var miterPointB = segments[i][3].position + vec1.normalized * miterDistance * sign;
    165.  
    166.           var joinType = LineJoins;
    167.           if (joinType == JoinType.Miter) {
    168.             // Make sure we can make a miter join without too many artifacts.
    169.             if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_MITER_JOIN) {
    170.               segments[i][2].position = miterPointA;
    171.               segments[i][3].position = miterPointB;
    172.               segments[i + 1][0].position = miterPointB;
    173.               segments[i + 1][1].position = miterPointA;
    174.             } else {
    175.               joinType = JoinType.Bevel;
    176.             }
    177.           }
    178.  
    179.           if (joinType == JoinType.Bevel) {
    180.             if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_BEVEL_NICE_JOIN) {
    181.               if (sign < 0) {
    182.                 segments[i][2].position = miterPointA;
    183.                 segments[i + 1][1].position = miterPointA;
    184.               } else {
    185.                 segments[i][3].position = miterPointB;
    186.                 segments[i + 1][0].position = miterPointB;
    187.               }
    188.             }
    189.  
    190.             var join = new UIVertex[] { segments[i][2], segments[i][3], segments[i + 1][0], segments[i + 1][1] };
    191.             vh.AddUIVertexQuad(join);
    192.           }
    193.         }
    194.         vh.AddUIVertexQuad(segments[i]);
    195.       }
    196.     }
    197.  
    198.     private UIVertex[] CreateLineCap(Vector2 start, Vector2 end, SegmentType type) {
    199.       if (type == SegmentType.Start) {
    200.         var capStart = start - ((end - start).normalized * LineThickness / 2);
    201.         return CreateLineSegment(capStart, start, SegmentType.Start);
    202.       } else if (type == SegmentType.End) {
    203.         var capEnd = end + ((end - start).normalized * LineThickness / 2);
    204.         return CreateLineSegment(end, capEnd, SegmentType.End);
    205.       }
    206.  
    207.       Debug.LogError("Bad SegmentType passed in to CreateLineCap. Must be SegmentType.Start or SegmentType.End");
    208.       return null;
    209.     }
    210.  
    211.     private UIVertex[] CreateLineSegment(Vector2 start, Vector2 end, SegmentType type) {
    212.       List<UIVertex> points = new List<UIVertex>();
    213.  
    214.       var uvs = middleUvs;
    215.       if (type == SegmentType.Start)
    216.         uvs = startUvs;
    217.       else if (type == SegmentType.End)
    218.         uvs = endUvs;
    219.  
    220.       Vector2 offset = new Vector2(start.y - end.y, end.x - start.x).normalized * LineThickness / 2;
    221.       var v1 = start - offset;
    222.       var v2 = start + offset;
    223.       var v3 = end + offset;
    224.       var v4 = end - offset;
    225.       return SetVbo(new[] { v1, v2, v3, v4 }, uvs);
    226.     }
    227.  
    228.     protected UIVertex[] SetVbo(Vector2[] vertices, Vector2[] uvs) {
    229.       UIVertex[] vbo = new UIVertex[4];
    230.       for (int i = 0; i < vertices.Length; i++) {
    231.         var vert = UIVertex.simpleVert;
    232.         vert.color = color;
    233.         vert.position = vertices[i];
    234.         vert.uv0 = uvs[i];
    235.         vbo[i] = vert;
    236.       }
    237.       return vbo;
    238.     }
    239.   }
    240. }
    241.  
     
  27. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    Fantastic stuff @firagon
    You ok with this update going back in to the UI Extensions project? (with credit of course :D)
     
  28. firagon

    firagon

    Joined:
    Feb 26, 2016
    Posts:
    3
    Of course!
     
  29. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    613
    Thanks @firagon for sharing his code, exactly what i needed to show the user's touch input!

    But how do you use it correctly? Everything works fine for Editor usage but when I create the LineRenderer by script and update the Points[] i run into some problems: Endcaps will not always show on both ends, Miter/Bevel are not created sometimes.
    • First I create the Component in script and set all the public variables like Miter/Bevel, Endcaps, Width...
    • Then i overwrite the Points[]
    • and then?
    The line only Updates when i disable and reenable the component. Rebuild() doesn't do it either.
     
  30. RSpicer

    RSpicer

    Joined:
    Feb 27, 2014
    Posts:
    9
    @Marrt, I had to call myUIRenderer.SetVerticesDirty() to trigger a redraw.

    This new version works with 5.3, but is much less performant than what I saw in 4.6/5.0, which I think is the fault of VertexHelper being pretty slow.

    Has anyone benchmarked VertexHelper.AddUIVertexTriangleStream vs. VertexHelper.AddUIVertexQuad? In theory we should be able to construct a list of verts in triangle strip format, and then hit VertexHelper once -- the question is, is whatever VertexHelper doing internally for AddUIVertexTriangleStream efficient, or just a loop over something like AddUIVertexTriangle (which I imagine is not all that much more efficient). Looking at what I know about immediate mode opengl, a triangle strip should be more efficient than a bunch of separate quads, but who knows re: Unity internal implementation?
     
    Marrt likes this.
  31. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
  32. RSpicer

    RSpicer

    Joined:
    Feb 27, 2014
    Posts:
    9
    Touche SimonDarksideJ -- counter to my hypothesis, it looks like AddUIVertexTriangleStream is likely to be equally or maybe slightly less efficient because it invokes an additional trip through CanvasRenderer.SplitUIVertexStreams to split the UIVertex data into separate lists, which then end up heading through VertexHelper.FillMesh anyway. Worth a thought, anyhow.

    Spending some more time with the profiler, the time spent is heavily in CreateLineSegment (~30% in my testing with 512-segment lines), vs. ~20% in VertexHelper.AddUIVertexQuad anyhow. I don't -need- to optimize this for my current development tasks (I'm using it for debug info, not shipping it) but I'm leaving this as a note for later, or for anyone else feeling optimization-minded.
     
    SimonDarksideJ likes this.
  33. eXntrc

    eXntrc

    Joined:
    Jan 12, 2015
    Posts:
    21
    Hey @firagon and @SimonDarksideJ, any news on Firagons changes making into the UI Extensions project? So glad I found this tonight. This was exactly what I needed.

    The main thing I need from Firagons version that's currently missing in the Extensions project is the option he calls "Line List". Basically it treats every 2 points as starting a new line instead of each point being a continuation of the same line. Without that feature I would need to create new instances of the line renderer for ever tick mark I need to make. This option is perfect! And I'd love to see it in the kit.
     
    zyzyx likes this.
  34. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    As it happens, I'm doing some work today:
    • Merging PR's
    • Grabbing some long awaited fixes that have been posted
    • Updating a couple of components based on feedback
    If I still have time after that, I'll look at some of the issues.

    I'll have a look at @firagon 's updates and see if I can include them @eXntrc

    Help and support is also welcome, the PR's are slowly flying in which helps to boost the project as my "free" time is dwindling at the mo due to work / family
     
  35. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    @firagon 's coded added as a new UIMultiLineRender component, so as not to break everyone's code using the existing UILineRenderer

    *edit, scratch that. The existing UILinerender code has been improved with @firagon 's new code as it's backwards compatible. Note the TextureLinerender is still the old code, may simply remove that one after testing.
     
    Last edited: May 18, 2016
  36. dradb

    dradb

    Joined:
    Jan 10, 2015
    Posts:
    86
    Kadaj,
    Thank you for your script. It works very well with manually entered points. I'm fairly new to C# and I'm having trouble writing a list of points to it from another script.
    Help please.
     
  37. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    @dradb Check the version in the UI Extensions. It has been "extended" further to allow for a more programmatic use.
    you can also check it in it's video here:
     
  38. dradb

    dradb

    Joined:
    Jan 10, 2015
    Posts:
    86
    Thank you Simon. It works great.
     
    SimonDarksideJ likes this.
  39. Devil_Inside

    Devil_Inside

    Joined:
    Nov 19, 2012
    Posts:
    1,119
    @SimonDarksideJ
    Just downloaded and tested the UI line renderer. Seems like point coordinate 0,0 is always bottom left corner of the rect transform. Is there plans to make point coordinates to somehow respect the anchor points of the rect transform?
     
  40. TheValar

    TheValar

    Joined:
    Nov 12, 2012
    Posts:
    760
    Yeah this would be nice
     
  41. Deankovitch

    Deankovitch

    Joined:
    Sep 28, 2012
    Posts:
    31
    Hi all,

    I'd like to share with you my plugin to create 2D Primitives.
    You can create these primitives
    • Circle
    • Star
    • Rounded square
    • Arrow
    • Spiral
    • N-Sides Polygon
    • Gradient Quad
    • 4 Corner Gradient Quad
    All primitives types are inherited from default Graphic class so it's behave as any canvas element.
    The main pros to use those primitives are:
    • They are resolution independent;
    • Fully animable;
    • Lightweight;
    • Fully configurable;
    • Source code included;
    • You can use the shapes included in the pack (as a static class Shape2DHelper) for many implementations: spawn objects, emit particles, draw, animation etc.
    • Fast and easy to prototype or create UI / UX;
    To next version I'm adding support to create 2D Sprite Primitives as well.

    Here is the link to the plugin on Asset Store
    2D Primitives
     
    iddqd likes this.
  42. jayadratha

    jayadratha

    Joined:
    Jan 19, 2017
    Posts:
    6
    @firagon can we make rounded line join in your code?
     
  43. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    Hi @Devil_Inside / @TheValar , sorry only just spotted your reply.
    There has been some talk on the project about this. Feel free to jump in on the issues / gitter discussion.
    https://bitbucket.org/UnityUIExtensions/unity-ui-extensions
     
  44. firagon

    firagon

    Joined:
    Feb 26, 2016
    Posts:
    3
    Here's a round-line join implementation.

    Code (CSharp):
    1.  
    2.  
    3. using System.Collections.Generic;
    4.  
    5. namespace UnityEngine.UI.Extensions {
    6.   [AddComponentMenu("UI/Extensions/Primitives/UILineRenderer")]
    7.   public class UILineRenderer : UIPrimitiveBase {
    8.     private enum SegmentType {
    9.       Start,
    10.       Middle,
    11.       End,
    12.     }
    13.  
    14.     public enum JoinType {
    15.       Bevel,
    16.       Miter,
    17.       Round
    18.     }
    19.     public enum BezierType {
    20.       None,
    21.       Quick,
    22.       Basic,
    23.       Improved,
    24.     }
    25.  
    26.     private const float MIN_MITER_JOIN = 15 * Mathf.Deg2Rad;
    27.  
    28.     // A bevel 'nice' join displaces the vertices of the line segment instead of simply rendering a
    29.     // quad to connect the endpoints. This improves the look of textured and transparent lines, since
    30.     // there is no overlapping.
    31.     private const float MIN_BEVEL_NICE_JOIN = 30 * Mathf.Deg2Rad;
    32.  
    33.     private static readonly Vector2 UV_TOP_LEFT = Vector2.zero;
    34.     private static readonly Vector2 UV_BOTTOM_LEFT = new Vector2(0, 1);
    35.     private static readonly Vector2 UV_TOP_CENTER = new Vector2(0.5f, 0);
    36.     private static readonly Vector2 UV_BOTTOM_CENTER = new Vector2(0.5f, 1);
    37.     private static readonly Vector2 UV_TOP_RIGHT = new Vector2(1, 0);
    38.     private static readonly Vector2 UV_BOTTOM_RIGHT = new Vector2(1, 1);
    39.  
    40.     private static readonly Vector2[] startUvs = new[] { UV_TOP_LEFT, UV_BOTTOM_LEFT, UV_BOTTOM_CENTER, UV_TOP_CENTER };
    41.     private static readonly Vector2[] middleUvs = new[] { UV_TOP_CENTER, UV_BOTTOM_CENTER, UV_BOTTOM_CENTER, UV_TOP_CENTER };
    42.     private static readonly Vector2[] endUvs = new[] { UV_TOP_CENTER, UV_BOTTOM_CENTER, UV_BOTTOM_RIGHT, UV_TOP_RIGHT };
    43.  
    44.     [SerializeField]
    45.     private Rect m_UVRect = new Rect(0f, 0f, 1f, 1f);
    46.     [SerializeField]
    47.     private Vector2[] m_points;
    48.  
    49.  
    50.     public float LineThickness = 2;
    51.     public bool UseMargins;
    52.     public Vector2 Margin;
    53.     public bool relativeSize;
    54.  
    55.     public bool LineList = false;
    56.     public bool LineCaps = false;
    57.     public JoinType LineJoins = JoinType.Bevel;
    58.  
    59.     public BezierType BezierMode = BezierType.None;
    60.     public int BezierSegmentsPerCurve = 10;
    61.  
    62.     /// <summary>
    63.     /// UV rectangle used by the texture.
    64.     /// </summary>
    65.     public Rect uvRect {
    66.       get {
    67.         return m_UVRect;
    68.       }
    69.       set {
    70.         if (m_UVRect == value)
    71.           return;
    72.         m_UVRect = value;
    73.         SetVerticesDirty();
    74.       }
    75.     }
    76.  
    77.     /// <summary>
    78.     /// Points to be drawn in the line.
    79.     /// </summary>
    80.     public Vector2[] Points {
    81.       get {
    82.         return m_points;
    83.       }
    84.       set {
    85.         if (m_points == value)
    86.           return;
    87.         m_points = value;
    88.         SetAllDirty();
    89.       }
    90.     }
    91.  
    92.     protected override void OnPopulateMesh(VertexHelper vh) {
    93.       if (m_points == null)
    94.         return;
    95.       Vector2[] pointsToDraw = m_points;
    96.       //If Bezier is desired, pick the implementation
    97.       if (BezierMode != BezierType.None && m_points.Length > 3) {
    98.         BezierPath bezierPath = new BezierPath();
    99.  
    100.         bezierPath.SetControlPoints(pointsToDraw);
    101.         bezierPath.SegmentsPerCurve = BezierSegmentsPerCurve;
    102.         List<Vector2> drawingPoints;
    103.         switch (BezierMode) {
    104.           case BezierType.Basic:
    105.             drawingPoints = bezierPath.GetDrawingPoints0();
    106.             break;
    107.           case BezierType.Improved:
    108.             drawingPoints = bezierPath.GetDrawingPoints1();
    109.             break;
    110.           default:
    111.             drawingPoints = bezierPath.GetDrawingPoints2();
    112.             break;
    113.         }
    114.         pointsToDraw = drawingPoints.ToArray();
    115.       }
    116.  
    117.       var sizeX = rectTransform.rect.width;
    118.       var sizeY = rectTransform.rect.height;
    119.       var offsetX = -rectTransform.pivot.x * rectTransform.rect.width;
    120.       var offsetY = -rectTransform.pivot.y * rectTransform.rect.height;
    121.  
    122.       // don't want to scale based on the size of the rect, so this is switchable now
    123.       if (!relativeSize) {
    124.         sizeX = 1;
    125.         sizeY = 1;
    126.       }
    127.  
    128.       if (UseMargins) {
    129.         sizeX -= Margin.x;
    130.         sizeY -= Margin.y;
    131.         offsetX += Margin.x / 2f;
    132.         offsetY += Margin.y / 2f;
    133.       }
    134.  
    135.       vh.Clear();
    136.  
    137.       // Generate the quads that make up the wide line
    138.       var segments = new List<UIVertex[]>();
    139.       if (LineList) {
    140.         for (var i = 1; i < pointsToDraw.Length; i += 2) {
    141.           var start = pointsToDraw[i - 1];
    142.           var end = pointsToDraw[i];
    143.           start = new Vector2(start.x * sizeX + offsetX, start.y * sizeY + offsetY);
    144.           end = new Vector2(end.x * sizeX + offsetX, end.y * sizeY + offsetY);
    145.  
    146.           if (LineCaps) {
    147.             segments.Add(CreateLineCap(start, end, SegmentType.Start));
    148.           }
    149.  
    150.           segments.Add(CreateLineSegment(start, end, SegmentType.Middle));
    151.  
    152.           if (LineCaps) {
    153.             segments.Add(CreateLineCap(start, end, SegmentType.End));
    154.           }
    155.         }
    156.       } else {
    157.         for (var i = 1; i < pointsToDraw.Length; i++) {
    158.           var start = pointsToDraw[i - 1];
    159.           var end = pointsToDraw[i];
    160.           start = new Vector2(start.x * sizeX + offsetX, start.y * sizeY + offsetY);
    161.           end = new Vector2(end.x * sizeX + offsetX, end.y * sizeY + offsetY);
    162.  
    163.           if (LineCaps && i == 1) {
    164.             segments.Add(CreateLineCap(start, end, SegmentType.Start));
    165.           }
    166.  
    167.           segments.Add(CreateLineSegment(start, end, SegmentType.Middle));
    168.  
    169.           if (LineCaps && i == pointsToDraw.Length - 1) {
    170.             segments.Add(CreateLineCap(start, end, SegmentType.End));
    171.           }
    172.         }
    173.       }
    174.  
    175.       // Add the line segments to the vertex helper, creating any joins as needed
    176.       for (var i = 0; i < segments.Count; i++) {
    177.         if (!LineList && i < segments.Count - 1) {
    178.           var vec1 = segments[i][1].position - segments[i][2].position;
    179.           var vec2 = segments[i + 1][2].position - segments[i + 1][1].position;
    180.           var angle = Vector2.Angle(vec1, vec2) * Mathf.Deg2Rad;
    181.  
    182.           // Positive sign means the line is turning in a 'clockwise' direction
    183.           var sign = Mathf.Sign(Vector3.Cross(vec1.normalized, vec2.normalized).z);
    184.  
    185.           // Calculate the miter point
    186.           var miterDistance = LineThickness / (2 * Mathf.Tan(angle / 2));
    187.           var miterPointA = segments[i][2].position - vec1.normalized * miterDistance * sign;
    188.           var miterPointB = segments[i][3].position + vec1.normalized * miterDistance * sign;
    189.  
    190.           var joinType = LineJoins;
    191.           if (joinType == JoinType.Miter) {
    192.             // Make sure we can make a miter join without too many artifacts.
    193.             if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_MITER_JOIN) {
    194.               segments[i][2].position = miterPointA;
    195.               segments[i][3].position = miterPointB;
    196.               segments[i + 1][0].position = miterPointB;
    197.               segments[i + 1][1].position = miterPointA;
    198.             } else {
    199.               joinType = JoinType.Bevel;
    200.             }
    201.           }
    202.  
    203.           if (joinType == JoinType.Bevel) {
    204.             if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_BEVEL_NICE_JOIN) {
    205.               if (sign < 0) {
    206.                 segments[i][2].position = miterPointA;
    207.                 segments[i + 1][1].position = miterPointA;
    208.               } else {
    209.                 segments[i][3].position = miterPointB;
    210.                 segments[i + 1][0].position = miterPointB;
    211.               }
    212.             }
    213.  
    214.             var join = new UIVertex[] { segments[i][2], segments[i][3], segments[i + 1][0], segments[i + 1][1] };
    215.             vh.AddUIVertexQuad(join);
    216.           }
    217.  
    218.           if (joinType == JoinType.Round) {
    219.             // Tessellate an approximation of a circle
    220.             var center = new Vector2(pointsToDraw[i + 1].x * sizeX + offsetX, pointsToDraw[i + 1].y * sizeY + offsetY);
    221.             Vector2 v0 = center;
    222.             Vector2 uv0 = new Vector2(0, 0.5f);
    223.  
    224.             if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_BEVEL_NICE_JOIN) {
    225.               if (sign < 0) {
    226.                 segments[i][2].position = miterPointA;
    227.                 segments[i + 1][1].position = miterPointA;
    228.                 v0 = miterPointA;
    229.                 uv0 = segments[i][2].uv0;
    230.               } else {
    231.                 segments[i][3].position = miterPointB;
    232.                 segments[i + 1][0].position = miterPointB;
    233.                 v0 = miterPointB;
    234.                 uv0 = segments[i][3].uv0;
    235.               }
    236.             }          
    237.  
    238.             var two = segments[i][3].position - (Vector3)center;
    239.             var one = segments[i + 1][0].position - (Vector3)center;
    240.             var uv1 = segments[i][3].uv0;
    241.             if (sign > 0) {
    242.               one = segments[i][2].position - (Vector3)center;
    243.               two = segments[i + 1][1].position - (Vector3)center;
    244.               uv1 = segments[i][2].uv0;
    245.             }
    246.  
    247.             var tesselation = 12;
    248.             List<UIVertex> verts = new List<UIVertex>();
    249.  
    250.             var v1 = one;
    251.             for (var iteration = 0; iteration < tesselation; iteration++) {
    252.               var v2 = Vector3.RotateTowards(v1, two, Mathf.PI / tesselation, 0.1f);
    253.               verts.AddRange(CreateTriangle(new[] { v0, center + (Vector2)v1, center + (Vector2)v2 }, new[] { uv0, uv1, uv1 }));
    254.               v1 = v2;
    255.             }
    256.             vh.AddUIVertexTriangleStream(verts);
    257.           }
    258.         }
    259.         vh.AddUIVertexQuad(segments[i]);
    260.       }
    261.     }
    262.  
    263.     private UIVertex[] CreateTriangle(Vector2[] vertices, Vector2[] uvs) {
    264.       UIVertex[] vbo = new UIVertex[3];
    265.       for (int i = 0; i < vertices.Length; i++) {
    266.         var vert = UIVertex.simpleVert;
    267.         vert.color = color;
    268.         vert.position = vertices[i];
    269.         vert.uv0 = uvs[i];
    270.         vbo[i] = vert;
    271.       }
    272.       return vbo;
    273.     }
    274.  
    275.     private UIVertex[] CreateLineCap(Vector2 start, Vector2 end, SegmentType type) {
    276.       if (type == SegmentType.Start) {
    277.         var capStart = start - ((end - start).normalized * LineThickness / 2);
    278.         return CreateLineSegment(capStart, start, SegmentType.Start);
    279.       } else if (type == SegmentType.End) {
    280.         var capEnd = end + ((end - start).normalized * LineThickness / 2);
    281.         return CreateLineSegment(end, capEnd, SegmentType.End);
    282.       }
    283.  
    284.       Debug.LogError("Bad SegmentType passed in to CreateLineCap. Must be SegmentType.Start or SegmentType.End");
    285.       return null;
    286.     }
    287.  
    288.     private UIVertex[] CreateLineSegment(Vector2 start, Vector2 end, SegmentType type) {
    289.       var uvs = middleUvs;
    290.       if (type == SegmentType.Start)
    291.         uvs = startUvs;
    292.       else if (type == SegmentType.End)
    293.         uvs = endUvs;
    294.  
    295.       Vector2 offset = new Vector2(start.y - end.y, end.x - start.x).normalized * LineThickness / 2;
    296.       var v1 = start - offset;
    297.       var v2 = start + offset;
    298.       var v3 = end + offset;
    299.       var v4 = end - offset;
    300.       return SetVbo(new[] { v1, v2, v3, v4 }, uvs);
    301.     }
    302.  
    303.   }
    304. }
     
    Last edited: Apr 18, 2017
  45. swredcam

    swredcam

    Joined:
    Apr 16, 2017
    Posts:
    130
    I'm trying to test UILineRenderer but can't seem to get it working. The error is the same one a user (T_s_walker) on the chat mentioned -- UIPrimitiveBase.cs is throwing two "UnityEngine.UI.SetPropertyUtility is inaccessible..." errors. I only imported the primitivebase and uilinerenderer scripts, plus cablecurve.cs. Do I need something else to get rid of these errors? Also, I am not seeing uilinrenderer in the menu -- is that because it is not compiling? Thank you!
     
  46. swredcam

    swredcam

    Joined:
    Apr 16, 2017
    Posts:
    130
    OK I figured out that I needed setpropertyutility.cs also, to clear those errors. Unfortunately that brought me to a large new group of errors. It seems like it is pretty tough to actually import only a single element of the UI extensions. I was hoping to verify that linerenderer worked for my needs before committing to the entire package. The nature of the package though is that there are a lot of dependencies.
     
  47. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    Hi @swredcam , Yes, the project isn't designed for picking out a single class / component. However, the entire project is quite small and Unity will strip out unused code (like any other asset and even your own unused code) on build.

    So tbh, you might as well import the entire project, either from the asset or the GitHub repo. You won't have any conflicts as it's all safely managed behind it's own namespace.
     
  48. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
  49. swredcam

    swredcam

    Joined:
    Apr 16, 2017
    Posts:
    130
    My early Unity explorations resulted in a lot of "stuff" getting added so I am pretty cautious now. That said uilinrenderer worked great for me and when I get a chance I plan to back out the mods I made for it to be standalone. Thank you for your help!
     
    SimonDarksideJ likes this.
  50. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    Ditto - tried to use this, it has tonnes of unwanted dependencies (hugely disappointing for something that DOES NOT need dependencies at all, and which was 80 lines of code in a single file ... but is now ****-loads of dependencies across many many files).

    TL;DR: don't use UI Extensions, take the working original scripts and go from there.