# [JASS/vJASS/Lua/Wurst] Perlin Noise

Submitted by Glint
This bundle is marked as approved. It works and satisfies the submission rules.
I haven't found any resources about Perlin Noise in Warcraft III, so I think this is a good start.

Perlin Noise is a type of gradient noise developed by Kenneth Perlin. For this resource, it uses his Improved Noise (2002). The source code can be found here.

This script is available for JASS, vJass, Lua, and Wurst.

Features

It features 1D, 2D, and 3D Perlin noise, the example maps only uses the 2D version.

It uses a permutation table. It represents as an array in JASS/vJass/Wurst and an integer table for Lua. As it follow Kenneth Perlin's implementation, the first 256 elements (0 - 255) contains random integer values ranges from 0 to 255. The elements from 256 - 512 only repeats the values of the first 256 elements. I think it is to avoid overflow?

You can modify the permutation table to satisfy your needs.

Popular sandbox games like Minecraft and Terraria uses a similar algorithm to create procedural generated terrain. This means you could now do the same in Warcraft III.

Screenshots

Sample Map

Modified settings in Sample Map

Application for custom maps

The video below is an early version of the code, written in Wurst.

Video

For Wurst, you can now use Grill to add wurstNoiselib as a dependency to your project:

Code (Text):

grill install https://github.com/eGlint/wurstNoiselib

Requires
None (JASS/vJASS/Lua)
WurstStdlib2 (Wurst)

Optional
OctavePerlin (plugin for Perlin Noise, comes along with it, original source)

Code

JASS

Requires the following GUI variables:
• Set NoisePermutation (integer array)

Code (vJASS):

//
//  Perlin Noise JASS v1.0.0
//
//  Port by Glint
//  Perlin Noise by Kenneth Perlin, https://mrl.nyu.edu/~perlin/noise/
//

function Floor takes real value returns integer
local integer n = R2I(value)
if value < 0 and value - n != 0. then
set n = n - 1
endif
return n
endfunction

function RealTernaryOp takes boolean cond, real a, real b returns real
if cond then
return a
else
return b
endif
endfunction

function Fade takes real t returns real
return t * t * t * (t * (t * 6. - 15.) + 10.)
endfunction

function Lerp takes real t, real a, real b returns real
return a + t * (b -a)
endfunction

function Gradient1D takes integer hash, real x returns real
local integer h = BlzBitAnd(hash, 15)
return RealTernaryOp(BlzBitAnd(h, 1) == 0, x, -x)
endfunction

function PerlinNoise1D takes real x returns real
local integer X = BlzBitAnd(Floor(x), 255)
set x = x - Floor(x)
endfunction

function Gradient2D takes integer hash, real x, real y returns real
local integer h = BlzBitAnd(hash, 15)
local real u = RealTernaryOp(h < 8, x, y)
local real v = RealTernaryOp(h < 4, y, x)
return RealTernaryOp(BlzBitAnd(h, 1) == 0, u, -u) + RealTernaryOp(BlzBitAnd(h, 2) == 0, v, -v)
endfunction

function PerlinNoise2D takes real x, real y returns real
local integer X = BlzBitAnd(Floor(x), 255)
local integer Y = BlzBitAnd(Floor(y), 255)
local real u
local real v
local integer A
local integer B
local real lerpA1
local real lerpA2
set x = x - Floor(x)
set y = y - Floor(y)
set A = udg_NoisePermutation[X] + Y
set B = udg_NoisePermutation[X + 1] + Y
set lerpA1 = Lerp(u, Gradient2D(udg_NoisePermutation[A], x, y), Gradient2D(udg_NoisePermutation[B], x - 1., y))
set lerpA2 = Lerp(u, Gradient2D(udg_NoisePermutation[A + 1], x, y - 1.), Gradient2D(udg_NoisePermutation[B + 1], x - 1., y - 1.))
return Lerp(v, lerpA1, lerpA2)
endfunction

function Gradient3D takes integer hash, real x, real y, real z returns real
local integer h = BlzBitAnd(hash, 15)
local real u = RealTernaryOp(h < 8, x, y)
local real v = RealTernaryOp(h < 4, y, RealTernaryOp(h == 12 or h == 14, x, z))
return RealTernaryOp(BlzBitAnd(h, 1) == 0, u, -u) + RealTernaryOp(BlzBitAnd(h, 2) == 0, v, -v)
endfunction

