Refactored API to take amplitudes instead of resolution/decayFn.

This commit is contained in:
Bruce Hill 2017-06-19 15:35:26 -07:00
parent 48f9da8196
commit 98e741ab9e
2 changed files with 59 additions and 50 deletions

View File

@ -11,12 +11,13 @@ local function rng()
local r = love.math.newRandomGenerator(1) local r = love.math.newRandomGenerator(1)
return function() return r:random() end return function() return r:random() end
end end
local n1,g1 = Noise.make1d(8,rng(),decay) local makeAmps = Noise.makeAmplitudes
local n2,g2 = Noise.make2d(9,rng(),decay) local n1,g1 = Noise.make1d(makeAmps(8, decay), rng())
local n3,g3 = Noise.make3d(11,rng(),decay) local n2,g2 = Noise.make2d(makeAmps(9, decay), rng())
local s1,s1g = Noise.make1dShader(9,rng(),decay) local n3,g3 = Noise.make3d(makeAmps(11, decay), rng())
local s2,s2g = Noise.make2dShader(13,rng(),decay) local s1,s1g = Noise.make1dShader(makeAmps(9, decay), rng())
local s3,s3g = Noise.make3dShader(17,rng(),decay) local s2,s2g = Noise.make2dShader(makeAmps(13, decay), rng())
local s3,s3g = Noise.make3dShader(makeAmps(17, decay), rng())
local cw,ch = W/2,H/3 local cw,ch = W/2,H/3
local canv = lg.newCanvas(cw,ch) local canv = lg.newCanvas(cw,ch)

View File

