-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathperlin.go
80 lines (69 loc) · 1.72 KB
/
perlin.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
package texture
import (
"math"
"math/rand"
)
// Perlin contains the hash structures for generating a noise value between [-1,1).
// Note noise wraps in 256.
type Perlin struct {
Name string
Seed int64
ph [512]uint8
}
// NewPerlin initializes a new Perlin hash structure.
func NewPerlin(seed int64) *Perlin {
res := &Perlin{}
res.Name = "Perlin"
res.Seed = seed
// Initialize hash
for i := 0; i < 256; i++ {
res.ph[i] = uint8(i)
}
lr := rand.New(rand.NewSource(seed))
// Scramble hash
lr.Shuffle(256, func(i, j int) { res.ph[i], res.ph[j] = res.ph[j], res.ph[i] })
// And replicate
for i := 0; i < 256; i++ {
res.ph[i+256] = res.ph[i]
}
return res
}
// Eval2 calculates the value at x,y based on the interpolated gradients of the four corners
// of the square which x,y resides in. It implements the Field interface.
func (p *Perlin) Eval2(x, y float64) float64 {
ix, iy := math.Floor(x), math.Floor(y)
rx, ry := x-ix, y-iy
u, v := blend(rx), blend(ry)
// Select corners from hash of ix and iy % 256
hx, hy := int(ix)&0xff, int(iy)&0xff
a := int(p.ph[hx]) + hy
b := int(p.ph[hx+1]) + hy
res := lerp(v,
lerp(u, gradient(p.ph[a], rx, ry), gradient(p.ph[b], rx-1, ry)),
lerp(u, gradient(p.ph[a+1], rx, ry-1), gradient(p.ph[b+1], rx-1, ry-1)))
return res
}
func lerp(t, s, e float64) float64 {
return (1-t)*s + t*e
}
func gradient(hash uint8, x, y float64) float64 {
u, v := 0.0, 0.0
switch hash % 4 {
case 0:
u, v = x, y
case 1:
u, v = x, -y
case 2:
u, v = -x, y
case 3:
u, v = -x, -y
}
return u + v
}
// [0, 1] -> [0, 1]
func blend(t float64) float64 {
// Improved blend poly^5
// d1: 30t^4-60t^3+30t^2 : 0 at t=0,1
// d2: 120t^3-180t^2+60t : 0 at t=0,1
return t * t * t * (t*(t*6-15) + 10)
}