• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Noise Library v1.2

Noise Library
"Making procedural generation accessible to all Warcraft III map makers"

Noise Library is used to generate smoothly-changing noise. In video games, noise functions can be used to create infinite procedurally generated worlds. A lot of games used this algorithm. With this library available in Warcraft III, you could now produce similar results in your custom maps.

Noise functions are not new in Warcraft III, there are few custom maps out there that uses this algorithm before Bitwise natives are introduced. When bitwise operators became available, Typescript map makers already have access to this by transpiling external noise libraries to Lua.

The goal of this library is to make procedural generation accessible to all Warcraft III map makers. I will be releasing a GUI-friendly version in the future.

Features
- Kenneth Perlin's 2002 Improved Noise (1D/2D/3D)
- Kurt Spencer's OpenSimplex Noise (2D only)
- Noise functions available in JASS, vJASS, Lua, and Wurst
- Access latest and older versions of the source code in Github (JASS/vJASS/Lua, Wurst)
- Backwards compatible to older versions of Warcraft III (1.28 and below)

Screenshots

192144-08eb9ff998198e30a63f062caf7f94fa.jpg



Video



API

JASS

vJASS

Lua

Wurst


JASS:
// Constants functions
constant function NoiseVersion takes nothing returns string

// Interface functions (pre-1.29 only)
function NoiseBitAnd takes integer x, integer y returns integer
function NoiseBitXor takes integer x, integer y returns integer

// GetRandomIntInterface arguments and return (GUI Variables)
integer NoiseGetRandomIntLow
integer NoiseGetRandomIntHigh
integer NoiseGetRandomIntReturn

// Noise functions
function PerlinNoise1D takes real x returns real
function PerlinNoise2D takes real x, real y returns real
function PerlinNoise3D takes real x, real y, real z returns real
function OpenSimplex2D takes real x, real y returns real

// Permutation Generation functions
function GeneratePermutationTableCustom takes code GetRandomIntInterface returns nothing
function GeneratePermutationTable takes nothing returns nothing

// Initialization
function InitNoise takes nothing returns nothing

vJASS:
struct Noise extends array

    // Constants
    readonly static string version

    // GetRandomIntInterface arguments and return
    static method operator getRandomIntLow  takes nothing returns integer
    static method operator getRandomIntHigh takes nothing returns integer
    static method operator getRandomIntReturn= takes integer value returns nothing

    // Noise static methods
    static method perlin1D takes real x returns real
    static method perlin2D takes real x, real y returns real
    static method perlin3D takes real x, real y, real z returns real
    static method openSimplex2D takes real x, real y returns real

    // Permutation Generation static methods
    static method generatePermutationTableCustom takes code GetRandomIntInterface returns nothing
    static method generatePermutationTable takes nothing returns nothing

    // Initialization
    static method initialize takes nothing returns nothing


Lua:
// Constants
Noise.version

// Noise functions
function Noise.perlin1D(x) returns number
function Noise.perlin2D(x, y) returns number
function Noise.perlin3D(x, y, z) returns number
function Noise.openSimplex2D(x, y) returns number

// Permutation Generation functions
function Noise.generatePermutationTable (getRandomIntInterface)

// Initialization
function InitNoise ()

Wurst:
class Noise

     // Constants
     constant string getVersion

     // Noise static methods
    static function perlin (real x) returns real
    static function perlin (vec2) returns real
    static function perlin (vec3) returns real
    static function openSimplex (vec2) returns real

    // Permutation Generation static methods
    static function generateRandomPermutation(NoiseRandom random)
    static function generateRandomPermutation()

    // Initialization
    static function initialize()


Wurst Features

You can use Grill to add wurstNoiselib as a dependency to your project:

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

wurstNoiselib is also searchable in Codemonkey11's chillup.


Requires
None (JASS/vJASS/Lua)
WurstStdlib2 (Wurst)
Bitwise (JASS pre-1.29)
Bitwise (vJASS pre-1.29)

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

Code

JASS, changelog
JASS (pre-1.29), changelog
vJASS, changelog
vJASS (pre-1.29), changelog
Lua, changelog
Wurst, changelog

