Skip to content

Commit

Permalink
noise: add simplex noise (#207)
Browse files Browse the repository at this point in the history
* noise: add simplex 2d implementation

* noise: add simplex 1d/3d implementation

* noise: add simplex 4d implementation

* noise: fmt and clean

* noise: rename `Perlin` struct to `Generator` and add tests for simplex noise

* noise: add comments

* noise: examples

* noise: add fractal noise example

* noise: fmt

* Update README.md

* Update README.md

---------

Co-authored-by: Ulises Jeremias <[email protected]>
  • Loading branch information
PottierLoic and ulises-jeremias authored Aug 5, 2024
1 parent c76b097 commit ebaaf2d
Show file tree
Hide file tree
Showing 11 changed files with 597 additions and 43 deletions.
16 changes: 16 additions & 0 deletions examples/noise_fractal_2d/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Example - noise_fractal_2d 📘

This example demonstrates the usage of the V Scientific Library for generating pink noise.

## Instructions

1. Ensure you have the V compiler installed. You can download it from [here](https://vlang.io).
2. Ensure you have the VSL installed. You can do it following the [installation guide](https://github.com/vlang/vsl?tab=readme-ov-file#-installation)!
3. Navigate to this directory.
4. Run the example using the following command:

```sh
v run main.v
```

Enjoy exploring the capabilities of the V Scientific Library! 😊
54 changes: 54 additions & 0 deletions examples/noise_fractal_2d/main.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
module main

import rand
import vsl.noise
import vsl.plot

fn main() {
// Creation of the noise generator.
// Other noise functions and dimensions count are available.
rand.seed([u32(3155200429), u32(3208395956)])
mut generator := noise.Generator.new()
generator.randomize()

mut x := []f64{}
mut y := []f64{}
mut z := []f64{}

// 5 layers of simplex noise
octaves := 5
persistence := 0.5

for xx in 0 .. 200 {
for yy in 0 .. 200 {
mut total := 0.0
mut frequency := 1.0
mut amplitude := 1.0
mut max_value := 0.0

for _ in 0 .. octaves {
total += generator.simplex_2d(0.03 * xx * frequency, 0.03 * yy * frequency) * amplitude
max_value += amplitude
amplitude *= persistence
frequency *= 2.0
}

// Normalize to [-1, 1]
total /= max_value
x << xx
y << yy
z << total
}
}

mut plt := plot.Plot.new()
plt.heatmap(
x: x
y: y
z: z
)
plt.layout(
title: 'Pink `fractal` noise 2d example'
)
plt.show()!
}
16 changes: 16 additions & 0 deletions examples/noise_simplex_2d/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Example - noise_simple_2d 📘

This example demonstrates the usage of the V Scientific Library for generating simplex noise.

## Instructions

1. Ensure you have the V compiler installed. You can download it from [here](https://vlang.io).
2. Ensure you have the VSL installed. You can do it following the [installation guide](https://github.com/vlang/vsl?tab=readme-ov-file#-installation)!
3. Navigate to this directory.
4. Run the example using the following command:

```sh
v run main.v
```

Enjoy exploring the capabilities of the V Scientific Library! 😊
38 changes: 38 additions & 0 deletions examples/noise_simplex_2d/main.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module main

import rand
import vsl.noise
import vsl.plot

fn main() {
// Creation of the noise generator.
// Other noise functions and dimensions count are available.
rand.seed([u32(3155200429), u32(3208395956)])
mut generator := noise.Generator.new()
generator.randomize()

mut x := []f64{}
mut y := []f64{}
mut z := []f64{}

for xx in 0 .. 40 {
for yy in 0 .. 40 {
// We need to scale the coordinates to control the frequency of the noise.
val := generator.simplex_2d(0.03 * xx, 0.03 * yy)
x << xx
y << yy
z << val
}
}

mut plt := plot.Plot.new()
plt.heatmap(
x: x
y: y
z: z
)
plt.layout(
title: 'Simplex noise 2d example'
)
plt.show()!
}
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
Loading

0 comments on commit ebaaf2d

Please sign in to comment.