Perlin noise: How does seed/randomizing generation work?

I’ve been dabbling with perlin noise generation on a 2D scale lately, and after reading countless articles and trying different changes, I’ve come to terms with the fact that I’m fundamentally not understanding something here.

I’m using the PerlinNoise module by Diegnified which essentially allows you to generate the noise simply taking into account amplitude, octaves and persistence.

It is to my understanding that by adding a 3rd dimension for the seed, you can effectively randomize the way the shapes generate each time, however with what I’ve gotten so far, the shapes are pretty much the same every time (save a few minor generational differences thanks to math.random).

What am I doing wrong :frowning:

local seed = Random.new(1,10e6)

local function generateTerrain(base, trueX, trueZ)
	workspace.GeneratedTerrain:ClearAllChildren()
	workspace.Base.Size = Vector3.new(trueX, 1, trueZ)
	local currX = (base.Position.X - trueX/2) + 2.5
	local currZ = (base.Position.Z - trueZ/2) + 2.5
	for x = 1, trueX / 5 do
		for z = 1, trueZ / 5 do
			local chunk = terrainAssets.Tile:Clone()
			local stoneChance = PerlinNoise.new({x/20, z/20, seed:NextNumber()}, 1, 10, 0.3)
			local treeChance = PerlinNoise.new({x/40, z/40, seed:NextNumber()}, 1, 20, 0.4)
			local occupied = false
			chunk.Name = tostring(x..z)
			chunk.Parent = workspace.GeneratedTerrain
			chunk:SetPrimaryPartCFrame(CFrame.new(currX, -0.1, currZ))
			if stoneChance > math.random(65,73)/100 then
				placeEntity(chunk.Tile, "Rock")
				occupied = true
			end
			if treeChance > math.random(38,48)/100 and not occupied then
				placeEntity(chunk.Tile, "Tree")
				occupied = true
			end
			currZ = currZ + 5
		end
		currX = currX + 5
		currZ = (base.Position.Z - trueZ/2) + 2.5
	end
end
3 Likes

local seed = Random.new(1,10e6)

Random.new returns a Random Number Generator, not a number. It also only takes 1 parameter, the seed to the RNG (which is not the same as the seed to your terrain gen algorithm). It’s optional, and if you leave it out you’ll just get a different seed each time.

PerlinNoise.new({x/20, z/20, seed:NextNumber()}, 1, 10, 0.3)

The seed is not an RNG. It’s a number!

The seed should not change every time you visit a new coordinate. It should be a constant number.


Instead of

local seed = Random.new(1,10e6) --Seed is an RNG
...
PerlinNoise.new({x/20, z/20, seed:NextNumber()}, 1, 10, 0.3) --Z is different each iteration

do

local seed = Random.new():NextNumber(1, 10e6) --Seed is a constant number
...
PerlinNoise.new({x/20, z/20, seed}, 1, 10, 0.3) --Z is the same each iteration

The way that the seed makes the terrain different each time is just that you choose to “look at a different part of the noise”. The following also gives you different terrain each time:

PerlinNoise.new({x/20 + seed, z/20}, 1, 10, 0.3)
2 Likes

This actually got it through my head; thanks again!

1 Like