What is math.noise() and How to Use it

Tutorial By Me, I Hope You Enjoy : )

What Is math.noise()?

To put it simply, `math.noise()` is a function that basically allows the user to create random terrain, by using a method known as Perlin Noise. Perlin Noise can be used for many things but mostly random terrain generation. An example of a popular game using Perlin Noise is Minecraft, which uses multiple Perlin Noise’s to determine Biomes, Mountains, Villages, etc. Perlin Noise uses randomness to determine everything, like i did in my Perlin Noise Generator which only uses `Math.Random`. Many people don’t really understand what randomness is, so here’s a definition and how it works.

“The quality or state of lacking a pattern or principle of organization; unpredictability.” (Taken From Google)

Lets say you went to the lottery, and you were asked to pick 6 numbers. Most people already, would think that it would be impossible for 123456 to be the winning code. Theoretically, it is still a Approximately 1/1000000 (0.0001 %*) chance that 123456 is the winning code, which is the same as the code 749286. So if you used `math.random(1,1000)`, there is a 1/1000 chance that 1, 2 and 3 and so on is picked. This is a very basic example. Before the 1990s, i believe people used the Time * Pi / (random number / seed or whatever ).

How To Use math.noise()

I’m not going to provide you the script, so you’ll have to follow along and learn : D

First, we need to make a place to store the parts for our Perlin Noise. In Workspace, create a folder named: “PerlinNoise_Storage”. This is where we are storing our Parts that will be generated when using `math.noise()`.

Now, open the Output (Toolbar > View > Output), And make a script named “PerlinNoiseHandler”. This Script will handle the generation with `math.noise()`

Next, create a variable that is the folder we made at the start, like this:

``````local PartStorage = workspace:WaitForChild("PerlinNoise_Storage")
``````

Now we need to create a few variables that will control how our Perlin Noise will look:

``````local RenderSize = 100 -- Controls The Size
local Resolution = 100 -- Controls The Resolution
local Frequency = 3
local Amplitude = 10
local BlockSize = 1 -- Controls The Block Size
local Blocky: boolean = false -- Controls If We're Making A Blocky Render Like Minecraft
``````

Here, the `RenderSize` is 100 meaning it will be 100 blocks wide, and 100 blocks long. The resolution controls how smooth it will be.

Next we need to make a Local Function. This will take in 2 variables, which will turn into Noise.

``````local function GetHeight(x :number, z :number): number -- Creates Our Function
local noiseHeight = math.noise( -- Math.Noise
x / Resoloution * Frequency, -- The First Value Is X Divided And Multiplied
z / Resoloution * Frequency -- The Second is Z but the same as X
)

noiseHeight = math.clamp(noiseHeight, -.5, .5) + .5
return noiseHeight -- Returns The 'Noise' Height / Value
end
``````

Now we need to make 2 For Loops. 1 For The X, And The Y.

``````for x = 0, RenderSize do
for z = 0, RenderSize do
``````