Example Code

JASS

vJASS

Lua

Wurst


JASS:
function GetResult takes nothing returns nothing
    local real x = (udg_Offset_X + I2R(udg_X)) * udg_Scale
    local real y = (udg_Offset_Y + I2R(udg_Y)) * udg_Scale
    if udg_IsOpenSimplex then
        set udg_Result = OpenSimplex2D(x, y) * udg_Amplitude
    elseif udg_IsOctavePerlin then
        set udg_Result = OctavePerlin2D(x, y, udg_Octaves, udg_Persistence)
    else
        set udg_Result = PerlinNoise2D(x, y) * udg_Amplitude
    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 < 0 then
        set udg_Result = udg_Result * -1
    endif
    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

vJASS:
function GetResult takes nothing returns nothing
    local real x = (udg_Offset_X + I2R(udg_X)) * udg_Scale
    local real y = (udg_Offset_Y+ I2R(udg_Y)) * udg_Scale
    if udg_IsOpenSimplex then
        set udg_Result = Noise.openSimplex2D(x, y) * udg_Amplitude
    elseif udg_IsOctavePerlin then
        set udg_Result = Noise.octavePerlin2D(x, y, udg_Octaves, udg_Persistence)
    else
        set udg_Result = Noise.perlin2D(x, y) * udg_Amplitude
    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 < 0 then
        set udg_Result = udg_Result * -1
    endif
    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

Lua:
function GetResult ()
    local x = (udg_Offset_X + I2R(udg_X)) * udg_Scale
    local y = (udg_Offset_Y + I2R(udg_Y)) * udg_Scale
    if udg_IsOpenSimplex then
        udg_Result = Noise.openSimplex2D(x, y) * udg_Amplitude
    elseif udg_IsOctavePerlin then
        udg_Result = Noise.octavePerlin2D(x, y,udg_Octaves, udg_Persistence)
    else
        udg_Result = Noise.perlin2D(x, y) * udg_Amplitude
    end
    x = udg_World_Offset_X + udg_X * udg_PerSquare_Width
    y = udg_World_Offset_Y + -( udg_Y * udg_PerSquare_Height)
    if udg_Result < 0 then
        udg_Result = udg_Result * -1.
    end
    if udg_Result < .1 then
        SetTerrainType(x, y, FourCC("Ldrt"), 0, 1, 0)
    elseif udg_Result < .2 then
        SetTerrainType(x, y, FourCC("Ldro"), 0, 1, 0)
    elseif udg_Result < .25 then
        SetTerrainType(x, y, FourCC("Lgrs"), 0, 1, 0)
    elseif udg_Result < .5 then
        SetTerrainType(x, y, FourCC("Ldrg"), 0, 1, 0)
    else
        SetTerrainType(x, y, FourCC("Lrok"), 0, 1, 0)
    end
end

Wurst:
function getResult()
    real x
    real y
    let noisePos = vec2((udg_Offset_X + udg_X) * udg_Scale,
                        (udg_Offset_Y + udg_Y) * udg_Scale)
    if udg_IsOpenSimplex
        udg_Result = Noise.openSimplex(noisePos) * udg_Amplitude
    else if udg_IsOctavePerlin
        udg_Result = octavePerlin(noisePos, udg_Octaves, udg_Persistence)
    else
        udg_Result = Noise.perlin(noisePos) * udg_Amplitude
    x = udg_World_Offset_X + udg_X * udg_PerSquare_Width
    y = udg_World_Offset_Y + -(udg_Y * udg_PerSquare_Height)
    if udg_Result < 0
        udg_Result *= -1
    if udg_Result < .1
        SetTerrainType(x, y, 'Ldrt', 0, 1, 0)
    else if udg_Result < .2
        SetTerrainType(x, y, 'Ldro', 0, 1, 0)
    else if udg_Result < .25
        SetTerrainType(x, y, 'Lgrs', 0, 1, 0)
    else if udg_Result < .5
        SetTerrainType(x, y, 'Ldrg', 0, 1, 0)
    else
        SetTerrainType(x, y, 'Lrok', 0, 1, 0)


