Using the ArrayMesh
ArrayMesh.
add_surface_from_arrays(), which takes up to four parameters. The first two are required, while the second two are optional.
PrimitiveType, an OpenGL concept that instructs the GPU how to arrange the primitive based on the vertices given, i.e. whether they represent triangles, lines, points, etc. See Mesh.PrimitiveType for the options available.
arrays, is the actual Array that stores the mesh information. The array is a normal Godot array that is constructed with empty brackets []. It stores a Pool**Array (e.g. PoolVector3Array, PoolIntArray, etc.) for each type of information that will be used to build the surface.
arrays are listed below, together with the position they must have within arrays. See also Mesh.ArrayType.
The array of vertices (at index 0) is always required. The index array is optional and will only be used if included. We won’t use it in this tutorial.
ARRAY_COLOR) use one entry per vertex to provide extra information about vertices. They must have the same size as the vertex array. Other arrays (e.g. ARRAY_TANGENT) use four entries to describe a single vertex. These must be exactly four times larger than the vertex array.
add_surface_from_arrays() are typically left empty.
ArrayMesh
MeshInstance and add an ArrayMesh to it in the Inspector. Normally, adding an ArrayMesh in the editor is not useful, but in this case it allows us to access the ArrayMesh from code without creating one.
Next, add a script to the MeshInstance.
_ready(), create a new Array.
GDScript
var surface_array = []
Mesh.ARRAY_MAX, so resize it accordingly.
GDScript
var surface_array = []surface_array.resize(Mesh.ARRAY_MAX)
Next create the arrays for each data type you will use. GDScript
var verts = PoolVector3Array()var uvs = PoolVector2Array()var normals = PoolVector3Array()var indices = PoolIntArray()
surface_array and then committing to the mesh.
GDScript
surface_array[Mesh.ARRAY_VERTEX] = vertssurface_array[Mesh.ARRAY_TEX_UV] = uvssurface_array[Mesh.ARRAY_NORMAL] = normalssurface_array[Mesh.ARRAY_INDEX] = indicesmesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array) # No blendshapes or compression used.
Note
Mesh.PRIMITIVE_TRIANGLES, but you can use any primitive type available from mesh.
Put together, the full code looks like:
GDScript
extends MeshInstancefunc _ready(): var surface_array= [] surface_array.resize(Mesh.ARRAY_MAX) # PoolVector**Arrays for mesh construction. var verts = PoolVector3Array() var uvs = PoolVector2Array() var normals = PoolVector3Array() var indices = PoolIntArray() ####################################### ## Insert code here to generate mesh ## ####################################### # Assign arrays to mesh array. surface_array[Mesh.ARRAY_VERTEX] = verts surface_array[Mesh.ARRAY_TEX_UV] = uvs surface_array[Mesh.ARRAY_NORMAL] = normals surface_array[Mesh.ARRAY_INDEX] = indices # Create mesh surface from mesh array. mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array) # No blendshapes or compression used.
The code that goes in the middle can be whatever you want. Below we will present some example code for generating a sphere.
Generating geometry
Here is sample code for generating a sphere. Although the code is presented in GDScript, there is nothing Godot specific about the approach to generating it. This implementation has nothing in particular to do with ArrayMeshes and is just a generic approach to generating a sphere. If you are having trouble understanding it or want to learn more about procedural geometry in general, you can use any tutorial that you find online. GDScript
extends MeshInstancevar rings = 50var radial_segments = 50var height = 1var radius = 1func _ready(): # Insert setting up the PoolVector**Arrays here. # Vertex indices. var thisrow = 0 var prevrow = 0 var point = 0 # Loop over rings. for i in range(rings + 1): var v = float(i) / rings var w = sin(PI * v) var y = cos(PI * v) # Loop over segments in ring. for j in range(radial_segments): var u = float(j) / radial_segments var x = sin(u * PI * 2.0) var z = cos(u * PI * 2.0) var vert = Vector3(x * radius * w, y, z * radius * w) verts.append(vert) normals.append(vert.normalized()) uvs.append(Vector2(u, v)) point += 1 # Create triangles in ring using indices. if i > 0 and j > 0: indices.append(prevrow + j - 1) indices.append(prevrow + j) indices.append(thisrow + j - 1) indices.append(prevrow + j) indices.append(thisrow + j) indices.append(thisrow + j - 1) if i > 0: indices.append(prevrow + radial_segments - 1) indices.append(prevrow) indices.append(thisrow + radial_segments - 1) indices.append(prevrow) indices.append(prevrow + radial_segments) indices.append(thisrow + radial_segments - 1) prevrow = thisrow thisrow = point # Insert committing to the ArrayMesh here.
Saving
ResourceSaver class to save the ArrayMesh. This is useful when you want to generate a mesh and then use it later without having to re-generate it. GDScript
# Saves mesh to a .tres file with compression enabled.ResourceSaver.save("res://sphere.tres", mesh, ResourceSaver.FLAG_COMPRESS)
