Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

noise: add simplex noise #207

Merged
merged 11 commits into from
Aug 5, 2024
Prev Previous commit
Next Next commit
noise: rename Perlin struct to Generator and add tests for simple…
…x noise
  • Loading branch information
PottierLoic committed Jul 8, 2024
commit 3f64daa88cd40f005bca114e8b58c5aca4efc849
20 changes: 20 additions & 0 deletions noise/noise.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module noise

import rand

// Generator is a struct holding the permutation table used in perlin and simplex noise
pub struct Generator {
mut:
perm []int = rand.shuffle_clone(permutations) or { panic(err) }
}

// new is a function that return a new Generator struct
pub fn Generator.new() Generator {
return Generator{}
}

// randomize is a function that shuffle the permutation set inside the Generator struct
// will not shuffle if rand.seed is not changed
pub fn (mut generator Generator) randomize() {
generator.perm = rand.shuffle_clone(permutations) or { panic(err) }
}
33 changes: 7 additions & 26 deletions noise/perlin2d.v
Original file line number Diff line number Diff line change
@@ -1,26 +1,7 @@
module noise

import rand

// Perlin is a struct that hold the permutation set for perlin noise
pub struct Perlin {
mut:
perm []int = rand.shuffle_clone(permutations) or { panic(err) }
}

// new is a function that return a new Perlin struct
pub fn Perlin.new() Perlin {
return Perlin{}
}

// randomize is a function that shuffle the permutation set inside the Perlin struct
// will not shuffle if rand.seed is not changed
pub fn (mut perlin Perlin) randomize() {
perlin.perm = rand.shuffle_clone(permutations) or { panic(err) }
}

