Biomes in my infinite world generator are too rare and small

So I redid terrain generation but now with smooth terrain instead of triangle terrain.
Issue now is, biomes appear to be too rare and if they do appear then they’re often way too small.
I’ve tried mudifying the noise functions multiple times but somehow this didn’t do much except make really small patches of sand/snow appear which is not intended, making the numbers large gives bigger biomes but makes them extremely rare (and still too small).

If anyone could help me on this it would be greatly appreciated.

local seed = 59379429379 * 0.69
local posoffset =, 0, 50000) --Center of the terrain.

local amp = 1000
local steepness = 1000
local steepness2 = 2000

local biomechancemultiplier = 1
local biomesize = 10000
local biomerarity = 2000
local biomesnap = 1
local biomes = {
	["1"] = {name = "desert";
		mat1 = Enum.Material.Sand;
		mat2 = Enum.Material.Ground;
	["0"] = {name = "default";
		mat1 = Enum.Material.Grass;
		mat2 = Enum.Material.Mud;
	["-1"] = {name = "snow";
		mat1 = Enum.Material.Snow;
		mat2 = Enum.Material.Glacier;
--==[[ No touchy below. ]]==--

local noise = math.noise
local floor = math.floor
local clamp = math.clamp

local mod = {}

local function snap(x, y)
	return floor((x / y) + 0.5) * y

mod.randomnoise = function(pos)
	return pos

mod.heightnoise = function(pos) --Basic terrain generation
	pos = pos + posoffset
	local n1 = noise(pos.x / steepness, pos.z / steepness, seed) * amp
	local n2 = noise(seed, pos.z / steepness2, pos.x / steepness2)
	return n1 * n2

mod.biomenoise = function(pos) --Biome selection and generation
	pos = pos + posoffset
	local n1 = noise(pos.x / biomesize, pos.z / biomesize, seed * 2) * amp
	n1 = clamp(n1 * biomechancemultiplier, -1, 1)
	local n2 = noise(seed / 2, pos.z / biomerarity, pos.x / biomerarity)
	local r = (n1 * n2) * biomesnap
	r = snap(r, biomesnap)
	local selbiome = biomes[tostring(r)]
	return selbiome.mat1

return mod

A second but small issue I have is that a lot of bumps seem to appear in my infinite terrain, I haven’t really looked into that yet but anyone have a idea what could possibly cause that?

(Also, have a good christmas eve.)

Edit: There are absolutely no errors and it runs completely fine, but biomes just appear to be extremely rare and too small.

Have you tried changing the value of biomerarity and biomesize?

Lower rarity and higher size.

I tried that many times, I even tried extremely low rarity and a size bigger than 10000.
But trying all of that just resulted in nearly no biomes showing up or in small patches of sand/snow, snow and desert connecting to each other (not supposed to happen).

Who made the “no touchy below” code?

Honestly I think you’re overcomplicating it slightly and I don’t really see the need for the two noise calls - multiplying two fractions makes a smaller one so your problems likely stem from the way these are combined, rounded and clamped.

Have you taken a look at @Crazyman32’s RDC2019 presentation on procedural generation? Personally I didn’t know much at all about noise and using it to procedurally generate stuff like this before seeing it. There’s some nice examples on there which you could trivially apply to your biome problem.

1 Like

So I should only do 1 noise function instead?
The second noise function is for the rarity.

Will try 1 noise function instead then and see if that works.
There is a weird issue by the way where sometimes desert and snow biomes can connect to each other, any idea on what causes that?
I think it also has to do with me doing double noise but not sure.

(Also the “no touchy” line, since I’m writing all of this for me and for other people to use I included that to tell them they don’t need to look there if they don’t know what they’re doing, it’s configurable and customizable.)

I think stick with 1 noise function. There’s various things you can do to the output to get what you’re after.

If you look at some of the code snippets in that presentation, it shows how you could do it. Instead of rounding to integers, use its fractional value. The noise function varies from -0.5 to +0.5 (ish) so what Crazyman32 does is add 0.5 onto it, clamp between 0 and 1, and then use that value to select the biome.

local yourNoise = math.clamp(
    math.noise( x, y, z ) + 0.5, 0, 1

If the value is less than, say, 0.3 you could use desert. If the value is greater than, say, 0.7 you could use snow. You could adjust the boundaries as well as the noise parameters to get the desired distribution (rarity and size).

if yourNoise < 0.3 then
    -- desert area
elseif yourNoise > 0.7 then
    -- snow area
    -- default grass area

There is a small issue with this.
This is for 3 biomes only, but I want to add possibly 10 biomes.
The desert and snow biome is really just a test to see if it works.

And the way the table was gonna work in the future is that rare biomes are placed at the beginning/end (-1, 1) and common ones in the middle (near 0).

I’d still reduce to 1 noise call and vary what you do to the inputs. You’ll want to multiply the noise result by 2, otherwise you’ll find it extremely rare to round to -1 and 1.

So you’d maybe use something along the following three lines to get your biome (obviously replacing x, y, z with the inputs for the noise).

local clamped = math.clamp(
    math.noise( x, y, z ) * 2, -1, 1
local snapped = snap( clamped, biomesnap )
local selbiome = biomes[ tostring( snapped ) ]

And vary x, y and z only to get the desired distribution if you’re finding the rare biomes are too rare or small.

It does seem to work so far.
However, now I might not be able to set biome rarity with only 1 noise function.
Is there a way where I could still set biome rarity?