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!