0
\$\begingroup\$

Since unity will not allow users to iterate over mesh.uv and mesh.vertices, I am stuck having to use GC intensive calls when applying an array of uvs and vertices to a mesh. I run into high GC allocation because every time I rebuild a mesh, the uv and vert arrays will be a different size due to the mesh being modified. In turn, this results in having to resize or create new uv/vert array and that is where the garbage collection comes in to be a problem when the old array or list is discarded as well as when applied to the mesh.

Example 1 - List: For example, building a List UVList for a mesh that is built frequently will require calls of UVList.Add(Vert), this creates garbage for the GC whenever the List is resized with List.Add because when the list is resized, it creates a new copy and the old copy goes into GC. Also, to apply this list to a mesh.uv requires the call UVList.ToArray(); which is a nasty call that creates huge GC if you have a long list of vertices because again, to convert to array, that array after it is copied mesh.uv = UVList.ToArray() the UVList array created goes to GC.

Example 2 Array: I've instead tried using fixed array sizes but then learned that you cannot iterate over vertices or uv array of a mesh. For example, using a for loop to directly apply a vertices array to mesh.vertices will result in no mesh showing (i.e. for(i = 0; ...){ mesh.uv[i] = uvArray[i];} )

If I cannot do this, then I run into the same problem as example 1, because the only way is to create new array every time you want to update your mesh that has diff uv/vert length. Resizing array requires creating a new copy of it, and then you have the same issue with GC.

I tried reading through this example of someone else dealing with Unity GC when frequently updating meshes http://gamasutra.com/blogs/RobertZubek/20150504/242572/C_memory_and_performance_tips_for_Unity.php

He doesn't really explain his helper method in applying the UVs to the mesh and when trying from his example, it also results in GC.

I guess my question is, how can I frequently update a mesh with diff uv/vert array size without running into GC Alloc slowing down my project?

\$\endgroup\$
  • 1
    \$\begingroup\$ List should have a reserve function that lets you preallocate the underlying data. \$\endgroup\$ – ratchet freak Nov 23 '15 at 22:27
  • \$\begingroup\$ You didn't read the question or I failed at explaining, having to call UVList.ToArray() creates GC because when the list is applied to mesh.uv, it creates a copy of the array and the UVList.ToArray() then has no pointer and goes to GC. This happens because Unity when moving the list onto GPU creates copy rather than keeping a pointer. \$\endgroup\$ – Euthyphro Nov 23 '15 at 22:31
1
\$\begingroup\$

According to http://answers.unity3d.com/questions/855637/mesh-uvs-wont-change-positions.html, mesh.uv is a deep copy, explaining why your second example doesn't work.

Another link corroborating this position, with less supporting detail: http://answers.unity3d.com/questions/956387/how-can-i-modify-a-mesh-objects-uv-variable-direct.html

In your link to Robert Zubek's post, I think it's crucial that he says "of the appropriate size." I.e., I think he's mutating some specific array size, not variable size. I don't believe he has a trick for UV arrays of variable sizes.

Given this information, I think the only suggestion I have is a truely sinful hack: maintain scratch arrays of each size you need.

Depending on what sort of geometry manipulation you're doing, this could actually be fairly benign, if a bit of a headache.

Also, if you're able to break the mesh into smaller chunks, then hypothetically you only need as many scratch arrays as the max size of those chunks. Again, a headache.

\$\endgroup\$
  • \$\begingroup\$ I unfortunately cant keep scratch arrays because theoretically each chunk of the terrain mesh could be 0 to 65k verts, to keep a scratch array of each of this would result in no memory left. I've tried, lol. \$\endgroup\$ – Euthyphro Nov 23 '15 at 23:35
  • \$\begingroup\$ Ah, indeed. Would it be possible to bin your manipulations? E.g. "It will always be some multiple of 1024" would get you down to just 64 arrays. I imagine it would cost you some terrain quality (whether rounding up or down), but perhaps a worthwhile sacrifice, if possible. Sorry, out of ideas. :) \$\endgroup\$ – Chris Mills-Price Nov 23 '15 at 23:40
  • \$\begingroup\$ Can you explain this a bit further? Sounds like a possible idea to try. \$\endgroup\$ – Euthyphro Nov 23 '15 at 23:43
  • \$\begingroup\$ Difficult without knowing the specifics of your situation, but the idea would be that instead of allowing fully arbitrary changes to the mesh, you require that all changes conform to a specific number of vertices. How you accomplish this... Well, you could subdivide triangles to add more vertices, or use poly count reduction algorithms to go the other way. Essentially, try to find ways to shift your vertex count to get specific values (maybe multiples of 1024 is terrible for that, but any arbitrary values are fine), and then you reduce the number of scratch arrays you need. \$\endgroup\$ – Chris Mills-Price Nov 23 '15 at 23:56
  • \$\begingroup\$ Also: I can't seem to find anything saying one way or another, but what happens if your UV array has more elements than are needed? Maybe it ignores them. :) That would make the binning pretty simple (just round up), although you'd likely still want several sizes to avoid shifting around unnecessary data. \$\endgroup\$ – Chris Mills-Price Nov 24 '15 at 0:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.