Skip to content

Instantly share code, notes, and snippets.

@merryhime
Created August 10, 2016 14:25
Show Gist options
  • Save merryhime/592f3f21450ea5e27798e1c4fdd25dfb to your computer and use it in GitHub Desktop.
Save merryhime/592f3f21450ea5e27798e1c4fdd25dfb to your computer and use it in GitHub Desktop.
package terraingen
var simplexPermutation [515]uint8
var simplexPermutationMod12 [515]uint8
func init() {
simplexPrecompute(0x12345678)
}
func simplexPrecompute(seed uint32) {
lfsr := makeLfsr(0x53494d50, 0x4c455830, seed)
// Here we use the Fisher–Yates shuffle to generate a random permutation
for i := 0; i < 256; i++ {
j := int(uint(lfsr.next()) % uint(i+1))
simplexPermutation[i] = simplexPermutation[j]
simplexPermutation[j] = uint8(i)
}
// We then duplicate the permutation to not have the need to check bounds
for i := 256; i < 515; i++ {
v := simplexPermutation[i-256]
simplexPermutation[i] = v
simplexPermutationMod12[i] = v % 12
simplexPermutationMod12[i-256] = v % 12
}
}
type simplexGradient struct {
x, y, z float32
}
var simplexGradients [12]simplexGradient = [12]simplexGradient{
{+1, +1, 0}, {+1, 0, +1}, {0, +1, +1},
{+1, -1, 0}, {+1, 0, -1}, {0, +1, -1},
{-1, +1, 0}, {-1, 0, +1}, {0, -1, +1},
{-1, -1, 0}, {-1, 0, -1}, {0, -1, -1},
}
func (g simplexGradient) dot(x, y, z float32) float32 {
return g.x*x + g.y*y + g.z*z
}
// Simplex noise is faster than perlin noise. In theory.
// In practice we have a super-optimized perlin variant.
// Based on http://webstaff.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf
// WARNING: The code below uses *both* (x,y,z) and (i,j,k) coordinate systems.
func simplex(x, y, z float32) float32 {
var i, j, k int32
// Do we want to skew or not?
skew1 := (x + y + z) * (1.0 / 3.0)
i, j, k = floor(x+skew1), floor(y+skew1), floor(z+skew1)
skew2 := float32(i+j+k) * (1.0 / 6.0)
x -= float32(i) - skew2
y -= float32(j) - skew2
z -= float32(k) - skew2
const corner0i, corner0j, corner0k = 0, 0, 0
var corner1i, corner1j, corner1k int
var corner2i, corner2j, corner2k int
const corner3i, corner3j, corner3k = 1, 1, 1
// Sort the coordinates
if x < y {
if y < z { // x < y < z
corner1i, corner1j, corner1k = 0, 0, 1
corner2i, corner2j, corner2k = 0, 1, 1
} else if z < x { // z < x < y
corner1i, corner1j, corner1k = 0, 1, 0
corner2i, corner2j, corner2k = 1, 1, 0
} else { // x < z < y
corner1i, corner1j, corner1k = 0, 1, 0
corner2i, corner2j, corner2k = 0, 1, 1
}
} else /* y < x */ {
if x < z { // y < x < z
corner1i, corner1j, corner1k = 0, 0, 1
corner2i, corner2j, corner2k = 1, 0, 1
} else if z < y { // z < y < x
corner1i, corner1j, corner1k = 1, 0, 0
corner2i, corner2j, corner2k = 1, 1, 0
} else { // y < z < x
corner1i, corner1j, corner1k = 1, 0, 0
corner2i, corner2j, corner2k = 1, 0, 1
}
}
x1, y1, z1 := x-float32(corner1i)+(1.0/6.0), y-float32(corner1j)+(1.0/6.0), z-float32(corner1k)+(1.0/6.0)
x2, y2, z2 := x-float32(corner2i)+(2.0/6.0), y-float32(corner2j)+(2.0/6.0), z-float32(corner2k)+(2.0/6.0)
x3, y3, z3 := x-float32(corner3i)+(3.0/6.0), y-float32(corner3j)+(3.0/6.0), z-float32(corner3k)+(3.0/6.0)
ii := int(i & 0xFF)
jj := int(j & 0xFF)
kk := int(k & 0xFF)
gi0 := simplexPermutationMod12[ii+corner0i+int(simplexPermutation[jj+corner0j+int(simplexPermutation[kk+corner0k])])]
gi1 := simplexPermutationMod12[ii+corner1i+int(simplexPermutation[jj+corner1j+int(simplexPermutation[kk+corner1k])])]
gi2 := simplexPermutationMod12[ii+corner2i+int(simplexPermutation[jj+corner2j+int(simplexPermutation[kk+corner2k])])]
gi3 := simplexPermutationMod12[ii+corner3i+int(simplexPermutation[jj+corner3j+int(simplexPermutation[kk+corner3k])])]
var n0, n1, n2, n3 float32
t0 := 0.6 - x*x - y*y - z*z
if t0 > 0 {
t0 *= t0
t0 *= t0
n0 = t0 * simplexGradients[gi0].dot(x, y, z)
} else {
n0 = 0
}
t1 := 0.6 - x1*x1 - y1*y1 - z1*z1
if t1 > 0 {
t1 *= t1
t1 *= t1
n1 = t1 * simplexGradients[gi1].dot(x1, y1, z1)
} else {
n1 = 0
}
t2 := 0.6 - x2*x2 - y2*y2 - z2*z2
if t2 > 0 {
t2 *= t2
t2 *= t2
n2 = t2 * simplexGradients[gi2].dot(x2, y2, z2)
} else {
n2 = 0
}
t3 := 0.6 - x3*x3 - y3*y3 - z3*z3
if t3 > 0 {
t3 *= t3
t3 *= t3
n3 = t3 * simplexGradients[gi3].dot(x3, y3, z3)
} else {
n3 = 0
}
return 32.0 * (n0 + n1 + n2 + n3)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment