[orx-fx] Directional blur tweaks (#357)

This commit is contained in:
Abe Pazos
2025-07-07 16:25:31 +02:00
committed by GitHub
parent 8323054519
commit f77c338608
7 changed files with 227 additions and 25 deletions

View File

@@ -2,14 +2,14 @@
package org.openrndr.extra.fx.blur
import org.openrndr.draw.*
import org.openrndr.draw.Filter2to1
import org.openrndr.extra.fx.fx_directional_blur
import org.openrndr.extra.fx.mppFilterShader
import org.openrndr.extra.parameters.BooleanParameter
import org.openrndr.extra.parameters.Description
import org.openrndr.extra.parameters.DoubleParameter
import org.openrndr.extra.parameters.IntParameter
import org.openrndr.shape.Rectangle
/**
* Directional blur filter. Takes source image and direction buffer inputs
@@ -24,13 +24,13 @@ class DirectionalBlur : Filter2to1(mppFilterShader(fx_directional_blur, "directi
var centerWindow: Boolean by parameters
/**
* The sample window, default is 5
* The sample window: how many samples to mix. The default is 5
*/
@IntParameter("window size", 1, 25)
var window: Int by parameters
/**
* Spread multiplier, default is 1.0
* Spread multiplier: the distance in pixels between sampled pixels. The default is 1.0
*/
@DoubleParameter("kernel spread", 1.0, 4.0)
var spread: Double by parameters
@@ -42,12 +42,22 @@ class DirectionalBlur : Filter2to1(mppFilterShader(fx_directional_blur, "directi
var gain: Double by parameters
/**
* Should filter use directions perpendicular to those in the direction buffer?
* Should filter use directions perpendicular to those in the direction buffer? default is false
*/
@BooleanParameter("perpendicular")
var perpendicular: Boolean by parameters
/**
* Wrap around left and right edges
*/
@BooleanParameter("wrapX")
var wrapX: Boolean by parameters
/**
* Wrap around top and bottom edges
*/
@BooleanParameter("wrapY")
var wrapY: Boolean by parameters
init {
window = 5
@@ -55,11 +65,7 @@ class DirectionalBlur : Filter2to1(mppFilterShader(fx_directional_blur, "directi
gain = 1.0
perpendicular = false
centerWindow = false
}
override fun apply(source: Array<ColorBuffer>, target: Array<ColorBuffer>, clip: Rectangle?) {
parameters["wrapX"] = false
parameters["wrapY"] = false
super.apply(source, target, clip)
wrapX = false
wrapY = false
}
}

View File

@@ -0,0 +1,55 @@
@file:Suppress("RUNTIME_ANNOTATION_NOT_SUPPORTED")
package org.openrndr.extra.fx.distort
import org.openrndr.draw.Filter2to1
import org.openrndr.extra.fx.fx_directional_displace
import org.openrndr.extra.fx.mppFilterShader
import org.openrndr.extra.parameters.BooleanParameter
import org.openrndr.extra.parameters.Description
import org.openrndr.extra.parameters.DoubleParameter
/**
* Directional displace filter. Takes source image and direction buffer inputs
*/
@Description("Directional displace")
class DirectionalDisplace : Filter2to1(mppFilterShader(fx_directional_displace, "directional-displace")) {
/**
* The distance of the sampled pixel. The default is 1.0
*/
@DoubleParameter("distance", 1.0, 1000.0)
var distance: Double by parameters
/**
* Post-displace gain, default is 1.0
*/
@DoubleParameter("gain", 0.0, 4.0)
var gain: Double by parameters
/**
* Should filter use directions perpendicular to those in the direction buffer? default is false
*/
@BooleanParameter("perpendicular")
var perpendicular: Boolean by parameters
/**
* Wrap around left and right edges
*/
@BooleanParameter("wrapX")
var wrapX: Boolean by parameters
/**
* Wrap around top and bottom edges
*/
@BooleanParameter("wrapY")
var wrapY: Boolean by parameters
init {
distance = 1.0
gain = 1.0
perpendicular = false
wrapX = false
wrapY = false
}
}

View File

@@ -6,6 +6,19 @@ import org.openrndr.math.smoothstep
import kotlin.math.cos
import kotlin.math.sin
/**
* Demonstrates how to use [DirectionalBlur] by creating a `direction`
* ColorBuffer in which the red and green components of the pixels point
* in various directions where to sample pixels from. All the pixel colors
* of the ColorBuffer are set one by one using two for loops.
*
* Note the FLOAT32 color type of the buffer to allow for negative values,
* so sampling can happen from every direction.
*
* Every 60 animation frames the `centerWindow` property is toggled
* between true and false to demonstrate how the result changes.
*
*/
fun main() = application {
program {
val db = DirectionalBlur()
@@ -31,6 +44,7 @@ fun main() = application {
drawer.image(image)
}
db.window = 10
db.centerWindow = frameCount % 120 > 60
db.apply(arrayOf(rt.colorBuffer(0), direction), blurred)
drawer.image(blurred)
}

View File

@@ -0,0 +1,50 @@
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.color.rgb
import org.openrndr.draw.ColorType
import org.openrndr.draw.colorBuffer
import org.openrndr.draw.loadImage
import org.openrndr.drawImage
import org.openrndr.extra.fx.distort.DirectionalDisplace
import org.openrndr.extra.noise.simplex
import org.openrndr.extra.shapes.primitives.grid
import kotlin.math.cos
/**
* Demonstrate how to use [DirectionalDisplace].
*
* The direction map is populated using `drawImage` instead of
* pixel by pixel. A grid of circles is drawn, each circle with a
* color based on simplex noise. The R and G channels of the colors
* control the direction of the sampling. By animating the sampling
* distance the result oscillates between no-effect and a noticeable one.
*/
fun main() = application {
program {
val displace = DirectionalDisplace()
val displaced = colorBuffer(width, height)
val direction = drawImage(width, height, type = ColorType.FLOAT32) {
clear(ColorRGBa.BLACK)
bounds.grid(32, 24).flatten().forEach {
fill = rgb(
simplex(133, it.center * 0.004),
simplex(197, it.center * 0.004),
0.0
)
stroke = null
//rectangle(it)
circle(it.center, 8.0)
}
}
val image = loadImage("demo-data/images/image-001.png")
extend {
displace.distance = 100.0 + 100.0 * cos(seconds)
displace.wrapX = true
displace.wrapX = true
displace.apply(arrayOf(image, direction), displaced)
drawer.image(displaced)
}
}
}

View File

@@ -0,0 +1,45 @@
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.color.rgb
import org.openrndr.draw.ColorType
import org.openrndr.draw.colorBuffer
import org.openrndr.draw.loadImage
import org.openrndr.drawImage
import org.openrndr.extra.fx.distort.DirectionalDisplace
import org.openrndr.math.Polar
/**
* Demonstrate how to use [DirectionalDisplace].
*
* The program draws 12 overlapping translucent circles on the
* `direction` color buffer to produce new color combinations
* on the overlapping areas. Those colors specify where the
* `DirectionalDisplace` effect will sample pixels from.
*/
fun main() = application {
program {
val displace = DirectionalDisplace()
val displaced = colorBuffer(width, height)
val direction = drawImage(width, height, type = ColorType.FLOAT32) {
clear(ColorRGBa.BLACK)
for(x in 0 until 6) {
val offset = Polar(x * 60.0).cartesian
fill = rgb(offset.y, offset.x, 0.0, 0.3)
stroke = null
val pos = bounds.center - offset * 110.0
circle(pos, 120.0)
circle(pos, 80.0)
}
}
val image = loadImage("demo-data/images/image-001.png")
extend {
displace.distance = 250.0
displace.apply(arrayOf(image, direction), displaced)
drawer.image(displaced)
//drawer.image(direction)
}
}
}

View File

@@ -1,8 +1,8 @@
in vec2 v_texCoord0;
uniform bool centerWindow;
uniform sampler2D tex0;// image
uniform sampler2D tex1;// blurDirection
uniform sampler2D tex0; // image
uniform sampler2D tex1; // blurDirection
uniform vec2 textureSize0;
uniform int window;
@@ -17,15 +17,11 @@ out vec4 o_color;
vec2 wrap(vec2 uv) {
vec2 res = uv;
if (wrapX) {
res.x = mod(res.x, 1.0);
}
if (wrapY) {
res.y = mod(res.y, 1.0);
}
if (wrapX) { res.x = fract(res.x); }
if (wrapY) { res.y = fract(res.y); }
return res;
}
void main() {
vec2 s = textureSize0;
s = vec2(1.0 / s.x, 1.0 / s.y);
@@ -37,15 +33,14 @@ void main() {
}
float weight = 0.0;
int start = centerWindow? -window/2 : 0;
int end = centerWindow? window/2 + 1 : window;
int start = centerWindow ? -window / 2 : 0;
int end = centerWindow ? window / 2 + 1 : window;
for (int x = 0; x < window; ++x) {
for (int x = start; x < end; ++x) {
sum += texture(tex0, wrap(v_texCoord0 + float(x) * blurDirection * s * spread));
weight += 1.0;
}
vec4 result = (sum/weight) * gain;
vec4 result = (sum / weight) * gain;
o_color = result;
}

View File

@@ -0,0 +1,37 @@
in vec2 v_texCoord0;
uniform sampler2D tex0; // image
uniform sampler2D tex1; // displaceDirection
uniform vec2 textureSize0;
uniform float gain;
uniform float distance;
uniform bool wrapX;
uniform bool wrapY;
uniform bool perpendicular;
out vec4 o_color;
vec2 wrap(vec2 uv) {
vec2 res = uv;
if (wrapX) { res.x = fract(res.x); }
if (wrapY) { res.y = fract(res.y); }
return res;
}
void main() {
vec2 s = textureSize0;
s = vec2(1.0 / s.x, 1.0 / s.y);
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
vec2 blurDirection = texture(tex1, v_texCoord0).xy;
if (perpendicular) {
blurDirection = vec2(-blurDirection.y, blurDirection.x);
}
vec4 result = texture(tex0, wrap(v_texCoord0 + blurDirection * s * distance))
* gain;
o_color = result;
}