Created
February 22, 2024 19:33
-
-
Save WithinAmnesia/025f8d1ae7b674fc2c2d4381e9e45c8b to your computer and use it in GitHub Desktop.
generator_test.gd
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#tool | |
extends VoxelGeneratorScript | |
const Structure = preload("./structure.gd") | |
const TreeGenerator = preload("./tree_generator.gd") | |
const HeightmapCurve = preload("./heightmap_curve.tres") | |
# TODO Don't hardcode, get by name from library somehow | |
const AIR = 0 | |
const DIRT = 1 | |
const GRASS = 2 | |
const WATER_FULL = 14 | |
const WATER_TOP = 13 | |
const LOG = 4 | |
const LEAVES = 25 | |
const TALL_GRASS = 8 | |
const DEAD_SHRUB = 26 | |
#const STONE = 8 | |
const _CHANNEL = VoxelBuffer.CHANNEL_TYPE | |
const _moore_dirs = [ | |
Vector3(-1, 0, -1), | |
Vector3(0, 0, -1), | |
Vector3(1, 0, -1), | |
Vector3(-1, 0, 0), | |
Vector3(1, 0, 0), | |
Vector3(-1, 0, 1), | |
Vector3(0, 0, 1), | |
Vector3(1, 0, 1) | |
] | |
var _tree_structures := [] | |
var _heightmap_min_y := 1 #int(HeightmapCurve.min_value) | |
var _heightmap_max_y := 1 #int(HeightmapCurve.max_value) | |
var _heightmap_range := 0 | |
var _heightmap_noise := 0 #FastNoiseLite.new() | |
var _trees_min_y := 0 | |
var _trees_max_y := 0 | |
func _init(): | |
# TODO Even this must be based on a seed, but I'm lazy | |
var tree_generator = TreeGenerator.new() | |
tree_generator.log_type = LOG | |
tree_generator.leaves_type = LEAVES | |
for i in 16: | |
var s = tree_generator.generate() | |
_tree_structures.append(s) | |
var tallest_tree_height = 0 | |
for structure in _tree_structures: | |
var h = int(structure.voxels.get_size().y) | |
if tallest_tree_height < h: | |
tallest_tree_height = h | |
_trees_min_y = _heightmap_min_y | |
_trees_max_y = _heightmap_max_y + tallest_tree_height | |
#_heightmap_noise.seed = 131183 | |
#_heightmap_noise.frequency = 1.0 / 128.0 | |
#_heightmap_noise.fractal_octaves = 4 | |
# IMPORTANT | |
# If we don't do this `Curve` could bake itself when interpolated, | |
# and this causes crashes when used in multiple threads | |
HeightmapCurve.bake() | |
func _get_used_channels_mask() -> int: | |
return 1 << _CHANNEL | |
func _generate_block(buffer: VoxelBuffer, origin_in_voxels: Vector3i, lod: int): | |
# TODO There is an issue doing this, need to investigate why because it should be supported | |
# Saves from this demo used 8-bit, which is no longer the default | |
# buffer.set_channel_depth(_CHANNEL, VoxelBuffer.DEPTH_8_BIT) | |
# Assuming input is cubic in our use case (it doesn't have to be!) | |
var block_size := int(buffer.get_size().x) | |
var oy := origin_in_voxels.y | |
# TODO This hardcodes a cubic block size of 16, find a non-ugly way... | |
# Dividing is a false friend because of negative values | |
var chunk_pos := Vector3( | |
origin_in_voxels.x >> 4, | |
origin_in_voxels.y >> 4, | |
origin_in_voxels.z >> 4) | |
_heightmap_range = _heightmap_max_y - _heightmap_min_y | |
# Ground | |
if origin_in_voxels.y > _heightmap_max_y: | |
buffer.fill(AIR, _CHANNEL) | |
elif origin_in_voxels.y + block_size < _heightmap_min_y: | |
buffer.fill(DIRT, _CHANNEL) | |
else: | |
var rng := RandomNumberGenerator.new() | |
rng.seed = _get_chunk_seed_2d(chunk_pos) | |
var gx : int | |
var gz := origin_in_voxels.z | |
for z in block_size: | |
gx = origin_in_voxels.x | |
for x in block_size: | |
var height := 1 | |
var relative_height := 1 | |
# Dirt and grass | |
if relative_height > block_size: | |
buffer.fill_area(DIRT, | |
Vector3(x, 0, z), Vector3(x + 1, block_size, z + 1), _CHANNEL) | |
elif relative_height > 0: | |
buffer.fill_area(DIRT, | |
Vector3(x, 0, z), Vector3(x + 1, relative_height, z + 1), _CHANNEL) | |
if height >= 0: | |
buffer.set_voxel(GRASS, x, relative_height +1, z, _CHANNEL) | |
if relative_height < block_size and rng.randf() > 0.1: | |
var foliage = GRASS # TALL_GRASS | |
#if # rng.randf() < 0.1: | |
# foliage = GRASS # DEAD_SHRUB | |
buffer.set_voxel(GRASS, x, relative_height, z, _CHANNEL) | |
# Water | |
if height < 0 and oy < 0: | |
var start_relative_height := 0 | |
if relative_height > 0: | |
start_relative_height = relative_height | |
buffer.fill_area(WATER_FULL, | |
Vector3(x, start_relative_height, z), | |
Vector3(x + 1, block_size, z + 1), _CHANNEL) | |
if oy + block_size == 0: | |
# Surface block | |
buffer.set_voxel(WATER_TOP, x, block_size - 1, z, _CHANNEL) | |
gx += 1 | |
gz += 1 | |
# Trees | |
# if origin_in_voxels.y <= _trees_max_y and origin_in_voxels.y + block_size >= _trees_min_y: | |
# var voxel_tool := buffer.get_voxel_tool() | |
# var structure_instances := [] | |
# | |
# _get_tree_instances_in_chunk(chunk_pos, origin_in_voxels, block_size, structure_instances) | |
# | |
# # Relative to current block | |
# var block_aabb := AABB(Vector3(), buffer.get_size() + Vector3i(1, 1, 1)) | |
# for dir in _moore_dirs: | |
# var ncpos : Vector3 = (chunk_pos + dir).round() | |
# _get_tree_instances_in_chunk(ncpos, origin_in_voxels, block_size, structure_instances) | |
# for structure_instance in structure_instances: | |
# var pos : Vector3 = structure_instance[0] | |
# var structure : Structure = structure_instance[1] | |
# var lower_corner_pos := pos - structure.offset | |
# var aabb := AABB(lower_corner_pos, structure.voxels.get_size() + Vector3i(1, 1, 1)) | |
# if aabb.intersects(block_aabb): | |
# voxel_tool.paste_masked(lower_corner_pos, | |
# structure.voxels, 1 << VoxelBuffer.CHANNEL_TYPE, | |
# # Masking | |
# VoxelBuffer.CHANNEL_TYPE, AIR) | |
# buffer.compress_uniform_channels() | |
#func _get_tree_instances_in_chunk( | |
# cpos: Vector3, offset: Vector3, chunk_size: int, tree_instances: Array): | |
# | |
# var rng := RandomNumberGenerator.new() | |
# rng.seed = _get_chunk_seed_2d(cpos) | |
# for i in 4: | |
# var pos := Vector3(rng.randi() % chunk_size, 0, rng.randi() % chunk_size) | |
# pos += cpos * chunk_size | |
# pos.y = 1 | |
# | |
# if pos.y > 0: | |
# pos -= offset | |
# var si := rng.randi() % len(_tree_structures) | |
# var structure : Structure = _tree_structures[si] | |
# tree_instances.append([pos.round(), structure]) | |
#static func get_chunk_seed(cpos: Vector3) -> int: | |
# return cpos.x ^ (13 * int(cpos.y)) ^ (31 * int(cpos.z)) | |
static func _get_chunk_seed_2d(cpos: Vector3) -> int: | |
return int(cpos.x) ^ (31 * int(cpos.z)) | |
#func _get_height_at(x: int, z: int) -> int: | |
# var t = 0.5 + 0.5 * _heightmap_noise.get_noise_2d(x, z) | |
# return int(HeightmapCurve.sample_baked(t)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment