Add 1d noise versions, Gaussian noise, noise gradients, 4D fractal functions

This commit is contained in:
Edwin Jakobs
2020-03-12 12:40:12 +01:00
parent 5b0775289c
commit eff96bac94
13 changed files with 538 additions and 164 deletions

View File

@@ -1,128 +1,161 @@
# orx-noise # orx-noise
A collection of noisy functions A collection of noisy functions
## Uniform random numbers ## Uniform random numbers
```kotlin ```kotlin
val sua = Double.uniform() val sua = Double.uniform()
val sub = Double.uniform(-1.0, 1.0) val sub = Double.uniform(-1.0, 1.0)
val v2ua = Vector2.uniform() val v2ua = Vector2.uniform()
val v2ub = Vector2.uniform(-1.0, 1.0) val v2ub = Vector2.uniform(-1.0, 1.0)
val v2uc = Vector2.uniform(Vector2(0.0, 0.0), Vector2(1.0, 1.0)) val v2uc = Vector2.uniform(Vector2(0.0, 0.0), Vector2(1.0, 1.0))
val v2ur = Vector2.uniformRing(0.5, 1.0) val v2ur = Vector2.uniformRing(0.5, 1.0)
val v3ua = Vector3.uniform() val v3ua = Vector3.uniform()
val v3ub = Vector3.uniform(-1.0, 1.0) val v3ub = Vector3.uniform(-1.0, 1.0)
val v3uc = Vector3.uniform(Vector3(0.0, 0.0, 0.0), Vector3(1.0, 1.0, 1.0)) val v3uc = Vector3.uniform(Vector3(0.0, 0.0, 0.0), Vector3(1.0, 1.0, 1.0))
val v3ur = Vector3.uniformRing(0.5, 1.0) val v3ur = Vector3.uniformRing(0.5, 1.0)
val v4ua = Vector4.uniform() val v4ua = Vector4.uniform()
val v4ub = Vector4.uniform(-1.0, 1.0) val v4ub = Vector4.uniform(-1.0, 1.0)
val v4uc = Vector4.uniform(Vector4(0.0, 0.0, 0.0, 0.0), Vector4(1.0, 1.0, 1.0, 1.0)) val v4uc = Vector4.uniform(Vector4(0.0, 0.0, 0.0, 0.0), Vector4(1.0, 1.0, 1.0, 1.0))
val v4ur = Vector4.uniformRing(0.5, 1.0) val v4ur = Vector4.uniformRing(0.5, 1.0)
val ringSamples = List(500) { Vector2.uniformRing() } val ringSamples = List(500) { Vector2.uniformRing() }
``` ```
## Multi-dimensional noise ## Multi-dimensional noise
These are a mostly straight port from FastNoise-Java but have a slightly different interface. These are a mostly straight port from FastNoise-Java but have a slightly different interface.
### Perlin noise ### Perlin noise
``` ```
// -- 2d // -- 1d
val v0 = perlinLinear(seed, x, y) val v0 = perlinLinear(seed, x)
val v1 = perlinQuintic(seed, x, y) val v1 = perlinQuintic(seed, x)
val v2 = perlinHermite(seed, x, y) val v2 = perlinHermite(seed, x)
// -- 3d // -- 2d
val v3 = perlinLinear(seed, x, y, z) val v3 = perlinLinear(seed, x, y)
val v4 = perlinQuintic(seed, x, y, z) val v4 = perlinQuintic(seed, x, y)
val v5 = perlinHermite(seed, x, y, z) val v5 = perlinHermite(seed, x, y)
```
// -- 3d
### Value noise val v6 = perlinLinear(seed, x, y, z)
``` val v7 = perlinQuintic(seed, x, y, z)
// -- 2d val v8 = perlinHermite(seed, x, y, z)
val v0 = valueLinear(seed, x, y) ```
val v1 = valueQuintic(seed, x, y)
val v2 = valueHermite(seed, x, y) ### Value noise
```
// -- 3d // -- 1d
val v3 = valueLinear(seed, x, y, z) val v0 = valueLinear(seed, x)
val v4 = valueQuintic(seed, x, y, z) val v1 = valueQuintic(seed, x)
val v5 = valueHermite(seed, x, y ,z) val v2 = valueHermite(seed, x)
```
// -- 2d
### Simplex noise val v2 = valueLinear(seed, x, y)
``` val v3 = valueQuintic(seed, x, y)
// -- 2d val v4 = valueHermite(seed, x, y)
val v0 = simplexLinear(seed, x, y)
val v1 = simplexQuintic(seed, x, y) // -- 3d
val v2 = simplexHermite(seed, x, y) val v5 = valueLinear(seed, x, y, z)
val v6 = valueQuintic(seed, x, y, z)
// -- 3d val v7 = valueHermite(seed, x, y ,z)
val v3 = simplexLinear(seed, x, y, z) ```
val v4 = simplexQuintic(seed, x, y, z)
val v5 = simplexHermite(seed, x, y ,z) ### Simplex noise
```
// -- 4d // -- 1d
val v6 = simplexLinear(seed, x, y, z, w) val v0 = simplex(seed, x)
val v7 = simplexQuintic(seed, x, y, z, w)
val v8 = simplexHermite(seed, x, y, z, w) // -- 2d
``` val v1 = simplex(seed, x, y)
### Cubic noise // -- 3d
``` val v2 = simplex(seed, x, y, z)
// -- 2d
val v0 = cubicLinear(seed, x, y) // -- 4d
val v1 = cubicQuintic(seed, x, y) val v3 = simplex(seed, x, y, z, w)
val v2 = cubicHermite(seed, x, y) ```
// -- 3d ### Cubic noise
val v3 = cubicLinear(seed, x, y, z) ```
val v4 = cubicQuintic(seed, x, y, z) // -- 1d
val v5 = cubicHermite(seed, x, y ,z) val v0 = cubic(seed, x, y)
``` val v1 = cubicQuintic(seed, x, y)
val v2 = cubicHermite(seed, x, y)
### Fractal noise
// -- 2d
The library provides 3 functions with which fractal noise can be composed. val v0 = cubic(seed, x, y)
val v1 = cubicQuintic(seed, x, y)
#### Fractal brownian motion (FBM) val v2 = cubicHermite(seed, x, y)
``` // -- 3d
val v0 = fbm(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) val v3 = cubic(seed, x, y, z)
val v1 = fbm(seed, x, y, ::simplexLinear, octaves, lacunarity, gain) val v4 = cubicQuintic(seed, x, y, z)
val v2 = fbm(seed, x, y, ::valueLinear, octaves, lacunarity, gain) val v5 = cubicHermite(seed, x, y ,z)
```
val v3 = fbm(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain)
val v4 = fbm(seed, x, y, z, ::simplexLinear, octaves, lacunarity, gain) ### Fractal noise
val v5 = fbm(seed, x, y, z, ::valueLinear, octaves, lacunarity, gain)
``` The library provides 3 functions with which fractal noise can be composed.
#### Rigid #### Fractal brownian motion (FBM)
``` ```
val v0 = rigid(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) // 1d
val v1 = rigid(seed, x, y, ::simplexLinear, octaves, lacunarity, gain) val v0 = fbm(seed, x, ::perlinLinear, octaves, lacunarity, gain)
val v2 = rigid(seed, x, y, ::valueLinear, octaves, lacunarity, gain) val v1 = fbm(seed, x, ::simplexLinear, octaves, lacunarity, gain)
val v2 = fbm(seed, x, ::valueLinear, octaves, lacunarity, gain)
val v3 = rigid(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain)
val v4 = rigid(seed, x, y, z, ::simplexLinear, octaves, lacunarity, gain) // 2d
val v5 = rigid(seed, x, y, z, ::valueLinear, octaves, lacunarity, gain) val v3 = fbm(seed, x, y, ::perlinLinear, octaves, lacunarity, gain)
``` val v4 = fbm(seed, x, y, ::simplexLinear, octaves, lacunarity, gain)
val v5 = fbm(seed, x, y, ::valueLinear, octaves, lacunarity, gain)
#### Billow
// 3d
``` val v6 = fbm(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain)
val v0 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) val v7 = fbm(seed, x, y, z, ::simplexLinear, octaves, lacunarity, gain)
val v1 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) val v8 = fbm(seed, x, y, z, ::valueLinear, octaves, lacunarity, gain)
val v2 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) ```
val v3 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) #### Rigid
val v4 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain)
val v5 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) ```
``` // 1d
val v0 = rigid(seed, x, ::perlinLinear, octaves, lacunarity, gain)
val v1 = rigid(seed, x, ::simplexLinear, octaves, lacunarity, gain)
val v2 = rigid(seed, x, ::valueLinear, octaves, lacunarity, gain)
// 2d
val v2 = rigid(seed, x, y, ::perlinLinear, octaves, lacunarity, gain)
val v3 = rigid(seed, x, y, ::simplexLinear, octaves, lacunarity, gain)
val v4 = rigid(seed, x, y, ::valueLinear, octaves, lacunarity, gain)
// 3d
val v3 = rigid(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain)
val v4 = rigid(seed, x, y, z, ::simplexLinear, octaves, lacunarity, gain)
val v5 = rigid(seed, x, y, z, ::valueLinear, octaves, lacunarity, gain)
```
#### Billow
```
// 1d
val v0 = billow(seed, x, ::perlinLinear, octaves, lacunarity, gain)
val v1 = billow(seed, x, ::perlinLinear, octaves, lacunarity, gain)
val v2 = billow(seed, x, ::perlinLinear, octaves, lacunarity, gain)
// 2d
val v3 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain)
val v4 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain)
val v5 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain)
// 3d
val v6 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain)
val v7 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain)
val v8 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain)
```