function PerlinNoise3D takes real x, real y, real z returns real
local integer X = BlzBitAnd(Floor(x), 255)
local integer Y = BlzBitAnd(Floor(y), 255)
local integer Z = BlzBitAnd(Floor(z), 255)
local real u
local real v
local real w
local integer A
local integer AA
local integer AB
local integer B
local integer BA
local integer BB
local real lerpA1
local real lerpA2
local real lerpB1
local real lerpB2
set x = x - Floor(x)
set y = y - Floor(y)
set z = z - Floor(z)
set A = udg_NoisePermutation[X] + Y
set AA = udg_NoisePermutation[A] + Z
set AB = udg_NoisePermutation[A + 1] + Z
set B = udg_NoisePermutation[X + 1] + Y
set BA = udg_NoisePermutation[B] + Z
set BB = udg_NoisePermutation[B + 1] + Z
set lerpA1 = Lerp(u, Gradient3D(udg_NoisePermutation[AA], x, y, z), Gradient3D(udg_NoisePermutation[BA], x - 1., y, z))
set lerpA2 = Lerp(u, Gradient3D(udg_NoisePermutation[AB], x, y - 1., z), Gradient3D(udg_NoisePermutation[BB], x - 1., y - 1., z))
set lerpB1 = Lerp(u, Gradient3D(udg_NoisePermutation[AA + 1], x, y, z - 1.), Gradient3D(udg_NoisePermutation[BA + 1], x - 1., y, z - 1.))
set lerpB2 = Lerp(u, Gradient3D(udg_NoisePermutation[AB + 1], x, y - 1., z - 1.), Gradient3D(udg_NoisePermutation[BB + 1], x - 1., y - 1., z - 1.))
return Lerp(w, Lerp(v, lerpA1, lerpA2), Lerp(v, lerpB1, lerpB2))
endfunction

vJass

Code (vJASS):

/*
Perlin Noise vJASS 1.0.0

Port by Glint
Perlin Noise by Kenneth Perlin, https://mrl.nyu.edu/~perlin/noise/
*/

library Noise

private module Init
private static method onInit takes nothing returns nothing
call permutationInit()
endmethod
endmodule

struct Noise extends array
readonly static string version = "1.0.0"
static integer array permutation

implement Init

private static method floor takes real value returns integer
local integer n = R2I(value)
if value < 0. and value - n != 0. then
set n = n - 1
endif
return n
endmethod

private static method realTernaryOp takes boolean cond, real a, real b returns real
if cond then
return a
else
return b
endif
endmethod

private static method fade takes real t returns real
return t * t * t * (t * (t * 6. - 15.) + 10.)
endmethod

private static method lerp takes real t, real a, real b returns real
return a + t * (b -a)
endmethod

private static method grad1D takes integer hash, real x returns real
local integer h = BlzBitAnd(hash, 15)
return realTernaryOp(BlzBitAnd(h, 1) == 0, x, -x)
endmethod

static method perlin1D takes real x returns real
local integer X = BlzBitAnd(floor(x), 255)
set x = x - floor(x)
endmethod

private static method grad2D takes integer hash, real x, real y returns real
local integer h = BlzBitAnd(hash, 15)
local real u = realTernaryOp(h < 8, x, y)
local real v = realTernaryOp(h < 4, y, x)
return realTernaryOp(BlzBitAnd(h, 1) == 0, u, -u) + realTernaryOp(BlzBitAnd(h, 2) == 0, v, -v)
endmethod

static method perlin2D takes real x, real y returns real
local integer X = BlzBitAnd(floor(x), 255)
local integer Y = BlzBitAnd(floor(y), 255)
local real u
local real v
local integer A
local integer B
local real lerpA1
local real lerpA2
set x = x - floor(x)
set y = y - floor(y)
set A = permutation[X] + Y
set B = permutation[X + 1] + Y
set lerpA1 = lerp(u, grad2D(permutation[A], x, y), grad2D(permutation[B], x - 1., y))
set lerpA2 = lerp(u, grad2D(permutation[A + 1], x, y - 1.), grad2D(permutation[B + 1], x - 1., y - 1.))
return lerp(v, lerpA1, lerpA2)
endmethod

private static method grad3D takes integer hash, real x, real y, real z returns real
local integer h = BlzBitAnd(hash, 15)
local real u = realTernaryOp(h < 8, x, y)
local real v = realTernaryOp(h < 4, y, realTernaryOp(h == 12 or h == 14, x, z))
return realTernaryOp(BlzBitAnd(h, 1) == 0, u, -u) + realTernaryOp(BlzBitAnd(h, 2) == 0, v, -v)
endmethod

