Biomes with perlin noise

Im trying to make world generator and want to make biomes like in minecraft with this code:

local X = 90
local Z = 90

local grid = {}

for x = -X, X do
	grid[x] = {}
	
	for z = -Z, Z do
		grid[x][z] = math.noise(x/10, z/10) * 15
	end
end

for x = -X, X do
	for z = -Z, Z do
		local yPos = grid[x][z]
		
		local Part = Instance.new("Part")
		Part.Anchored = true
		
		if yPos < -3 then
			Part.Material = Enum.Material.Sand
			Part.BrickColor = BrickColor.new("Cool yellow")
		else
			Part.Material = Enum.Material.Grass
			Part.BrickColor = BrickColor.new("Forest green")
		end
		
		Part.Position = Vector3.new(x*5, yPos, z*5)
		Part.Size = Vector3.new(5, 30, 5)
		Part.Parent = workspace
	end
end

i want to make this
image
to this
image
how can i do that?

You could use something called temperature maps

Simulate other aspects of your terrain like temperature and humidity. Then you can see what biome fits a position best.

What I did in a previous project was, I set an optimal point for each biome. For example, a desert would have a humidity of 0 and a temperature of 30. Then I would calculate what those parameters were for a given point.

Then I treated the terrain aspects as points. I used multi-dimensional euclidean distance (scalable approach for multiple terrain aspects) to determine the most fitting biome for a given point relative to the optimal biome points (see ‘Euclidean Distance’). You can even make an aspect more influential by multiplying it with some number.

My approach is easily scalable and easier to use than hard coding a biome diagram (which I believe is something that Minecraft works with). In fact, my approach is essentially the same as a biome diagram but not hard coded.

5 Likes

How to get temperature from noise?

Use a noise function with a position as the parameter T(p) = noise(p.X, p.Y, p.Z).

Im trying to make biomes but temperature are random on every stud
here is code, can you check it?

local X = 20
local Z = 20

local seed= math.random(-10000,10000)

local grid = {}
local temperatureGrid = {}

for x = -X, X do
	grid[x] = {}
	temperatureGrid[x] = {}
	
	for z = -Z, Z do
		grid[x][z] = math.noise(x/10,seed, z/10) * 30
		temperatureGrid[x][z] = math.noise(x,grid[x][z],z) * 100
	end
end

for x = -X, X do
	for z = -Z, Z do
		local yPos = grid[x][z]
		local temperature = math.floor(temperatureGrid[x][z])
		
		local Part = Instance.new("Part")
		Part.Anchored = true
		Part.Position = Vector3.new(x*10, yPos, z*10)
		Part.Size = Vector3.new(10, 30, 10)
		Part.Parent = workspace
		local gui = Instance.new("SurfaceGui",Part)
		gui.Face = Enum.NormalId.Top
		local textt = Instance.new("TextLabel",gui)
		textt.Text = temperature
		textt.Size = UDim2.new(1,0,1,0)
		textt.BackgroundTransparency = 1
		textt.TextScaled = true
	end
end

It might seem completely random, because it is way too dense. You should multiply each parameter by some scale (for instance 1 / 100).

i think this is working because i made this


and its look like truth but i made
rocks after yPos 5 and temperature >30
water yPos <-4 and temperature < 10
and grass between them, and grass only at some places, i need to add more biomes or i made something wrong?

local X = 50
local Z = 50

local seed= math.random(-10000,10000)

local grid = {}
local temperatureGrid = {}

for x = -X, X do
	grid[x] = {}
	temperatureGrid[x] = {}
	
	for z = -Z, Z do
		grid[x][z] = math.noise(x/10,seed, z/10) * 30
		temperatureGrid[x][z] = math.noise(x*(1/100),grid[x][z]*(1/100),z*(1/100)) * 100
	end
end
for x = -X, X do
	for z = -Z, Z do
		local yPos = grid[x][z]
		local temperature = math.floor(temperatureGrid[x][z])
		
		local Part = Instance.new("Part")
		Part.Anchored = true
		if yPos >= 5 and temperature >= 30 then
			Part.Material = Enum.Material.Slate
			Part.BrickColor = BrickColor.new("Grey")
		elseif (yPos < 5 and yPos >=-4) and (temperature>=10 and temperature < 30) then
			Part.Material = Enum.Material.Grass
			Part.BrickColor = BrickColor.new("Forest green")
		elseif yPos <-4 and temperature < 10 then
			Part.Material = Enum.Material.Sand
			Part.BrickColor = BrickColor.new("Deep blue")
		end
		Part.Position = Vector3.new(x*10, yPos, z*10)
		Part.Size = Vector3.new(10, 30, 10)
		Part.Parent = workspace
		local gui = Instance.new("SurfaceGui",Part)
		gui.Face = Enum.NormalId.Top
		local textt = Instance.new("TextLabel",gui)
		textt.Text = temperature
		textt.Size = UDim2.new(1,0,1,0)
		textt.BackgroundTransparency = 1
		textt.TextScaled = true
	end
end

because the temperature is different?

There seem to be some cases where parts do not get colored at all. In other words, the if-statement does not include all possible cases from your example. You only specified one type of grey, while there are 2 types of grey that emerge in your picture.