orx-noise

A collection of noise generator functions. Source and extra documentation can be found in the orx-noise sourcetree.

Prerequisites

If you are working on an openrndr-template based project, orx-noise should be ready to use because it is part of the basic orx bundle, as described in ORX.

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.

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.

val v2 = Vector2.uniforms(100, Vector2(0.0), Vector2(640.0))
val v3 = Vector3.uniforms(100, Vector3(0.0), Vector3(640.0))

The Random class can also be used to generate Double numbers and vector, but also booleans and integers.

// Boolean
val b = Boolean.random(probability = 0.2)

// Int
val i1 = Int.uniform(0, 640)

// Double
val d2 = Double.uniform(0.0, 640.0)

// Vectors
val v2 = Vector2.uniform(0.0, 640.0)
val v3 = Vector3.uniform(0.0, 640.0)
val v4 = Vector4.uniform(0.0, 640.0)

Perlin, Value and Simplex noise

perlin() and value() accept 2D and 3D arguments, simplex() up to 4D.

All three method take an integer seed as first argument and return a Double.

Some examples:

// 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 = perlin(1234, 0.1, 0.2)
val d2 = perlin(1248, v2)
val d3 = value(1234, 0.1, 0.2, 0.3)
val d4 = simplex(1234, v4)

Uniform ring noise

val v2 = Vector2.uniformRing(innerRadius = 0.0, outerRadius = 300.0)
val v3 = Vector3.uniformRing(0.0, 300.0)
val v4 = Vector4.uniformRing(0.0, 300.0)
/media/orx-noise-001.jpg
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.LineCap
import org.openrndr.draw.colorBuffer
import org.openrndr.extra.noise.*
import org.openrndr.extra.noise.filters.CellNoise
import org.openrndr.extra.noise.filters.HashNoise
import org.openrndr.extra.noise.filters.SimplexNoise3D
import org.openrndr.extra.noise.filters.SpeckleNoise
import org.openrndr.extra.noise.filters.ValueNoise
import org.openrndr.extra.noise.primitives.random
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.absoluteValue

fun main() = application {
    program {
        extend {
            drawer.fill = ColorRGBa.PINK
            drawer.stroke = 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)
            }
        }
    }
}

Link to the full example

Perlin noise

/media/orx-noise-002.jpg
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.LineCap
import org.openrndr.draw.colorBuffer
import org.openrndr.extra.noise.*
import org.openrndr.extra.noise.filters.CellNoise
import org.openrndr.extra.noise.filters.HashNoise
import org.openrndr.extra.noise.filters.SimplexNoise3D
import org.openrndr.extra.noise.filters.SpeckleNoise
import org.openrndr.extra.noise.filters.ValueNoise
import org.openrndr.extra.noise.primitives.random
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.absoluteValue

fun main() = application {
    program {
        extend {
            drawer.fill = ColorRGBa.PINK
            drawer.stroke = null
            val scale = 0.005
            for (y in 16 until height step 32) {
                for (x in 16 until width step 32) {
                    val radius = perlinLinear(123, x * scale, y * scale) * 16.0 + 16.0
                    drawer.circle(x * 1.0, y * 1.0, radius)
                }
            }
        }
    }
}

Link to the full example

Value noise

/media/orx-noise-003.jpg
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.LineCap
import org.openrndr.draw.colorBuffer
import org.openrndr.extra.noise.*
import org.openrndr.extra.noise.filters.CellNoise
import org.openrndr.extra.noise.filters.HashNoise
import org.openrndr.extra.noise.filters.SimplexNoise3D
import org.openrndr.extra.noise.filters.SpeckleNoise
import org.openrndr.extra.noise.filters.ValueNoise
import org.openrndr.extra.noise.primitives.random
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.absoluteValue

fun main() = application {
    program {
        extend {
            drawer.fill = ColorRGBa.PINK
            drawer.stroke = null
            val scale = 0.0150
            for (y in 16 until height step 32) {
                for (x in 16 until width step 32) {
                    val radius = valueLinear(123, x * scale, y * scale) * 16.0 + 16.0
                    drawer.circle(x * 1.0, y * 1.0, radius)
                }
            }
        }
    }
}

