Tool script mesh only showing 1x1x1 cube instead of 16x16x16 chunk

Godot Version

Godot 4.2.2

Intention

I’m trying to make blocky, voxel terrain generation, creating a chunk of blocks as a single mesh. The script takes arrays of vertices that define the basic cube shape, forms triangle indices out of those vertices for each face of the cube, and feeds all of that into the MeshInstance3D’s ArrayMesh. The script is also a tool, so I can see what I’m doing in the editor.

What Is Working

So far, I have been able to make a single 1x1x1 block, and then have extrapolated on this by running through a 3d array to change the vertex positions for each subsequent block in the chunk, currently making a 16x16x16 chunk. When selecting the MeshInstance3D (the chunk), the orange outline in the editor appears around where the chunk should be, showing that it is, on some level, correctly registering that this is a 16x16x16 object.

The Problem

Despite the orange selection outline clearly silhouetting a 16x16x16 cubic chunk, there is no visible mesh beyond the single 1x1x1 cube I started with. I have tried reloading the tool script, the scene, and the project itself multiple times. I have scoured my code line by line and everything looks like it should be working as intended. When I print out the positions of every individual vertex in the chunk, every single one is exactly where they are supposed to be. And yet, no matter what, the editor only renders the first block even despite highlighting the entire chunk at its actual size.

The Code

@tool
extends MeshInstance3D

@export var update_mesh : bool

const CUBE_VERTICES = [
	#Top vertices, clockwise
	Vector3(0, 1, 0), #0
	Vector3(1, 1, 0), #1
	Vector3(1, 1, 1), #2
	Vector3(0, 1, 1), #3
	#Bottom vertices, clockwise
	Vector3(0, 0, 0), #4
	Vector3(1, 0, 0), #5
	Vector3(1, 0, 1), #6
	Vector3(0, 0, 1), #7
]
const CUBE_FACES = [
	#Indices of the CUBE_VERTICES array
	[0, 1, 2, 3], #0: Face +Y, TOP
	[5, 4, 7, 6], #1: Face -Y, BOTTOM
	[2, 1, 5, 6], #2: Face +X, LEFT
	[0, 3, 7, 4], #3: Face -X, RIGHT
	[3, 2, 6, 7], #4: Face +Z, FRONT
	[1, 0, 4, 5]  #5: Face -Z, BACK
]
const CUBE_SIZE = 1

enum BlockType {Void, Test}

var array_mesh = ArrayMesh.new()
var	vertices = PackedVector3Array()
var	indices = PackedInt32Array()
var	uvs = PackedVector2Array()
var texture_divisor = 0.125

var blocks = []

func _process(delta):
	if(update_mesh):
		init_block_array()
		generate_chunk()
		update_mesh = false

func init_block_array():
	blocks.resize(Global.CHUNK_DIMENSIONS.x)
	for x in range(Global.CHUNK_DIMENSIONS.x):
		blocks[x] = []
		for y in range(Global.CHUNK_DIMENSIONS.y):
			blocks[x].append([])
			for z in range(Global.CHUNK_DIMENSIONS.z):
				blocks[x][y].append(BlockType.Test)

func generate_chunk():
	array_mesh = ArrayMesh.new()
	vertices = PackedVector3Array()
	indices = PackedInt32Array()
	uvs = PackedVector2Array()
	
	var total_block_count = Global.CHUNK_DIMENSIONS.x * Global.CHUNK_DIMENSIONS.y * Global.CHUNK_DIMENSIONS.z
	var void_count = 0
	for x in range(Global.CHUNK_DIMENSIONS.x):
		for y in range(Global.CHUNK_DIMENSIONS.y):
			for z in range(Global.CHUNK_DIMENSIONS.z):
				var block_data = blocks[x][y][z]
				if(block_data == BlockType.Void):
					void_count += 1
				else:
					generate_cube_mesh(Vector3(x, y, z), block_data)
	
	if(void_count < total_block_count):
		var array = []
		array.resize(Mesh.ARRAY_MAX)
		array[Mesh.ARRAY_VERTEX] = vertices
		array[Mesh.ARRAY_INDEX] = indices
		array[Mesh.ARRAY_TEX_UV] = uvs
		array_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, array)
		mesh = array_mesh

func generate_cube_mesh(offset_position : Vector3, block_data : int):
	for i in CUBE_FACES.size():
		create_face(i, offset_position)
		add_triangles(i)
		add_uvs(i, block_data - 1)

func create_face(face, offset):
	for i in CUBE_FACES[face].size():
		var vert_index = CUBE_FACES[face][i]
		var current_vertex = CUBE_VERTICES[vert_index]
		var offset_vertex = (current_vertex + offset) * CUBE_SIZE
		vertices.append(offset_vertex)

func add_uvs(x, y):
	uvs.append(Vector2(texture_divisor * x, texture_divisor * y))
	uvs.append(Vector2(texture_divisor * x + texture_divisor, texture_divisor * y))
	uvs.append(Vector2(texture_divisor * x + texture_divisor, texture_divisor * y + texture_divisor))
	uvs.append(Vector2(texture_divisor * x, texture_divisor * y + texture_divisor))

func add_triangles(face):
	indices.append(face * 4 + 0)
	indices.append(face * 4 + 1)
	indices.append(face * 4 + 2)
	indices.append(face * 4 + 0)
	indices.append(face * 4 + 2)
	indices.append(face * 4 + 3)

Screenshots


Hopefully this is a thorough enough explanation of the issue I’m facing. What I’m guessing is, there’s either some tiny part of my code I’m just not seeing that’s causing my problem, or there’s some aspect about how Godot handles meshes that I’m not understanding; or both. If there’s anything anyone spots, or any other information needed, please let me know! Any help is greatly appreciated!