-
Notifications
You must be signed in to change notification settings - Fork 0
/
noise.go
123 lines (109 loc) · 2.36 KB
/
noise.go
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
package main
import (
"math"
"math/rand"
)
type noiseGen [256]uint8
type NoiseGen []noiseGen
func NewNoiseGen(seed int64, octaves int) NoiseGen {
n := make(NoiseGen, octaves)
r := rand.New(rand.NewSource(seed))
for i := range n {
perm := r.Perm(len(n[i]))
for j := range n[i] {
n[i][j] = uint8(perm[j])
}
}
return n
}
func (n NoiseGen) Noise(x, y, z float64) float64 {
mul := 1.0
cur := 0.0
max := 0.0
for i := range n {
cur += n[i].noise(x/mul, y/mul, z/mul) * mul
max += mul
mul *= 0.25
}
return cur / max
}
func noisegen_floor(f float64) (mod uint8, frac float64) {
fl := math.Floor(f)
return uint8(fl), f - fl
}
// Adapted from http://mrl.nyu.edu/~perlin/noise/
func (n noiseGen) noise(x, y, z float64) float64 {
// Find unit cube that contains point.
// Find relative X, Y, Z of point in cube.
X, x := noisegen_floor(x)
Y, y := noisegen_floor(y)
Z, z := noisegen_floor(z)
// Compute fade curves for each of X, Y, Z.
u, v, w := noisegen_fade(x), noisegen_fade(y), noisegen_fade(z)
// Hash coordinates of the 8 cube corners,
var (
A = n[X] + Y
AA = n[A] + Z
AB = n[A+1] + Z
B = n[X+1] + Y
BA = n[B] + Z
BB = n[B+1] + Z
)
// and add blended results from 8 corners of cube.
return noisegen_lerp(w, noisegen_lerp(v, noisegen_lerp(u,
noisegen_grad(n[AA], x, y, z),
noisegen_grad(n[BA], x-1, y, z)),
noisegen_lerp(u,
noisegen_grad(n[AB], x, y-1, z),
noisegen_grad(n[BB], x-1, y-1, z))),
noisegen_lerp(v, noisegen_lerp(u,
noisegen_grad(n[AA+1], x, y, z-1),
noisegen_grad(n[BA+1], x-1, y, z-1)),
noisegen_lerp(u,
noisegen_grad(n[AB+1], x, y-1, z-1),
noisegen_grad(n[BB+1], x-1, y-1, z-1))))
}
func noisegen_fade(t float64) float64 {
return t * t * t * (t*(t*6-15) + 10)
}
func noisegen_lerp(t, a, b float64) float64 {
return a + t*(b-a)
}
func noisegen_grad(hash uint8, x, y, z float64) float64 {
// Convert low four bits of hash code into twelve gradient directions.
switch uint(hash & 15) {
case 0:
return x + y
case 1:
return -x + y
case 2:
return x - y
case 3:
return -x - y
case 4:
return x + z
case 5:
return -x + z
case 6:
return x - z
case 7:
return -x - z
case 8:
return y + z
case 9:
return -y + z
case 10:
return y - z
case 11:
return -y - z
case 12:
return y + x
case 13:
return -y + z
case 14:
return y - x
case 15:
return -y - z
}
panic("unreachable")
}