Blend filters between colorBuffers

I wanted to perform an accumulation pass between colorBuffers.
Something like Add().apply(sourceBuffer, targetBuffer), where some parts of the sourceBuffer are transparent.

However this overrules what was stored in targetBuffer and is effectively the same as sourceBuffer.copyTo(targetBuffer).

I wrote a small program to illustrate this and verify for yourself:

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.*
import org.openrndr.extra.fx.blend.Add
import org.openrndr.extra.fx.color.ColorCorrection
import kotlin.math.*

fun main() = application {
    program {

        // Pipeline setup
        val rt = renderTarget(width, height) {
        val drawBuffer = rt.colorBuffer(0)
        val accumulator = drawBuffer.createEquivalent()

        val colorCorrectionFx = ColorCorrection().apply { hueShift = 5.0 }
        val addBlend = Add()

        extend {
            drawer.isolatedWithTarget(rt) {
                // This clears the buffer, add will use TRANSPARENT to overwrite target
                clear(ColorRGBa.TRANSPARENT) // Equivalent to drawBuffer.fill(TRANSPARENT)

                stroke = null
                val lumFac = sin(seconds * 1.5)*0.5 + 0.5
                val opaFac = sin(seconds*3)*0.5 + 0.5
                fill = ColorRGBa.PINK.shade(lumFac).opacify(opaFac)

                val x = sin(seconds).map(-1.0, 1.0, width*0.2, width*0.8)
                val y = cos(seconds).map(-1.0, 1.0, height*0.2, height*0.8)
                circle(x, y, 50.0)

            // Works fine, just for illustration
            colorCorrectionFx.apply(accumulator, accumulator)

            // On blend, the transparent part of the image gets destroyed
            if (frameCount%10 == 0) {
                addBlend.apply(drawBuffer, accumulator)


I am 99% certain I misunderstand something about blend filters and colorBuffers.

How would you actually perform an addtive pass from one colorBuffer to another ?

Hi! I guess it’s maybe not very obvious, but the Add() effect is a Filter2to1 kind of effect, which means it takes two inputs and produces one output. Which in code it may look like this:

if (frameCount % 10 == 0) {
    addBlend.apply(arrayOf(drawBuffer, accumulator), accumulator)

Exactly what I was looking for !

This also answers why apply has so many signatures, some with 1-n and m-1 relationships from source to target.

I would guess that 1-1 is “apply and copy to one”, 1-n is “apply and copy to many” and m-1 is “combine and copy to one”. Or are they reserved for other use cases ?

1 Like

I think there are 4 variations: Filter1to1Filter4to1:

Color filters are Filter1to1 (Invert, Sepia, etc): take an image, alter its colors, return a modified version.

Blend modes are Filter2to1 (Add, Subtract, etc): take two images and combine them in some way into a new one.

I only find DirectionalHashBlurDynamic being Filter3to1 and no Filter4to1 uses yet.

I can imagine a Filter1to4 filter being an effect to produce various images out of one. For instance, take an RGBA image and produce 4 textures with the 4 channels. But there are no 1toN effects yet afaik.

BTW, all of these were added quite recently, on December 2022 :slight_smile:

How about an RGB split into 3 buffers.
Then distort R/G/B with StackRepat with different strengths.

That’s what I can think of :smiley:

Yeah I think that will look cool. Split, process, merge. Probably creates some interesting chromatic aberrations. I actually have an effect that produces 3 colorBuffers and another that joins them :slight_smile: