I noticed that the Mesh calss provide two ways of accessing the vertex and other structures.
The SetVertices/UV and so on functions and the direct access to member array variables like .vertices, .uv and so on.
All examples in the docs use the direct member variable arrays for modifying vertex data.
What is the difference between these two, what should we prefer?
There are several reasons for the new SetVertices / SetIndices / SetUVs / methods. First of all the old vertices property is not a variable. This fact has confused many users. It’s a property. So actually there’s a get method and a set method but the usage just looks like a variable.
What most did not understand is that the getter does not return a reference to an internall array but returns a copy. This is necessary since the actual vertex data is stored in the native C++ side of Unity. When you use the property (or the new GetXXX method) you always get a copy of the actual data so changing that copy has no effect on the actual data. To apply changes you had to assign that temp array back to the property in order to call the setter and pass the array back to Unity.
The new GetXXX and SetXXX makes it more clear about that since there are two seperate methods for getting the data and setting the data.
However the most important difference is if you want to change the data frequently you create a lot of garbage each time you convert a List to an array or when you use the getter of those properties. It’s common to use Lists since they provide an easy and efficient way of adding / removing elements with minimal garbage production. You can keep your List instance and the GetXXX methods take in a List reference which they will fill. So once the List has reached the max amount you don’t create any garbage when using GetXXX or SetXXX. So for frequent changes it’s strongly recommended to use the GetXXX and SetXXX methods.
The next major point is the Get / Set method have now multiple overloads which allow you to pass in different types of vertex data. For example
mesh.vertices is an array of Vector3 Get and SetVertices can take in a List of Vector 2 / 3 / 4. So you finally can use the whole data channels. For vertices it seems irrelevant but it can be very important for UV. Most people use just 2d texture coordinates. However to get perspective correct texture mapping at very steep angles or non rectangles you would need 4d texcoords (uvpq):
See this image for a basic reference.
The shader does an automatic perspective correction of the texture coordinates in screen space based on the depth of each vertex. However since each triangle is rendered seperately it doesn’t know how the mesh might continue in other triangles. At very steep angles or unusual shapes (not rectangular shapes) the seem between the triangles won’t match. That’s why there are UVPQ coordinates. For each vertex you can also define information on the actual shape of the mesh.
See this SO question.
So since there is now a
SeUVs(List<Vector4>) overload we finally can pass in 4d texture coordinates.
SetIndices allows you to specify a different mesh topology.
mesh.triangles only allows you to render triangles.
To sum up:
It’s generally adviced to use the new GetXXX and SetXXX method if you do frequent changes to your mesh. They also allow you to use the full power of the GPU since you can now fill in almost any vertex data you like. So the new methods:
- are more GC friendly
- are more versatile
- avoid confusion about the usage.
Based on a quick comparison of Unity’s documentation for Mesh.SetVertices() and Mesh.vertices, SetVertices() reads in a List of values while Mesh.vertices utilizes a Vector3 Array.
// These do the same thing using different data types
m.vertices = vertexArray;
In many circumstances, using the array might be ideal, since it already matches the data type of the vertices in the array, but if the assembly is better handled using a List, it could be more worthwhile to simply pass the List through instead.