[JASS/vJASS/Lua/Wurst] Noise Library

User avatar
Glint
Registered users
Registered users
Posts: 2
Joined: Sat Oct 26, 2019 4:27 pm
Reputation: 0
Contact:
Philippines

[JASS/vJASS/Lua/Wurst] Noise Library

#1

Post by Glint » Sat Oct 26, 2019 5:16 pm

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.

It features 1D, 2D, and 3D Perlin noise.

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.

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

Code: Select all

grill install https://github.com/eGlint/wurstNoiselib
grill install
Requires
None (JASS/vJASS/Lua)
WurstStdlib2 (Wurst)

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

For JASS version, it requires the following GUI variables:
NoisePermutation (integer array)

JASS:

Code: Select all

//
//  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)
    return Lerp(Fade(x), Gradient1D(udg_NoisePermutation[X], x), Gradient1D(udg_NoisePermutation[X + 1], x - 1)) * 2
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 u = Fade(x)
    set v = Fade(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 u = Fade(x)
    set v = Fade(y)
    set w = Fade(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: Select all

/*
    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)
            return lerp(fade(x), grad1D(permutation[X], x), grad1D(permutation[X + 1], x - 1.)) * 2
        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 u = fade(x)
            set v = fade(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 u = fade(x)
            set v = fade(y)
            set w = fade(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: Select all

--[[
    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

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

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

    local function grad1D(hash, x)
        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)
        return lerp(fade(x), grad1D(Noise.permutation[X], x), grad1D(Noise.permutation[X + 1], x - 1)) * 2
    end

    local function grad2D(hash, x, y)
        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 u, v = fade(x), fade(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 u, v, w = fade(x), fade(y), fade(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: Select all

/*
    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)

function real.fade () returns real
    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()
        return grad(p[X], lx).lerp(
               grad(p[X + 1], lx - 1), lx.fade()) * 2

    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 u = lvec.x.fade()
        let v = lvec.y.fade()
        let A = p[X] + Y
        let B = p[X + 1] + Y
        return grad(p[A], lvec).lerp(
               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 u = lvec.x.fade()
        let v = lvec.y.fade()
        let w = lvec.z.fade()
        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
        return grad(p[AA], lvec).lerp(
               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: Select all

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
Application:
Popular games like Minecraft and Terraria uses a similar algorithm to create procedural generated worlds. This means you could now do the same in Warcraft III.

Changelogs:
JASS changelog
vJASS changelog
Lua changelog
Wurst changelog
Glint wrote:I like hashbrowns!
Noise Library (available for JASS/vJASS/Lua/Wurst)

Return to “Systems”

×