summaryrefslogtreecommitdiff
path: root/noise.lua
diff options
context:
space:
mode:
authorubq323 <ubq323@ubq323.website>2025-02-17 14:48:34 +0000
committerubq323 <ubq323@ubq323.website>2025-02-17 14:48:34 +0000
commitf1492b52414b6f2ad6cfff45375c08677feab18c (patch)
tree2eac341c813f513b4acef7ff591f6f68936eb334 /noise.lua
initial
Diffstat (limited to 'noise.lua')
-rw-r--r--noise.lua74
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}