This will obviously render a square. You can change this to your liking.
For this next part, you can use the Inbuilt Instance.New() or use the BetterInstances Module (Note the BetterInstances Module May Be Very Inefficient

BetterInstances Module
``````local BetterInstances = {}
local ClipBoard = {}

--local Settings = require(script.Settings.Settings)

--if script.Config:GetAttribute("DevMode") == true then
--	BetterInstances.Changelog = function()
--		return [[

--	-- BetterInstances Changelog --

--	- Created Module

--		]]
--	end

--	BetterInstances.Credits = function()
--		return [[
--		-- BETTER INSTANCES CHANGELOG --

--

--		]]
--	end

--	BetterInstances.Version = function()
--	end

--end

BetterInstances.new = function(INName:string, NewParent:Instance?, NewName:string?):Instance
local inst = Instance.new(INName, NewParent)
inst.Name = NewName
return inst
end

BetterInstances.Copy = function(Obj:Instance, NewParent:Instance, Name:string?):Instance
table.clear(ClipBoard)
table.insert(ClipBoard, Obj.Name)
Obj:Clone().Parent = NewParent
if Name ~= "" or nil then
Obj.Name = Name
end
end

function BetterInstances:GetClipboard()
return table.unpack(ClipBoard)
end

function BetterInstances:ClearClipboard()
table.clear(ClipBoard)
end

function BetterInstances:SetClipboard(Obj:Instance)
table.clear(ClipBoard)
table.insert(ClipBoard, Obj.Name)
end

return BetterInstances
``````

Anyways, Here’s The Next Part Of The Script.

``````local Part = Instance.new("Part") -- Creates The Part
Part.Parent = PartStorage
Part.Anchored = true
Part.Size = Vector3.new(BlockSize,BlockSize,BlockSize) -- Sets The Part Size
local height = GetHeight(x,z) -- Gets The Perlin Noise Height

if Blocky then -- Checks If We Want The Blocky Terrain
Part.Position = Vector3.new(math.floor(x), math.floor(height * Amplitude), math.floor(z))
else
Part.Position = Vector3.new(x, height * Amplitude, z)
end
Part.Color = Color3.new(height + BlockSize, height + BlockSize, height + BlockSize) -- Sets The Parts Colour
end

end
``````

If you save the script, and run it, You should get something like this:

Obviously, this is super basic and can be built apon. Try adding + Number in random places and experiment.

(Also Here’s A Module )
PerlinNoise.lua (994 Bytes)
Or, The Text Version

Module
``````local PN = {}

function PN.Render(PartStorage: Instance, RenderSize:number, Resoloution:number, Frequency:number, Amplitude:number, BlockSize: number, Blocky: boolean)

local function GetHeight(x :number, z :number): number
local noiseHeight = math.noise(
x / Resoloution * Frequency,
z / Resoloution * Frequency
)

noiseHeight = math.clamp(noiseHeight, -.5, .5) + .5
return noiseHeight
end

for x = 0, RenderSize do
for z = 0, RenderSize do
local Part = Instance.new("Part")
Part.Parent = PartStorage
Part.Anchored = true
Part.Size = Vector3.new(BlockSize,BlockSize,BlockSize)
local height = GetHeight(x,z)

if Blocky then
Part.Position = Vector3.new(math.floor(x), math.floor(height * Amplitude), math.floor(z))
else
Part.Position = Vector3.new(x, height * Amplitude, z)
end
Part.Color = Color3.new(height + BlockSize, height + BlockSize, height + BlockSize)
end

end
return true
end

return PN.Render
``````

If you’ve found any mistakes or somethings not working, please let me know. This iks my first tutorial!

Thank you for reading and making it this far.
From what you’ve made and learnt, how do you rate the Final Product You’ve Made.

How happy are you with the final Product and How much Do You Think You’ve learnt??
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10

0 voters

As always, have a good day.

12 Likes

I also HIGHLY recommend Watching This Video, Which Taught Me This A Few Months Ago.

4 Likes

Hi, this is a great tutorial for using Perlin Noise!
Also you said you were not gonna provide the scrip but at the end you did (not a problem)

Hopefully there’s more tutorials like this!

Yeah i was gonna put i lied but they have to scroll to the bottom and most people wouldn’t do that

1 Like

Everyone would do that as in almost every tutorial the full script so at the end, I suggest if you want people to actually learn remove the full script at the end so they need to at least copy-paste different parts

Great Tutorial, but I suggest using a table with some typings to make the code more readable

``````type PerlinConfiguration = {
PartStorage:Instance,
RenderSize:number,
Resoloution:number,
Frequency:number,
Amplitude:number,
BlockSize:number,
Blocky:boolean
}

return function(Config:PerlinConfiguration):boolean
local Resoloution = Config.Resoloution
local Frequency = Config.Frequency
local RenderSize = Config.RenderSize
local PartStorage = Config.PartStorage
local BlockSize = Config.BlockSize
local Amplitude = Config.Amplitude
local Blocky = Config.Blocky

local function GetHeight(x :number, z :number): number
local noiseHeight = math.noise(
x / Resoloution * Frequency,
z / Resoloution * Frequency
)

noiseHeight = math.clamp(noiseHeight, -.5, .5) + .5
return noiseHeight
end

for x = 0, RenderSize do
for z = 0, RenderSize do
local Part = Instance.new("Part")
Part.Parent = PartStorage
Part.Anchored = true
Part.Size = Vector3.new(BlockSize,BlockSize,BlockSize)
local height = GetHeight(x,z)

if Blocky then
Part.Position = Vector3.new(math.floor(x), math.floor(height * Amplitude), math.floor(z))
else
Part.Position = Vector3.new(x, height * Amplitude, z)
end
Part.Color = Color3.new(height + BlockSize, height + BlockSize, height + BlockSize)
end

end
return true
end``````
1 Like