C#

If you are using C# for making Warcraft III maps, read Drake53's thread to know how to integrate Noise Library's Lua source code to C#:


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

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

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

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

        [NativeLuaMember("Noise.initialize")]
        public static extern void Initialize();
    }
Previews
Contents

[JASS] Noise Viewer (Map)

[Lua] Noise Viewer (Map)

[vJASS] Noise Viewer (Map)

[Wurst] Noise Viewer (Map)

Level 18
Joined
Jan 1, 2018
Messages
728
Thumbs up for covering all scripting languages :thumbs_up:
You sure you're not forgetting something? Don't worry though, I got you covered.

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:
Lua:
function Noise.perlin1D (x, y, z)
 
Level 7
Joined
Dec 28, 2014
Messages
82
Is there a git repo for it, so it can be used as dependency via grill? If not, that would be a nice addition.

I'll work on that one. I was just to upload the source code in Github.

`lerp` already exists as `linear` in the Interpolation package.

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

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

Nice catch! I caught another one as well.

Lua:
function Noise.grad1D (hash, x, y)

I updated the Lua version to 1.0.1.
 
Level 7
Joined
Dec 28, 2014
Messages
82
Noise Library v1.2
Custom GenerateRandomPermutation and Bugfixes

Custom GenerateRandomPermutation

If you want to generate random values in the permutation table using your own random function, you can now do it:


JASS

vJASS

Lua

Wurst


JASS:
function MyGetRandomInt takes integer low, integer high returns integer
    // logic how random value is created
    return // output integer
endfunction

function MyGetRandomIntForNoiseLib takes nothing returns nothing
    set udg_NoiseGetRandomIntReturn = MyGetRandomInt(udg_NoiseGetRandomIntLow, udg_NoiseGetRandomIntHigh)
endfunction

function MyInitializer takes nothing returns nothing
   call GenerateRandomPermutationCustom(function MyGetRandomIntForNoiseLib)
endfunction

vJASS:
function MyGetRandomInt takes integer low, integer high returns integer
    // logic how random value is created
    return // output integer
endfunction

function MyGetRandomIntForNoiseLib takes nothing returns nothing
    set Noise.getRandomIntReturn = MyGetRandomInt(Noise.getRandomIntLow, Noise.getRandomIntHigh)
endfunction

function MyInitializer takes nothing returns nothing
   call GenerateRandomPermutationCustom(function MyGetRandomIntForNoiseLib)
endfunction


Lua:
function myGetRandomInt (low, high)
    -- logic how random value is created
    return -- output integer
end
Noise.generateRandomPermutation(myGetRandomInt)

Wurst:
let myCustomPrng = new MyCustomPRNG("Seed")
generateRandomPermutation (low, high) ->
     return myCustomPrng.getRandomInt(low, high)
destroy myCustomPrng



Initialization

The permutation and gradient tables of vJASS, Lua, and Wurst, are now initialized by default.

For JASS, you have to manually call InitNoise() in a trigger with map initialization or in the main section InitTrig_<Trigger Name> of the custom script with "Run on map initialization" enabled.

OpenSimplex 1.2.1 Update

Thanks to @Frotty and @kari0003, a major bug is fixed in Wurst's OpenSimplex. This fix is also applied in JASS, vJASS, and Lua.


wc3-opensimplex-fix.jpg



Improved Noise 1.2.1 Update

Wurst's 2D Perlin Noise is now fixed as well.


wc3-wurst-noise-fix.jpg



Wurst

@kari0003 provided a code where you view Perlin Noise or OpenSimplex in a text form via unit test command in Visual Studio Code.


wc3-visualtest.jpg



Deprecated Functions as of 1.2

The following functions will be removed in the next major update:

vJASS:
vJASS:
// struct Noise extends array
static method permutationInit takes nothing returns nothing // use Noise.initialize instead
static method openSimplexInit takes nothing returns nothing // use Noise.initialize instead
Lua:
Lua:
function Noise.permutationInit () -- use Noise.initialize instead
 
Top