Search Unity

How to draw lines in unity efficiently?

Discussion in 'General Graphics' started by ZhengzhongSun, Jan 16, 2018.

  1. ZhengzhongSun

    ZhengzhongSun

    Joined:
    Oct 12, 2016
    Posts:
    20
    As we all know, we can set a lot of triangles no more than 65536 faces in one mesh. Now, I want to draw a lot of lines(more than 10000). When I call SetIndices(int[] indices, MeshTopology.LineStrip, int submesh), I only can set one line in one mesh. If I need to draw 10000 lines, do I need to use 10000 meshes? It's crazy!
    It's really appreciate if anyone could give me some advice!

    Thanks,
    Dobbie
     
  2. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,023
    Hi!
    Why not use MeshTopology.Lines?
     
  3. ZhengzhongSun

    ZhengzhongSun

    Joined:
    Oct 12, 2016
    Posts:
    20
    If I use MeshTopology.Lines, there will be a lot of duplicate vertices. Because I need to draw curves actually.
    For example, If I have 10 points in each curve, I will add perhaps 2 times vertices than using Line_Strip. Does it influence the performance? I think it's still not efficient.
     
  4. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    If you use an index buffer with MeshTopology.Lines, it will be fine.
    Alternatively, use a line strip, and insert degenerates to break the line (add 2 vertices at the same location to end a line strip, and add 2 vertices at the same location to start the new line strip).

    Still, the first suggestion (use an index buffer) is probably the most efficient. (Google for "post transform cache" to learn about how the GPU will re-use vertices with the same index, instead of re-running the vertex shader, on many platforms)
     
    JoeMan500 and hippocoder like this.
  5. ZhengzhongSun

    ZhengzhongSun

    Joined:
    Oct 12, 2016
    Posts:
    20
    Thanks! I will have a test about it.
    But I can still set no more than 65536 vertices or indices in one mesh?
     
  6. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Unity has 32 bit indices from 2017.3
     
    karl_jones and richardkettlewell like this.
  7. ZhengzhongSun

    ZhengzhongSun

    Joined:
    Oct 12, 2016
    Posts:
    20
    Does it also support 32 bit vertices? I only see a indexformat in Mesh.
     
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
  9. ZhengzhongSun

    ZhengzhongSun

    Joined:
    Oct 12, 2016
    Posts:
    20
  10. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,291
    Kokowolo likes this.
  11. ZhengzhongSun

    ZhengzhongSun

    Joined:
    Oct 12, 2016
    Posts:
    20
    Thanks! I will take a look. I'm not familiar about LineRenderer.
    But I think it just draw the linestrip. If so, each line needs a LineRenderer?
     
  12. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,291
    Hey sorry. You don't need to use a line renderer. If you just have a list of points then that is enough. https://docs.unity3d.com/ScriptReference/LineUtility.Simplify.html
     
  13. ZhengzhongSun

    ZhengzhongSun

    Joined:
    Oct 12, 2016
    Posts:
    20
    OK. You mean I need to preprocess the vertices data before rendering.
    1. But for public static void Simplify(List<Vector3> points, float tolerance, List<int> pointsToKeep), the input points must be a list of line_strip points? If I want to simplify a lot of lines, could I finish it in one simplify command?
    2. Do you know if there are some tools to simplify the lines before put it into Unity3d?

    Thanks!
     
  14. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,291
    The input needs to be a list of points that form the line, not a line strip. E.g a straight line from a to b would be 2 points. Most 3d modelling programs can simplify lines, I know blender can.
     
  15. ZhengzhongSun

    ZhengzhongSun

    Joined:
    Oct 12, 2016
    Posts:
    20
    But the simplify function will think the input data is a continuous line. E.g a line from a to b to c would be 3 points. it's the same as line strip.
    So each simplify function can only deal with 1 continuous line. I need to call a lot of times simplify functions to preprocess my lines. Right?
     
  16. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,291
    Yes it expects that the points will form one continuous line. So if you have lots of lines then you need to call it multiple times as you said. How complex are these lines? How many points do they have?
     
  17. ZhengzhongSun

    ZhengzhongSun

    Joined:
    Oct 12, 2016
    Posts:
    20
    Every lines have perhaps 32 points and there are maybe 10000 to 50000 lines. So I need to call thousands of simplify functions. Is it too much?
     
  18. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,291
    Depends how often you need to do it. Try it and see how it goes :)
     
  19. xotonic

    xotonic

    Joined:
    Feb 21, 2016
    Posts:
    11
    Sorry for necroposting.
    I've just tried to use degenerate vertices in a cube and doesn't seem to work with LINE_SPRIP. I do it like below:
    Code (CSharp):
    1.        
    2.         /*
    3.          *  4 . . . 7
    4.          *  . \     . \
    5.          *  .   5 . . . 6
    6.          *  .   .   .   .
    7.          *  0 . . . 3   .
    8.          *    \ .     \ .
    9.          *      1 . . . 2
    10.          */
    11.         public static readonly int[] CubeIndicesLineStrip =
    12.         {
    13.             0, 1, 2, 3, 0, 0,  // Draw bottom
    14.             4, 4, 5, 6, 7, 4,  // Draw top
    15.         };
    16.  
    The result:
    unknown.png
     
  20. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    looks correct to me - you didn’t draw some of the lines, you should have 12 proper lines but you only drew 9.
    Eg where is 7,3 or 6,2 or 5,1?
     
    karl_jones likes this.
  21. Rickmc3280

    Rickmc3280

    Joined:
    Jun 28, 2014
    Posts:
    189
    For Line Strip, how does it work exactly? You can terminate a line by putting for instance line 1 = 0,1,2,3,4,5. so 0,1,2,3,4,5,5 and then respectively 6,6,7,8,9,10? Or would you double the vertices and not the buffer?

    edited again to add: Does MeshTopology.StripLines look for repeating indices? Every time it finds a new index (does not equal the previous one) it continues the line, and if it finds the same index it ends it there and if there are more it makes new lines?

    Seems like from a memory management perspective there doesnt need be an index buffer, I would just mark 0,5 and then 6,10. Unity could divide the buffer size by 2 and get the number of lines.

    Also do I have to specify the color for each vertex using MeshTopology.Line and StripLines?

    Edit To Add:

    I would like to consider using multiple lines of differnt colors but it would seem easier if you had an array of lines and line[1].color = color.something;

    So Line1: 0,1,2,3,4,5,6,7,8,9
    Line2: 10,11,12,13,14,15,16

    LineColors[0] = color.red;
    LineColors[1] = color.green;

    etc etc where each element in the array represents all of the colors in the line array.

    Line1 could be an int vector 2 as well so that...

    Line1.x = 0, y = 9;

    Better yet:

    LineArray[0].color = red;
    LineArray[0].vertices = Vector3[];

    Mesh myMesh = new Mesh(bool isLineArray, vector3[] vertices, vector2[] buffers, color[] colorsForEachLine)


    Could be made so that if it recieves a color instead of a color array, all lines are of this color, or if it receives a color array that does not match the indices, it knows that the colors are for ranges of lines. IF the GPU requires indices, Im sure it would be simple enough to write a shader that generates that on load? Or if it requires a full array of colors that match each vertex, it could just copy the value for each one. It would in theory save on data transfer, also if clever, I am sure it would save GPU processing time too.

    *** Last edit
    Also is there any under the hood stuff going on so that we can create our own lines? is it like the GL.Draw type of stuff? Or what would be the absolutely most efficient way to render lines?
     
    Last edited: Mar 9, 2021
  22. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    They don't want the vertical line connecting the top and bottom halves of the cube. Specifically I believe they're asking about your old comment here:
    To me this sounds like a driver implementation quirk / bug as it's not part of any spec for LINE_STRIP I know of for either OpenGL or Direct3D. So it's possible on some hardware degenerate line segments would create a break a line strip, but it certainly doesn't appear to on my RTX 2080 or the GPU @xotonic is using.

    Generally speaking there's not a lot of reason to use a line strip, explicitly because to make a break in a line strip is supposed to require creating a new sub mesh which is going to be bad for performance if you need a lot of separate lines. On very old GPUs (90's) there used to be a noticeable performance improvement when using Triangles Strip vs Triangle based indices, but on modern GPUs there's no benefit, and possibly even a performance hit from using triangle strips so basically all engines expunged support for them. Including Unity.
    LineStrip
    remains, but I suspect on modern GPUs there's a similar lack of performance improvement from using them over
    Lines
    . I just setup a test case with a 65535 vertex spiral sphere that I could switch between
    Lines
    and
    LineStrip
    topology & matching indices and I could not see a performance difference even though the
    Line
    has twice as many indices. That's because the "work" the GPU has to do is per vertex and per pixel, not per index or index pair. And the difference between 0.125MB of 16 bit
    LineStrip
    index data and 0.25MB of
    Line
    index data is inconsequential compared to the constant 0.75MB of vertex positional data.

    TLDR: Stop using
    MeshTopology.LineStrip
    and use
    MeshTopology.Line
    if you want multiple unconnected lines in a single line mesh.

    That depends on the material, or more specifically the shader you're using on the mesh. A line mesh is still "just" a mesh. Basically any shader you can use on a triangle mesh you can use on a line mesh. As long as you provide the vertex data that shader needs, it'll render however you want. Just as 1 pixel thin lines instead of as triangles. If you want to assign the color per vertex, then assign the vertex colors. If you need to have one line that's a solid color and another line that's a different solid color but which shares a vertex position, then you need a duplicate vertex at that position with two colors. Or you need to draw two completely separate line (sub)meshes with different materials that have a different constant color assigned. If you want lines that accept the vertex color, you probably want to use a particle shader.
     
    xotonic likes this.
  23. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    Ah yes you’re right - my bad. I can only assume I was thinking about how to break triangle strips by inserting degenerates, and extrapolating that same idea to line strips without really thinking it through. Due to lines only needing 2 points to form the line, it’s not possible to break it up in this way, unless you inserted zero alpha verts too, to make the “degenerates” invisible.

    It was so long ago though, who knows what I was thinking about :)
     
    karl_jones and bgolus like this.