Link to the full example

Simplex noise

/media/orx-noise-004.jpg
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.LineCap
import org.openrndr.draw.colorBuffer
import org.openrndr.extra.noise.*
import org.openrndr.extra.noise.filters.CellNoise
import org.openrndr.extra.noise.filters.HashNoise
import org.openrndr.extra.noise.filters.SimplexNoise3D
import org.openrndr.extra.noise.filters.SpeckleNoise
import org.openrndr.extra.noise.filters.ValueNoise
import org.openrndr.extra.noise.primitives.random
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.absoluteValue

fun main() = application {
    program {
        extend {
            drawer.fill = ColorRGBa.PINK
            drawer.stroke = null
            val scale = 0.004
            for (y in 16 until height step 32) {
                for (x in 16 until width step 32) {
                    val radius =
                        simplex(123, x * scale, y * scale) * 16.0 + 16.0
                    drawer.circle(x * 1.0, y * 1.0, radius)
                }
            }
        }
    }
}

Link to the full example

Fractal/FBM noise

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.LineCap
import org.openrndr.draw.colorBuffer
import org.openrndr.extra.noise.*
import org.openrndr.extra.noise.filters.CellNoise
import org.openrndr.extra.noise.filters.HashNoise
import org.openrndr.extra.noise.filters.SimplexNoise3D
import org.openrndr.extra.noise.filters.SpeckleNoise
import org.openrndr.extra.noise.filters.ValueNoise
import org.openrndr.extra.noise.primitives.random
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.absoluteValue

fun main() = application {
    program {
        extend {
            drawer.fill = ColorRGBa.PINK
            drawer.stroke = 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 -> fbm(135, x * s, y * s, t, ::perlinLinear).absoluteValue * 16.0
                        t < 6.0 -> billow(471, x * s, y * s, t, ::perlinLinear) * 2.0
                        else -> rigid(193, x * s, y * s, t, ::perlinLinear) * 16.0
                    }
                    drawer.circle(x * 1.0, y * 1.0, radius)
                }
            }
        }
    }
}

Link to the full example

Noise gradients

Noise functions have evaluable gradients, a direction to where the value of the function increases the fastest. The gradient1D, gradient2D, gradient3D and gradient4D functions can be used to estimate gradients for noise functions.

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.LineCap
import org.openrndr.draw.colorBuffer
import org.openrndr.extra.noise.*
import org.openrndr.extra.noise.filters.CellNoise
import org.openrndr.extra.noise.filters.HashNoise
import org.openrndr.extra.noise.filters.SimplexNoise3D
import org.openrndr.extra.noise.filters.SpeckleNoise
import org.openrndr.extra.noise.filters.ValueNoise
import org.openrndr.extra.noise.primitives.random
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.absoluteValue

fun main() = application {
    program {
        extend {
            drawer.fill = null
            drawer.stroke = ColorRGBa.PINK
            drawer.lineCap = LineCap.ROUND
            drawer.strokeWeight = 3.0
            val t = seconds
            for (y in 4 until height step 8) {
                for (x in 4 until width step 8) {
                    val g = gradient3D(
                        ::perlinQuintic, 100,
                        x * 0.005, y * 0.005, t, 0.0005
                    ).xy
                    drawer.lineSegment(
                        Vector2(x * 1.0, y * 1.0) - g * 2.0,
                        Vector2(x * 1.0, y * 1.0) + g * 2.0
                    )

                }
            }
        }
    }
}

Link to the full example

Gradients can also be calculated for the fbm, rigid and billow versions of the noise functions. However, we first have to create a function that can be used by the gradient estimator. For this .fbm(), .billow(), and .rigid() can be used (which works through partial application).

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.LineCap
import org.openrndr.draw.colorBuffer
import org.openrndr.extra.noise.*
import org.openrndr.extra.noise.filters.CellNoise
import org.openrndr.extra.noise.filters.HashNoise
import org.openrndr.extra.noise.filters.SimplexNoise3D
import org.openrndr.extra.noise.filters.SpeckleNoise
import org.openrndr.extra.noise.filters.ValueNoise
import org.openrndr.extra.noise.primitives.random
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.absoluteValue

