Add vector based noise functions

This commit is contained in:
Abe Pazos
2020-04-23 18:46:05 +02:00
committed by Edwin Jakobs
parent a28f298690
commit 400347aad1
12 changed files with 278 additions and 4 deletions

View File

@@ -1,10 +1,19 @@
package org.openrndr.extra.noise
import org.openrndr.math.Vector2
fun cubic(seed: Int, x: Double, y: Double) = cubic(seed, x, y, ::linear)
fun cubicLinear(seed: Int, x: Double, y: Double) = cubic(seed, x, y, ::linear)
fun cubicQuintic(seed: Int, x: Double, y: Double) = cubic(seed, x, y, ::quintic)
fun cubicHermite(seed: Int, x: Double, y: Double) = cubic(seed, x, y, ::hermite)
fun cubic(seed: Int, position: Vector2) = cubic(seed, position.x, position.y, ::linear)
fun cubicLinear(seed: Int, position: Vector2) = cubic(seed, position.x, position.y, ::linear)
fun cubicQuintic(seed: Int, position: Vector2) = cubic(seed, position.x, position.y, ::quintic)
fun cubicHermite(seed: Int, position: Vector2) = cubic(seed, position.x, position.y, ::hermite)
private const val CUBIC_2D_BOUNDING = 1 / (1.5 * 1.5).toFloat()
fun cubic(seed: Int, x: Double, y: Double, interpolator: (Double) -> Double = ::linear): Double {
val x1 = x.fastFloor()
val y1 = y.fastFloor()

View File

@@ -1,5 +1,7 @@
package org.openrndr.extra.noise
import org.openrndr.math.Vector3
private const val CUBIC_3D_BOUNDING = 1 / (1.5 * 1.5 * 1.5).toFloat()
fun cubic(seed: Int, x: Double, y: Double, z: Double) = cubic(seed, x, y, z, ::linear)
@@ -7,6 +9,11 @@ fun cubicLinear(seed: Int, x: Double, y: Double, z: Double) = cubic(seed, x, y,
fun cubicQuintic(seed: Int, x: Double, y: Double, z: Double) = cubic(seed, x, y, z, ::quintic)
fun cubicHermite(seed: Int, x: Double, y: Double, z: Double) = perlin(seed, x, y, z, ::hermite)
fun cubic(seed: Int, position: Vector3) = cubic(seed, position.x, position.y, position.z, ::linear)
fun cubicLinear(seed: Int, position: Vector3) = cubic(seed, position.x, position.y, position.z, ::linear)
fun cubicQuintic(seed: Int, position: Vector3) = cubic(seed, position.x, position.y, position.z, ::quintic)
fun cubicHermite(seed: Int, position: Vector3) = perlin(seed, position.x, position.y, position.z, ::hermite)
fun cubic(seed: Int, x: Double, y: Double, z: Double, interpolator: (Double) -> Double): Double {
val x1 = x.fastFloor()
val y1 = y.fastFloor()

View File

@@ -1,7 +1,13 @@
package org.openrndr.extra.noise
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.abs
inline fun fbm(seed: Int, position: Vector4, crossinline noise: (Int, Double, Double, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) =
fbm(seed, position.x, position.y, position.z, position.w, noise, octaves, lacunarity, gain)
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 {
@@ -23,6 +29,10 @@ inline fun fbm(seed: Int, x: Double, y: Double, z: Double, w: Double, crossinlin
return sum
}
inline fun fbm(seed: Int, position: Vector3, crossinline noise: (Int, Double, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) =
fbm(seed, position.x, position.y, position.z, noise, octaves, lacunarity, gain)
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 {
var sum = noise(seed, x, y, z)
@@ -41,6 +51,10 @@ inline fun fbm(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (I
return sum
}
inline fun fbm(seed: Int, position: Vector2, crossinline noise: (Int, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) =
fbm(seed, position.x, position.y, noise, octaves, lacunarity, gain)
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 {
var sum = noise(seed, x, y)
@@ -95,7 +109,9 @@ inline fun fbmFunc4D(crossinline noise: (Int, Double, Double, Double, Double) ->
}
}
inline fun billow(seed: Int, position: Vector4, crossinline noise: (Int, Double, Double, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) = billow(seed, position.x, position.y,
position.z, position.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 {
@@ -117,6 +133,10 @@ inline fun billow(seed: Int, x: Double, y: Double, z: Double, w: Double, crossin
return sum
}
inline fun billow(seed: Int, position: Vector3, crossinline noise: (Int, Double, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) =
billow(seed, position.x, position.y, position.z, noise, octaves, lacunarity, gain)
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 {
var sum = Math.abs(noise(seed, x, y, z) * 2.0 - 1.0)
@@ -135,6 +155,10 @@ inline fun billow(seed: Int, x: Double, y: Double, z: Double, crossinline noise:
return sum
}
inline fun billow(seed: Int, position: Vector2, crossinline noise: (Int, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) =
billow(seed, position.x, position.y, noise, octaves, lacunarity, gain)
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 {
var sum = abs(noise(seed, x, y) * 2.0 - 1.0)
@@ -189,6 +213,10 @@ inline fun billowFunc4D(crossinline noise: (Int, Double, Double, Double, Double)
}
}
inline fun rigid(seed: Int, position: Vector4, crossinline noise: (Int, Double, Double, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) =
rigid(seed, position.x, position.y, position.z, position.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))
@@ -209,6 +237,10 @@ inline fun rigid(seed: Int, x: Double, y: Double, z: Double, w: Double, crossinl
return sum
}
inline fun rigid(seed: Int, position: Vector3, crossinline noise: (Int, Double, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) =
rigid(seed, position.x, position.y, position.z, noise, octaves, lacunarity, gain)
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))
@@ -227,6 +259,10 @@ inline fun rigid(seed: Int, x: Double, y: Double, z: Double, crossinline noise:
return sum
}
inline fun rigid(seed: Int, position: Vector2, crossinline noise: (Int, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) =
rigid(seed, position.x, position.y, noise, octaves, lacunarity, gain)
inline fun rigid(seed: Int, x: Double, y: Double, crossinline noise: (Int, 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))

View File

@@ -1,10 +1,17 @@
package org.openrndr.extra.noise
import org.openrndr.math.Vector2
fun perlin(seed: Int, x: Double, y: Double) = perlin(seed, x, y, ::linear)
fun perlinLinear(seed: Int, x: Double, y: Double) = perlin(seed, x, y, ::linear)
fun perlinQuintic(seed: Int, x: Double, y: Double) = perlin(seed, x, y, ::quintic)
fun perlinHermite(seed: Int, x: Double, y: Double) = perlin(seed, x, y, ::hermite)
fun perlin(seed: Int, position: Vector2) = perlin(seed, position.x, position.y, ::linear)
fun perlinLinear(seed: Int, position: Vector2) = perlin(seed, position.x, position.y, ::linear)
fun perlinQuintic(seed: Int, position: Vector2) = perlin(seed, position.x, position.y, ::quintic)
fun perlinHermite(seed: Int, position: Vector2) = perlin(seed, position.x, position.y, ::hermite)
inline fun perlin(seed: Int, x: Double, y: Double, crossinline interpolator: (Double) -> Double): Double {
val x0 = x.fastFloor()
val y0 = y.fastFloor()

View File

@@ -1,9 +1,15 @@
package org.openrndr.extra.noise
import org.openrndr.math.Vector3
fun perlinLinear(seed: Int, x: Double, y: Double, z: Double) = perlin(seed, x, y, z, ::linear)
fun perlinQuintic(seed: Int, x: Double, y: Double, z: Double) = perlin(seed, x, y, z, ::quintic)
fun perlinHermite(seed: Int, x: Double, y: Double, z: Double) = perlin(seed, x, y, z, ::hermite)
fun perlinLinear(seed: Int, position: Vector3) = perlin(seed, position.x, position.y, position.z, ::linear)
fun perlinQuintic(seed: Int, position: Vector3) = perlin(seed, position.x, position.y, position.z, ::quintic)
fun perlinHermite(seed: Int, position: Vector3) = perlin(seed, position.x, position.y, position.z, ::hermite)
inline fun perlin(seed: Int, x: Double, y: Double, z: Double, crossinline interpolator: (Double) -> Double = ::linear): Double {
val x0 = x.fastFloor()
val y0 = y.fastFloor()

View File

@@ -1,14 +1,13 @@
package org.openrndr.extra.noise
import org.openrndr.extra.noise.*
import org.openrndr.extra.noise.fbm as orxFbm
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.ln
import kotlin.math.max
import kotlin.math.sqrt
import kotlin.math.pow
import kotlin.math.sqrt
import org.openrndr.extra.noise.fbm as orxFbm
import kotlin.random.Random as DefaultRandom
@@ -165,6 +164,16 @@ object Random {
}
}
fun perlin(position: Vector2, type: Noise = Noise.LINEAR): Double {
val sd = stringToInt(seed)
return when (type) {
Noise.LINEAR -> perlinLinear(sd, position)
Noise.QUINTIC -> perlinQuintic(sd, position)
Noise.HERMIT -> perlinHermite(sd, position)
}
}
fun perlin(x: Double, y: Double, z: Double, type: Noise = Noise.LINEAR): Double {
val sd = stringToInt(seed)
@@ -175,6 +184,16 @@ object Random {
}
}
fun perlin(position: Vector3, type: Noise = Noise.LINEAR): Double {
val sd = stringToInt(seed)
return when (type) {
Noise.LINEAR -> perlinLinear(sd, position)
Noise.QUINTIC -> perlinQuintic(sd, position)
Noise.HERMIT -> perlinHermite(sd, position)
}
}
fun value(x: Double, y: Double, type: Noise = Noise.LINEAR): Double {
val sd = stringToInt(seed)
@@ -185,6 +204,16 @@ object Random {
}
}
fun value(position: Vector2, type: Noise = Noise.LINEAR): Double {
val sd = stringToInt(seed)
return when (type) {
Noise.LINEAR -> valueLinear(sd, position)
Noise.QUINTIC -> valueQuintic(sd, position)
Noise.HERMIT -> valueHermite(sd, position)
}
}
fun value(x: Double, y: Double, z: Double, type: Noise = Noise.LINEAR): Double {
val sd = stringToInt(seed)
@@ -195,18 +224,40 @@ object Random {
}
}
fun value(position: Vector3, type: Noise = Noise.LINEAR): Double {
val sd = stringToInt(seed)
return when (type) {
Noise.LINEAR -> valueLinear(sd, position)
Noise.QUINTIC -> valueQuintic(sd, position)
Noise.HERMIT -> valueHermite(sd, position)
}
}
fun simplex(x: Double, y: Double): Double {
return simplex(stringToInt(seed), x, y)
}
fun simplex(position: Vector2): Double {
return simplex(stringToInt(seed), position)
}
fun simplex(x: Double, y: Double, z: Double): Double {
return simplex(stringToInt(seed), x, y, z)
}
fun simplex(position: Vector3): Double {
return simplex(stringToInt(seed), position)
}
fun simplex(x: Double, y: Double, z: Double, w: Double): Double {
return simplex(stringToInt(seed), x, y, z, w)
}
fun simplex(position: Vector4): Double {
return simplex(stringToInt(seed), position)
}
fun fbm(x: Double, y: Double, noiseFun: (Int, Double, Double) -> Double, type: Fractal = Fractal.FBM,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
val s = stringToInt(seed)
@@ -218,6 +269,18 @@ object Random {
}
}
fun fbm(position: Vector2, noiseFun: (Int, Double, Double) -> Double,
type: Fractal = Fractal.FBM,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
val s = stringToInt(seed)
return when (type) {
Fractal.FBM -> orxFbm(s, position, noiseFun, octaves, lacunarity, gain)
Fractal.RIGID -> rigid(s, position, noiseFun, octaves, lacunarity, gain)
Fractal.BILLOW -> billow(s, position, noiseFun, octaves, lacunarity, gain)
}
}
fun fbm(x: Double, y: Double, z: Double, noiseFun: (Int, Double, Double, Double) -> Double, type: Fractal = Fractal.FBM,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
val s = stringToInt(seed)
@@ -229,14 +292,34 @@ object Random {
}
}
fun fbm(position: Vector3, noiseFun: (Int, Double, Double, Double) -> Double,
type: Fractal = Fractal.FBM, octaves: Int = 8,
lacunarity: Double = 0.5, gain: Double = 0.5): Double {
val s = stringToInt(seed)
return when (type) {
Fractal.FBM -> orxFbm(s, position, noiseFun, octaves, lacunarity, gain)
Fractal.RIGID -> rigid(s, position, noiseFun, octaves, lacunarity, gain)
Fractal.BILLOW -> billow(s, position, noiseFun, octaves, lacunarity, gain)
}
}
fun cubic(x: Double, y: Double): Double {
return cubic(stringToInt(seed), x, y)
}
fun cubic(position: Vector2): Double {
return cubic(stringToInt(seed), position)
}
fun cubic(x: Double, y: Double, z: Double): Double {
return cubic(stringToInt(seed), x, y, z)
}
fun cubic(position: Vector3):Double {
return cubic(stringToInt(seed), position)
}
fun ring2d(innerRadius: Double = 0.0, outerRadius: Double = 1.0, count: Int = 1): Any {
return when (count) {
1 -> Vector2.uniformRing(innerRadius, outerRadius, rnd)

View File

@@ -1,9 +1,13 @@
package org.openrndr.extra.noise
import org.openrndr.math.Vector2
private const val SQRT3 = 1.7320508075688772935274463415059
private const val F2 = 0.5 * (SQRT3 - 1.0)
private const val G2 = (3.0 - SQRT3) / 6.0
fun simplex(seed: Int, position: Vector2): Double = simplex(seed, position.x, position.y)
fun simplex(seed: Int, x: Double, y: Double): Double {
var t = (x + y) * F2
val i = (x + t).fastFloor()

View File

@@ -1,10 +1,13 @@
package org.openrndr.extra.noise
import org.openrndr.math.Vector3
private const val F3 = (1.0 / 3.0).toFloat()
private const val G3 = (1.0 / 6.0).toFloat()
private const val G33 = G3 * 3 - 1
fun simplex(seed: Int, position: Vector3): Double = simplex(seed, position.x, position.y, position.z)
fun simplex(seed: Int, x: Double, y: Double, z: Double): Double {
val t = (x + y + z) / 3.0

View File

@@ -1,5 +1,7 @@
package org.openrndr.extra.noise
import org.openrndr.math.Vector4
private val SIMPLEX_4D = byteArrayOf(
0, 1, 2, 3, 0, 1, 3, 2, 0, 0, 0, 0, 0, 2, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0,
0, 2, 1, 3, 0, 0, 0, 0, 0, 3, 1, 2, 0, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 2, 0,
@@ -14,6 +16,8 @@ private val SIMPLEX_4D = byteArrayOf(
private const val F4 = ((2.23606797 - 1.0) / 4.0)
private const val G4 = ((5.0 - 2.23606797) / 20.0)
fun simplex(seed: Int, position: Vector4) =
simplex(seed, position.x, position.y, position.z, position.w)
fun simplex(seed: Int, x: Double, y: Double, z: Double, w: Double): Double {

View File

@@ -1,9 +1,20 @@
package org.openrndr.extra.noise
import org.openrndr.math.Vector2
fun valueLinear(seed: Int, x: Double, y: Double) = value(seed, x, y, ::linear)
fun valueQuintic(seed: Int, x: Double, y: Double) = value(seed, x, y, ::quintic)
fun valueHermite(seed: Int, x: Double, y: Double) = value(seed, x, y, ::hermite)
fun valueLinear(seed: Int, position: Vector2) =
value(seed, position.x, position.y, ::linear)
fun valueQuintic(seed: Int, position: Vector2) =
value(seed, position.x, position.y, ::quintic)
fun valueHermite(seed: Int, position: Vector2) =
value(seed, position.x, position.y, ::hermite)
inline fun value(seed: Int, x: Double, y: Double, crossinline interpolation: (Double) -> Double = ::linear): Double {
val x0 = x.fastFloor()
val y0 = y.fastFloor()

View File

@@ -1,9 +1,20 @@
package org.openrndr.extra.noise
import org.openrndr.math.Vector3
fun valueLinear(seed: Int, x: Double, y: Double, z: Double) = value(seed, x, y, z, ::linear)
fun valueQuintic(seed: Int, x: Double, y: Double, z: Double) = value(seed, x, y, z, ::quintic)
fun valueHermite(seed: Int, x: Double, y: Double, z: Double) = value(seed, x, y, z, ::hermite)
fun valueLinear(seed: Int, position: Vector3) =
value(seed, position.x, position.y, position.z, ::linear)
fun valueQuintic(seed: Int, position: Vector3) =
value(seed, position.x, position.y, position.z, ::quintic)
fun valueHermite(seed: Int, position: Vector3) =
value(seed, position.x, position.y, position.z, ::hermite)
inline fun value(seed: Int, x: Double, y: Double, z: Double, crossinline interpolation: (Double) -> Double = ::linear): Double {
val x0 = x.fastFloor()
val y0 = y.fastFloor()

View File

@@ -0,0 +1,93 @@
import org.openrndr.extra.noise.Random
import org.openrndr.extra.noise.perlinQuintic
import org.openrndr.math.Vector4
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
import kotlin.test.assertEquals
object TestVectorShortcutFunctions : Spek({
val v = Vector4(1.13, 2.74, 3.59, 4.83)
describe("perlin with Vector2") {
it("produces expected result") {
assertEquals(Random.perlin(v.x, v.y, Random.Noise.QUINTIC),
Random.perlin(v.xy, Random.Noise.QUINTIC))
}
}
describe("perlin with Vector3") {
it("produces expected result") {
assertEquals(Random.perlin(v.x, v.y, v.z, Random.Noise.QUINTIC),
Random.perlin(v.xyz, Random.Noise.QUINTIC))
}
}
// ---
describe("value with Vector2") {
it("produces expected result") {
assertEquals(Random.value(v.x, v.y, Random.Noise.QUINTIC),
Random.value(v.xy, Random.Noise.QUINTIC))
}
}
describe("value with Vector3") {
it("produces expected result") {
assertEquals(Random.value(v.x, v.y, v.z, Random.Noise.QUINTIC),
Random.value(v.xyz, Random.Noise.QUINTIC))
}
}
// ---
describe("simplex with Vector2") {
it("produces expected result") {
assertEquals(Random.simplex(v.x, v.y), Random.simplex(v.xy))
}
}
describe("simplex with Vector3") {
it("produces expected result") {
assertEquals(Random.simplex(v.x, v.y, v.z), Random.simplex(v.xyz))
}
}
describe("simplex with Vector4") {
it("produces expected result") {
assertEquals(Random.simplex(v.x, v.y, v.z, v.w),
Random.simplex(v))
}
}
// ---
describe("fbm with Vector2") {
it("produces expected result") {
assertEquals(Random.fbm(v.x, v.y, ::perlinQuintic),
Random.fbm(v.xy, ::perlinQuintic))
}
}
describe("fbm with Vector3") {
it("produces expected result") {
assertEquals(Random.fbm(v.x, v.y, v.z, ::perlinQuintic),
Random.fbm(v.xyz, ::perlinQuintic))
}
}
// ---
describe("cubic with Vector2") {
it("produces expected result") {
assertEquals(Random.cubic(v.x, v.y), Random.cubic(v.xy))
}
}
describe("cubic with Vector3") {
it("produces expected result") {
assertEquals(Random.cubic(v.x, v.y, v.z), Random.cubic(v.xyz))
}
}
})