@ -10,37 +10,44 @@ local function cdf_prime(x, dx)
return (0.31831 * exp(-2/PI * x*x) * abs(x)*dx)/sqrt(1-exp(-2/PI*x*x)) return (0.31831 * exp(-2/PI * x*x) * abs(x)*dx)/sqrt(1-exp(-2/PI*x*x))
end end
local function _defaultArgs(resolution,random,decayFn) local function _defaultArgs(amplitudes,random)
if not resolution then resolution = 4 end if amplitudes == nil then amplitudes = 5 end
if type(amplitudes) == 'number' then
amplitudes = noise.makeAmplitudes(amplitudes, function(x) return .1^x end)
end
if not random then random = math.random end if not random then random = math.random end
if not decayFn then decayFn = function(x) return .1^x end end return amplitudes, random
return resolution,random,decayFn
end end
local function _amplitudesAndOffsets(decayFn,numAmplitudes, numOffsets, random) local function calculateSigma(amplitudes)
local sigma = 0 local sigma = 0
local amplitudes = {} for _,a in ipairs(amplitudes) do
for i=1,numAmplitudes do sigma = sigma + a*a
local a = decayFn((i-1+random())/numAmplitudes)
amplitudes[i] = a
assert(a > 0.0001)
sigma = sigma + a^2
end end
sigma = math.sqrt(sigma/2) return math.sqrt(sigma/2)
end
local function makeOffsets(count, random)
local offsets = {} local offsets = {}
for i=1,numOffsets do for i=1,count do
offsets[i] = random()*TAU offsets[i] = random()*TAU
end end
return amplitudes,sigma,offsets return offsets
end end
local function sign(x) noise.makeAmplitudes = function(count, fn)
if x == 0 then return 0 local amplitudes = {}
elseif x < 0 then return -1 else return 1 end for i=1,count do
amplitudes[i] = fn((i-.5)/count)
end
return amplitudes
end end
noise.make1d = function(resolution,random,decayFn)
resolution,random,decayFn = _defaultArgs(resolution,random,decayFn) noise.make1d = function(amplitudes,random)
local amplitudes,sigma,offsets = _amplitudesAndOffsets(decayFn,resolution,resolution,random) amplitudes, random = _defaultArgs(amplitudes, random)
local resolution = #amplitudes
local sigma = calculateSigma(amplitudes)
local offsets = makeOffsets(#amplitudes, random)
local function noise(x) local function noise(x)
local n = 0 local n = 0
for i,a in ipairs(amplitudes) do for i,a in ipairs(amplitudes) do
@ -63,9 +70,11 @@ noise.make1d = function(resolution,random,decayFn)
return noise, gradient return noise, gradient
end end
noise.make2d = function(resolution,random,decayFn) noise.make2d = function(amplitudes, random)
resolution,random,decayFn = _defaultArgs(resolution,random,decayFn) amplitudes, random = _defaultArgs(amplitudes, random)
local amplitudes,sigma,offsets = _amplitudesAndOffsets(decayFn,resolution,2*resolution,random) local resolution = #amplitudes
local sigma = calculateSigma(amplitudes)
local offsets = makeOffsets(2*#amplitudes, random)
sigma = sigma/sqrt(2) sigma = sigma/sqrt(2)
local function noise(x,y) local function noise(x,y)
local n = 0 local n = 0
@ -100,9 +109,11 @@ noise.make2d = function(resolution,random,decayFn)
return noise, gradient return noise, gradient
end end
noise.make3d = function(resolution,random,decayFn) noise.make3d = function(amplitudes, random)
resolution,random,decayFn = _defaultArgs(resolution,random,decayFn) amplitudes, random = _defaultArgs(amplitudes, random)
local amplitudes,sigma,offsets = _amplitudesAndOffsets(decayFn,resolution,3*resolution,random) local resolution = #amplitudes
local sigma = calculateSigma(amplitudes)
local offsets = makeOffsets(3*#amplitudes, random)
sigma = sigma/sqrt(3) sigma = sigma/sqrt(3)
local function noise(x,y,z) local function noise(x,y,z)
-- Find the biggest fibonacci number F_n such that F_n < resolution -- Find the biggest fibonacci number F_n such that F_n < resolution
@ -228,15 +239,14 @@ vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords)
} }
]] ]]
noise.make1dShader = function(resolution,random,decayFn) noise.make1dShader = function(amplitudes, random)
resolution,random,decayFn = _defaultArgs(resolution,random,decayFn) amplitudes, random = _defaultArgs(amplitudes, random)
if type(resolution) ~= 'number' or (resolution % 1 > 0) or (resolution <= 0) then local resolution = #amplitudes
error("Resolution must be a positive integer.") local sigma = calculateSigma(amplitudes)
end local offsets = makeOffsets(#amplitudes, random)
local shaderCode = "#define RESOLUTION "..tostring(resolution).."\n"..shader1d local shaderCode = "#define RESOLUTION "..tostring(resolution).."\n"..shader1d
local noiseShader = lg.newShader(shaderCode) local noiseShader = lg.newShader(shaderCode)
local gradShader = lg.newShader("#define GRADIENT\n"..shaderCode) local gradShader = lg.newShader("#define GRADIENT\n"..shaderCode)
local amplitudes,sigma,offsets = _amplitudesAndOffsets(decayFn,resolution,resolution,random)
do -- Dumb hack to work around a bug in Love 0.10.2 not sending the last value do -- Dumb hack to work around a bug in Love 0.10.2 not sending the last value
table.insert(amplitudes, 1.) table.insert(amplitudes, 1.)
table.insert(offsets, 1.) table.insert(offsets, 1.)
@ -299,15 +309,14 @@ vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords)
} }
]] ]]
noise.make2dShader = function(resolution,random,decayFn) noise.make2dShader = function(amplitudes, random)
resolution,random,decayFn = _defaultArgs(resolution,random,decayFn) amplitudes, random = _defaultArgs(amplitudes, random)
if type(resolution) ~= 'number' or (resolution % 1 > 0) or (resolution <= 0) then local resolution = #amplitudes
error("Resolution must be a positive integer.") local sigma = calculateSigma(amplitudes)
end local offsets = makeOffsets(2*#amplitudes, random)
local shaderCode = "#define RESOLUTION "..tostring(resolution).."\n"..shader2d local shaderCode = "#define RESOLUTION "..tostring(resolution).."\n"..shader2d
local noiseShader = lg.newShader(shaderCode) local noiseShader = lg.newShader(shaderCode)
local gradShader = lg.newShader("#define GRADIENT\n"..shaderCode) local gradShader = lg.newShader("#define GRADIENT\n"..shaderCode)
local amplitudes,sigma,offsets = _amplitudesAndOffsets(decayFn,resolution,2*resolution,random)
sigma = sigma/sqrt(2) sigma = sigma/sqrt(2)
local offsets2 = {} local offsets2 = {}
for i=1,#offsets-1,2 do for i=1,#offsets-1,2 do
@ -405,15 +414,14 @@ vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords)
} }
]] ]]
noise.make3dShader = function(resolution,random,decayFn) noise.make3dShader = function(amplitudes, random)
resolution,random,decayFn = _defaultArgs(resolution,random,decayFn) amplitudes, random = _defaultArgs(amplitudes, random)
if type(resolution) ~= 'number' or (resolution % 1 > 0) or (resolution <= 0) then local resolution = #amplitudes
error("Resolution must be a positive integer.") local sigma = calculateSigma(amplitudes)
end local offsets = makeOffsets(3*#amplitudes, random)
local shaderCode = "#define RESOLUTION "..tostring(resolution).."\n"..shader3d local shaderCode = "#define RESOLUTION "..tostring(resolution).."\n"..shader3d
local noiseShader = lg.newShader(shaderCode) local noiseShader = lg.newShader(shaderCode)
local gradShader = lg.newShader("#define GRADIENT\n"..shaderCode) local gradShader = lg.newShader("#define GRADIENT\n"..shaderCode)
local amplitudes,sigma,offsets = _amplitudesAndOffsets(decayFn,resolution,3*resolution,random)
sigma = sigma/sqrt(3) sigma = sigma/sqrt(3)
local offsets2 = {} local offsets2 = {}
for i=1,#offsets-1,3 do for i=1,#offsets-1,3 do