// perlin2d is a function that return a single value of perlin noise for a given 2d position
pub fn (perlin Perlin) perlin2d(x f64, y f64) f64 {
pub fn (generator Generator) perlin2d(x f64, y f64) f64 {
xi := int(x) & 0xFF
yi := int(y) & 0xFF

Expand All @@ -30,13 +11,13 @@ pub fn (perlin Perlin) perlin2d(x f64, y f64) f64 {
u := fade(xf)
v := fade(yf)

pxi := perlin.perm[xi]
pxi1 := perlin.perm[xi + 1]
pxi := generator.perm[xi]
pxi1 := generator.perm[xi + 1]

aa := perlin.perm[pxi + yi]
ab := perlin.perm[pxi + yi + 1]
ba := perlin.perm[pxi1 + yi]
bb := perlin.perm[pxi1 + yi + 1]
aa := generator.perm[pxi + yi]
ab := generator.perm[pxi + yi + 1]
ba := generator.perm[pxi1 + yi]
bb := generator.perm[pxi1 + yi + 1]

x1 := lerp(grad2d(aa, xf, yf), grad2d(ba, xf - 1, yf), u)
x2 := lerp(grad2d(ab, xf, yf - 1), grad2d(bb, xf - 1, yf - 1), u)
Expand Down
2 changes: 1 addition & 1 deletion noise/perlin2d_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import vsl.float.float64
fn test_perlin2d() {
rand.seed([u32(3155200429), u32(3208395956)])

mut gen := Perlin.new()
mut gen := Generator.new()
gen.randomize()

result := gen.perlin2d(0.125, 0.125)
Expand Down
30 changes: 15 additions & 15 deletions noise/perlin3d.v
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module noise

// perlin3d is a function that return a single value of perlin noise for a given 3d position
pub fn (perlin Perlin) perlin3d(x f64, y f64, z f64) f64 {
pub fn (generator Generator) perlin3d(x f64, y f64, z f64) f64 {
xi := int(x) & 0xFF
yi := int(y) & 0xFF
zi := int(z) & 0xFF
Expand All @@ -12,21 +12,21 @@ pub fn (perlin Perlin) perlin3d(x f64, y f64, z f64) f64 {
v := fade(yf)
w := fade(zf)

pxi := perlin.perm[xi]
pxi_yi := perlin.perm[pxi + yi]
pxi_yi1 := perlin.perm[pxi + yi + 1]
pxi1 := perlin.perm[xi + 1]
pxi1_yi := perlin.perm[pxi1 + yi]
pxi1_yi1 := perlin.perm[pxi1 + yi + 1]
pxi := generator.perm[xi]
pxi_yi := generator.perm[pxi + yi]
pxi_yi1 := generator.perm[pxi + yi + 1]
pxi1 := generator.perm[xi + 1]
pxi1_yi := generator.perm[pxi1 + yi]
pxi1_yi1 := generator.perm[pxi1 + yi + 1]

aaa := perlin.perm[pxi_yi + zi]
aba := perlin.perm[pxi_yi1 + zi]
aab := perlin.perm[pxi_yi + zi + 1]
abb := perlin.perm[pxi_yi1 + zi + 1]
baa := perlin.perm[pxi1_yi + zi]
bba := perlin.perm[pxi1_yi1 + zi]
bab := perlin.perm[pxi1_yi + zi + 1]
bbb := perlin.perm[pxi1_yi1 + zi + 1]
aaa := generator.perm[pxi_yi + zi]
aba := generator.perm[pxi_yi1 + zi]
aab := generator.perm[pxi_yi + zi + 1]
abb := generator.perm[pxi_yi1 + zi + 1]
baa := generator.perm[pxi1_yi + zi]
bba := generator.perm[pxi1_yi1 + zi]
bab := generator.perm[pxi1_yi + zi + 1]
bbb := generator.perm[pxi1_yi1 + zi + 1]

mut x1 := lerp(grad3d(aaa, xf, yf, zf), grad3d(baa, xf - 1, yf, zf), u)
mut x2 := lerp(grad3d(aba, xf, yf - 1, zf), grad3d(bba, xf - 1, yf - 1, zf), u)
Expand Down
2 changes: 1 addition & 1 deletion noise/perlin3d_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import vsl.float.float64
fn test_perlin3d() {
rand.seed([u32(3155200429), u32(3208395956)])

mut gen := Perlin.new()
mut gen := Generator.new()
gen.randomize()

result := gen.perlin3d(0.125, 0.125, 0.125)
Expand Down
53 changes: 27 additions & 26 deletions noise/simplex.v
Original file line number Diff line number Diff line change
Expand Up @@ -86,25 +86,25 @@ fn grad_4d(hash int, x f64, y f64, z f64, t f64) f64 {
})
}

pub fn simplex_1d(x f64) f64 {
pub fn (generator Generator) simplex_1d(x f64) f64 {
i0 := int(x)
i1 := i0 + 1
x0 := x - i0
x1 := x0 - 1

mut t0 := 1.0 - x0 * x0
t0 *= t0
n0 := t0 * t0 * grad_1d(permutations[i0 & 0xff], x0)
n0 := t0 * t0 * grad_1d(generator.perm[i0 & 0xff], x0)

mut t1 := 1.0 - x1 * x1
t1 *= t1
n1 := t1 * t1 * grad_1d(permutations[i1 & 0xff], x1)
n1 := t1 * t1 * grad_1d(generator.perm[i1 & 0xff], x1)

// we scale it to [-1, 1]
return 0.395 * (n0 + n1)
}

pub fn simplex_2d(x f64, y f64) f64 {
pub fn (generator Generator) simplex_2d(x f64, y f64) f64 {
// skew the input space to determine which simplex cell we're in
s := (x + y) * noise.f2
i := int(x + s)
Expand Down Expand Up @@ -140,7 +140,7 @@ pub fn simplex_2d(x f64, y f64) f64 {
n0 = 0.0
} else {
t0 *= t0
n0 = t0 * t0 * grad_2d(permutations[ii + permutations[jj]], x0, y0)
n0 = t0 * t0 * grad_2d(generator.perm[ii + generator.perm[jj]], x0, y0)
}

mut t1 := 0.5 - x1 * x1 - y1 * y1
Expand All @@ -149,7 +149,8 @@ pub fn simplex_2d(x f64, y f64) f64 {
n1 = 0.0
} else {
t1 *= t1
n1 = t1 * t1 * grad_2d(permutations[ii + i1 + permutations[jj + j1]], x1, y1)
n1 = t1 * t1 * grad_2d(generator.perm[ii + i1 + generator.perm[jj + j1]], x1,
y1)
}

mut t2 := 0.5 - x2 * x2 - y2 * y2
Expand All @@ -158,14 +159,14 @@ pub fn simplex_2d(x f64, y f64) f64 {
n2 = 0.0
} else {
t2 *= t2
n2 = t2 * t2 * grad_2d(permutations[ii + 1 + permutations[jj + 1]], x2, y2)
n2 = t2 * t2 * grad_2d(generator.perm[ii + 1 + generator.perm[jj + 1]], x2, y2)
}

// scale the return value to [-1, 1]
return 40.0 * (n0 + n1 + n2)
}

pub fn simplex_3d(x f64, y f64, z f64) f64 {
pub fn (generator Generator) simplex_3d(x f64, y f64, z f64) f64 {
// skew the input space to determine which simplex cell we're in
s := (x + y + z) * noise.f3
xs := x + s
Expand Down Expand Up @@ -240,7 +241,7 @@ pub fn simplex_3d(x f64, y f64, z f64) f64 {
n0 = 0.0
} else {
t0 *= t0
n0 = t0 * t0 * grad_3d(permutations[ii + permutations[jj + permutations[kk]]],
n0 = t0 * t0 * grad_3d(generator.perm[ii + generator.perm[jj + generator.perm[kk]]],
x0, y0, z0)
}

Expand All @@ -250,8 +251,8 @@ pub fn simplex_3d(x f64, y f64, z f64) f64 {
n1 = 0.0
} else {
t1 *= t1
n1 = t1 * t1 * grad_3d(permutations[ii + i1 + permutations[jj + j1 + permutations[kk + k1]]],
x1, y1, z1)
n1 = t1 * t1 * grad_3d(generator.perm[ii + i1 + generator.perm[jj + j1 + generator.perm[kk +
k1]]], x1, y1, z1)
}

mut t2 := 0.6 - x2 * x2 - y2 * y2 - z2 * z2
Expand All @@ -260,8 +261,8 @@ pub fn simplex_3d(x f64, y f64, z f64) f64 {
n2 = 0.0
} else {
t2 *= t2
n2 = t2 * t2 * grad_3d(permutations[ii + i2 + permutations[jj + j2 + permutations[kk + k2]]],
x2, y2, z2)
n2 = t2 * t2 * grad_3d(generator.perm[ii + i2 + generator.perm[jj + j2 + generator.perm[kk +
k2]]], x2, y2, z2)
}

mut t3 := 0.6 - x3 * x3 - y3 * y3 - z3 * z3
Expand All @@ -270,15 +271,15 @@ pub fn simplex_3d(x f64, y f64, z f64) f64 {
n3 = 0.0
} else {
t3 *= t3
n3 = t3 * t3 * grad_3d(permutations[ii + 1 + permutations[jj + 1 + permutations[kk + 1]]],
x3, y3, z3)
n3 = t3 * t3 * grad_3d(generator.perm[ii + 1 + generator.perm[jj + 1 + generator.perm[kk +
1]]], x3, y3, z3)
}

// scale the return value to [-1, 1]
return 32.0 * (n0 + n1 + n2 + n3)
}

pub fn simplex_4d(x f64, y f64, z f64, w f64) f64 {
pub fn (generator Generator) simplex_4d(x f64, y f64, z f64, w f64) f64 {
s := (x + y + z + w) * noise.f4
xs := x + s
ys := y + s
Expand Down Expand Up @@ -346,8 +347,8 @@ pub fn simplex_4d(x f64, y f64, z f64, w f64) f64 {
n0 = 0.0
} else {
t0 *= t0
n0 = t0 * t0 * grad_4d(permutations[ii + permutations[jj + permutations[kk +
permutations[ll]]]], x0, y0, z0, w0)
n0 = t0 * t0 * grad_4d(generator.perm[ii + generator.perm[jj + generator.perm[kk +
generator.perm[ll]]]], x0, y0, z0, w0)
}

mut t1 := 0.6 - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1
Expand All @@ -356,8 +357,8 @@ pub fn simplex_4d(x f64, y f64, z f64, w f64) f64 {
n1 = 0.0
} else {
t1 *= t1
n1 = t1 * t1 * grad_4d(permutations[ii + i1 + permutations[jj + j1 + permutations[kk + k1 +
permutations[ll + l1]]]], x1, y1, z1, w1)
n1 = t1 * t1 * grad_4d(generator.perm[ii + i1 + generator.perm[jj + j1 + generator.perm[kk +
k1 + generator.perm[ll + l1]]]], x1, y1, z1, w1)
}

mut t2 := 0.6 - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2
Expand All @@ -366,8 +367,8 @@ pub fn simplex_4d(x f64, y f64, z f64, w f64) f64 {
n2 = 0.0
} else {
t2 *= t2
n2 = t2 * t2 * grad_4d(permutations[ii + i2 + permutations[jj + j2 + permutations[kk + k2 +
permutations[ll + l2]]]], x2, y2, z2, w2)
n2 = t2 * t2 * grad_4d(generator.perm[ii + i2 + generator.perm[jj + j2 + generator.perm[kk +
k2 + generator.perm[ll + l2]]]], x2, y2, z2, w2)
}

mut t3 := 0.6 - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3
Expand All @@ -376,8 +377,8 @@ pub fn simplex_4d(x f64, y f64, z f64, w f64) f64 {
n3 = 0.0
} else {
t3 *= t3
n3 = t3 * t3 * grad_4d(permutations[ii + i3 + permutations[jj + j3 + permutations[kk + k3 +
permutations[ll + l3]]]], x3, y3, z3, w3)
n3 = t3 * t3 * grad_4d(generator.perm[ii + i3 + generator.perm[jj + j3 + generator.perm[kk +
k3 + generator.perm[ll + l3]]]], x3, y3, z3, w3)
}

mut t4 := 0.6 - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4
Expand All @@ -386,8 +387,8 @@ pub fn simplex_4d(x f64, y f64, z f64, w f64) f64 {
n4 = 0.0
} else {
t4 *= t4
n4 = t4 * t4 * grad_4d(permutations[ii + 1 + permutations[jj + 1 + permutations[kk + 1 +
permutations[ll + 1]]]], x4, y4, z4, w4)
n4 = t4 * t4 * grad_4d(generator.perm[ii + 1 + generator.perm[jj + 1 + generator.perm[kk +
1 + generator.perm[ll + 1]]]], x4, y4, z4, w4)
}

return 27.0 * (n0 + n1 + n2 + n3 + n4)
Expand Down
40 changes: 40 additions & 0 deletions noise/simplex_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module noise

import rand
import vsl.float.float64

fn test_simplex_1d() {
rand.seed([u32(3155200429), u32(3208395956)])
mut generator := Generator.new()
generator.randomize()
result := generator.simplex_1d(0.287)
expected := -0.3544283326507284
assert float64.tolerance(result, expected, 1.0e-6)
}

fn test_simplex_2d() {
rand.seed([u32(3075200429), u32(3094395956)])
mut generator := Generator.new()
generator.randomize()
result := generator.simplex_2d(0.287, 0.475)
expected := -0.09948661872545192
assert float64.tolerance(result, expected, 1.0e-6)
}

fn test_simplex_3d() {
rand.seed([u32(3155200429), u32(3208395956)])
mut generator := Generator.new()
generator.randomize()
result := generator.simplex_3d(0.287, 0.475, 1.917)
expected := -0.06034653476116279
assert float64.tolerance(result, expected, 1.0e-6)
}

fn test_simplex_4d() {
rand.seed([u32(3075200429), u32(3094395956)])
mut generator := Generator.new()
generator.randomize()
result := generator.simplex_4d(0.287, 0.475, 1.917, 0.684)
expected := 0.015098415881100141
assert float64.tolerance(result, expected, 1.0e-6)
}
Loading