From 32e81a82c55a64241b737e05d2abdeefb879f6a4 Mon Sep 17 00:00:00 2001 From: Edwin Jakobs Date: Mon, 26 Jul 2021 20:14:30 +0200 Subject: [PATCH] [orx-noise] Add gradient and crossFade tools --- orx-noise/src/commonMain/kotlin/Functions.kt | 46 +++++++++++++++++-- orx-noise/src/commonMain/kotlin/Polar.kt | 7 +-- orx-noise/src/commonMain/kotlin/Vector.kt | 23 ++++++---- .../kotlin/DemoFunctionalComposition01.kt | 38 +++++++++++++++ 4 files changed, 98 insertions(+), 16 deletions(-) create mode 100644 orx-noise/src/demo/kotlin/DemoFunctionalComposition01.kt diff --git a/orx-noise/src/commonMain/kotlin/Functions.kt b/orx-noise/src/commonMain/kotlin/Functions.kt index 333788df..86592483 100644 --- a/orx-noise/src/commonMain/kotlin/Functions.kt +++ b/orx-noise/src/commonMain/kotlin/Functions.kt @@ -1,8 +1,6 @@ package org.openrndr.extra.noise -import org.openrndr.math.Vector2 -import org.openrndr.math.Vector3 -import org.openrndr.math.Vector4 +import org.openrndr.math.* import kotlin.jvm.JvmName fun ((Double) -> Double).withSeedAsOffset(offset: Double): (Int, Double) -> Double = { seed, x -> @@ -11,6 +9,46 @@ fun ((Double) -> Double).withSeedAsOffset(offset: Double): (Int, Double) -> Doub fun ((Int, Double) -> Double).withFixedSeed(seed: Int): (Double) -> Double = { x -> this(seed, x) } + +fun ((Int, Double) -> Double).gradient(epsilon: Double = 1e-6): (Int, Double) -> Double = { seed, x -> + (this(seed, x + epsilon) - this(seed, x - epsilon)) / (2 * epsilon) +} + +fun ((Int, Double, Double) -> Vector2).gradient(epsilon: Double = 1e-6): (Int, Double, Double) -> Vector2 = + { seed, x, y -> + val dfdx = (this(seed, x + epsilon, y) - this(seed, x - epsilon, y)) / (2 * epsilon) + val dfdy = (this(seed, x, y + epsilon) - this(seed, x, y - epsilon)) / (2 * epsilon) + dfdx + dfdy + } + +fun ((Int, Double, Double, Double) -> Double).crossFade( + start: Double, + end: Double, + width: Double = 0.5 +): (Int, Double, Double, Double) -> Double { + return { seed, x, y, z -> + val a = z.map(start, end, 0.0, 1.0).mod_(1.0) + val f = (a / width).coerceAtMost(1.0) + + val o = this(seed, x, y, a.map(0.0, 1.0, start, end)) * f + (1.0 - f) * this( + seed, + x, + y, + (a + 1.0).map(0.0, 1.0, start, end) + ) + o + + } +} + +fun ((Int, Double, Double, Double) -> Vector2).gradient(epsilon: Double = 1e-2 / 2.0): (Int, Double, Double, Double) -> Vector2 = + { seed, x, y, z -> + val dfdx = (this(seed, x + epsilon, y, z) - this(seed, x - epsilon, y, z)) / (2 * epsilon) + val dfdy = (this(seed, x, y + epsilon, z) - this(seed, x, y - epsilon, z)) / (2 * epsilon) + dfdx + dfdy + } + + fun ((Int, Double) -> Double).scaleBiasOutput( scale: Double = 1.0, bias: Double = 0.0 @@ -18,7 +56,7 @@ fun ((Int, Double) -> Double).scaleBiasOutput( this(seed, x) * scale + bias } -fun ((Int, Double) -> Double).mapOutput(map: (Double)->Double): (Int, Double) -> Double = { seed, x -> +fun ((Int, Double) -> Double).mapOutput(map: (Double) -> Double): (Int, Double) -> Double = { seed, x -> map(this(seed, x)) } diff --git a/orx-noise/src/commonMain/kotlin/Polar.kt b/orx-noise/src/commonMain/kotlin/Polar.kt index f073f2ba..60d37ba2 100644 --- a/orx-noise/src/commonMain/kotlin/Polar.kt +++ b/orx-noise/src/commonMain/kotlin/Polar.kt @@ -37,7 +37,7 @@ fun polarOffsetFunc( noise: (Int, Double, Double) -> Double, origin: Vector2 = Vector2.ZERO, -): (seed: Int, polar: Polar, offset: Vector2) -> Double { + ): (seed: Int, polar: Polar, offset: Vector2) -> Double { return { seed, polar, offset -> val c = polar.cartesian + origin + offset noise(seed, c.x, c.y) @@ -59,14 +59,15 @@ fun ((Int, Vector2) -> Double).withPolarOffsetInput(origin: Vector2 = Vector2.ZE polarOffsetFunc(this.withScalarInput(), origin) - fun ((Int, Double, Double) -> Double).fixedRadiusPolar( radius: Double, origin: Vector2 = Vector2.ZERO ): (Int, Double) -> Double = fixedRadiusPolarFunc(this, radius, origin) -private fun example() { + + +fun example() { val polarFbmSimplex = polarFunc(noise = fbmFunc2D(noise = ::simplex)) val polarBillowPerlin = polarFunc(noise = billowFunc2D(noise = ::perlin)) diff --git a/orx-noise/src/commonMain/kotlin/Vector.kt b/orx-noise/src/commonMain/kotlin/Vector.kt index 18495f9e..95ff9816 100644 --- a/orx-noise/src/commonMain/kotlin/Vector.kt +++ b/orx-noise/src/commonMain/kotlin/Vector.kt @@ -1,14 +1,19 @@ package org.openrndr.extra.noise +import org.openrndr.math.Polar import org.openrndr.math.Vector2 +import kotlin.jvm.JvmName -fun ((Int, Double) -> Double).vector2(): (seed: Int, x: Double) -> Vector2 { - val ref = this - return { seed:Int, x:Double -> - Vector2(ref(-seed, x), ref(seed, -x)) - } -} +@JvmName("polarWithVector2Output") +fun ((Int, Polar) -> Double).withVector2Output(): (Int, Polar) -> Vector2 = + { seed, polar -> Vector2(this(seed, polar), this(seed xor 0x7f7f7f7f, Polar(-polar.theta, polar.radius))) } + +fun ((Int, Double) -> Double).withVector2Output(): (seed: Int, x: Double) -> Vector2 = + { seed: Int, x: Double -> Vector2(this(seed, x), this(seed xor 0x7f7f7f7f, -x)) } + +fun ((Int, Double, Double) -> Double).withVector2Output(): (seed: Int, x: Double, y: Double) -> Vector2 = + { seed, x, y -> Vector2(this(seed, x, y), this(seed xor 0x7f7f7f7f, y, -x)) } + +fun ((Int, Double, Double, Double) -> Double).withVector2Output(): (seed: Int, x: Double, y: Double, z: Double) -> Vector2 = + { seed, x, y, z -> Vector2(this(seed, x, y, z), this(seed xor 0x7f7f7f7f, y, -x, z)) } -private fun exampleVector() { - ::simplex2D -} diff --git a/orx-noise/src/demo/kotlin/DemoFunctionalComposition01.kt b/orx-noise/src/demo/kotlin/DemoFunctionalComposition01.kt new file mode 100644 index 00000000..b5ee86e8 --- /dev/null +++ b/orx-noise/src/demo/kotlin/DemoFunctionalComposition01.kt @@ -0,0 +1,38 @@ +import org.openrndr.application +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.LineJoin +import org.openrndr.extensions.SingleScreenshot +import org.openrndr.extra.noise.simplex +import org.openrndr.extra.noise.simplex1D +import org.openrndr.extra.noise.simplex2D +import org.openrndr.extra.noise.simplex3D +import org.openrndr.extra.noise.withVector2Output +import org.openrndr.extra.noise.gradient +import org.openrndr.shape.contour + +suspend fun main() = application { + configure { + width = 720 + height = 720 + } + program { + if (System.getProperty("takeScreenshot") == "true") { + extend(SingleScreenshot()) { + this.outputFile = System.getProperty("screenshotPath") + } + } + val n = simplex3D.withVector2Output().gradient() + extend { + drawer.stroke = null + drawer.fill = ColorRGBa.PINK + drawer.lineJoin = LineJoin.ROUND + drawer.stroke = ColorRGBa.WHITE + for (y in 0 until height step 20) { + for (x in 0 until width step 20) { + val d = n(40, x * 0.003, y * 0.003,seconds) * 5.0 + drawer.lineSegment(x * 1.0, y * 1.0, x * 1.0 + d.x, y * 1.0 + d.y) + } + } + } + } +} \ No newline at end of file