Search Unity

Question New Mesh.SetVertices vs. Old Mesh.vertices - array versus list and mobile performance

Discussion in 'General Graphics' started by bigpants, Jan 24, 2023.

  1. bigpants

    bigpants

    Joined:
    Dec 9, 2009
    Posts:
    49
    I am an expert at using "Mesh.vertices = MyArray".
    I'm switching to "Mesh.SetVertices(MyArray)" and I'm concerned about mobile performance.
    I'm currently unable to test on mobile, which is why I'm posting here.

    Question 1
    On mobile, is there a difference in performance between passing an array "Vector3[]" or a list "List<Vector3>" to Mesh.SetVertices? I thought array would be best BUT Mesh.GetVertices returns a list, implying list is the way to go. Ideally I'd like to switch to "List<Vector3>" but not if it costs performance. I'm doing a significant amount of procedural generation, so this is important to me.

    Question 2
    On older mobile, using "Mesh.vertices = MyArray",
    the size of MyArray mattered EVEN if there was nothing in it.
    Example:
    If I wanted to render 100 cubes, I would need to pass in an array perfectly sized to 100 cubes.
    Using an array of 200 cubes, with the last 100 zeroed out, would render perfectly BUT perform poorly.

    I'm ASSUMING Mesh.SetVertices FINALLY SOLVES this problem
    (since it can be passed the length of the array/list) BUT is that true?
    Specifically, on mobile, if MyArray contains 200 elements,
    does "Mesh.SetVertices(MyArray, 0, 100)"
    perform as well as "Mesh.vertices = Array-of-JUST-100-Elements"?

    Thankyou!
     
  2. DevDunk

    DevDunk

    Joined:
    Feb 13, 2020
    Posts:
    5,048
    Answer 1:
    Use the profiler, the only way to find out how performance heavy something is for your specific usecase. Differences on PC (especially when testing in builds) should be the same on mobile (but with different performance tiers of course). You could even use a nativearray.
    It also depends on how you generate objects. If you use a list for that, use that. Calling ToArray each time would probably be worse performance.

    Answer 2:
    For this again, profile it.
    I assume it will fix the performance issue, but the only way to know for sure is to try
     
  3. bigpants

    bigpants

    Joined:
    Dec 9, 2009
    Posts:
    49
    Appreciate the reply but as mentioned my concern is mobile and I can't test on that currently.
    From my experience years ago, mobile is NOT the same as PC for "Mesh.vertices = MyArray",
    that's why I'm posting :)
     
  4. DevDunk

    DevDunk

    Joined:
    Feb 13, 2020
    Posts:
    5,048
    When I messed around with mesh generation the gap in performance between mobile and PC was different (4ms on pc, 28ms on mobile), but when one got faster the other got faster as well.

    Unless someone by chance just benchmarked it, you probably gotta profile it yourself.
    I am curious about the results however
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    1. GetVertices using a List is to let you avoid an additional allocation in C#. You can reuse one List if you need to call GetVertices multiple times. Using a List is beneficial it's something that needs to change size frequently. In terms of rendering performance, there's no difference as both will end up as an array in C++ that gets passed to the GPU.

    So, using List is trading the cost of an allocation in C# for some minor overhead in C++. This is usually a good trade.

    2. An array of 200 cubes worth of vertices is 200 cubes worth of vertices. Neither Unity (nor the GPU) know, or care, about the difference between those vertices making cubes, or all being zeros. All either know is there are 4800 vertices that need to be passed to the GPU and that the GPU will try to render. So yes, you do want to rescale the arrays to match exactly the size you need. Or use a List.


    Note that performance differences should be measurable on PC too between these options. They'll just be accentuated on mobile because the CPU and memory are slower. As @DevDunk noted, the only way to know exactly how something will perform is by profiling it on the device. We can theory craft all we want, but there's no guarantee until you try it.
     
    DevDunk likes this.
  6. bigpants

    bigpants

    Joined:
    Dec 9, 2009
    Posts:
    49
    Reply appreciated!

    I realize once they get to the GPU they're both the same thing.
    My concern is the overhead in >getting< to the GPU.
    Currently, I pass different perfectly sized arrays to ".vertices", which improves mobile performance.
    I want to switch to ONE large list where I pass the start and end parameters to " .SetVertices" instead.
    BUT do I switch to one large list or one large array?
    It doesn't matter to me, but I want the one that passes to the the GPU with the least overhead.
    Again, I'm currently unable to test mobile.

    While trying to post short/readable, I just realized I omitted a key detail.
    I am using ".vertices" and ".triangles" simultaneously (of course!)
    Let's say I have 100 default cubes:
    I pass a 100 x 24 = 2,400 element array to ".vertices"
    and a 100 x 36 = 3,600 element array to ".triangles"

    Now I want just 10 cubes, AND I want to re-use that array.
    I fill out the vertices and triangles arrays with the first 10 x 24 array elements, and ZERO out the rest.
    On PC, this significantly improves performance.
    On older mobile (haven't tested new), this does NOT change performance.

    My guess is PC GPU is smart enough to see the triangles have ended (a 1 x 36 array of zeroes is an end marker),
    so there's no point in rendering further. Whereas on mobile it's rendering all of the zero triangles.

    I fixed this by passing EXACT array sizes to ".vertices" and ".triangles".
    However, it sounds like ".SetVertices" SOLVES my mobile problem!
    I'm hoping someone here can confirm!