Meshes made by scripts
A script makes a mesh with new Mesh(), as in Unity, fills it with vertices and indices, and gives it to a MeshFilter to be seen and to a MeshCollider to be touched. A script can also change a mesh of the scene. The API is Unity's: SetVertices, SetNormals, SetTangents, SetColors, SetUVs (channels 0 to 7), SetTriangles and SetIndices per submesh, subMeshCount, indexFormat, RecalculateNormals, RecalculateTangents, RecalculateBounds, Clear, MarkDynamic, and the same data read back (vertices, GetVertices, GetIndices…).
Meshes exist on the players' devices only: the server has no rendering and no physics, and a script that makes a mesh there gets an error.
Make a mesh
using NodeWorld.Flux;
public class Ramp : FluxScript
{
protected override void Start()
{
var mesh = new Mesh();
mesh.SetVertices(new[] { new Vector3(0, 0, 0), new Vector3(1, 0, 0), new Vector3(0, 0.5f, 1), new Vector3(1, 0.5f, 1) });
mesh.SetUVs(0, new[] { new Vector2(0, 0), new Vector2(1, 0), new Vector2(0, 1), new Vector2(1, 1) });
mesh.SetTriangles(new[] { 0, 2, 1, 2, 3, 1 }, 0);
mesh.RecalculateNormals();
GetComponent<MeshFilter>().sharedMesh = mesh; // seen
var collider = GetComponent<MeshCollider>();
collider.sharedMesh = mesh; // touched: the physics takes its shape now
}
}MeshFilter.sharedMeshgives the mesh to the filter.MeshFilter.meshgives the filter's own mesh: the first read makes a copy of its shared mesh for that filter alone, as in Unity.MeshCollider.sharedMeshgives the shape to the collider. Setconvex = truefor a mesh collider on a moving rigidbody or one that must touch another mesh collider.- Set
indexFormat = IndexFormat.UInt32before giving more than 65 535 vertices.
Change it every frame
The arrays you give stay in the memory of the world: the game reads them there, without a copy, and hands them to Unity. Keep your arrays, change them, and give them again:
protected override void Update()
{
for (var i = 0; i < _vertices.Length; i++)
_vertices[i].y = 0.2f * Mathf.Sin(_vertices[i].x * 2f + Time.time);
_mesh.SetVertices(_vertices);
_mesh.RecalculateNormals();
_mesh.RecalculateBounds();
}Call MarkDynamic() once on a mesh that changes often. A thread of your script (Parallel.For, Task.Run) may fill the arrays; the calls that change the mesh (SetVertices…) are made on the main thread.
Vertex and index buffers
For a layout of your own (several attributes in one stream, 16-bit floats…), use Unity's advanced API: SetVertexBufferParams with VertexAttributeDescriptors, SetVertexBufferData with an array of your vertex struct, SetIndexBufferParams, SetIndexBufferData and SetSubMesh with a SubMeshDescriptor. The game lays a NativeArray on your arrays and gives it to Mesh.SetVertexBufferData and Mesh.SetIndexBufferData.
Lifetime
A mesh made by a script belongs to its world: it is destroyed when the world unloads, or earlier by Object.Destroy(mesh). A mesh of the scene changed by a script changes for every renderer of the world that uses it.
