2021-03-09 05:41:11 +00:00
|
|
|
package common
|
|
|
|
|
|
|
|
import (
|
|
|
|
"math"
|
|
|
|
"math/rand"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
perlinYwrapb = 4
|
|
|
|
perlinYwrap = 1 << perlinYwrapb
|
|
|
|
perlinZwrapb = 8
|
|
|
|
perlinZwrap = 1 << perlinZwrapb
|
|
|
|
perlinSize = 4095
|
|
|
|
perlinOctaves = 4
|
|
|
|
perlinAmpFalloff = 0.5
|
|
|
|
)
|
|
|
|
|
2021-06-22 02:11:40 +00:00
|
|
|
// PerlinNoise is a perlin noise struct to generate perlin noise.
|
2021-03-11 03:24:14 +00:00
|
|
|
type PerlinNoise struct {
|
2021-03-09 05:41:11 +00:00
|
|
|
perlin []float64
|
|
|
|
}
|
|
|
|
|
2021-03-16 08:10:50 +00:00
|
|
|
// NewPerlinNoise returns a PerlinNoise object.
|
2021-03-11 03:24:14 +00:00
|
|
|
func NewPerlinNoise() *PerlinNoise {
|
|
|
|
perlin := &PerlinNoise{perlin: nil}
|
2021-03-09 05:41:11 +00:00
|
|
|
perlin.perlin = make([]float64, perlinSize+1)
|
|
|
|
|
|
|
|
for i, _ := range perlin.perlin {
|
|
|
|
perlin.perlin[i] = rand.Float64()
|
|
|
|
}
|
|
|
|
return perlin
|
|
|
|
}
|
|
|
|
|
2021-03-16 08:10:50 +00:00
|
|
|
// Noise1D returns a float noise number on one dimension.
|
2021-03-11 03:24:14 +00:00
|
|
|
func (p *PerlinNoise) Noise1D(x float64) float64 {
|
|
|
|
return p.noise(x, 0, 0)
|
|
|
|
}
|
|
|
|
|
2021-06-22 02:11:40 +00:00
|
|
|
// Noise2D returns a float noise number on two dimensions.
|
2021-03-11 03:24:14 +00:00
|
|
|
func (p *PerlinNoise) Noise2D(x, y float64) float64 {
|
|
|
|
return p.noise(x, y, 0)
|
|
|
|
}
|
|
|
|
|
2021-06-22 02:11:40 +00:00
|
|
|
// Noise3D returns a float noise number on three dimensions.
|
2021-03-11 03:24:14 +00:00
|
|
|
func (p *PerlinNoise) Noise3D(x, y, z float64) float64 {
|
|
|
|
return p.noise(x, y, z)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *PerlinNoise) noise(x, y, z float64) float64 {
|
2021-03-09 05:41:11 +00:00
|
|
|
if x < 0 {
|
|
|
|
x = -x
|
|
|
|
}
|
|
|
|
|
|
|
|
if y < 0 {
|
|
|
|
y = -y
|
|
|
|
}
|
|
|
|
|
|
|
|
if z < 0 {
|
|
|
|
z = -z
|
|
|
|
}
|
|
|
|
|
|
|
|
xi, yi, zi := int(math.Floor(x)), int(math.Floor(y)), int(math.Floor(z))
|
|
|
|
xf, yf, zf := x-float64(xi), y-float64(yi), z-float64(zi)
|
|
|
|
|
|
|
|
var rxf, ryf, n1, n2, n3 float64
|
|
|
|
var r float64
|
|
|
|
var ampl float64 = 0.5
|
|
|
|
|
|
|
|
for o := 0; o < perlinOctaves; o++ {
|
|
|
|
of := xi + (yi << perlinYwrapb) + (zi << perlinZwrapb)
|
|
|
|
|
|
|
|
rxf = scaledCosin(xf)
|
|
|
|
ryf = scaledCosin(yf)
|
|
|
|
|
|
|
|
n1 = p.perlin[of&perlinSize]
|
|
|
|
n1 += rxf * (p.perlin[(of+1)&perlinSize] - n1)
|
|
|
|
n2 = p.perlin[(of+perlinYwrap)&perlinSize]
|
|
|
|
n2 += rxf * (p.perlin[(of+perlinYwrap+1)&perlinSize] - n2)
|
|
|
|
n1 += ryf * (n2 - n1)
|
|
|
|
|
|
|
|
of += perlinZwrap
|
|
|
|
n2 = p.perlin[of&perlinSize]
|
|
|
|
n2 += rxf * (p.perlin[(of+1)&perlinSize] - n2)
|
|
|
|
n3 = p.perlin[(of+perlinYwrap)&perlinSize]
|
|
|
|
n3 += rxf * (p.perlin[(of+perlinYwrap+1)&perlinSize] - n3)
|
|
|
|
n2 += ryf * (n3 - n2)
|
|
|
|
|
|
|
|
n1 += scaledCosin(zf) * (n2 - n1)
|
|
|
|
|
|
|
|
r += n1 * ampl
|
|
|
|
ampl *= perlinAmpFalloff
|
|
|
|
xi <<= 1
|
|
|
|
xf *= 2
|
|
|
|
yi <<= 1
|
|
|
|
yf *= 2
|
|
|
|
zi <<= 1
|
|
|
|
zf *= 2
|
|
|
|
|
|
|
|
if xf >= 1.0 {
|
|
|
|
xi += 1
|
|
|
|
xf -= 1
|
|
|
|
}
|
|
|
|
if yf >= 1.0 {
|
|
|
|
yi += 1
|
|
|
|
yf -= 1
|
|
|
|
}
|
|
|
|
if zf >= 1.0 {
|
|
|
|
zi += 1
|
|
|
|
zf -= 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
|
|
|
func scaledCosin(x float64) float64 {
|
|
|
|
return 0.5 * (1.0 - math.Cos(x*math.Pi))
|
|
|
|
}
|