Godot Version
4.7
Question
I’m working on implementing Marching Cubes for a fun side project. So far I’ve gotten the actual mesh generation down, but I’m now trying to implement procedural mesh generation with Simplex Noise so I can make infinite worlds. However, when I tried to add a function to generate data points for chunk meshes, it didn’t work. Can anyone help?
This is my Chunk.gd:
class_name Chunk
var mat := StandardMaterial3D.new()
var data: Array[float] = []
var rsinst: RID
var scenario: RID
var mesh: BakedMesh
var phinst: RID
var space: RID
var coll: ConcavePolygonShape3D
var pos: Vector3i
static func IDX(x: int, y: int, z: int) -> int:
return x+y*Globals.chunk_size*Globals.grid_res+z*Globals.chunk_size*Globals.chunk_size*Globals.grid_res*Globals.grid_res
static func VIDX(v: Vector3i) -> int:
return IDX(v.x, v.y, v.z)
func _init(pos: Vector3i, world: World3D) -> void:
data.resize((Globals.chunk_size*Globals.grid_res)**3)
self.pos = pos
scenario = world.scenario
space = world.space
mat.albedo_color = Color(1, 0, 0)
mat.cull_mode = BaseMaterial3D.CULL_FRONT
func render() -> void:
var verts = PackedVector3Array()
var inds = PackedInt32Array()
for x in range(Globals.chunk_size*Globals.grid_res-1):
for y in range(Globals.chunk_size*Globals.grid_res-1):
for z in range(Globals.chunk_size*Globals.grid_res-1):
var points := [
Vector3i(x, y, z),
Vector3i(x+1, y, z),
Vector3i(x+1, y, z+1),
Vector3i(x, y, z+1),
Vector3i(x, y+1, z),
Vector3i(x+1, y+1, z),
Vector3i(x+1, y+1, z+1),
Vector3i(x, y+1, z+1)
]
var noises = [
data[VIDX(points[0])],
data[VIDX(points[1])],
data[VIDX(points[2])],
data[VIDX(points[3])],
data[VIDX(points[4])],
data[VIDX(points[5])],
data[VIDX(points[6])],
data[VIDX(points[7])]
]
var pidcs = Globals.MC_LOOKUP_TABLE[_get_lookup_value(noises)]
for pidx in pidcs:
if pidx == -1: break
var idcs = Globals.MC_EDGES[pidx]
var vec = (Vector3(points[idcs[0]])/Globals.grid_res + Vector3(points[idcs[1]])/Globals.grid_res) * 0.5
verts.append(vec)
inds.append(verts.size()-1)
mesh = BakedMesh.create(verts, inds, Mesh.PRIMITIVE_TRIANGLES)
mesh.surface_set_material(0, mat)
rsinst = RenderingServer.instance_create()
RenderingServer.instance_set_scenario(rsinst, scenario)
RenderingServer.instance_set_base(rsinst, mesh.get_rid())
coll = mesh.create_trimesh_shape()
phinst = PhysicsServer3D.body_create()
PhysicsServer3D.body_set_space(phinst, space)
PhysicsServer3D.body_add_shape(phinst, coll.get_rid())
PhysicsServer3D.body_set_mode(phinst, PhysicsServer3D.BODY_MODE_STATIC)
static func _get_lookup_value(vals: Array) -> int:
var idx = 0
for i in range(vals.size()):
if vals[i] > Globals.MC_CUTOFF: idx |= (1 << i)
return idx
My World.gd:
class_name World
var biome = StaticNoise.create(FastNoiseLite.TYPE_PERLIN, randi(), 1)
var noise = StaticNoise.create(FastNoiseLite.TYPE_SIMPLEX, randi(), 1)
var chunks: Array[Chunk] = []
func gen_terrain(chunk: Chunk, xz: Vector2i) -> void:
var h = noise.get_noise_2d(xz.x, xz.y)
chunk.data[Chunk.IDX(xz.x, floor(h), xz.y)] = h % 1.0
func render() -> void:
for chunk in chunks:
chunk.render()
My globals file, autoloaded:
extends Node
const chunk_size := 16
const grid_res := 1.0
const render_distance := 16
const MC_CUTOFF := 0.0
const MC_LOOKUP_TABLE := (marching cubes lookup table)
const MC_EDGES := [
[ 0, 1 ],
[ 1, 2 ],
[ 2, 3 ],
[ 3, 0 ],
[ 4, 5 ],
[ 5, 6 ],
[ 6, 7 ],
[ 7, 4 ],
[ 0, 4 ],
[ 1, 5 ],
[ 2, 6 ],
[ 3, 7 ]
]
And my main file, attached to the root node of my scene:
extends Node3D
var world := World.new()
func _ready() -> void:
var chunk = Chunk.new(Vector3i.ZERO, get_world_3d())
for x in range(Globals.chunk_size*Globals.grid_res):
for z in range(Globals.chunk_size*Globals.grid_res):
world.gen_terrain(chunk, Vector2i(x, z))
world.chunks.append(chunk)
world.render()
Any help would be greatly appreciated. Thanks!