static method perlin3D takes real x, real y, real z returns real
local integer X = BlzBitAnd(floor(x), 255)
local integer Y = BlzBitAnd(floor(y), 255)
local integer Z = BlzBitAnd(floor(z), 255)
local real u
local real v
local real w
local integer A
local integer AA
local integer AB
local integer B
local integer BA
local integer BB
local real lerpA1
local real lerpA2
local real lerpB1
local real lerpB2
set x = x - floor(x)
set y = y - floor(y)
set z = z - floor(z)
set A = permutation[X] + Y
set AA = permutation[A] + Z
set AB = permutation[A + 1] + Z
set B = permutation[X + 1] + Y
set BA = permutation[B] + Z
set BB = permutation[B + 1] + Z
set lerpA1 = lerp(u, grad3D(permutation[AA], x, y, z), grad3D(permutation[BA], x - 1., y, z))
set lerpA2 = lerp(u, grad3D(permutation[AB], x, y - 1., z), grad3D(permutation[BB], x - 1., y - 1., z))
set lerpB1 = lerp(u, grad3D(permutation[AA + 1], x, y, z - 1.), grad3D(permutation[BA + 1], x - 1., y, z - 1.))
set lerpB2 = lerp(u, grad3D(permutation[AB + 1], x, y - 1., z - 1.), grad3D(permutation[BB + 1], x - 1., y - 1., z - 1.))
return lerp(w, lerp(v, lerpA1, lerpA2), lerp(v, lerpB1, lerpB2))
endmethod

static method permutationInit takes nothing returns nothing
local integer i = 0
loop
exitwhen i > 255
set permutation[i] = GetRandomInt(0, 255)
set permutation[i + 256] = permutation[i]
set i = i + 1
endloop
endmethod
endstruct
endlibrary

Lua

Code (Lua):

--[[
Perlin Noise Lua v1.0.1

Port by Glint
Perlin Noise by Kenneth Perlin, https://mrl.nyu.edu/~perlin/noise/
]]
--
do
Noise = {}

Noise.version = "1.0.1"
Noise.permutation = {}

local function floor(value)
local n = R2I(value)
if value < 0. and value - n ~= 0. then n = n - 1 end
return n
end

return t * t * t * (t * (t * 6. - 15.) + 10.)
end

local function lerp(t, a, b)
return a + t * (b -a)
end

local h = BlzBitAnd(hash, 15)
return (BlzBitAnd(h, 1) == 0 and x or -x)
end

function Noise.perlin1D (x)
local X = BlzBitAnd(floor(x), 255)
x = x - floor(x)
end

local h = BlzBitAnd(hash, 15)
local u, v = h < 8 and x or y, h < 4 and y or x
return (BlzBitAnd(h, 1) == 0 and u or -u) + (BlzBitAnd(h, 2) == 0 and v or -v)
end

function Noise.perlin2D (x, y)
local X, Y = BlzBitAnd(floor(x), 255), BlzBitAnd(floor(y), 255)
x, y = x - floor(x), y - floor(y)
local A = Noise.permutation[X] + Y
local B = Noise.permutation[X + 1] + Y
local a1 = lerp(u, grad2D(Noise.permutation[A], x, y), grad2D(Noise.permutation[B], x - 1, y))
local a2 = lerp(u, grad2D(Noise.permutation[A + 1], x, y - 1), grad2D(Noise.permutation[B + 1], x - 1, y - 1))
return lerp(v, a1, a2)
end

local function grad3D(hash, x, y, z)
local h = BlzBitAnd(hash, 15)
local u, v = h < 8 and x or y, h < 4 and y or ((h == 12 or h == 14) and x or z)
return (BlzBitAnd(h, 1) == 0 and u or -u) + (BlzBitAnd(h, 2) == 0 and v or -v)
end

function Noise.perlin3D (x, y, z)
local X, Y, Z = BlzBitAnd(floor(x), 255), BlzBitAnd(floor(y), 255), BlzBitAnd(floor(z), 255)
x, y, z = x - floor(x), y - floor(y), z - floor(z)
local A = Noise.permutation[X] + Y
local AA = Noise.permutation[A] + Z
local AB = Noise.permutation[A + 1] + Z
local B = Noise.permutation[X + 1] + Y
local BA = Noise.permutation[B] + Z
local BB = Noise.permutation[B + 1] + Z
local a1 = lerp(u, grad3D(Noise.permutation[AA], x, y, z), grad3D(Noise.permutation[BA], x - 1, y, z))
local a2 = lerp(u, grad3D(Noise.permutation[AB], x, y - 1, z), grad3D(Noise.permutation[BB], x - 1, y - 1, z))
local b1 = lerp(u, grad3D(Noise.permutation[AA + 1], x, y, z - 1), grad3D(Noise.permutation[BA + 1], x - 1, y, z - 1))
local b2 = lerp(u, grad3D(Noise.permutation[AB + 1], x, y - 1, z - 1), grad3D(Noise.permutation[BB + 1], x - 1, y - 1, z - 1))
return lerp(w, lerp(v, a1, a2), lerp(v, b1, b2))
end

