orx-fx Filters
The orx-fx library contains many filters that can be readily used. See the chapter Filters and post-processing for instructions on using them.
A (more-or-less) complete listing of the effects in orx-fx is maintained in the repository’s README.md
Prerequisites
Assuming you are working on an openrndr-template
based project, all you have to do is enable orx-fx
in the orxFeatures
set in build.gradle.kts
and reimport the gradle project.
Effect Index
In this index we demonstrate selected filters, this is in no way a complete overview of what orx-fx offers.
Blur effects
BoxBlur
fun main() = application {
program {
// -- load a source image
val image = loadImage("data/images/cheeta.jpg")
// -- create a filter
val blur = BoxBlur()
// -- create a colorBuffer where to store the result
val blurred = colorBuffer(image.width, image.height)
extend {
// -- configure the filter
blur.window = (cos(seconds * 2) * 4.0 + 5.0).toInt()
// -- filter.apply(source, target)
blur.apply(image, blurred)
// -- draw the result
drawer.image(blurred)
}
}
}
ApproximateGaussianBlur
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val blurred = colorBuffer(image.width, image.height)
val blur = ApproximateGaussianBlur()
extend {
blur.window = 25
blur.sigma = cos(seconds * 2) * 10.0 + 10.1
blur.apply(image, blurred)
drawer.image(blurred)
}
}
}
GaussianBloom
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val blurred = colorBuffer(image.width, image.height)
val bloom = GaussianBloom()
extend {
bloom.window = 5
bloom.sigma = 3.0
bloom.gain = cos(seconds * 2) * 2.0 + 2.0
bloom.apply(image, blurred)
drawer.image(blurred)
}
}
}
HashBlur
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val blurred = colorBuffer(image.width, image.height)
val blur = HashBlur()
extend {
blur.samples = 50
blur.radius = cos(seconds * 2) * 25.0 + 25.0
blur.apply(image, blurred)
drawer.image(blurred)
}
}
}
FrameBlur
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val blurred = colorBuffer(image.width, image.height)
val blur = FrameBlur()
val rt = renderTarget(width, height) {
colorBuffer()
}
extend {
drawer.isolatedWithTarget(rt) {
drawer.clear(ColorRGBa.BLACK)
drawer.image(image, cos(seconds * 2) * 40.0, sin(seconds * 2) * 40.0)
}
blur.blend = 0.01
blur.apply(rt.colorBuffer(0), blurred)
drawer.image(blurred)
}
}
}
ZoomBlur
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val blurred = colorBuffer(image.width, image.height)
val blur = ZoomBlur()
extend {
blur.center = Vector2(cos(seconds) * 0.5 + 0.5, sin(seconds * 2) * 0.5 + 0.5)
blur.strength = cos(seconds * 2) * 0.5 + 0.5
blur.apply(image, blurred)
drawer.image(blurred)
}
}
}
Color filters
ChromaticAberration
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = ChromaticAberration()
val filtered = colorBuffer(image.width, image.height)
extend {
filter.aberrationFactor = cos(seconds * 2) * 10.0
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
ColorCorrection
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = ColorCorrection()
val filtered = colorBuffer(image.width, image.height)
extend {
filter.hueShift = cos(seconds * 1) * 180.0
filter.saturation = cos(seconds * 2)
filter.brightness = sin(seconds * 3) * 0.1
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
Sepia
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = Sepia()
val filtered = colorBuffer(image.width, image.height)
extend {
filter.amount = cos(seconds * 2) * 0.5 + 0.5
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
LumaOpacity
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = LumaOpacity()
val filtered = colorBuffer(image.width, image.height)
extend {
// -- a pink background to demonstrate the introduced transparencies
drawer.clear(ColorRGBa.PINK)
filter.backgroundOpacity = 0.0
filter.foregroundOpacity = 1.0
filter.backgroundLuma = cos(seconds) * 0.25 + 0.25
filter.foregroundLuma = 1.0 - (cos(seconds) * 0.25 + 0.25)
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
Edge-detection filters
LumaSobel
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = LumaSobel()
val filtered = colorBuffer(image.width, image.height)
extend {
filter.backgroundColor = ColorRGBa.PINK.toHSVa().shiftHue(cos(seconds) * 180).toRGBa().shade(0.25)
filter.edgeColor = ColorRGBa.PINK
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
Contour
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = Contour()
val filtered = colorBuffer(image.width, image.height)
extend {
filter.backgroundOpacity = 1.0
filter.contourColor = ColorRGBa.BLACK
filter.contourWidth = 0.4
filter.levels = cos(seconds) * 3.0 + 5.1
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
EdgesWork
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = EdgesWork()
val filtered = colorBuffer(image.width, image.height)
extend {
filter.radius = (cos(seconds) * 5 + 5).toInt()
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
Distortion filters
BlockRepeat
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = BlockRepeat()
val filtered = colorBuffer(image.width, image.height)
extend {
filter.sourceScale = seconds / 5.0
filter.blockWidth = cos(seconds) * 0.3 + 0.4
filter.blockHeight = sin(seconds) * 0.3 + 0.4
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
StackRepeat
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = StackRepeat()
val filtered = colorBuffer(image.width, image.height)
extend {
filter.repeats = 4
filter.zoom = (cos(seconds) * 0.1 + 0.11)
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
HorizontalWave
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = HorizontalWave()
val filtered = colorBuffer(image.width, image.height)
extend {
filter.amplitude = cos(seconds) * 0.1
filter.frequency = sin(seconds) * 4.0
if (seconds > 2.5) {
filter.segments = 10
}
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
VerticalWave
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = VerticalWave()
val filtered = colorBuffer(image.width, image.height)
extend {
filter.amplitude = cos(seconds) * 0.1
filter.frequency = sin(seconds) * 4.0
if (seconds > 2.5) {
filter.segments = 10
}
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
Perturb
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = Perturb()
val filtered = colorBuffer(image.width, image.height)
extend {
filter.phase = seconds * 0.1
filter.decay = 0.168
filter.gain = cos(seconds) * 0.5 + 0.5
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
Tiles
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = Tiles()
val filtered = colorBuffer(image.width, image.height)
extend {
filter.rotation = seconds * 60.0
filter.xSegments = (10 + cos(seconds * PI / 3) * 5.0).toInt()
filter.ySegments = 30
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
Fisheye
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = Fisheye()
val filtered = colorBuffer(image.width, image.height)
extend {
filter.strength = cos(seconds) * 0.125
filter.scale = 1.1
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
DisplaceBlend
fun main() = application {
program {
val composite = compose {
colorType = ColorType.FLOAT16
layer {
val image = loadImage("data/images/cheeta.jpg")
draw {
drawer.imageFit(image, 0.0, 0.0, width * 1.0, height * 1.0)
}
}
layer {
draw {
drawer.shadeStyle = linearGradient(ColorRGBa.BLACK, ColorRGBa.WHITE)
drawer.stroke = null
val size = cos(seconds * PI / 3) * 100.0 + 200.0
drawer.rectangle(width / 2.0 - size / 2, height / 2.0 - size / 2, size, size)
}
blend(DisplaceBlend()) {
gain = cos(seconds * PI / 3) * 0.5 + 0.5
rotation = seconds * 60.0
}
}
}
extend {
composite.draw(drawer)
}
}
}
StretchWaves
fun main() = application {
program {
val composite = compose {
colorType = ColorType.FLOAT16
layer {
val image = loadImage("data/images/cheeta.jpg")
draw {
drawer.imageFit(image, 0.0, 0.0, width * 1.0, height * 1.0)
}
post(StretchWaves()) {
distortion = 0.25
rotation = seconds * 60.0
phase = seconds * 0.25
frequency = 5.0
}
}
}
extend {
composite.draw(drawer)
}
}
}
PerspectivePlane
fun main() = application {
program {
val composite = compose {
layer {
post(Checkers())
}
layer {
val image = loadImage("data/images/cheeta.jpg")
draw {
drawer.imageFit(image, 0.0, 0.0, width * 1.0, height * 1.0)
}
post(PerspectivePlane()) {
planePitch = cos(seconds) * 22.5
planeYaw = sin(seconds) * 22.5
}
}
}
extend {
composite.draw(drawer)
}
}
}
Dithering filters
ADither
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = ADither()
val filtered = colorBuffer(image.width, image.height)
extend {
filter.pattern = ((seconds / 5.0) * 4).toInt().coerceAtMost(3)
filter.levels = ((seconds % 1.0) * 3).toInt() + 1
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
CMYKHalftone
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = CMYKHalftone()
val filtered = colorBuffer(image.width, image.height)
extend {
// -- need a white background because the filter introduces transparent areas
drawer.clear(ColorRGBa.WHITE)
filter.dotSize = 1.2
filter.scale = cos(seconds) * 2.0 + 6.0
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
Crosshatch
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = Crosshatch()
val filtered = colorBuffer(image.width, image.height)
extend {
// -- need a white background because the filter introduces transparent areas
drawer.clear(ColorRGBa.WHITE)
filter.t1 = cos(seconds * PI) * 0.25 + 0.25
filter.t2 = filter.t1 + cos(seconds * 3) * 0.25 + 0.25
filter.t3 = filter.t2 + cos(seconds * 2) * 0.25 + 0.25
filter.t4 = filter.t3 + cos(seconds * 1) * 0.25 + 0.25
filter.apply(image, filtered)
drawer.image(filtered)
}
}
}
Shadow filters
DropShadow
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val filter = DropShadow()
val filtered = colorBuffer(image.width, image.height)
val rt = renderTarget(width, height) {
colorBuffer()
}
extend {
drawer.isolatedWithTarget(rt) {
drawer.clear(ColorRGBa.TRANSPARENT)
drawer.image(image, (image.width - image.width * 0.8) / 2, (image.height - image.height * 0.8) / 2, image.width * 0.8, image.height * 0.8)
}
// -- need a pink background because the filter introduces transparent areas
drawer.clear(ColorRGBa.PINK)
filter.window = (cos(seconds) * 16 + 16).toInt()
filter.xShift = cos(seconds * 2) * 16.0
filter.yShift = sin(seconds * 2) * 16.0
filter.apply(rt.colorBuffer(0), filtered)
drawer.image(filtered)
}
}
}
Pattern filters
Checkers
Checkers
is a simple checker generator filter.
fun main() = application {
program {
val composite = compose {
layer {
post(Checkers()) {
size = cos(seconds) * 0.6 + 0.4
}
}
}
extend {
composite.draw(drawer)
}
}
}