84 lines
2.2 KiB
GDScript

extends Node3D
@export var tree: Mesh
@export var leaves: Mesh
@export var noise: Noise
@export var size_x: float
@export var size_z: float
@export var step: float = 1
@export var density: float
@export var position_randomness := 1.0
const TILE_SIZE := 10
func _ready():
if !visible:
return
var total_count := 0
var tile_count := 0
var old_tile_x := NAN
var old_tile_z := NAN
var offsets: Array[Vector3] = []
for x in range(-size_x, size_x, step):
for z in range(-size_z, size_z, step):
if noise.get_noise_2d(x, z) < 1 - density * 2:
continue
var tile_x := x / TILE_SIZE
var tile_z := z / TILE_SIZE
if tile_x != old_tile_x || tile_z != old_tile_z:
if tile_count > 0:
var tile := make_tile(old_tile_x, old_tile_z)
tile.multimesh.instance_count = tile_count
tile.multimesh.visible_instance_count = tile_count
for i in range(tile_count):
tile.multimesh.set_instance_transform(i, Transform3D(Basis(), offsets[i] - tile.position))
add_child(tile)
var tile2 := make_tile(old_tile_x, old_tile_z)
tile2.multimesh.mesh = leaves
tile2.multimesh.instance_count = tile_count
tile2.multimesh.visible_instance_count = tile_count
for i in range(tile_count):
tile2.multimesh.set_instance_transform(i, Transform3D(Basis(), offsets[i] - tile.position))
add_child(tile2)
tile_count = 0
offsets.resize(0)
old_tile_x = tile_x
old_tile_z = tile_z
var offset := Vector3.ZERO
offset.x = x + (randf() - 0.5) * position_randomness
offset.z = z + (randf() - 0.5) * position_randomness
offsets.append(offset)
tile_count += 1
total_count += 1
print("Generated %d trees" % total_count)
func make_tile(x, z) -> MultiMeshInstance3D:
prints("Tile:", x * TILE_SIZE, z * TILE_SIZE)
var instance := MultiMeshInstance3D.new()
instance.multimesh = MultiMesh.new()
instance.multimesh.mesh = tree
instance.multimesh.transform_format = MultiMesh.TRANSFORM_3D
var safe_area := Vector3(0, 0, 0)
instance.position = Vector3(x * TILE_SIZE, 0, z * TILE_SIZE)
instance.custom_aabb.position = -safe_area
instance.custom_aabb.size = Vector3(TILE_SIZE, 30, TILE_SIZE) + safe_area * 2
return instance