fun main() = application {
    program {
        val noise = simplex3D.fbm(octaves = 3)
        extend {
            drawer.fill = null
            drawer.stroke = ColorRGBa.PINK
            drawer.lineCap = LineCap.ROUND
            drawer.strokeWeight = 1.5
            val t = seconds
            for (y in 4 until height step 8) {
                for (x in 4 until width step 8) {
                    val g = gradient3D(
                        noise, 100, x * 0.002, y * 0.002, t, 0.002
                    ).xy
                    drawer.lineSegment(
                        Vector2(x * 1.0, y * 1.0) - g * 1.0,
                        Vector2(x * 1.0, y * 1.0) + g * 1.0
                    )
                }
            }
        }
    }
}

Link to the full example

Noise filters

The library contains a number of Filters with which noise image can be generated efficiently on the GPU.

Hash noise

A white-noise-like noise generator.

ParameterDefault valueDescription
seed0.0Noise seed
gainVector4(1.0, 1.0, 1.0, 0.0)Noise gain per channel
biasVector4(0.0, 0.0, 0.0, 1.0)Value to add to the generated noise
monochrometrueOutputs monochrome noise if true
premultipliedAlphatrueOutputs premultiplied alpha if true
/media/orx-noise-filter-001.jpg
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.LineCap
import org.openrndr.draw.colorBuffer
import org.openrndr.extra.noise.*
import org.openrndr.extra.noise.filters.CellNoise
import org.openrndr.extra.noise.filters.HashNoise
import org.openrndr.extra.noise.filters.SimplexNoise3D
import org.openrndr.extra.noise.filters.SpeckleNoise
import org.openrndr.extra.noise.filters.ValueNoise
import org.openrndr.extra.noise.primitives.random
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.absoluteValue

fun main() = application {
    program {
        val cb = colorBuffer(width, height)
        val hn = HashNoise()
        extend {
            hn.seed = seconds
            hn.apply(emptyArray(), cb)
            drawer.image(cb)
        }
    }
}

Link to the full example

3D Simplex noise filter

The SimplexNoise3D filter is based on Ken Perlin’s improvement over Perlin noise, but with fewer directional artifacts and, in higher dimensions, a lower computational overhead.

ParameterDefault valueDescription
seedVector3(0.0, 0.0, 0.0)Noise seed / offset
scaleVector3(1.0, 1.0, 1.0)The noise scale at the first octave
octaves4The number of octaves
gainVector4(0.5, 0.5, 0.5, 0.5)Noise gain per channel per octave
decayVector4(0.5, 0.5, 0.5, 0.5)Noise decay per channel per octave
biasVector4(0.5, 0.5, 0.5, 0.5)Value to add to the generated noise
lacunarityVector4(2.0, 2.0, 2.0, 2.0)Multiplication of noise scale per octave
premultipliedAlphatrueOutputs premultiplied alpha if true
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.LineCap
import org.openrndr.draw.colorBuffer
import org.openrndr.extra.noise.*
import org.openrndr.extra.noise.filters.CellNoise
import org.openrndr.extra.noise.filters.HashNoise
import org.openrndr.extra.noise.filters.SimplexNoise3D
import org.openrndr.extra.noise.filters.SpeckleNoise
import org.openrndr.extra.noise.filters.ValueNoise
import org.openrndr.extra.noise.primitives.random
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.absoluteValue

fun main() = application {
    program {
        val cb = colorBuffer(width, height)
        val sn = SimplexNoise3D()
        extend {
            sn.seed = Vector3(0.0, 0.0, seconds * 0.1)
            sn.scale = Vector3.ONE * 2.0
            sn.octaves = 8
            sn.premultipliedAlpha = false
            sn.apply(emptyArray(), cb)
            drawer.image(cb)
        }
    }
}

Link to the full example

Cell noise

A cell, Worley or Voronoi noise generator

