Pinned replies
Avatar
Freya Holmér creator
  • Answer
  • Planned

dashed polylines are one of those features that feel obvious and essential, but, in practice, implementing dashed polylines has a few implications that are difficult to deal with


  • technically, it's a tradeoff between quality and performance here
    • naively implementing this for polylines means using the current geometry and just passing in distance data, will actually make skew dashes, especially near sharp turns
    • a quick and dirty fix is to add additional vertices to the mesh, but I want to avoid this since I want Shapes to be very light on the CPU
    • I might end up having to do the quick an dirty one in the end, but, I got a cursed idea a few days ago that might work out that I need to experiment with~


    • design-wise, some questions now arise, because dash size is currently relative to the thickness of the line
      • If you change thickness across the line, it's a little ambiguous how this should be handled
      • I could ignore it, and let dash length change relative to changing thickness, but I think this is somewhat nontrivial and also just not very practically useful
      • The other option is to change dash size to no longer be relative to thickness, but,
        • this is a breaking change (but might be worth it), and having relative dash sizes is still useful for lines that don't change width
        • a non-breaking way of doing this, is to make it an option, but, options require a lot of design too, especially for the component side of the library


    anyway sorry for thought dump!

    tldr: it's more complicated than one might think, but it's something people expect to have, so I'll have to solve it somehow! I just want to make sure I do it the right way

    Avatar
    Freya Holmér creator
    • Answer
    • Planned

    dashed polylines are one of those features that feel obvious and essential, but, in practice, implementing dashed polylines has a few implications that are difficult to deal with


    • technically, it's a tradeoff between quality and performance here
      • naively implementing this for polylines means using the current geometry and just passing in distance data, will actually make skew dashes, especially near sharp turns
      • a quick and dirty fix is to add additional vertices to the mesh, but I want to avoid this since I want Shapes to be very light on the CPU
      • I might end up having to do the quick an dirty one in the end, but, I got a cursed idea a few days ago that might work out that I need to experiment with~


      • design-wise, some questions now arise, because dash size is currently relative to the thickness of the line
        • If you change thickness across the line, it's a little ambiguous how this should be handled
        • I could ignore it, and let dash length change relative to changing thickness, but I think this is somewhat nontrivial and also just not very practically useful
        • The other option is to change dash size to no longer be relative to thickness, but,
          • this is a breaking change (but might be worth it), and having relative dash sizes is still useful for lines that don't change width
          • a non-breaking way of doing this, is to make it an option, but, options require a lot of design too, especially for the component side of the library


      anyway sorry for thought dump!

      tldr: it's more complicated than one might think, but it's something people expect to have, so I'll have to solve it somehow! I just want to make sure I do it the right way

      Avatar
      Ernest Szoka

      I too second dashed polylines, I would rather have a compromised/limited version than none at all.  I've been contemplating linking multiple dashed lines to do the effect but I know it won't be as good as something native to shapes.   Really appreciate the the whole toolset and I think this would really be a great addition. 

      Avatar
      Jose Javier Palacio
      Quote from Ernest Szoka

      I too second dashed polylines, I would rather have a compromised/limited version than none at all.  I've been contemplating linking multiple dashed lines to do the effect but I know it won't be as good as something native to shapes.   Really appreciate the the whole toolset and I think this would really be a great addition. 

      Hello! Are there any updates regarding this feature? I came across it and was really bumped by it :( I didn't think it would be that hard and just assumed it would be there. Right now I am working on a project where I am 'drawing' math functions, and so I am using PolyLines, but I really was counting on this 'dashed' feature to work. Regardless, thanks a lot for your hard work, it's an awesome tool.

      Avatar
      Freya Holmér creator
      Quote from Jose Javier Palacio

      Hello! Are there any updates regarding this feature? I came across it and was really bumped by it :( I didn't think it would be that hard and just assumed it would be there. Right now I am working on a project where I am 'drawing' math functions, and so I am using PolyLines, but I really was counting on this 'dashed' feature to work. Regardless, thanks a lot for your hard work, it's an awesome tool.

      I started the refactor a while back, but I've yet to finish it as I got pulled into other projects, and now I'm trying to recover from burnout

      Avatar
      nick maunder

      For anyone who wants an alternative solution and happy to script something up, you can extend ImmediateModeShapeDrawer and make your own drawing behaviour. No need to have several line segment gameobjects in the scene.

      DashStyle is a struct that contains all of the detail about the dash style. You will need to ensure the SashSnapping is set to tiling to ensure a relatively seamless transition between line segments.

      In the DrawShapes method, which you must override, you will need to ensure that Dash drawing is enabled and your style is applied before drawing the line segments. 

      See the example below.

      public class DashedLineDrawer: ImmediateModeShapeDrawer
      { public List pointList = new List();
      public Color m_colour = Color.green;
      public float m_thickness = 0.125f;
      public DashStyle m_dashStyle = DashStyle.RelativeDashes(DashType.Rounded, 0.2f, 0.2f, DashSnapping.Tiling, 0, 0);


      public override void DrawShapes(Camera cam)
      {
      if (pointList.Count == 0)
      {
      return;
      }

      using (Draw.Command(cam))
      {
      Draw.LineGeometry = LineGeometry.Billboard;
      Draw.ThicknessSpace = ThicknessSpace.Meters;

      Draw.UseDashes = true;
      Draw.DashStyle = m_dashStyle;

      for (int i = 0; i < pointList.Count-1; i++)
      {
      Draw.Line(pointList[i], pointList[i+1], m_thickness, m_colour);
      }
      }
      }

      Granted the solution isn't perfect for big differences in direction between line segments. But the drawn curve I've been able to achieve satisfies the effect that I've been trying to achieve.

      Image 645

      Also worth checking out the documentation about ImmediateMode drawing

      https://acegikmo.com/shapes/docs/#immediate-mode

      Avatar
      yinon oshrat

      Any news about dashed Polylines?
      Unfortunately the solution above does not work in my case. I have polylines with many close points and need the dashes to span multiple line segments.

      Thanks for the help

      Avatar
      Freya Holmér creator
      Quote from yinon oshrat

      Any news about dashed Polylines?
      Unfortunately the solution above does not work in my case. I have polylines with many close points and need the dashes to span multiple line segments.

      Thanks for the help

      I have a half-finished polylines 2.0 update in the works, but it's been on ice since I've spent a lot of time working on my spline video, and got burnt out in the process. I'm taking january off, theoretically/hopefully, and so I might get back to finishing the polylines update in february or so! or earlier if we're lucky, but I wouldn't count on it

      Avatar
      patrick hogenboom

      Nick's workaround works super nice! It allowed me to do this cylinder wireframe, thanks a lot!

      Image 786

      For anyone interested, here's the source:

      using System.Collections.Generic;
      using Shapes;
      using UnityEngine;

      [ExecuteAlways]
      public class ShapesCylinder : ImmediateModeShapeDrawer
      {
      public float Radius = 1;
      public float Height = 3;
      public bool UseDashes = true;
      public int CapSubdivisions = 64;
      public int BodySubdivisions = 8;
      [Range(0, 1f)]
      public float LineWidth;
      public Color Color;
      public DashStyle CapDashStyle = DashStyle.RelativeDashes(DashType.Rounded, 5.5f, 3.5f, DashSnapping.Tiling, 0, 0);
      public DashStyle BodyDashStyle = DashStyle.RelativeDashes(DashType.Rounded, 3.5f, 1.25f, DashSnapping.Tiling, 0, 0);

      private List<Vector3> m_capTopPoints = new List<Vector3>();
      private List<Vector3> m_capBotPoints = new List<Vector3>();
      private List<Vector3> m_bodyTopPoints = new List<Vector3>();
      private List<Vector3> m_bodyBotPoints = new List<Vector3>();
      private float HalfHeight => Height /2.0f;
      private Vector3 m_cameraPos;

      void OnValidate()
      {
      m_capTopPoints.Clear();
      m_capBotPoints.Clear();
      int angleStep = Mathf.RoundToInt(360.0f / CapSubdivisions);
      for (int i = 0; i < CapSubdivisions; i++)
      {
      float rad = i * angleStep * Mathf.Deg2Rad;
      Vector3 pos = new Vector3(Mathf.Sin(rad) * Radius, HalfHeight, Mathf.Cos(rad) * Radius);
      m_capTopPoints.Add(pos);
      pos.y *= -1;
      m_capBotPoints.Add(pos);
      }

      m_bodyTopPoints.Clear();
      m_bodyBotPoints.Clear();
      angleStep = Mathf.RoundToInt(360.0f / BodySubdivisions);
      for (int i = 0; i < BodySubdivisions; i++)
      {
      float rad = i * angleStep * Mathf.Deg2Rad;
      Vector3 pos = new Vector3(Mathf.Sin(rad) * Radius, HalfHeight, Mathf.Cos(rad) * Radius);
      m_bodyTopPoints.Add(pos);
      pos.y *= -1;
      m_bodyBotPoints.Add(pos);
      }
      }

      public override void DrawShapes(Camera cam)
      {
      if (m_capTopPoints.Count == 0) return;

      using (Draw.Command(cam))
      {
      Draw.LineGeometry = LineGeometry.Billboard;
      Draw.ThicknessSpace = ThicknessSpace.Meters;
      Draw.UseDashes = UseDashes;

      Draw.DashStyle = CapDashStyle;
      for (int i = 0; i < m_capTopPoints.Count - 1; i++)
      {
      Draw.Line(m_capTopPoints[i], m_capTopPoints[i + 1], LineWidth, Color);
      Draw.Line(m_capBotPoints[i], m_capBotPoints[i + 1], LineWidth, Color);
      }

      Draw.DashStyle = BodyDashStyle;
      for (int i = 0; i < m_bodyTopPoints.Count; i++)
      Draw.Line(m_bodyTopPoints[i], m_bodyBotPoints[i], LineWidth, Color);
      }
      }
      }
      Avatar
      patrick hogenboom

      I got a little carried away...

      Image 787

      Avatar
      christian petry

      Any news on official implementation?
      Should I also go the 'unofficial way' like patrick or is something in the pipeline for the next months?

      Avatar
      Freya Holmér creator
      Quote from christian petry

      Any news on official implementation?
      Should I also go the 'unofficial way' like patrick or is something in the pipeline for the next months?

      definitely don't wait for the release of the official one, it's been on ice for a while now since it's required quite a lot of restructuring due to other changes in the same update, and I'm currently busy with other things for the most part. I still plan on wrapping it up and releasing it eventually, it's just not scheduled at the moment