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().
image

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

image

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
--	- Added Commands
		
--		]]
--	end
	
--	BetterInstances.Credits = function()
--		return [[ 
--		-- BETTER INSTANCES CHANGELOG --
		
--
		
--		]]
--	end
	
--	BetterInstances.Version = function()
--		return tostring(script.Config:GetAttribute("Ver"))
--	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 :slight_smile: )
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