Skip to content

Commit 361140f

Browse files
committed
enforce consistency between 2D and 3D worley noise
1 parent 9db3722 commit 361140f

File tree

2 files changed

+73
-68
lines changed

2 files changed

+73
-68
lines changed

sources/noise/cell.swift

Lines changed: 73 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,9 @@ struct CellNoise2D:Noise
4242
public
4343
func evaluate(_ x:Double, _ y:Double) -> Double
4444
{
45-
let sample:DoubleV2 = (x * self.frequency, y * self.frequency)
46-
47-
let bin:IntV2 = (floor(sample.x), floor(sample.y)),
48-
offset:DoubleV2 = (sample.x - Double(bin.a), sample.y - Double(bin.b))
45+
let sample:DoubleV2 = (x * self.frequency , y * self.frequency),
46+
bin:IntV2 = (floor(sample.x) , floor(sample.y)),
47+
sample_rel:DoubleV2 = (sample.x - Double(bin.a), sample.y - Double(bin.b))
4948

5049
// determine kernel
5150

@@ -80,34 +79,37 @@ struct CellNoise2D:Noise
8079
// square since it cannot produce a feature point closer than we have already
8180
// found.
8281

83-
let quadrant:IntV2 = (offset.x > 0.5 ? 1 : -1, offset.y > 0.5 ? 1 : -1),
82+
let quadrant:IntV2 = (sample_rel.x > 0.5 ? 1 : -1 , sample_rel.y > 0.5 ? 1 : -1),
8483
near:IntV2 = (bin.a + (quadrant.a + 1) >> 1, bin.b + (quadrant.b + 1) >> 1),
85-
far:IntV2 = (near.a - quadrant.a, near.b - quadrant.b)
84+
far:IntV2 = (near.a - quadrant.a , near.b - quadrant.b)
8685

87-
let nearpoint_disp:DoubleV2 = (abs(offset.x - Double((quadrant.a + 1) >> 1)),
88-
abs(offset.y - Double((quadrant.b + 1) >> 1)))
86+
let nearpoint_disp:DoubleV2 = (abs(sample_rel.x - Double((quadrant.a + 1) >> 1)),
87+
abs(sample_rel.y - Double((quadrant.b + 1) >> 1)))
8988

9089
var r2:Double = self.distance(from: sample, generating_point: near)
9190

9291
@inline(__always)
93-
func test(generating_point:IntV2, dx:Double = 0, dy:Double = 0)
92+
func _inspect(generating_point:IntV2, dx:Double = 0, dy:Double = 0)
9493
{
9594
if dx*dx + dy*dy < r2
9695
{
9796
r2 = min(r2, self.distance(from: sample, generating_point: generating_point))
9897
}
9998
}
10099

100+
// Cell group:
101+
// within r^2 = 0.25
102+
// cumulative sample coverage = 65.50%
103+
101104
// A points
102-
test(generating_point: (near.a, far.b), dy: nearpoint_disp.y - 0.5)
103-
test(generating_point: (far.a, near.b), dx: nearpoint_disp.x - 0.5)
105+
_inspect(generating_point: (near.a, far.b), dy: nearpoint_disp.y - 0.5)
106+
_inspect(generating_point: (far.a, near.b), dx: nearpoint_disp.x - 0.5)
104107

105108
// far point
106-
test(generating_point: far, dx: nearpoint_disp.x - 0.5, dy: nearpoint_disp.y - 0.5)
109+
_inspect(generating_point: far, dx: nearpoint_disp.x - 0.5, dy: nearpoint_disp.y - 0.5)
107110

108-
// EARLY EXIT: if we have a point within 0.5 units, we don’t have to check
109-
// the outer kernel
110-
if r2 < 0.25
111+
guard r2 > 0.25
112+
else
111113
{
112114
return self.amplitude * r2
113115
}
@@ -131,32 +133,37 @@ struct CellNoise2D:Noise
131133
// inner ----- B ------- C --------+ ← quadrant
132134
// ↓
133135

136+
// Cell group:
137+
// within r^2 = 1.0
138+
// cumulative sample coverage = 99.96%
134139
let inner:IntV2 = (near.a + quadrant.a, near.b + quadrant.b)
135140

136141
// B points
137-
test(generating_point: (inner.a, near.b), dx: nearpoint_disp.x + 0.5)
138-
test(generating_point: (near.a, inner.b), dy: nearpoint_disp.y + 0.5)
142+
_inspect(generating_point: (inner.a, near.b), dx: nearpoint_disp.x + 0.5)
143+
_inspect(generating_point: (near.a, inner.b), dy: nearpoint_disp.y + 0.5)
139144

140145
// C points
141-
test(generating_point: (inner.a, far.b), dx: nearpoint_disp.x + 0.5, dy: nearpoint_disp.y - 0.5)
142-
test(generating_point: (far.a, inner.b), dx: nearpoint_disp.x - 0.5, dy: nearpoint_disp.y + 0.5)
146+
_inspect(generating_point: (inner.a, far.b), dx: nearpoint_disp.x + 0.5, dy: nearpoint_disp.y - 0.5)
147+
_inspect(generating_point: (far.a, inner.b), dx: nearpoint_disp.x - 0.5, dy: nearpoint_disp.y + 0.5)
143148

144-
// EARLY EXIT: if we have a point within 1 unit, we don’t have to check
145-
// the D points or the E points
146-
if r2 < 1
149+
guard r2 > 1.0
150+
else
147151
{
148152
return self.amplitude * r2
149153
}
150154

155+
// Cell group:
156+
// within r^2 = 2.0
157+
// cumulative sample coverage = 100%
151158
let outer:IntV2 = (far.a - quadrant.a, far.b - quadrant.b)
152159

153160
// D points
154-
test(generating_point: (near.a, outer.b), dy: nearpoint_disp.y - 1.5)
155-
test(generating_point: (outer.a, near.b), dx: nearpoint_disp.x - 1.5)
161+
_inspect(generating_point: (near.a, outer.b), dy: nearpoint_disp.y - 1.5)
162+
_inspect(generating_point: (outer.a, near.b), dx: nearpoint_disp.x - 1.5)
156163

157164
// E points
158-
test(generating_point: (far.a, outer.b), dx: nearpoint_disp.x - 0.5, dy: nearpoint_disp.y - 1.5)
159-
test(generating_point: (outer.a, far.b), dx: nearpoint_disp.x - 1.5, dy: nearpoint_disp.y - 0.5)
165+
_inspect(generating_point: (far.a, outer.b), dx: nearpoint_disp.x - 0.5, dy: nearpoint_disp.y - 1.5)
166+
_inspect(generating_point: (outer.a, far.b), dx: nearpoint_disp.x - 1.5, dy: nearpoint_disp.y - 0.5)
160167

161168
return self.amplitude * r2
162169
}
@@ -228,8 +235,9 @@ struct CellNoise3D:Noise
228235
public
229236
func evaluate(_ x:Double, _ y:Double, _ z:Double) -> Double
230237
{
231-
let sample:DoubleV3 = (x * self.frequency, y * self.frequency, z * self.frequency),
232-
bin:IntV3 = (floor(sample.x), floor(sample.y), floor(sample.z))
238+
let sample:DoubleV3 = (x * self.frequency , y * self.frequency , z * self.frequency),
239+
bin:IntV3 = (floor(sample.x) , floor(sample.y) , floor(sample.z)),
240+
sample_rel:DoubleV3 = (sample.x - Double(bin.a), sample.y - Double(bin.b), sample.z - Double(bin.c))
233241

234242
// determine kernel
235243

@@ -242,14 +250,12 @@ struct CellNoise3D:Noise
242250
// near - quadrant.x ————— near quadrant →
243251
// ↓
244252

245-
let quadrant:IntV3 = (sample.x - Double(bin.a) > 0.5 ? 1 : -1,
246-
sample.y - Double(bin.b) > 0.5 ? 1 : -1,
247-
sample.z - Double(bin.c) > 0.5 ? 1 : -1)
253+
let quadrant:IntV3 = (sample_rel.x > 0.5 ? 1 : -1 , sample_rel.y > 0.5 ? 1 : -1 , sample_rel.z > 0.5 ? 1 : -1)
248254
let near:IntV3 = (bin.a + (quadrant.a + 1) >> 1, bin.b + (quadrant.b + 1) >> 1, bin.c + (quadrant.c + 1) >> 1)
249255

250-
let nearpoint_disp:DoubleV3 = (abs(offset.x - Double((quadrant.a + 1) >> 1)),
251-
abs(offset.y - Double((quadrant.b + 1) >> 1)),
252-
abs(offset.z - Double((quadrant.c + 1) >> 1)))
256+
let nearpoint_disp:DoubleV3 = (abs(sample_rel.x - Double((quadrant.a + 1) >> 1)),
257+
abs(sample_rel.y - Double((quadrant.b + 1) >> 1)),
258+
abs(sample_rel.z - Double((quadrant.c + 1) >> 1)))
253259

254260
var r2:Double = self.distance(from: sample, generating_point: near)
255261

@@ -258,25 +264,25 @@ struct CellNoise3D:Noise
258264
{
259265
// calculate distance from quadrant volume to kernel cell
260266
var cell_distance2:Double
261-
if cell_offset.a != 0
267+
if offset.a != 0
262268
{ // move by 0.5 towards zero
263-
let dx:Double = nearpoint_disp.x + Double(cell_offset.a) + (cell_offset.a > 0 ? -0.5 : 0.5)
269+
let dx:Double = nearpoint_disp.x + Double(offset.a) + (offset.a > 0 ? -0.5 : 0.5)
264270
cell_distance2 = dx*dx
265271
}
266272
else
267273
{
268274
cell_distance2 = 0
269275
}
270276

271-
if cell_offset.b != 0
277+
if offset.b != 0
272278
{ // move by 0.5 towards zero
273-
let dy:Double = nearpoint_disp.y + Double(cell_offset.b) + (cell_offset.b > 0 ? -0.5 : 0.5)
279+
let dy:Double = nearpoint_disp.y + Double(offset.b) + (offset.b > 0 ? -0.5 : 0.5)
274280
cell_distance2 += dy*dy
275281
}
276282

277-
if cell_offset.c != 0
283+
if offset.c != 0
278284
{ // move by 0.5 towards zero
279-
let dz:Double = nearpoint_disp.z + Double(cell_offset.c) + (cell_offset.c > 0 ? -0.5 : 0.5)
285+
let dz:Double = nearpoint_disp.z + Double(offset.c) + (offset.c > 0 ? -0.5 : 0.5)
280286
cell_distance2 += dz*dz
281287
}
282288

@@ -286,9 +292,9 @@ struct CellNoise3D:Noise
286292
return
287293
}
288294

289-
let generating_point:IntV3 = (near.a + quadrant.a*cell_offset.a,
290-
near.b + quadrant.b*cell_offset.b,
291-
near.c + quadrant.c*cell_offset.c)
295+
let generating_point:IntV3 = (near.a + quadrant.a*offset.a,
296+
near.b + quadrant.b*offset.b,
297+
near.c + quadrant.c*offset.c)
292298
r2 = min(r2, self.distance(from: sample, generating_point: generating_point))
293299
}
294300

