Randomness
Generating random numbers can be a useful technique to produce variety in a design or to make things look more organic.
OPENRNDR provides many noise and random number generators thanks to the orx-noise extension.
Prerequisites
Assuming you are working on an openrndr-template based project, all you have to do is enable orx-noise in the orxFeatures set in build.gradle.kts and reimport the gradle project.
Uniformly distributed random values
The library provides extension methods for Double, Vector2, Vector3, Vector4 to create random vectors easily. To create scalars and vectors with uniformly distributed noise you use the uniform extension function.
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.*
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.abs
val d1 = Double.uniform(0.0, 640.0)
val v2 = Vector2.uniform(0.0, 640.0)
val v3 = Vector3.uniform(0.0, 640.0)
val v4 = Vector4.uniform(0.0, 640.0)
To create multiple samples of noise one uses the uniforms function.
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.*
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.abs
val v2 = Vector2.uniforms(100, Vector2(0.0, 0.0), Vector2(640.0, 640.0))
val v3 = Vector3.uniforms(100, Vector3(0.0, 0.0, 0.0), Vector3(640.0, 640.0, 640.0))
The Random class can also be used to generate Double numbers and vector, but also booleans and integers.
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.*
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.abs
// Boolean
val b = Random.bool(probability = 0.2)
// Int
val i1 = Random.int(0, 640)
val i2 = Random.int0(640)
// Double
val d2 = Random.double(0.0, 640.0)
val d3 = Random.double0(640.0)
// Vectors
val v2 = Random.vector2(0.0, 640.0)
val v3 = Random.vector3(0.0, 640.0)
val v4 = Random.vector4(0.0, 640.0)
Perlin, Value and Simplex noise
Random.perlin() and Random.value() accept 2D and 3D arguments. Random.simplex() up to 4D. They all return a Double. Some examples:
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.*
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.abs
// Test vectors to use
val v2 = Vector2(0.1, 0.2)
val v4 = Vector4(0.1, 0.2, 0.3, 0.4)
// Now generate random values
val d1 = Random.perlin(0.1, 0.2)
val d2 = Random.perlin(v2)
val d3 = Random.value(0.1, 0.2, 0.3)
val d4 = Random.simplex(v4)
Uniform ring noise
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.*
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.abs
val v2 = Vector2.uniformRing(0.0, 300.0)
val v3 = Vector3.uniformRing(0.0, 300.0)
val v4 = Vector4.uniformRing(0.0, 300.0)

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.*
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.abs
fun main() = application {
program {
extend {
drawer.clear(ColorRGBa.WHITE)
drawer.fill = null
drawer.translate(width / 2.0, height / 2.00)
for (i in 0 until 1000) {
drawer.circle(Vector2.uniformRing(150.0, 250.0), 10.0)
}
}
}
}
Perlin noise

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.*
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.abs
fun main() = application {
program {
extend {
drawer.clear(ColorRGBa.WHITE)
drawer.fill = null
val scale = 0.005
for (y in 16 until height step 32) {
for (x in 16 until width step 32) {
val radius = perlinLinear(100, x * scale, y * scale) * 16.0 + 16.0
drawer.circle(x * 1.0, y * 1.0, radius)
}
}
}
}
}
Value noise

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.*
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.abs
fun main() = application {
program {
extend {
drawer.clear(ColorRGBa.WHITE)
drawer.fill = null
val scale = 0.0150
for (y in 16 until height step 32) {
for (x in 16 until width step 32) {
val radius = valueLinear(100, x * scale, y * scale) * 16.0 + 16.0
drawer.circle(x * 1.0, y * 1.0, radius)
}
}
}
}
}
Simplex noise

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.*
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.abs
fun main() = application {
program {
extend {
drawer.clear(ColorRGBa.WHITE)
drawer.fill = null
val scale = 0.004
for (y in 16 until height step 32) {
for (x in 16 until width step 32) {
val radius = simplex(100, x * scale, y * scale) * 16.0 + 16.0
drawer.circle(x * 1.0, y * 1.0, radius)
}
}
}
}
}
Fractal/FBM noise

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.*
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.abs
fun main() = application {
program {
extend {
drawer.clear(ColorRGBa.WHITE)
drawer.fill = null
val s = 0.0080
val t = seconds
for (y in 4 until height step 8) {
for (x in 4 until width step 8) {
val radius = when {
t < 3.0 -> abs(fbm(100, x * s, y * s, t, ::perlinLinear)) * 16.0
t < 6.0 -> billow(100, x * s, y * s, t, ::perlinLinear) * 2.0
else -> rigid(100, x * s, y * s, t, ::perlinLinear) * 16.0
}
drawer.circle(x * 1.0, y * 1.0, radius)
}
}
}
}
}