ParameterDefault valueDescription
seedVector2(0.0, 0.0)Noise seed / offset
scaleVector2(1.0, 1.0)The noise scale at the first octave
octaves4The number of octaves
gainVector4(1.0, 1.0, 1.0, 0.0)Noise gain per channel per octave
decayVector4(0.5, 0.5, 0.5, 0.5)Noise decay per channel per octave
biasVector4(0.0, 0.0, 0.0, 1.0)Value to add to the generated noise
lacunarityVector4(2.0, 2.0, 2.0, 2.0)Multiplication of noise scale per octave
premultipliedAlphatrueOutputs premultiplied alpha if true
/media/orx-noise-filter-002.jpg
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.LineCap
import org.openrndr.draw.colorBuffer
import org.openrndr.extra.noise.*
import org.openrndr.extra.noise.filters.CellNoise
import org.openrndr.extra.noise.filters.HashNoise
import org.openrndr.extra.noise.filters.SimplexNoise3D
import org.openrndr.extra.noise.filters.SpeckleNoise
import org.openrndr.extra.noise.filters.ValueNoise
import org.openrndr.extra.noise.primitives.random
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.absoluteValue

fun main() = application {
    program {
        val cb = colorBuffer(width, height)
        val cn = CellNoise()
        extend {
            cn.octaves = 4
            cn.apply(emptyArray(), cb)
            drawer.image(cb)
        }
    }
}

Link to the full example

Speckle noise

A speckle noise generator.

ParameterDefault valueDescription
colorColorRGBa.WHITESpeckle color
density1.0Speckle density
seed0.0Noise seed
noise0.0Speckle noisiness
premultipliedAlphatrueOutputs premultiplied alpha if true
/media/orx-noise-filter-003.jpg
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.LineCap
import org.openrndr.draw.colorBuffer
import org.openrndr.extra.noise.*
import org.openrndr.extra.noise.filters.CellNoise
import org.openrndr.extra.noise.filters.HashNoise
import org.openrndr.extra.noise.filters.SimplexNoise3D
import org.openrndr.extra.noise.filters.SpeckleNoise
import org.openrndr.extra.noise.filters.ValueNoise
import org.openrndr.extra.noise.primitives.random
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.absoluteValue

fun main() = application {
    program {
        val cb = colorBuffer(width, height)
        val sn = SpeckleNoise()
        extend {
            sn.seed = seconds
            sn.apply(emptyArray(), cb)
            drawer.image(cb)
        }
    }
}

Link to the full example

Value noise

The ValueNoise filter generates a simple fractal noise. Value noise is a computationally cheap form of creating ‘smooth noise’ by interpolating random values on a lattice.

ParameterDefault valueDescription
seedVector2(0.0, 0.0)Noise seed / offset
scaleVector2(1.0, 1.0)The noise scale at the first octave
octaves4The number of octaves
gainVector4(1.0, 1.0, 1.0, 0.0)Noise gain per channel per octave
decayVector4(0.5, 0.5, 0.5, 0.5)Noise decay per channel per octave
biasVector4(0.0, 0.0, 0.0, 1.0)Value to add to the generated noise
lacunarityVector4(2.0, 2.0, 2.0, 2.0)Multiplication of noise scale per octave
premultipliedAlphatrueOutputs premultiplied alpha if true
/media/orx-noise-filter-004.jpg
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.LineCap
import org.openrndr.draw.colorBuffer
import org.openrndr.extra.noise.*
import org.openrndr.extra.noise.filters.CellNoise
import org.openrndr.extra.noise.filters.HashNoise
import org.openrndr.extra.noise.filters.SimplexNoise3D
import org.openrndr.extra.noise.filters.SpeckleNoise
import org.openrndr.extra.noise.filters.ValueNoise
import org.openrndr.extra.noise.primitives.random
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.Vector4
import kotlin.math.absoluteValue

fun main() = application {
    program {
        val cb = colorBuffer(width, height)
        val vn = ValueNoise()
        extend {
            vn.scale = Vector2.ONE * 4.0
            vn.gain = Vector4.ONE * 0.5
            vn.octaves = 8
            vn.apply(emptyArray(), cb)
            drawer.image(cb)
        }
    }
}

Link to the full example

edit on GitHub