function Noise.permutationInit ()
for i = 0, 255 do
Noise.permutation[i] = GetRandomInt(0, 255)
Noise.permutation[i + 256] = Noise.permutation[i]
end
end
end

Wurst

Code (WurstScript):

/*
Perlin Noise Wurst v1.0.1

Port by Glint
Perlin Noise by Kenneth Perlin, https://mrl.nyu.edu/~perlin/noise/
*/

package Noise

import NoWurst
import Integer
import Vectors

function grad(int hash, real x) returns real
var h = hash.bitAnd(15)
return h.bitAnd(1) == 0 ? x : -x

function grad(int hash, vec2 vec) returns real
var h = hash.bitAnd(15)
let u = h < 8 ? vec.x : vec.y
let v = h < 4 ? vec.y : vec.x
return (h.bitAnd(1) == 0 ? u: -u) + (h.bitAnd(2) == 0 ? v : -v)

function grad(int hash, vec3 vec) returns real
let h = hash.bitAnd(15)
let u = h < 8 ? vec.x : vec.y
let v = h < 4 ? vec.y : (h == 12 or h == 14 ? vec.x : vec.z)
return (h.bitAnd(1) == 0 ? u : -u) + (h.bitAnd(2) == 0 ? v : -v)

return this * this * this * (this * (this * 6. - 15.) + 10.)

public class Noise
static int array p

static function perlin (real x) returns real
var lx = x
let X = lx.floor().bitAnd(255)
lx -= lx.floor()

static function perlin (vec2 vec) returns real
var lvec = vec
let X = lvec.x.floor().bitAnd(255)
let Y = lvec.y.floor().bitAnd(255)
lvec = vec2(lvec.x - lvec.x.floor(), lvec.y - lvec.y.floor())
let A = p[X] + Y
let B = p[X + 1] + Y
grad(p[B], lvec - vec2(1, 0)), u).lerp(
grad(p[A + 1], lvec - vec2(0, 1)).lerp(
grad(p[B + 1], lvec - vec2(1, 1)), u), v)

static function perlin (vec3 vec) returns real
var lvec = vec
let X = vec.x.floor().bitAnd(255)
let Y = vec.y.floor().bitAnd(255)
let Z = vec.z.floor().bitAnd(255)
lvec = vec3(lvec.x - lvec.x.floor(), lvec.y - lvec.y.floor(), lvec.z - lvec.z.floor())
let A = p[X] + Y
let AA = p[A] + Z
let AB = p[A + 1] + Z
let B = p[X + 1] + Y
let BA = p[B] + Z
let BB = p[B + 1] + Z
grad(p[BA], lvec - vec3(1, 0, 0)), u).lerp(
grad(p[AB], lvec - vec3(0, 1, 0)).lerp(
grad(p[BB], lvec - vec3(1, 1, 0)), u), v).lerp(
grad(p[AA + 1], lvec - vec3(0, 0, 1)).lerp(
grad(p[BA + 1], lvec - vec3(1, 0, 1)), u).lerp(
grad(p[AB + 1], lvec - vec3(0, 1, 1)).lerp(
grad(p[BB + 1], lvec - vec3(1, 1, 1)), u), v), w)

static function generateRandomPermutation()
for i = 0 to 255
p[i] = GetRandomInt(0, 255)
p[i + 256] = p [i]

Example

Code (vJASS):

function GetResult takes nothing returns nothing
local real x = (udg_Offset_X + udg_World_Offset_X + I2R(udg_X)) * udg_Scale
local real y = (udg_Offset_Y + udg_World_Offset_Y + I2R(udg_Y)) * udg_Scale
if udg_IsOctavePerlin then
set udg_Result = OctavePerlin2D(x, y,udg_Octaves, udg_Persistence)
else
set udg_Result = PerlinNoise2D(x, y)
endif
set x = udg_World_Offset_X + udg_X * udg_PerSquare_Width
set y = udg_World_Offset_Y + -(udg_Y * udg_PerSquare_Height)
if udg_Result < .1 then
call SetTerrainType(x, y, 'Ldrt', 0, 1, 0)
elseif udg_Result < .2 then
call SetTerrainType(x, y, 'Ldro', 0, 1, 0)
elseif udg_Result < .25 then
call SetTerrainType(x, y, 'Lgrs', 0, 1, 0)
elseif udg_Result < .5 then
call SetTerrainType(x, y, 'Ldrg', 0, 1, 0)
else
call SetTerrainType(x, y, 'Lrok', 0, 1, 0)
endif
endfunction

