Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lua - Perlin Noise Generation - Getting bars rather than squares

I'm currently learning Löve 2d/Lua and trying my hand at generating noise using the Perlin Noise algorithm.

I've adapted Ken Perlin's Improved Noise code here:

Code edited with fixes per Doug's answer

-- original code by Ken Perlin: http://mrl.nyu.edu/~perlin/noise/

perlin = {}
perlin.p = {}
perlin.permutation = { 151,160,137,91,90,15,
   131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
   190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
   88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
   77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
   102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
   135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
   5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
   223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
   129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
   251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
   49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
   138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
}
perlin.size = 256
perlin.gx = {}
perlin.gy = {}
perlin.randMax = 256

function perlin:load(  )
    for i=1,self.size do
        self.p[i] = self.permutation[i]
        self.p[256+i] = self.p[i]
    end
end

function perlin:noise( x, y, z )
    local X = math.floor(x) % 256
    local Y = math.floor(y) % 256
    local Z = math.floor(z) % 256
    x = x - math.floor(x)
    y = y - math.floor(y)
    z = z - math.floor(z)
    local u = fade(x)
    local v = fade(y)
    local w = fade(z)
    local A  = self.p[X+1]+Y
    local AA = self.p[A+1]+Z
    local AB = self.p[A+2]+Z
    local B  = self.p[X+2]+Y
    local BA = self.p[B+1]+Z
    local BB = self.p[B+2]+Z

    return lerp(w, lerp(v, lerp(u, grad(self.p[AA+1], x  , y  , z  ),
                                   grad(self.p[BA+1], x-1, y  , z  )),
                           lerp(u, grad(self.p[AB+1], x  , y-1, z  ),
                                   grad(self.p[BB+1], x-1, y-1, z  ))),
                   lerp(v, lerp(u, grad(self.p[AB+2], x  , y  , z-1),
                                   grad(self.p[BA+2], x-1, y  , z-1)),
                           lerp(u, grad(self.p[AB+2], x  , y-1, z-1),
                                   grad(self.p[BB+2], x-1, y-1, z-1))))
end

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

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

function grad( hash, x, y, z )
    local h = hash % 16
    local u = h < 8 and x or y
    local v = h < 4 and y or ((h == 12 or h == 14) and x or z)
    return ((h % 2) == 0 and u or -u) + ((h % 3) == 0 and v or -v)
end

and here's my main.lua Löve script:

require 'noise'

function love.load(  )
    perlin:load()
    -- love.graphics.setBackgroundColor(255, 255, 255)
    love.window.setMode(500, 500)
end

function love.update( dt )

end

function love.draw(  )
    for i=1,500 do
        for j=1,500 do
            local x = perlin:noise(i/10, j/10, 0.3)
            love.graphics.setColor(math.floor(x*255), math.floor(x*255), math.floor(x*255))
            love.graphics.rectangle("fill", 5*(i-1), 5*(j-1), 5, 5)
        end
    end
end

The problem I'm encountering is that rather than getting a nice image of pseudorandom squares, I'm getting some gradient-like bars like this:

noise generated in Löve 2d

I'm pretty stumped as to why I'm not getting the usual noise rendering.

EDIT: Here's the working rendering!

working rendering of perlin noise

like image 696
GHandel Avatar asked Oct 29 '15 21:10

GHandel


People also ask

Is simplex noise better than Perlin noise?

The advantages of simplex noise over Perlin noise: Simplex noise has lower computational complexity and requires fewer multiplications. Simplex noise scales to higher dimensions (4D, 5D) with much less computational cost: the complexity is. for.

Is Perlin noise procedural generation?

Perlin noise is a popular procedural generation algorithm invented by Ken Perlin. It can be used to generate things like textures and terrain procedurally, meaning without them being manually made by an artist or designer. The algorithm can have 1 or more dimensions, which is basically the number of inputs it gets.

Is Perlin noise Gaussian?

Gaussian noise is the closest match to the classic Perlin Noises from before Designer 2017 2.1, despite the name. See also the newer Perlin Noise for a newer, slightly different version of the classic.

How does Perlin make one direction noise?

To generate Perlin noise in one dimension, you associate a pseudo-random gradient (or slope) for the noise function with each integer coordinate, and set the function value at each integer coordinate to zero.


1 Answers

One problem:

local X = math.floor(x) and 255
local Y = math.floor(y) and 255
local Z = math.floor(z) and 255

should be

local X = math.floor(x) & 255
local Y = math.floor(y) & 255
local Z = math.floor(z) & 255

assuming you have Lua 5.3.x. If you have an earlier version of Lua, there are bitwise libraries that may or may not be available for Löve. So, in this case you can use:

local X = math.floor(x) % 256
local Y = math.floor(y) % 256
local Z = math.floor(z) % 256

Explanation: The conjunction operator and returns its first argument if this value is false or nil; otherwise, and returns its second argument.

like image 97
Doug Currie Avatar answered Sep 19 '22 03:09

Doug Currie