View File

@@ -0,0 +1,10 @@
package org.openrndr.extra.noise
fun cubicLinear(seed: Int, x: Double) = cubic(seed, x, ::linear)
fun cubicQuintic(seed: Int, x: Double) = cubic(seed, x, ::quintic)
fun cubicHermite(seed: Int, x: Double) = cubic(seed, x, ::hermite)
fun cubic(seed: Int, x: Double, interpolator: (Double) -> Double = ::linear): Double {
return cubic(seed, x, 0.0, interpolator)
}

View File

@@ -1,5 +1,28 @@
package org.openrndr.extra.noise package org.openrndr.extra.noise
import kotlin.math.abs
inline fun fbm(seed: Int, x: Double, y: Double, z: Double, w: Double, crossinline noise: (Int, Double, Double, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
var sum = noise(seed, x, y, z, w)
var amp = 1.0
var x = x
var y = y
var z = z
var w = w
for (i in 1 until octaves) {
x *= lacunarity
y *= lacunarity
z *= lacunarity
w *= lacunarity
amp *= gain
sum += noise(seed + i, x, y, z, w) * amp
}
return sum
}
inline fun fbm(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double, inline fun fbm(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
var sum = noise(seed, x, y, z) var sum = noise(seed, x, y, z)
@@ -18,7 +41,6 @@ inline fun fbm(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (I
return sum return sum
} }
inline fun fbm(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double, Double) -> Double, inline fun fbm(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
var sum = noise(seed, x, y) var sum = noise(seed, x, y)
@@ -35,6 +57,66 @@ inline fun fbm(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double,
return sum return sum
} }
inline fun fbm(seed: Int, x: Double, crossinline noise: (Int, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
var sum = noise(seed, x)
var amp = 1.0
var x = x
for (i in 1 until octaves) {
x *= lacunarity
amp *= gain
sum += noise(seed + i, x) * amp
}
return sum
}
inline fun fbmFunc1D(crossinline noise: (Int, Double) -> Double, octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): (Int, Double) -> Double {
return { seed, x ->
fbm(seed, x, noise, octaves, lacunarity, gain)
}
}
inline fun fbmFunc2D(crossinline noise: (Int, Double, Double) -> Double, octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): (Int, Double, Double) -> Double {
return { seed, x, y ->
fbm(seed, x, y, noise, octaves, lacunarity, gain)
}
}
inline fun fbmFunc3D(crossinline noise: (Int, Double, Double, Double) -> Double, octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): (Int, Double, Double, Double) -> Double {
return { seed, x, y, z ->
fbm(seed, x, y, z, noise, octaves, lacunarity, gain)
}
}
inline fun fbmFunc4D(crossinline noise: (Int, Double, Double, Double, Double) -> Double, octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): (Int, Double, Double, Double, Double) -> Double {
return { seed, x, y, z, w ->
fbm(seed, x, y, z, w, noise, octaves, lacunarity, gain)
}
}
inline fun billow(seed: Int, x: Double, y: Double, z: Double, w: Double, crossinline noise: (Int, Double, Double, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
var sum = Math.abs(noise(seed, x, y, z, w) * 2.0 - 1.0)
var amp = 1.0
var x = x
var y = y
var z = z
var w = w
for (i in 1 until octaves) {
x *= lacunarity
y *= lacunarity
z *= lacunarity
w *= lacunarity
amp *= gain
sum += Math.abs(noise(seed + i, x, y, z, w) * 2.0 - 1.0) * amp
}
return sum
}
inline fun billow(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double, inline fun billow(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
var sum = Math.abs(noise(seed, x, y, z) * 2.0 - 1.0) var sum = Math.abs(noise(seed, x, y, z) * 2.0 - 1.0)
@@ -55,7 +137,7 @@ inline fun billow(seed: Int, x: Double, y: Double, z: Double, crossinline noise:
inline fun billow(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double, Double) -> Double, inline fun billow(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
var sum = Math.abs(noise(seed, x, y) * 2.0 - 1.0) var sum = abs(noise(seed, x, y) * 2.0 - 1.0)
var amp = 1.0 var amp = 1.0
var x = x var x = x
@@ -64,7 +146,83 @@ inline fun billow(seed: Int, x: Double, y: Double, crossinline noise: (Int, Doub
x *= lacunarity x *= lacunarity
y *= lacunarity y *= lacunarity
amp *= gain amp *= gain
sum += Math.abs(noise(seed + i, x, y) * 2.0 - 1.0) * amp sum += abs(noise(seed + i, x, y) * 2.0 - 1.0) * amp
}
return sum
}
inline fun billow(seed: Int, x: Double, crossinline noise: (Int, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
var sum = abs(noise(seed, x) * 2.0 - 1.0)
var amp = 1.0
var x = x
for (i in 1 until octaves) {
x *= lacunarity
amp *= gain
sum += abs(noise(seed + i, x) * 2.0 - 1.0) * amp
}
return sum
}
inline fun billowFunc1D(crossinline noise: (Int, Double) -> Double, octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): (Int, Double) -> Double {
return { seed, x ->
billow(seed, x, noise, octaves, lacunarity, gain)
}
}
inline fun billowFunc2D(crossinline noise: (Int, Double, Double) -> Double, octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): (Int, Double, Double) -> Double {
return { seed, x, y ->
billow(seed, x, y, noise, octaves, lacunarity, gain)
}
}
inline fun billowFunc3D(crossinline noise: (Int, Double, Double, Double) -> Double, octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): (Int, Double, Double, Double) -> Double {
return { seed, x, y, z ->
billow(seed, x, y, z, noise, octaves, lacunarity, gain)
}
}
inline fun billowFunc4D(crossinline noise: (Int, Double, Double, Double, Double) -> Double, octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): (Int, Double, Double, Double, Double) -> Double {
return { seed, x, y, z, w ->
billow(seed, x, y, z, w, noise, octaves, lacunarity, gain)
}
}
inline fun rigid(seed: Int, x: Double, y: Double, z: Double, w: Double, crossinline noise: (Int, Double, Double, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
var sum = 1.0 - Math.abs(noise(seed, x, y, z, w))
var amp = 1.0
var x = x
var y = y
var z = z
var w = w
for (i in 1 until octaves) {
x *= lacunarity
y *= lacunarity
z *= lacunarity
w *= lacunarity
amp *= gain
sum -= (1.0 - abs(noise(seed + i, x, y, z, w))) * amp
}
return sum
}
inline fun rigid(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
var sum = 1.0 - Math.abs(noise(seed, x, y, z))
var amp = 1.0
var x = x
var y = y
var z = z
for (i in 1 until octaves) {
x *= lacunarity
y *= lacunarity
z *= lacunarity
amp *= gain
sum -= (1.0 - abs(noise(seed + i, x, y, z))) * amp
} }
return sum return sum
} }
@@ -85,21 +243,40 @@ inline fun rigid(seed: Int, x: Double, y: Double, crossinline noise: (Int, Doubl
return sum return sum
} }
inline fun rigid(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double, inline fun rigid(seed: Int, x: Double, crossinline noise: (Int, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
var sum = 1.0 - Math.abs(noise(seed, x, y, z)) var sum = 1.0 - abs(noise(seed, x))
var amp = 1.0 var amp = 1.0
var x = x var x = x
var y = y
var z = z
for (i in 1 until octaves) { for (i in 1 until octaves) {
x *= lacunarity x *= lacunarity
y *= lacunarity
z *= lacunarity
amp *= gain amp *= gain
sum -= (1.0 - Math.abs(noise(seed + i, x, y, z))) * amp sum -= (1.0 - abs(noise(seed + i, x))) * amp
} }
return sum return sum
} }
inline fun rigidFunc1D(crossinline noise: (Int, Double) -> Double, octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): (Int, Double) -> Double {
return { seed, x ->
rigid(seed, x, noise, octaves, lacunarity, gain)
}
}
inline fun rigidFunc2D(crossinline noise: (Int, Double, Double) -> Double, octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): (Int, Double, Double) -> Double {
return { seed, x, y ->
rigid(seed, x, y, noise, octaves, lacunarity, gain)
}
}
inline fun rigidFunc3D(crossinline noise: (Int, Double, Double, Double) -> Double, octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): (Int, Double, Double, Double) -> Double {
return { seed, x, y, z ->
rigid(seed, x, y, z, noise, octaves, lacunarity, gain)
}
}
inline fun rigidFunc4D(crossinline noise: (Int, Double, Double, Double, Double) -> Double, octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): (Int, Double, Double, Double, Double) -> Double {
return { seed, x, y, z, w ->
rigid(seed, x, y, z, w, noise, octaves, lacunarity, gain)
}
}

View File

@@ -0,0 +1,37 @@
package org.openrndr.extra.noise
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.random.Random
fun gaussian(mean: Double = 0.0, deviation: Double = 1.0, random: Random = Random.Default): Double {
var v1: Double
var v2: Double
var s: Double
do {
v1 = 2 * random.nextDouble() - 1
v2 = 2 * random.nextDouble() - 1
s = v1 * v1 + v2 * v2
} while (s >= 1 || s == 0.0)
val multiplier = StrictMath.sqrt(-2 * StrictMath.log(s) / s)
return v1 * multiplier * deviation + mean
}
fun Double.Companion.gaussian(mean: Double = 0.0, deviation: Double = 1.0, random: Random = Random.Default): Double {
return gaussian(mean, deviation, random)
}
fun Vector2.Companion.gaussian(mean: Vector2 = Vector2.ZERO, deviation: Vector2 = Vector2.ONE, random: Random = Random.Default): Vector2 {
return Vector2(gaussian(mean.x, deviation.x, random), gaussian(mean.y, deviation.y, random))
}
fun Vector3.Companion.gaussian(mean: Vector3 = Vector3.ZERO, deviation: Vector3 = Vector3.ONE, random: Random = Random.Default): Vector3 {
return Vector3(gaussian(mean.x, deviation.x, random), gaussian(mean.y, deviation.y, random), gaussian(mean.z, deviation.z, random))
}
fun Vector4.Companion.gaussian(mean: Vector4 = Vector4.ZERO, deviation: Vector4 = Vector4.ONE, random: Random = Random.Default): Vector4 {
return Vector4(gaussian(mean.x, deviation.x, random), gaussian(mean.y, deviation.y, random), gaussian(mean.z, deviation.z, random), gaussian(mean.w, deviation.w, random))
}

View File

@@ -0,0 +1,72 @@
package org.openrndr.extra.noise
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
inline fun gradient(
crossinline noise: (seed: Int, x: Double) -> Double,
seed: Int,
x: Double,
epsilon: Double = 0.01
): Double {
val xn = noise(seed, x - epsilon)
val xp = noise(seed, x + epsilon)
return (xp - xn) / (2.0 * epsilon)
}
inline fun gradient(
crossinline noise: (seed: Int, x: Double, y: Double) -> Double,
seed: Int,
x: Double,
y: Double,
epsilon: Double = 0.01
): Vector2 {
val xn = noise(seed, x - epsilon, y)
val xp = noise(seed, x + epsilon, y)
val yn = noise(seed, x, y - epsilon)
val yp = noise(seed, x, y + epsilon)
return Vector2((xp - xn) / (2.0 * epsilon), (yp - yn) / (2.0 * epsilon))
}
inline fun gradient(
crossinline noise: (seed: Int, x: Double, y: Double, z: Double) -> Double,
seed: Int,
x: Double,
y: Double,
z: Double,
epsilon: Double = 0.01
): Vector3 {
val xn = noise(seed, x - epsilon, y, z)
val xp = noise(seed, x + epsilon, y, z)
val yn = noise(seed, x, y - epsilon, z)
val yp = noise(seed, x, y + epsilon, z)
val zn = noise(seed, x, y, z - epsilon)
val zp = noise(seed, x, y, z + epsilon)
return Vector3((xp - xn) / (2.0 * epsilon), (yp - yn) / (2.0 * epsilon), (zp - zn) / (2.0 * epsilon))
}
inline fun gradient(
crossinline noise: (seed: Int, x: Double, y: Double, z: Double, w: Double) -> Double,
seed: Int,
x: Double,
y: Double,
z: Double,
w: Double,
epsilon: Double = 0.01
): Vector4 {
val xn = noise(seed, x - epsilon, y, z, w)
val xp = noise(seed, x + epsilon, y, z, w)
val yn = noise(seed, x, y - epsilon, z, w)
val yp = noise(seed, x, y + epsilon, z, w)
val zn = noise(seed, x, y, z - epsilon, w)
val zp = noise(seed, x, y, z + epsilon, w)
val wn = noise(seed, x, y, z, w - epsilon)
val wp = noise(seed, x, y, z, w + epsilon)
return Vector4(
(xp - xn) / (2.0 * epsilon),
(yp - yn) / (2.0 * epsilon),
(zp - zn) / (2.0 * epsilon),
(wp - wn) / (2.0 * epsilon)
)
}

View File

@@ -0,0 +1,9 @@
package org.openrndr.extra.noise
fun perlin(seed: Int, x: Double) = perlin(seed, x, ::linear)
fun perlinLinear(seed: Int, x: Double) = perlin(seed, x, ::linear)
fun perlinQuintic(seed: Int, x: Double) = perlin(seed, x, ::quintic)
fun perlinHermite(seed: Int, x: Double) = perlin(seed, x, ::hermite)
inline fun perlin(seed: Int, x: Double, crossinline interpolator: (Double) -> Double): Double =
perlin(seed, x, 0.0, interpolator)

View File

@@ -0,0 +1,3 @@
package org.openrndr.extra.noise
fun simplex(seed: Int, x: Double): Double = simplex(seed, x, 0.0)

View File

@@ -3,11 +3,7 @@ package org.openrndr.extra.noise
private const val G2 = 1.0 / 4.0 private const val G2 = 1.0 / 4.0
private const val F2 = 1.0 / 2.0 private const val F2 = 1.0 / 2.0
fun simplexLinear(seed: Int, x: Double, y: Double) = simplex(seed, x, y, ::linear) fun simplex(seed: Int, x: Double, y: Double): Double {
fun simplexQuintic(seed: Int, x: Double, y: Double) = simplex(seed, x, y, ::quintic)
fun simplexHermite(seed: Int, x: Double, y: Double) = simplex(seed, x, y, ::hermite)
fun simplex(seed: Int, x: Double, y: Double, interpolator: (Double) -> Double = ::linear): Double {
var t = (x + y) * F2 var t = (x + y) * F2
val i = (x + t).fastFloor() val i = (x + t).fastFloor()
val j = (y + t).fastFloor() val j = (y + t).fastFloor()
@@ -16,8 +12,8 @@ fun simplex(seed: Int, x: Double, y: Double, interpolator: (Double) -> Double =
val X0 = i - t val X0 = i - t
val Y0 = j - t val Y0 = j - t
val x0 = interpolator(x - X0) val x0 = x - X0
val y0 = interpolator(y - Y0) val y0 = y - Y0
val i1: Int val i1: Int
val j1: Int val j1: Int
@@ -29,10 +25,10 @@ fun simplex(seed: Int, x: Double, y: Double, interpolator: (Double) -> Double =
j1 = 1 j1 = 1
} }
val x1 = x0 - i1 + G2 val x1 = (x0 - i1 + G2)
val y1 = y0 - j1 + G2 val y1 = (y0 - j1 + G2)
val x2 = x0 - 1 + F2 val x2 = (x0 - 1 + F2)
val y2 = y0 - 1 + F2 val y2 = (y0 - 1 + F2)
val n0: Double val n0: Double
val n1: Double val n1: Double

View File

@@ -1,10 +1,7 @@
package org.openrndr.extra.noise package org.openrndr.extra.noise
fun simplexLinear(seed: Int, x: Double, y: Double, z: Double) = simplex(seed, x, y, z, ::linear)
fun simplexQuintic(seed: Int, x: Double, y: Double, z: Double) = simplex(seed, x, y, z, ::quintic)
fun simplexHermite(seed: Int, x: Double, y: Double, z: Double) = simplex(seed, x, y, z, ::hermite)
fun simplex(seed: Int, x: Double, y: Double, z: Double, interpolator: (Double) -> Double = ::linear): Double { fun simplex(seed: Int, x: Double, y: Double, z: Double): Double {
val t = (x + y + z) / 3.0 val t = (x + y + z) / 3.0
val i = (x + t).fastFloor() val i = (x + t).fastFloor()
@@ -12,9 +9,9 @@ fun simplex(seed: Int, x: Double, y: Double, z: Double, interpolator: (Double) -
val k = (z + t).fastFloor() val k = (z + t).fastFloor()
val t2 = (i + j + k) / 6.0 val t2 = (i + j + k) / 6.0
val x0 = interpolator(x - (i - t2)) val x0 = x - (i - t2)
val y0 = interpolator(y - (j - t2)) val y0 = y - (j - t2)
val z0 = interpolator(z - (k - t2)) val z0 = z - (k - t2)
val i1: Int val i1: Int
val j1: Int val j1: Int

View File

@@ -14,11 +14,8 @@ private val SIMPLEX_4D = byteArrayOf(
private const val F4 = ((2.23606797 - 1.0) / 4.0) private const val F4 = ((2.23606797 - 1.0) / 4.0)
private const val G4 = ((5.0 - 2.23606797) / 20.0) private const val G4 = ((5.0 - 2.23606797) / 20.0)
fun simplexLinear(seed: Int, x: Double, y: Double, z: Double, w: Double) = simplex(seed, x, y, z, w, ::linear)
fun simplexQuintic(seed: Int, x: Double, y: Double, z: Double, w: Double) = simplex(seed, x, y, z, w, ::quintic)
fun simplexHermite(seed: Int, x: Double, y: Double, z: Double, w: Double) = simplex(seed, x, y, z, w, ::hermite)
fun simplex(seed: Int, x: Double, y: Double, z: Double, w: Double, interpolator: (Double) -> Double = ::linear): Double { fun simplex(seed: Int, x: Double, y: Double, z: Double, w: Double): Double {
var t = (x + y + z + w) * F4 var t = (x + y + z + w) * F4
val i = (x + t).fastFloor() val i = (x + t).fastFloor()
@@ -27,10 +24,10 @@ fun simplex(seed: Int, x: Double, y: Double, z: Double, w: Double, interpolator:
val l = (w + t).fastFloor() val l = (w + t).fastFloor()
val t2 = (i + j + k + l) * G4 val t2 = (i + j + k + l) * G4
val x0 = interpolator(x - (i - t2)) val x0 = x - (i - t2)
val y0 = interpolator(y - (j - t2)) val y0 = y - (j - t2)
val z0 = interpolator(z - (k - t2)) val z0 = z - (k - t2)
val w0 = interpolator(w - (l - t2)) val w0 = w - (l - t2)
var c = if (x0 > y0) 32 else 0 var c = if (x0 > y0) 32 else 0
c += if (x0 > z0) 16 else 0 c += if (x0 > z0) 16 else 0

View File

@@ -9,6 +9,8 @@ fun random(min: Double = -1.0, max: Double = 1.0, random: Random = Random.Defaul
return (random.nextDouble() * (max - min)) + min return (random.nextDouble() * (max - min)) + min
} }
fun Double.Companion.uniform(min: Double = -1.0, max: Double = 1.0, random: Random = Random.Default): Double { fun Double.Companion.uniform(min: Double = -1.0, max: Double = 1.0, random: Random = Random.Default): Double {
return (random.nextDouble() * (max - min)) + min return (random.nextDouble() * (max - min)) + min
} }

View File

@@ -0,0 +1,8 @@
package org.openrndr.extra.noise
fun valueLinear(seed: Int, x: Double) = value(seed, x, ::linear)
fun valueQuintic(seed: Int, x: Double) = value(seed, x, ::quintic)
fun valueHermite(seed: Int, x: Double) = value(seed, x, ::hermite)
inline fun value(seed: Int, x: Double, crossinline interpolation: (Double) -> Double = ::linear): Double =
value(seed, x, 0.0)

View File

@@ -0,0 +1,33 @@
import org.openrndr.extra.noise.*
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
import kotlin.test.assertEquals
object TestGradient : Spek({
describe("Noise") {
it("has a gradient") {
gradient(::perlinLinear, 100, 0.1)
}
}
describe("FBM noise func") {
it("has a gradient") {
val func = fbmFunc1D(::perlinLinear)
gradient(func, 100, 0.1)
}
}
describe("Billow noise func") {
it("has a gradient") {
val func = billowFunc1D(::perlinLinear)
gradient(func, 100, 0.1)
}
}
describe("Rigid noise func") {
it("has a gradient") {
val func = rigidFunc1D(::perlinLinear)
gradient(func, 100, 0.1)
}
}
})