Previews
Contents

# WurstPerlinNoise(Map)

### Spell Reviewer

Joined:
May 9, 2014
Messages:
1,359
Resources:
7
Models:
1
Icons:
2
Spells:
3
JASS:
1
Resources:
7
This â€¦ is quite an unusual resource in the Spells section. An algorithm of sorts that normally doesn't pertain to the usual ideas centered around spells. I'll reserve judgment to @Dr Super Good and @Frotty.

### Wurst Reviewer

Joined:
Jan 1, 2009
Messages:
1,473
Resources:
11
Models:
3
Tools:
1
Maps:
5
Tutorials:
1
Wurst:
1
Resources:
11
Cool, Wurst code looks good from a first viewing. `lerp` already exists as `linear` in the Interpolation package.
Is there a git repo for it, so it can be used as dependency via grill? If not, that would be a nice addition.
Thumbs up for covering all scripting languages

3. ### Drake53

Joined:
Jan 1, 2018
Messages:
265
Resources:
0
Resources:
0
You sure you're not forgetting something? Don't worry though, I got you covered.

Code (C#):
[NativeLuaMemberContainer]
internal static class PerlinNoise
{
[NativeLuaMember("Noise.perlin1D")]
public static extern float Noise(float x);

[NativeLuaMember("Noise.perlin2D")]
public static extern float Noise(float x, float y);

[NativeLuaMember("Noise.perlin3D")]
public static extern float Noise(float x, float y, float z);

[NativeLuaMember("Noise.permutationInit")]
public static extern void Init();
}
It's probably more efficient like this anyways, compared to writing the entire library in C#.

Also, spotted a small mistake here:
Code (Lua):
function Noise.perlin1D (x, y, z)

4. ### Glint

Joined:
Dec 28, 2014
Messages:
68
Resources:
2
Maps:
1
Spells:
1
Resources:
2
I'll work on that one. I was just to upload the source code in Github.

Oh my, I even remember using it before. Well, I'm gonna update that one once I upload it to git.

Nice catch! I caught another one as well.

Code (Lua):
I updated the Lua version to 1.0.1.

5. ### Glint

Joined:
Dec 28, 2014
Messages:
68
Resources:
2
Maps:
1
Spells:
1
Resources:
2
JASS, vJASS and Lua now have a git repository.

Updated Wurst version to 1.0.1.
- Removed lerp() and used the one in the standard library: real.lerp()

Also for Wurst, you can now use Grill to add wurstNoiselib as a dependency to your project.

Code (Text):

grill install https://github.com/eGlint/wurstNoiselib
grill install

6. ### Chaosy

Joined:
Jun 9, 2011
Messages:
10,719
Resources:
18
Maps:
1
Spells:
11
Tutorials:
6
Resources:
18
Underrated dedication to multiple languages.

I do not have use for this right now, but I will try to keep it in mind in the future

### Wurst Reviewer

Joined:
Jan 1, 2009
Messages:
1,473
Resources:
11
Models:
3
Tools:
1
Maps:
5
Tutorials:
1
Wurst:
1
Resources:
11
You don't need an 'install' after installing the dependency.
Other than that, good stuff

8. ### Glint

Joined:
Dec 28, 2014
Messages:
68
Resources:
2
Maps:
1
Spells:
1
Resources:
2
Oh, thank you for the correction.

9. ### Cheezeman

Joined:
Aug 19, 2008
Messages:
488
Resources:
2
Spells:
1
Tutorials:
1
Resources:
2
Iirc perlin says in the paper it is to align the array with memory or some such. He mentions it anyway.

Joined:
Jan 1, 2009
Messages:
1,473
Resources:
11
Models:
3
Tools:
1
Maps:
5
Tutorials:
1
Wurst:
1
Resources:
11
11. ### Edy

Joined:
Nov 21, 2015
Messages:
226
Resources:
1
Maps:
1
Resources:
1
1x1 pathing blockers and smaller tiles are the things that I hope for Wc3.
Good stuff