2.3. Unity Mesh API

This is about how meshes are updated from C++ Eigen matrices to Unity, so that they can be rendered.

Since Unity 2019.3 there have been some updates to the mesh API. However, there are still various limitations and currently the older API (SetVertices) is being used with NativeArray as it is much simpler and thus more reliable. The flowchart below shows the different copies of the mesh data (e.g. vertex position matrix V).

Indeed there are 4 copies of the mesh currently. Potentially, the ‘CPU Unity internal’ copy does not exist, but this is unclear. Libigl currently only reliably supports column-major, but Unity requires row-major data. A necessary transpose is required. In this case it is most efficient to have two copies.

Note that updates to the mesh only occur when a DirtyFlag is set in the MeshState.DirtyState. DirtyFlag are propagated and cleared when processed. The native ApplyDirty() is called by the managed ApplyDirty in UMeshData.

It is also important to note that the transposing in ApplyDirty() is done on the worker thread. mesh.SetVertices() must be called on the main thread (as it is a Unity API). It is called by the managed ApplyDirtyToMesh function in UMeshData.

Some useful points when working with Unity meshes:

  • Call mesh.MarkDynamic() on a readable mesh to keep a copy of the buffers on the managed CPU memory and make mesh.vertices read/writable. This is required in order to be able to modify the vertices at runtime. The mesh must be marked as writable in the import settings in the Inspector.

  • Call mesh.SetVertexBufferParams() to specify the layout on the GPU, attributes in the same stream are interleaved. Here you can specify the precision as well. See VertexBufferLayout in Native.cs.

  • mesh.UploadData(false) to copy the mesh.vertices ‘CPU Unity internal’ managed data to the GPU immediately (else done pre-render), using true will delete the CPU copy and the mesh will no longer by dynamic/writable.

  • mesh.GetNativeVertexBufferPtr() gets the GPU (DirectX/OpenGL) pointer

    • Potentially with this we can apply changes to the GPU copy directly, potentially gaining performance. This has been experimented with in the source/CustomUploadMesh.cpp