-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathnoise.lua
190 lines (162 loc) · 5.13 KB
/
noise.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
-- Made by Xella#8655
local function randomValue()
return math.random(0, 1023) / 1023
end
local function getRawLayer(layerWidth, x, y, seed)
math.randomseed(seed + x * 1000 + y * 1000000)
local prelayer = {}
for x = 1, layerWidth + 2 do
prelayer[x] = {}
for y = 1, layerWidth + 2 do
local value = randomValue()
prelayer[x][y] = value
end
end
return prelayer
end
local function getValueLinear(X1, X2, Y1, Y2, X3)
local a = (Y2 - Y1) / (X2 - X1)
local b = Y2 - a * X2
local Y3 = a * X3 + b
return Y3
end
local function getValueCosine(X1, X2, Y1, Y2, X3)
local Y3 = (1-math.cos(math.pi/(X1-X2) * (X3-X1))) / 2 * (Y2-Y1) + Y1
return Y3
end
local function createNoiseLayer(size, layerWidth, x, y, seed)
local prelayer = getRawLayer(layerWidth, x, y, seed)
local prelayerUp = getRawLayer(layerWidth, x, y - 1, seed)
local prelayerDown = getRawLayer(layerWidth, x, y + 1, seed)
local prelayerLeft = getRawLayer(layerWidth, x - 1, y, seed)
local prelayerRight = getRawLayer(layerWidth, x + 1, y, seed)
for x = 2, layerWidth + 1 do
prelayer[x][1] = prelayerUp[x][layerWidth + 1]
end
for x = 2, layerWidth + 1 do
prelayer[x][layerWidth + 2] = prelayerDown[x][2]
end
for y = 2, layerWidth + 1 do
prelayer[1][y] = prelayerLeft[layerWidth + 1][y]
end
for y = 2, layerWidth + 1 do
prelayer[layerWidth + 2][y] = prelayerRight[2][y]
end
local layer = {}
for x = 2, layerWidth + 1 do
for y = 2, layerWidth + 1 do
local value = prelayer[x][y]
local valueUp = prelayer[x][y - 1]
local valueDown = prelayer[x][y + 1]
local valueLeft = prelayer[x - 1][y]
local valueRight = prelayer[x + 1][y]
for x2 = (x - 1 - 1) * size / layerWidth + 1, (x - 1) * size / layerWidth do
if (layer[x2] == nil) then
layer[x2] = {}
end
for y2 = (y - 1 - 1) * size / layerWidth + 1, (y - 1) * size / layerWidth do
local localX = x2 - (x - 1 - 1) * size / layerWidth
local localY = y2 - (y - 1 - 1) * size / layerWidth
if localX == size / layerWidth / 2 and localY == size / layerWidth / 2 then
layer[x2][y2] = value
elseif localX - localY > 0 then -- upper right
if size / layerWidth - localX - localY > 0 then -- upper left
local X1 = -size / layerWidth / 2
local X2 = size / layerWidth / 2
local Y1 = valueUp
local Y2 = value
local X3 = localY
local newValue = getValueCosine(X1, X2, Y1, Y2, X3)
layer[x2][y2] = newValue -- up
else -- bottom right
local X1 = size / layerWidth / 2
local X2 = size / layerWidth / 2 * 3
local Y1 = value
local Y2 = valueRight
local X3 = localX
local newValue = getValueCosine(X1, X2, Y1, Y2, X3)
layer[x2][y2] = newValue -- right
end
else -- bottom left
if (size / layerWidth - localX - localY > 0) then -- upper left
local X1 = -size / layerWidth / 2
local X2 = size / layerWidth / 2
local Y1 = valueLeft
local Y2 = value
local X3 = localX
local newValue = getValueCosine(X1, X2, Y1, Y2, X3)
layer[x2][y2] = newValue -- left
else -- bottom right
local X1 = size / layerWidth / 2
local X2 = size / layerWidth / 2 * 3
local Y1 = value
local Y2 = valueDown
local X3 = localY
local newValue = getValueCosine(X1, X2, Y1, Y2, X3)
layer[x2][y2] = newValue -- bottom
end
end
end
end
end
end
return layer
end
local function compressNoiseLayers(noiseLayers)
local noise = {}
noiseSize = #noiseLayers[1]
for layerNr, layer in pairs(noiseLayers) do
for x = 1, noiseSize do
if not noise[x] then
noise[x] = {}
end
for y = 1, noiseSize do
if layerNr == 1 then
noise[x][y] = layer[x][y]
else
noise[x][y] = (noise[x][y] * (layerNr - 1) + layer[x][y]) / layerNr
end
end
end
end
return noise
end
function createNoise(size, x, y, seed, smoothness)
local smoothness = smoothness or 1
if not size then
error("createNoise arg#1: integer expected, got nil")
elseif type(size) ~= "number" then
error("createNoise arg#1: integer expected, got "..type(size))
else
if (size / (2 ^ smoothness)) / 2 % 1 ~= 0 then
error("createNoise arg#1 and/or arg#5: the size must be at least 2 and divisible by 2^(smoothness+1)")
end
end
if not x then
error("createNoiseLayers arg#2 integer expected, got nil")
elseif type(x) ~= "number" then
error("createNoiseLayers arg#2: integer expected, got "..type(x))
end
if not y then
error("createNoiseLayers arg#3: integer expected, got nil")
elseif type(y) ~= "number" then
error("createNoiseLayers arg#3: integer expected, got "..type(y))
end
if not seed then
error("createNoiseLayers arg#4: integer expected, got nil")
elseif type(seed) ~= "number" then
error("createNoiseLayers arg#4: integer expected, got "..type(seed))
end
local noiseLayers = {}
local layerWidth = 2
while layerWidth <= size / (2 ^ smoothness) do
local layer = createNoiseLayer(size, layerWidth, x, y, seed)
noiseLayers[#noiseLayers+1] = layer
layerWidth = layerWidth * 2
end
local compressedNoise = compressNoiseLayers(noiseLayers)
return compressedNoise
end
return {
createNoise = createNoise,
}