I am going to assume extra emphasis on the performance. There are plenty of thorough answers on this topic already, but if you are interested in something brutally simple and fast (as in real-time Python), I can offer you a method of "squeezed squares".
General idea is as follows:
- Each block belongs to some bigger chunk. This is purely virtual construct, the chunk does not need to be a storage unit. Chunk's coordinates can be easily inferred from block's coordinates. The point here is that clusters of blocks may share common seed.
- Chunk's coordinates are feed to deterministic RNG to generate two properties:
- To determine blocks's
biome_id, scan surrounding NxN chunks to select closest one after adjusting for
- That is it. Tweak the parameters (
N) for best results.
Few examples with different settings. (Blue arrows point to selected chunk.)
half = chunk_size / 2
location = Vector(location.x % chunk_size + half, location.y % chunk_size + half)
seed = global_seed + location.x + location.y
rng = make_rng(seed)
biome_id = rng.range(num_biome_types)
size_bias = rng.uniform(1.0, max_size_bias)
return ChunkInfo(location, biome_id, size_bias)
for x in range(block.location.x - N, block.location.x + N + 1):
for y in range(block.location.y - N, block.location.y + N + 1):
yield get_chunk(Vector(x, y))
chunks = list(get_nearby_chunks(block))
biased_distance = lambda chunk: (block.location - chunk.location).size - chunk.size_bias
- Not ideal for 3D: surface might look crater-y.
- Sometimes visibly aligns to chunk grid — decrease chunk size, increase sample radius and bias variance.