@@ -316,11 +322,11 @@ struct CellNoise3D:Noise
316322
// Cell group:
317323
// within r^2 = 0.5
318324
// cumulative sample coverage = 88.60%
319-
for cell_offset in [(1, 0, 0), ( 0, 1, 0), ( 0, 0, 1),
320-
(0, -1, 1), ( 0, 1, -1), ( 1, 0, -1), (-1, 0, 1), (-1, 1, 0), (1, -1, 0),
321-
(1, -1, -1), (-1, 1, -1), (-1, -1, 1)]
325+
for offset in [(1, 0, 0), ( 0, 1, 0), ( 0, 0, 1),
326+
(0, -1, 1), ( 0, 1, -1), ( 1, 0, -1), (-1, 0, 1), (-1, 1, 0), (1, -1, 0),
327+
(1, -1, -1), (-1, 1, -1), (-1, -1, 1)]
322328
{
323-
_inspect_cell(offset: cell_offset)
329+
_inspect_cell(offset: offset)
324330
}
325331
guard r2 > 0.5
326332
else
@@ -331,9 +337,9 @@ struct CellNoise3D:Noise
331337
// Cell group:
332338
// within r^2 = 0.75
333339
// cumulative sample coverage = 98.26%
334-
for cell_offset in [(0, 1, 1), (1, 0, 1), (1, 1, 0), (-1, 1, 1), (1, -1, 1), (1, 1, -1)]
340+
for offset in [(0, 1, 1), (1, 0, 1), (1, 1, 0), (-1, 1, 1), (1, -1, 1), (1, 1, -1)]
335341
{
336-
_inspect_cell(offset: cell_offset)
342+
_inspect_cell(offset: offset)
337343
}
338344
guard r2 > 0.75
339345
else
@@ -354,11 +360,11 @@ struct CellNoise3D:Noise
354360
// Cell group:
355361
// within r^2 = 1.25
356362
// cumulative sample coverage > 99.99%
357-
for cell_offset in [(-2, 0, 0), ( 0, -2, 0), ( 0, 0, -2),
358-
( 0, -2, -1), ( 0, -1, -2), (-2, 0, -1), (-1, 0, -2), (-2, -1, 0), (-1, -2, 0),
359-
(-2, -1, -1), (-1, -2, -1), (-1, -1, -2)]
363+
for offset in [(-2, 0, 0), ( 0, -2, 0), ( 0, 0, -2),
364+
( 0, -2, -1), ( 0, -1, -2), (-2, 0, -1), (-1, 0, -2), (-2, -1, 0), (-1, -2, 0),
365+
(-2, -1, -1), (-1, -2, -1), (-1, -1, -2)]
360366
{
361-
_inspect_cell(offset: cell_offset)
367+
_inspect_cell(offset: offset)
362368
}
363369
guard r2 > 1.25
364370
else
@@ -369,10 +375,10 @@ struct CellNoise3D:Noise
369375
// Cell group:
370376
// within r^2 = 1.5
371377
// cumulative sample coverage > 99.99%
372-
for cell_offset in [( 0, 1, -2), ( 0, -2, 1), (1, 0, -2), (-2, 0, 1), (1, -2, 0), (-2, 1, 0),
373-
(-2, 1, -1), (-2, -1, 1), (1, -2, -1), (-1, -2, 1), (1, -1, -2), (-1, 1, -2)]
378+
for offset in [( 0, 1, -2), ( 0, -2, 1), (1, 0, -2), (-2, 0, 1), (1, -2, 0), (-2, 1, 0),
379+
(-2, 1, -1), (-2, -1, 1), (1, -2, -1), (-1, -2, 1), (1, -1, -2), (-1, 1, -2)]
374380
{
375-
_inspect_cell(offset: cell_offset)
381+
_inspect_cell(offset: offset)
376382
}
377383
guard r2 > 1.5
378384
else
@@ -395,9 +401,9 @@ struct CellNoise3D:Noise
395401
// Cell group:
396402
// within r^2 = 2.25
397403
// cumulative sample coverage > 99.99%
398-
for cell_offset in [(0, -2, -2), (-2, 0, -2), (-2, -2, 0), (-1, -2, -2), (-2, -1, -2), (-2, -2, -1)]
404+
for offset in [(0, -2, -2), (-2, 0, -2), (-2, -2, 0), (-1, -2, -2), (-2, -1, -2), (-2, -2, -1)]
399405
{
400-
_inspect_cell(offset: cell_offset)
406+
_inspect_cell(offset: offset)
401407
}
402408
guard r2 > 2.25
403409
else
@@ -408,11 +414,11 @@ struct CellNoise3D:Noise
408414
// Cell group:
409415
// within r^2 = 2.5
410416
// cumulative sample coverage > 99.99%
411-
for cell_offset in [(2, 0, 0), (0, 2, 0), (0, 0, 2),
412-
(0, -1, 2), (0, 2, -1), (-1, 0, 2), ( 2, 0, -1), (-1, 2, 0), ( 2, -1, 0),
413-
(1, -2, -2), (2, -1, -1), (-2, -2, 1), (-1, -1, 2), (-2, 1, -2), (-1, 2, -1)]
417+
for offset in [(2, 0, 0), (0, 2, 0), (0, 0, 2),
418+
(0, -1, 2), (0, 2, -1), (-1, 0, 2), ( 2, 0, -1), (-1, 2, 0), ( 2, -1, 0),
419+
(1, -2, -2), (2, -1, -1), (-2, -2, 1), (-1, -1, 2), (-2, 1, -2), (-1, 2, -1)]
414420
{
415-
_inspect_cell(offset: cell_offset)
421+
_inspect_cell(offset: offset)
416422
}
417423
guard r2 > 2.5
418424
else
@@ -423,10 +429,10 @@ struct CellNoise3D:Noise
423429
// Cell group:
424430
// within r^2 = 2.75
425431
// cumulative sample coverage > 99.99%
426-
for cell_offset in [(0, 1, 2), (0, 2, 1), (1, 0, 2), ( 2, 0, 1), (1, 2, 0), ( 2, 1, 0),
427-
(2, 1, -1), (2, -1, 1), (1, 2, -1), (-1, 2, 1), (1, -1, 2), (-1, 1, 2)]
432+
for offset in [(0, 1, 2), (0, 2, 1), (1, 0, 2), ( 2, 0, 1), (1, 2, 0), ( 2, 1, 0),
433+
(2, 1, -1), (2, -1, 1), (1, 2, -1), (-1, 2, 1), (1, -1, 2), (-1, 1, 2)]
428434
{
429-
_inspect_cell(offset: cell_offset)
435+
_inspect_cell(offset: offset)
430436
}
431437
guard r2 > 2.75
432438
else
@@ -437,9 +443,9 @@ struct CellNoise3D:Noise
437443
// Cell group:
438444
// within r^2 = 3.0
439445
// cumulative sample coverage = 100%
440-
for cell_offset in [(2, 1, 1), (1, 2, 1), (1, 1, 2)]
446+
for offset in [(2, 1, 1), (1, 2, 1), (1, 1, 2)]
441447
{
442-
_inspect_cell(offset: cell_offset)
448+
_inspect_cell(offset: offset)
443449
}
444450
return self.amplitude * r2
445451
}

tests/LinuxMain.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ t0 = clock()
4949
pixbuf = V3.sample_area_saturated_to_u8(width: viewer_size, height: viewer_size, offset: 0)
5050
print(clock() - t0)
5151
try png_encode(path: "voronoi3D.png", raw_data: pixbuf, properties: png_properties)
52-
print(1 - Double(CellNoise3D._ccount) / Double(CellNoise3D._ctotal))
5352

5453
let S:fBm<SimplexNoise2D> = fBm<SimplexNoise2D>(amplitude: 0.5*127.5, frequency: 0.001, octaves: 10)
5554
t0 = clock()

0 commit comments

Comments
 (0)