extends Node3D # Noise that will generate the terrain @export var noise : Noise # Maximum height of our terrain @export var height : float = 16. # Sea level (in [-1, 1]) @export var sea_level : float = -0.26 # Terrain size (in cells) @export var size : Vector2i = Vector2i(32, 32) # Terrain mesh @export var terrain : MultiMeshInstance3D func _ready() -> void: assert(noise) # Generate the terrain. var count : int = size.x * size.y var heights : PackedFloat32Array = PackedFloat32Array() var data : PackedVector3Array = PackedVector3Array() heights.resize(count) data.resize(count) # Compute Heights -------------------------------------------------------- var start_timer : int = Time.get_ticks_usec() var idx : int = 0 for y : int in range(size.y): for x : int in range(size.x): heights[idx] = max(sea_level, noise.get_noise_2d(x, y)) * height idx += 1 var end_timer : int = Time.get_ticks_usec() print("Height %s generated in %d µs" % [ size, end_timer - start_timer ]) # Compute Texture Data --------------------------------------------------- start_timer = Time.get_ticks_usec() idx = 0 for y : int in range(size.y): for x : int in range(size.x): var h : float = heights[idx] var hmx : float = heights[idx - 1] if x > 0 else h var hpx : float = heights[idx + 1] if x < size.x - 1 else h var hmz : float = heights[idx - size.x] if y > 0 else h var hpz : float = heights[idx + size.x] if y < size.y - 1 else h var dX : float = hmx - hpx var dZ : float = hmz - hpz var n : Vector3 = Vector3(dX, 2., dZ).normalized() n.y *= -3. data[idx] = Vector3(h, n.x / n.y, n.z / n.y) idx += 1 var image : Image = Image.create_from_data(size.x, size.y, false, Image.FORMAT_RGBF, data.to_byte_array()) var texture : ImageTexture = ImageTexture.create_from_image(image) end_timer = Time.get_ticks_usec() print("Texture generated in %d µs" % (end_timer - start_timer )) # Bind the uniforms ------------------------------------------------------ assert(terrain.material_override) var shader : ShaderMaterial = (terrain.material_override as ShaderMaterial) shader.set_shader_parameter("terrain_size", Vector2(size)) shader.set_shader_parameter("data_tex", texture) # Instanciate geometry --------------------------------------------------- var multimesh : MultiMesh = terrain.multimesh assert(multimesh) multimesh.set_instance_count(count) idx = 0 for y : int in range(size.y): for x : int in range(size.x): multimesh.set_instance_custom_data(idx, Color(float(x), float(y), 0., 0.)) var t : Transform3D = Transform3D.IDENTITY.translated(Vector3(x, 0., y)) multimesh.set_instance_transform(idx, t) idx += 1
or share this direct link: