@@ -9,7 +9,7 @@ struct CellNoise2D:Noise
9
9
public
10
10
init ( amplitude: Double , frequency: Double , seed: Int = 0 )
11
11
{
12
- self . amplitude = 2 . squareRoot ( ) * amplitude
12
+ self . amplitude = amplitude * 1 / 2 . squareRoot ( )
13
13
self . frequency = frequency
14
14
self . permutation_table = PermutationTable ( seed: seed)
15
15
}
@@ -19,31 +19,15 @@ struct CellNoise2D:Noise
19
19
{
20
20
let hash : Int = self . permutation_table. hash ( generating_point. a, generating_point. b)
21
21
// hash is within 0 ... 255, take it to 0 ... 0.5
22
- let length : Double = Double ( hash) * 0.5 / 255 ,
23
- diagonal : Double = length * ( 1 / 2 . squareRoot ( ) )
24
22
25
- let ( dpx, dpy) : ( Double , Double )
26
- switch hash & 0b0111
27
- {
28
- case 0 :
29
- ( dpx, dpy) = ( diagonal, diagonal)
30
- case 1 :
31
- ( dpx, dpy) = ( - diagonal, diagonal)
32
- case 2 :
33
- ( dpx, dpy) = ( - diagonal, - diagonal)
34
- case 3 :
35
- ( dpx, dpy) = ( diagonal, - diagonal)
36
- case 4 :
37
- ( dpx, dpy) = ( length, 0 )
38
- case 5 :
39
- ( dpx, dpy) = ( 0 , length)
40
- case 6 :
41
- ( dpx, dpy) = ( - length, 0 )
42
- case 7 :
43
- ( dpx, dpy) = ( 0 , - length)
44
- default :
45
- fatalError ( " unreachable " )
46
- }
23
+ // Notice that we have 256 possible hashes, and therefore 8 bits of entropy,
24
+ // to be divided up between 2 axes. We can assign 4 bits to the x and y
25
+ // axes each (16 levels each)
26
+
27
+ // 0b XXXX YYYY
28
+
29
+ let dpx : Double = ( Double ( hash >> 4 ) - 15 / 2 ) * 1 / 16 ,
30
+ dpy : Double = ( Double ( hash & 0b1111 ) - 15 / 2 ) * 1 / 16
47
31
48
32
let dx : Double = Double ( generating_point. a) + dpx - sample_point. x,
49
33
dy : Double = Double ( generating_point. b) + dpy - sample_point. y
@@ -60,7 +44,7 @@ struct CellNoise2D:Noise
60
44
61
45
// determine kernel
62
46
63
- // The control points do not live within the grid cells, rather they float
47
+ // The feature points do not live within the grid cells, rather they float
64
48
// around the *corners* of the grid cells (the ‘O’s in the diagram).
65
49
// The grid cell that the sample point has been binned into is shaded.
66
50
@@ -73,28 +57,29 @@ struct CellNoise2D:Noise
73
57
// | | | |
74
58
// +------------------+
75
59
76
- // The bin itself is divided into quadrants to classify the four corners as
77
- // “near” and “far” points. We call these points the *generating points*.
60
+ // The bin itself is divided into quadrants to classify the four corners
61
+ // as “near” and “far” points. We call these points the *generating points*.
78
62
// The sample point (example) has been marked with an ‘*’.
79
63
80
- // O ------- far
64
+ // A ------- far
81
65
// | | |
82
66
// |----+----|
83
67
// | * | |
84
- // near ------- O
68
+ // near ------- A
85
69
86
- // The actual control points never spawn more than 0.5 normalized units
87
- // away from the near and far points, and their cross-analogues. Therefore,
88
- // the quadrants also provide a means of early exit, since if a sample is
89
- // closer to a control point than the quadrant dividers, it is impossible
90
- // for the sample to be closer to the control point that lives on the
91
- // other side of the divider .
70
+ // The actual feature points never spawn outside of the unit square surrounding
71
+ // their generating points. Therefore, the boundaries of the generating
72
+ // squares serve as a useful means of early exit — if the square is farther
73
+ // away than a point already found, then there is no point checking that
74
+ // square since it cannot produce a feature point closer than we have already
75
+ // found .
92
76
93
77
let quadrant : ( x: Bool , y: Bool ) = ( offset. x > 0.5 , offset. y > 0.5 ) ,
94
78
near : ( a: Int , b: Int ) = ( bin. a + ( quadrant. x ? 1 : 0 ) , bin. b + ( quadrant. y ? 1 : 0 ) ) ,
95
79
far : ( a: Int , b: Int ) = ( bin. a + ( quadrant. x ? 0 : 1 ) , bin. b + ( quadrant. y ? 0 : 1 ) )
96
80
97
- let divider_distance : ( x: Double , y: Double ) = ( ( offset. x - 0.5 ) * ( offset. x - 0.5 ) , ( offset. y - 0.5 ) * ( offset. y - 0.5 ) )
81
+ let nearpoint_disp : ( x: Double , y: Double ) = ( abs ( offset. x - ( quadrant. x ? 1 : 0 ) ) ,
82
+ abs ( offset. y - ( quadrant. y ? 1 : 0 ) ) )
98
83
99
84
var r2_min : Double = self . distance ( from: sample, generating_point: near)
100
85
@@ -109,21 +94,84 @@ struct CellNoise2D:Noise
109
94
}
110
95
}
111
96
112
- if divider_distance. x < r2_min
97
+ // A points
98
+ if ( 0.5 - nearpoint_disp. y) * ( 0.5 - nearpoint_disp. y) < r2_min
113
99
{
114
- test ( generating_point: ( far . a, near . b) ) // near point horizontal
100
+ test ( generating_point: ( near . a, far . b) )
115
101
}
116
102
117
- if divider_distance . y < r2_min
103
+ if ( 0.5 - nearpoint_disp . x ) * ( 0.5 - nearpoint_disp . x ) < r2_min
118
104
{
119
- test ( generating_point: ( near . a, far . b) ) // near point vertical
105
+ test ( generating_point: ( far . a, near . b) )
120
106
}
121
107
122
- if divider_distance. x < r2_min && divider_distance. y < r2_min
108
+ // far point
109
+ if ( 0.5 - nearpoint_disp. x) * ( 0.5 - nearpoint_disp. x) + ( 0.5 - nearpoint_disp. y) * ( 0.5 - nearpoint_disp. y) < r2_min
123
110
{
124
111
test ( generating_point: far)
125
112
}
126
113
114
+ // This is the part where shit hits the fan. (`inner` and `outer` are never
115
+ // sampled directly, they are used for calculating the coordinates of the
116
+ // generating point.)
117
+
118
+ // +-------- D ------- E ----- outer
119
+ // | | | | | | |
120
+ // |----+----|----+----|----+----|
121
+ // | | | | | | |
122
+ // C ------- A —————— far ------ E
123
+ // | | | | | | |
124
+ // |----+----|----+----|----+----|
125
+ // | | | * | | | |
126
+ // B ----- near —————— A ------- D
127
+ // | | | | | | |
128
+ // |----+----|----+----|----+----|
129
+ // | | | | | | |
130
+ // inner ----- B ------- C --------+
131
+
132
+ let inner : ( a: Int , b: Int ) = ( bin. a + ( quadrant. x ? 2 : - 1 ) , bin. b + ( quadrant. y ? 2 : - 1 ) ) ,
133
+ outer : ( a: Int , b: Int ) = ( bin. a + ( quadrant. x ? - 1 : 2 ) , bin. b + ( quadrant. y ? - 1 : 2 ) )
134
+
135
+ // B points
136
+ if ( nearpoint_disp. x + 0.5 ) * ( nearpoint_disp. x + 0.5 ) < r2_min
137
+ {
138
+ test ( generating_point: ( inner. a, near. b) )
139
+ }
140
+ if ( nearpoint_disp. y + 0.5 ) * ( nearpoint_disp. y + 0.5 ) < r2_min
141
+ {
142
+ test ( generating_point: ( near. a, inner. b) )
143
+ }
144
+
145
+ // C points
146
+ if ( nearpoint_disp. x + 0.5 ) * ( nearpoint_disp. x + 0.5 ) + ( 0.5 - nearpoint_disp. y) * ( 0.5 - nearpoint_disp. y) < r2_min
147
+ {
148
+ test ( generating_point: ( inner. a, far. b) )
149
+ }
150
+ if ( nearpoint_disp. y + 0.5 ) * ( nearpoint_disp. y + 0.5 ) + ( 0.5 - nearpoint_disp. x) * ( 0.5 - nearpoint_disp. x) < r2_min
151
+ {
152
+ test ( generating_point: ( far. a, inner. b) )
153
+ }
154
+
155
+ // D points
156
+ if ( 1.5 - nearpoint_disp. y) * ( 1.5 - nearpoint_disp. y) < r2_min
157
+ {
158
+ test ( generating_point: ( near. a, outer. b) )
159
+ }
160
+ if ( 1.5 - nearpoint_disp. x) * ( 1.5 - nearpoint_disp. x) < r2_min
161
+ {
162
+ test ( generating_point: ( outer. a, near. b) )
163
+ }
164
+
165
+ // E points
166
+ if ( 0.5 - nearpoint_disp. x) * ( 0.5 - nearpoint_disp. x) + ( 1.5 - nearpoint_disp. y) * ( 1.5 - nearpoint_disp. y) < r2_min
167
+ {
168
+ test ( generating_point: ( far. a, outer. b) )
169
+ }
170
+ if ( 0.5 - nearpoint_disp. y) * ( 0.5 - nearpoint_disp. y) + ( 1.5 - nearpoint_disp. x) * ( 1.5 - nearpoint_disp. x) < r2_min
171
+ {
172
+ test ( generating_point: ( outer. a, far. b) )
173
+ }
174
+
127
175
return self . amplitude * r2_min
128
176
}
129
177
@@ -178,14 +226,14 @@ struct CellNoise3D:Noise
178
226
// Notice that we have 256 possible hashes, and therefore 8 bits of entropy,
179
227
// to be divided up between three axes. We can assign 3 bits to the x and
180
228
// y axes each (8 levels each), and 2 bits to the z axis (4 levels). To
181
- // compensate for the lack of z resolution, we bump up every other control
229
+ // compensate for the lack of z resolution, we bump up every other feature
182
230
// point by half a level.
183
231
184
232
// 0b XXX YYY ZZ
185
233
186
- let dpx : Double = ( Double ( hash >> 5 ) - 3.5 ) * 0.25 ,
187
- dpy : Double = ( Double ( hash >> 2 & 0b0111 ) - 3.5 ) * 0.25 ,
188
- dpz : Double = ( Double ( hash << 1 & 0b0111 + ( ( hash >> 5 ^ hash >> 2 ) & 1 ) ) - 3.5 ) * 0.25
234
+ let dpx : Double = ( Double ( hash >> 5 ) - 7 / 2 ) * 1 / 8 ,
235
+ dpy : Double = ( Double ( hash >> 2 & 0b0111 ) - 7 / 2 ) * 1 / 8 ,
236
+ dpz : Double = ( Double ( hash << 1 & 0b0111 + ( ( hash >> 5 ^ hash >> 2 ) & 1 ) ) - 7 / 2 ) * 1 / 8
189
237
190
238
let dx : Double = Double ( generating_point. a) + dpx - sample_point. x,
191
239
dy : Double = Double ( generating_point. b) + dpy - sample_point. y,
@@ -196,80 +244,6 @@ struct CellNoise3D:Noise
196
244
public
197
245
func evaluate( _ x: Double , _ y: Double ) -> Double
198
246
{
199
- /*
200
- let sample:(x:Double, y:Double) = (x * self.frequency, y * self.frequency)
201
-
202
- let bin:(a:Int, b:Int) = (floor(sample.x), floor(sample.y)),
203
- offset:(x:Double, y:Double) = (sample.x - Double(bin.a), sample.y - Double(bin.b))
204
-
205
- // determine kernel
206
-
207
- // The control points do not live within the grid cells, rather they float
208
- // around the *corners* of the grid cells (the ‘O’s in the diagram).
209
- // The grid cell that the sample point has been binned into is shaded.
210
-
211
- // xb xb + 1
212
- // +------------------+
213
- // | | | |
214
- // yb |---- O//////O ----|
215
- // | |//////| |
216
- // yb + 1 |---- O//////O ----|
217
- // | | | |
218
- // +------------------+
219
-
220
- // The bin itself is divided into quadrants to classify the four corners as
221
- // “near” and “far” points. We call these points the *generating points*.
222
- // The sample point (example) has been marked with an ‘*’.
223
-
224
- // O ------- far
225
- // | | |
226
- // |----+----|
227
- // | * | |
228
- // near ------- O
229
-
230
- // The actual control points never spawn more than 0.5 normalized units
231
- // away from the near and far points, and their cross-analogues. Therefore,
232
- // the quadrants also provide a means of early exit, since if a sample is
233
- // closer to a control point than the quadrant dividers, it is impossible
234
- // for the sample to be closer to the control point that lives on the
235
- // other side of the divider.
236
-
237
- let quadrant:(x:Bool, y:Bool) = (offset.x > 0.5, offset.y > 0.5),
238
- near:(a:Int, b:Int) = (bin.a + (quadrant.x ? 1 : 0), bin.b + (quadrant.y ? 1 : 0)),
239
- far:(a:Int, b:Int) = (bin.a + (quadrant.x ? 0 : 1), bin.b + (quadrant.y ? 0 : 1))
240
-
241
- let divider_distance:(x:Double, y:Double) = ((offset.x - 0.5) * (offset.x - 0.5), (offset.y - 0.5) * (offset.y - 0.5))
242
-
243
- var r2_min:Double = self.distance(from: sample, generating_point: near)
244
-
245
- @inline(__always)
246
- func test(generating_point:(a:Int, b:Int))
247
- {
248
- let r2:Double = self.distance(from: sample, generating_point: generating_point)
249
-
250
- if r2 < r2_min
251
- {
252
- r2_min = r2
253
- }
254
- }
255
-
256
- if divider_distance.x < r2_min
257
- {
258
- test(generating_point: (far.a, near.b)) // near point horizontal
259
- }
260
-
261
- if divider_distance.y < r2_min
262
- {
263
- test(generating_point: (near.a, far.b)) // near point vertical
264
- }
265
-
266
- if divider_distance.x < r2_min && divider_distance.y < r2_min
267
- {
268
- test(generating_point: far)
269
- }
270
-
271
- return self.amplitude * r2_min
272
- */
273
247
return 0
274
248
}
275
249
0 commit comments