Poisson fills
orx-poisson-fills offers tool for GPU-based Poisson operations.
Prerequisites
Assuming you are working on an openrndr-template based project, all you have to do is to add implementation(orx.poisson.fill) to the dependencies block in build.gradle.kts and reload Gradle, as described in ORX.
Filling
The PoissonFill filter can be used to fill in transparent parts of an image. In the following example we use orx-compose to simplify the code a bit. The same results can be achieved using render targets.
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.loadImage
import org.openrndr.extra.compositor.*
import org.openrndr.poissonfill.PoissonBlend
import org.openrndr.poissonfill.PoissonFill
import org.openrndr.shape.Rectangle
import kotlin.math.cos
import kotlin.math.sin
fun main() = application {
program {
val c = compose {
layer {
draw {
drawer.stroke = null
drawer.fill = ColorRGBa.RED
drawer.circle(
(cos(seconds) * 0.5 + 0.5) * width,
(sin(seconds * 0.5) * 0.5 + 0.5) * height,
20.0
)
drawer.fill = ColorRGBa.PINK
drawer.circle(
(sin(seconds * 2.0) * 0.5 + 0.5) * width,
(cos(seconds) * 0.5 + 0.5) * height,
20.0
)
drawer.fill = ColorRGBa.BLACK
drawer.circle(
(sin(seconds * 1.0) * 0.5 + 0.5) * width,
(cos(seconds * 2.0) * 0.5 + 0.5) * height,
20.0
)
}
post(PoissonFill())
}
layer {
// -- an extra layer just to demonstrate where the original data points are drawn
draw {
drawer.stroke = ColorRGBa.WHITE
drawer.strokeWeight = 5.0
drawer.fill = ColorRGBa.RED
drawer.circle(
(cos(seconds) * 0.5 + 0.5) * width,
(sin(seconds * 0.5) * 0.5 + 0.5) * height,
20.0
)
drawer.fill = ColorRGBa.PINK
drawer.circle(
(sin(seconds * 2.0) * 0.5 + 0.5) * width,
(cos(seconds) * 0.5 + 0.5) * height,
20.0
)
drawer.fill = ColorRGBa.BLACK
drawer.circle(
(sin(seconds * 1.0) * 0.5 + 0.5) * width,
(cos(seconds * 2.0) * 0.5 + 0.5) * height,
20.0
)
}
}
}
extend {
c.draw(drawer)
}
}
}
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.loadImage
import org.openrndr.extra.compositor.*
import org.openrndr.poissonfill.PoissonBlend
import org.openrndr.poissonfill.PoissonFill
import org.openrndr.shape.Rectangle
import kotlin.math.cos
import kotlin.math.sin
fun main() = application {
program {
val c = compose {
layer {
val image = loadImage("data/images/cheeta.jpg")
draw {
drawer.image(
image,
Rectangle(
(cos(seconds) * 0.5 + 0.5) * 100.0,
(sin(seconds) * 0.5 + 0.5) * 100.0,
200.0,
200.0
),
Rectangle(
width / 2 - 100.0,
height / 2.0 - 100.0,
200.0,
200.0
)
)
}
post(PoissonFill())
}
}
extend {
c.draw(drawer)
}
}
}
Blending
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.loadImage
import org.openrndr.extra.compositor.*
import org.openrndr.poissonfill.PoissonBlend
import org.openrndr.poissonfill.PoissonFill
import org.openrndr.shape.Rectangle
import kotlin.math.cos
import kotlin.math.sin
fun main() = application {
program {
val c = compose {
layer {
val image = loadImage("data/images/cheeta.jpg")
draw {
drawer.image(image)
}
}
layer {
draw {
drawer.stroke = null
drawer.fill = ColorRGBa.BLACK
drawer.circle(
(cos(seconds) * 0.5 + 0.5) * width,
(sin(seconds * 0.5) * 0.5 + 0.5) * height,
120.0
)
}
blend(PoissonBlend())
}
}
extend {
c.draw(drawer)
}
}
}
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.loadImage
import org.openrndr.extra.compositor.*
import org.openrndr.poissonfill.PoissonBlend
import org.openrndr.poissonfill.PoissonFill
import org.openrndr.shape.Rectangle
import kotlin.math.cos
import kotlin.math.sin
fun main() = application {
program {
val image = loadImage("data/images/cheeta.jpg")
val c = compose {
layer {
draw {
drawer.image(image)
}
}
layer {
draw {
drawer.stroke = ColorRGBa.GRAY
drawer.fill = null
drawer.strokeWeight = 40.0
drawer.circle(
(cos(seconds) * 0.5 + 0.5) * width,
(sin(seconds * 0.5) * 0.5 + 0.5) * height,
120.0
)
}
//post(LumaOpacity()) {
// this.backgroundLuma = 0.8
//}
blend(PoissonBlend())
}
}
extend {
c.draw(drawer)
}
}
}