Last active
January 2, 2017 17:01
-
-
Save Kaixhin/022ffbfbcf8d542ca1a5f562b28b740a to your computer and use it in GitHub Desktop.
Using Perlin Noise to Generate 2D Terrain and Water
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
-- Using Perlin Noise to Generate 2D Terrain and Water | |
-- http://gpfault.net/posts/perlin-noise.txt.html | |
--]] | |
local image = require 'image' | |
-- Fade function | |
local fade = function(t) | |
-- Provides continuous higher order derivatives for smoothness (this specifically is in the class of sigmoid functions) | |
return math.pow(t, 3) * (t * (t * 6 - 15) + 10) | |
end | |
-- Lookup table of permuted integers | |
local P = torch.cat(torch.randperm(256), torch.randperm(256)) | |
-- Uniformly distributed gradient values | |
local grads = torch.Tensor(512):uniform(-1, 1) | |
-- 1D gradient function | |
local grad = function(p) | |
-- Have to use p + 1 as Lua is 1-indexed | |
return grads[P[p + 1]] | |
end | |
-- 1D noise function | |
local noise = function(p) | |
local p0 = math.floor(p) | |
local p1 = p0 + 1 | |
local t = p - p0 | |
local fadeT = fade(t) -- Used for linear interpolation | |
local g0 = grad(p0) | |
local g1 = grad(p1) | |
-- Specifies desired growth in the neighbourhood and fits a smooth curve given the growth requirements | |
return (1 - fadeT) * g0 * t + fadeT * g1 * (p - p1) | |
end | |
-- Create 1D Perlin noise | |
local frequencies = {1/300, 1/150, 1/75, 1/37.5} | |
local amplitudes = {1, 0.5, 0.25, 0.125} | |
local dim = 300 | |
local img = torch.Tensor(dim, dim) | |
for x = 1, dim do | |
for y = 1, dim do | |
local n = noise(x * frequencies[1]) * amplitudes[1] + noise(x * frequencies[2]) * amplitudes[2] + noise(x * frequencies[3]) * amplitudes[3] + noise(x * frequencies[4]) * amplitudes[4] | |
local y2 = 2 * (y / dim) - 1 -- Map y into [-1, 1] range | |
local colour = n > y2 and 1 or 0 | |
img[y][x] = colour | |
end | |
end | |
image.display(img) | |
-- 2D gradient function | |
local grad2 = function(p) | |
-- Just use random values | |
--local g = torch.Tensor(2):uniform(-1, 1) | |
local g = torch.Tensor{grads[P[p[1] + 1]], grads[P[p[1] + 1] + p[2]]} | |
g:div(g:norm()) -- Normalise to unit vector | |
return g | |
end | |
-- 2D noise function | |
local noise2 = function(p) | |
-- Calculate lattice points | |
local p0 = torch.floor(p) | |
local p1 = p0 + torch.Tensor{1, 0} | |
local p2 = p0 + torch.Tensor{0, 1} | |
local p3 = p0 + torch.Tensor{1, 1} | |
-- Look up gradients at lattice points | |
local g0 = grad2(p0) | |
local g1 = grad2(p1) | |
local g2 = grad2(p2) | |
local g3 = grad2(p3) | |
local t0 = p[1] - p0[1] | |
local fadeT0 = fade(t0) -- Used for horizontal interpolation | |
local t1 = p[2] - p0[2] | |
local fadeT1 = fade(t1) -- Used for vertical interpolation | |
-- Calculate dot products and interpolate | |
local p0p1 = (1 - fadeT0) * torch.dot(g0, p - p0) + fadeT0 * torch.dot(g1, p - p1) -- Between upper two lattice points | |
local p2p3 = (1 - fadeT0) * torch.dot(g2, p - p2) + fadeT0 * torch.dot(g3, p - p3) -- Between lower two lattice points | |
-- Calculate final result | |
return (1 - fadeT1) * p0p1 + fadeT1 * p2p3 | |
end | |
-- Create 2D Perlin noise | |
for x = 1, dim do | |
for y = 1, dim do | |
local xy = torch.Tensor{x, y} | |
local n = noise2(xy * frequencies[1]) * amplitudes[1] + noise2(xy * frequencies[2]) * amplitudes[2] + noise2(xy * frequencies[3]) * amplitudes[3] + noise2(xy * frequencies[4]) * amplitudes[4] | |
img[y][x] = n | |
end | |
end | |
image.display(img) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment