diff options
author | ubq323 <ubq323@ubq323.website> | 2025-02-17 14:48:34 +0000 |
---|---|---|
committer | ubq323 <ubq323@ubq323.website> | 2025-02-17 14:48:34 +0000 |
commit | f1492b52414b6f2ad6cfff45375c08677feab18c (patch) | |
tree | 2eac341c813f513b4acef7ff591f6f68936eb334 /noise.lua |
initial
Diffstat (limited to 'noise.lua')
-rw-r--r-- | noise.lua | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/noise.lua b/noise.lua new file mode 100644 index 0000000..f802ea2 --- /dev/null +++ b/noise.lua @@ -0,0 +1,74 @@ +local Pos = require'r.pos' +local class = require'r.class' +local rmath = require'r.math' +local bit = require'bit' +local tau = 2*math.pi + +math.randomseed(os.time()) + +local function hash_list(t) + local h = #t + for _,x in ipairs(t) do + x = bit.bxor(bit.rshift(x,16),x) * 0x7feb352d + x = bit.bxor(bit.rshift(x,15),x) * 0x846ca68b + x = bit.bxor(bit.rshift(x,16),x) + h = bit.bxor(h,x + 0x9e3779b9 + bit.lshift(h,6) + bit.rshift(h,2)) + end + return h +end + +local function hash_to_unit_vec(t) + local h = hash_list(t) + math.randomseed(h) + local theta = math.random()*tau + return Pos:make(math.cos(theta),math.sin(theta)) +end + +local PerlinNoise = class() +function PerlinNoise.make(cls,seed) + return setmetatable({seed=seed},cls) +end +function PerlinNoise.vertex(self,ix,iy) + return hash_to_unit_vec{ix,iy,self.seed} +end + +function PerlinNoise.at(self,x,y) + local x0 = math.floor(x) + local y0 = math.floor(y) + local x1 = x0 + 1 + local y1 = y0 + 1 + + local v00 = self:vertex(x0,y0) + local v01 = self:vertex(x0,y1) + local v10 = self:vertex(x1,y0) + local v11 = self:vertex(x1,y1) + + local p = function(...) return Pos:make(...) end + local d00 = v00:dot(p(x-x0,y-y0)) + local d01 = v01:dot(p(x-x0,y-y1)) + local d10 = v10:dot(p(x-x1,y-y0)) + local d11 = v11:dot(p(x-x1,y-y1)) + + local q0 = rmath.slerp(d00,d01,y-y0) + local q1 = rmath.slerp(d10,d11,y-y0) + local z = rmath.slerp(q0,q1,x-x0) + return z +end + +local NoiseAgg = class() +function NoiseAgg.make(cls,things) + return setmetatable({things=things or {}},cls) +end +function NoiseAgg.at(self,x,y) + local n = 0 + local t = 0 + assert(#self.things>0,"can't generate noise with no noise things") + for _,thing in ipairs(self.things) do + local gen,scale,amp = thing.gen,thing.scale,thing.amp + n = n + amp + t = t + gen:at(x/scale,y/scale)*amp + end + return t/n +end + +return {PerlinNoise=PerlinNoise,NoiseAgg=NoiseAgg} |