[orx-fx] Add fade to Contour and CannyEdgeDetector
This commit is contained in:
@@ -34,6 +34,8 @@ kotlin {
|
|||||||
implementation(project(":orx-color"))
|
implementation(project(":orx-color"))
|
||||||
implementation(project(":orx-fx"))
|
implementation(project(":orx-fx"))
|
||||||
implementation(project(":orx-noise"))
|
implementation(project(":orx-noise"))
|
||||||
|
implementation(project(":orx-shapes"))
|
||||||
|
implementation(project(":orx-image-fit"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ class CannyEdgeDetector : Filter1to1(
|
|||||||
var backgroundOpacity: Double by parameters
|
var backgroundOpacity: Double by parameters
|
||||||
|
|
||||||
|
|
||||||
|
@DoubleParameter("fade", 0.0, 1.0, order = 7)
|
||||||
|
var fade: Double by parameters
|
||||||
|
|
||||||
init {
|
init {
|
||||||
threshold0 = 2.0
|
threshold0 = 2.0
|
||||||
threshold1 = 0.0
|
threshold1 = 0.0
|
||||||
@@ -45,6 +48,7 @@ class CannyEdgeDetector : Filter1to1(
|
|||||||
backgroundColor = ColorRGBa.BLACK
|
backgroundColor = ColorRGBa.BLACK
|
||||||
backgroundOpacity = 1.0
|
backgroundOpacity = 1.0
|
||||||
foregroundOpacity = 1.0
|
foregroundOpacity = 1.0
|
||||||
|
fade = 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,7 @@ import org.openrndr.color.ColorRGBa
|
|||||||
import org.openrndr.draw.Filter1to1
|
import org.openrndr.draw.Filter1to1
|
||||||
import org.openrndr.extra.fx.fx_contour
|
import org.openrndr.extra.fx.fx_contour
|
||||||
import org.openrndr.extra.fx.mppFilterShader
|
import org.openrndr.extra.fx.mppFilterShader
|
||||||
import org.openrndr.extra.parameters.ColorParameter
|
import org.openrndr.extra.parameters.*
|
||||||
import org.openrndr.extra.parameters.Description
|
|
||||||
import org.openrndr.extra.parameters.DoubleParameter
|
|
||||||
import org.openrndr.extra.parameters.IntParameter
|
|
||||||
|
|
||||||
@Description("Contour")
|
@Description("Contour")
|
||||||
class Contour : Filter1to1(mppFilterShader(fx_contour, "contour")) {
|
class Contour : Filter1to1(mppFilterShader(fx_contour, "contour")) {
|
||||||
@@ -28,13 +25,18 @@ class Contour : Filter1to1(mppFilterShader(fx_contour, "contour")) {
|
|||||||
@DoubleParameter("bias", -1.0, 1.0)
|
@DoubleParameter("bias", -1.0, 1.0)
|
||||||
var bias: Double by parameters
|
var bias: Double by parameters
|
||||||
|
|
||||||
|
|
||||||
@ColorParameter("contour color")
|
@ColorParameter("contour color")
|
||||||
var contourColor: ColorRGBa by parameters
|
var contourColor: ColorRGBa by parameters
|
||||||
|
|
||||||
@IntParameter("window", 0, 10)
|
@IntParameter("window", 0, 10)
|
||||||
var window: Int by parameters
|
var window: Int by parameters
|
||||||
|
|
||||||
|
@BooleanParameter("output bands", order = 100)
|
||||||
|
var outputBands: Boolean by parameters
|
||||||
|
|
||||||
|
@DoubleParameter("fade", 0.0, 1.0, order = 200)
|
||||||
|
var fade: Double by parameters
|
||||||
|
|
||||||
init {
|
init {
|
||||||
levels = 6.0
|
levels = 6.0
|
||||||
contourWidth = 0.4
|
contourWidth = 0.4
|
||||||
@@ -43,5 +45,7 @@ class Contour : Filter1to1(mppFilterShader(fx_contour, "contour")) {
|
|||||||
contourOpacity = 1.0
|
contourOpacity = 1.0
|
||||||
window = 1
|
window = 1
|
||||||
bias = 0.0
|
bias = 0.0
|
||||||
|
outputBands = false
|
||||||
|
fade = 1.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
56
orx-fx/src/jvmDemo/kotlin/DemoContour01.kt
Normal file
56
orx-fx/src/jvmDemo/kotlin/DemoContour01.kt
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* Demonstrate the Contour filter
|
||||||
|
* @author Edwin Jakobs
|
||||||
|
*/
|
||||||
|
|
||||||
|
import org.openrndr.application
|
||||||
|
import org.openrndr.color.ColorRGBa
|
||||||
|
import org.openrndr.draw.createEquivalent
|
||||||
|
import org.openrndr.draw.loadImage
|
||||||
|
import org.openrndr.extra.fx.edges.Contour
|
||||||
|
import org.openrndr.extra.imageFit.imageFit
|
||||||
|
import org.openrndr.extra.shapes.primitives.grid
|
||||||
|
|
||||||
|
fun main() = application {
|
||||||
|
configure {
|
||||||
|
width = 720
|
||||||
|
height = 720
|
||||||
|
}
|
||||||
|
program {
|
||||||
|
val image = loadImage("demo-data/images/image-001.png")
|
||||||
|
val contour = Contour()
|
||||||
|
contour.levels = 4.0
|
||||||
|
contour.window = 1
|
||||||
|
contour.outputBands = true
|
||||||
|
contour.contourColor = ColorRGBa.PINK
|
||||||
|
contour.backgroundOpacity = 0.0
|
||||||
|
|
||||||
|
val edges = image.createEquivalent()
|
||||||
|
extend {
|
||||||
|
val cells = drawer.bounds.grid(2, 2).flatten()
|
||||||
|
val actions = listOf(
|
||||||
|
{
|
||||||
|
contour.outputBands = true
|
||||||
|
contour.levels = 2.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contour.outputBands = false
|
||||||
|
contour.levels = 2.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contour.outputBands = false
|
||||||
|
contour.levels = 8.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contour.outputBands = true
|
||||||
|
contour.levels = 8.0
|
||||||
|
},
|
||||||
|
)
|
||||||
|
for ((cell, action) in cells zip actions) {
|
||||||
|
action()
|
||||||
|
contour.apply(image, edges)
|
||||||
|
drawer.imageFit(edges, cell)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,44 +15,46 @@ uniform vec4 foregroundColor;
|
|||||||
uniform float backgroundOpacity;
|
uniform float backgroundOpacity;
|
||||||
uniform float foregroundOpacity;
|
uniform float foregroundOpacity;
|
||||||
|
|
||||||
|
uniform float fade;
|
||||||
|
|
||||||
vec2 iResolution;
|
vec2 iResolution;
|
||||||
|
|
||||||
float getAve(vec2 uv){
|
float getAve(vec2 uv) {
|
||||||
vec3 rgb = texture(tex0, uv).rgb;
|
vec3 rgb = texture(tex0, uv).rgb;
|
||||||
vec3 lum = vec3(0.299, 0.587, 0.114);
|
vec3 lum = vec3(0.299, 0.587, 0.114);
|
||||||
return dot(lum, rgb);
|
return dot(lum, rgb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect edge.
|
// Detect edge.
|
||||||
vec4 sobel(vec2 fragCoord, vec2 dir){
|
vec4 sobel(vec2 fragCoord, vec2 dir) {
|
||||||
vec2 uv = fragCoord/iResolution.xy;
|
vec2 uv = fragCoord / iResolution.xy;
|
||||||
vec2 texel = 1./iResolution.xy;
|
vec2 texel = 1. / iResolution.xy;
|
||||||
float np = getAve(uv + (vec2(-1,+1) + dir ) * texel * thickness);
|
float np = getAve(uv + (vec2(-1, + 1) + dir) * texel * thickness);
|
||||||
float zp = getAve(uv + (vec2( 0,+1) + dir ) * texel * thickness);
|
float zp = getAve(uv + (vec2(0, + 1) + dir) * texel * thickness);
|
||||||
float pp = getAve(uv + (vec2(+1,+1) + dir ) * texel * thickness);
|
float pp = getAve(uv + (vec2(+ 1, + 1) + dir) * texel * thickness);
|
||||||
|
|
||||||
float nz = getAve(uv + (vec2(-1, 0) + dir ) * texel * thickness);
|
float nz = getAve(uv + (vec2(-1, 0) + dir) * texel * thickness);
|
||||||
// zz = 0
|
// zz = 0
|
||||||
float pz = getAve(uv + (vec2(+1, 0) + dir ) * texel * thickness);
|
float pz = getAve(uv + (vec2(+ 1, 0) + dir) * texel * thickness);
|
||||||
|
|
||||||
float nn = getAve(uv + (vec2(-1,-1) + dir ) * texel * thickness);
|
float nn = getAve(uv + (vec2(-1, -1) + dir) * texel * thickness);
|
||||||
float zn = getAve(uv + (vec2( 0,-1) + dir ) * texel * thickness);
|
float zn = getAve(uv + (vec2(0, -1) + dir) * texel * thickness);
|
||||||
float pn = getAve(uv + (vec2(+1,-1) + dir ) * texel * thickness);
|
float pn = getAve(uv + (vec2(+ 1, -1) + dir) * texel * thickness);
|
||||||
|
|
||||||
// np zp pp
|
// np zp pp
|
||||||
// nz zz pz
|
// nz zz pz
|
||||||
// nn zn pn
|
// nn zn pn
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
float gx = (np*-1. + nz*-2. + nn*-1. + pp*1. + pz*2. + pn*1.);
|
float gx = (np * -1. + nz * -2. + nn * -1. + pp * 1. + pz * 2. + pn * 1.);
|
||||||
float gy = (np*-1. + zp*-2. + pp*-1. + nn*1. + zn*2. + pn*1.);
|
float gy = (np * -1. + zp * -2. + pp * -1. + nn * 1. + zn * 2. + pn * 1.);
|
||||||
#else
|
#else
|
||||||
// https://www.shadertoy.com/view/Wds3Rl
|
// https://www.shadertoy.com/view/Wds3Rl
|
||||||
float gx = (np*-3. + nz*-10. + nn*-3. + pp*3. + pz*10. + pn*3.);
|
float gx = (np * -3. + nz * -10. + nn * -3. + pp * 3. + pz * 10. + pn * 3.);
|
||||||
float gy = (np*-3. + zp*-10. + pp*-3. + nn*3. + zn*10. + pn*3.);
|
float gy = (np * -3. + zp * -10. + pp * -3. + nn * 3. + zn * 10. + pn * 3.);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
vec2 G = vec2(gx,gy);
|
vec2 G = vec2(gx, gy);
|
||||||
|
|
||||||
float grad = length(G);
|
float grad = length(G);
|
||||||
|
|
||||||
@@ -62,49 +64,53 @@ vec4 sobel(vec2 fragCoord, vec2 dir){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make edge thinner.
|
// Make edge thinner.
|
||||||
vec2 hysteresisThr(vec2 fragCoord, float mn, float mx){
|
vec2 hysteresisThr(vec2 fragCoord, float mn, float mx) {
|
||||||
|
|
||||||
vec4 edge = sobel(fragCoord, vec2(0));
|
vec4 edge = sobel(fragCoord, vec2(0));
|
||||||
|
|
||||||
vec2 dir = vec2(cos(edge.w), sin(edge.w));
|
vec2 dir = vec2(cos(edge.w), sin(edge.w));
|
||||||
dir *= vec2(-1,1); // rotate 90 degrees.
|
dir *= vec2(-1, 1); // rotate 90 degrees.
|
||||||
|
|
||||||
vec4 edgep = sobel(fragCoord, dir);
|
vec4 edgep = sobel(fragCoord, dir);
|
||||||
vec4 edgen = sobel(fragCoord, -dir);
|
vec4 edgen = sobel(fragCoord, -dir);
|
||||||
|
|
||||||
if(edge.z < edgep.z || edge.z < edgen.z ) edge.z = 0.;
|
if (edge.z < edgep.z || edge.z < edgen.z) edge.z = 0.;
|
||||||
|
|
||||||
return vec2(
|
return vec2(
|
||||||
(edge.z > mn) ? edge.z : 0.,
|
(edge.z > mn) ? edge.z : 0.,
|
||||||
(edge.z > mx) ? edge.z : 0.
|
(edge.z > mx) ? edge.z : 0.
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
float cannyEdge(vec2 fragCoord, float mn, float mx){
|
float cannyEdge(vec2 fragCoord, float mn, float mx) {
|
||||||
|
|
||||||
vec2 np = hysteresisThr(fragCoord + vec2(-1,+1), mn, mx);
|
vec2 np = hysteresisThr(fragCoord + vec2(-1, + 1), mn, mx);
|
||||||
vec2 zp = hysteresisThr(fragCoord + vec2( 0,+1), mn, mx);
|
vec2 zp = hysteresisThr(fragCoord + vec2(0, + 1), mn, mx);
|
||||||
vec2 pp = hysteresisThr(fragCoord + vec2(+1,+1), mn, mx);
|
vec2 pp = hysteresisThr(fragCoord + vec2(+ 1, + 1), mn, mx);
|
||||||
|
|
||||||
vec2 nz = hysteresisThr(fragCoord + vec2(-1, 0), mn, mx);
|
vec2 nz = hysteresisThr(fragCoord + vec2(-1, 0), mn, mx);
|
||||||
vec2 zz = hysteresisThr(fragCoord + vec2( 0, 0), mn, mx);
|
vec2 zz = hysteresisThr(fragCoord + vec2(0, 0), mn, mx);
|
||||||
vec2 pz = hysteresisThr(fragCoord + vec2(+1, 0), mn, mx);
|
vec2 pz = hysteresisThr(fragCoord + vec2(+ 1, 0), mn, mx);
|
||||||
|
|
||||||
vec2 nn = hysteresisThr(fragCoord + vec2(-1,-1), mn, mx);
|
vec2 nn = hysteresisThr(fragCoord + vec2(-1, -1), mn, mx);
|
||||||
vec2 zn = hysteresisThr(fragCoord + vec2( 0,-1), mn, mx);
|
vec2 zn = hysteresisThr(fragCoord + vec2(0, -1), mn, mx);
|
||||||
vec2 pn = hysteresisThr(fragCoord + vec2(+1,-1), mn, mx);
|
vec2 pn = hysteresisThr(fragCoord + vec2(+ 1, -1), mn, mx);
|
||||||
|
|
||||||
// np zp pp
|
// np zp pp
|
||||||
// nz zz pz
|
// nz zz pz
|
||||||
// nn zn pn
|
// nn zn pn
|
||||||
//return min(1., step(1e-3, zz.x) * (zp.y + nz.y + pz.y + zn.y)*8.);
|
//return min(1., step(1e-3, zz.x) * (zp.y + nz.y + pz.y + zn.y)*8.);
|
||||||
//return min(1., step(1e-3, zz.x) * (np.y + pp.y + nn.y + pn.y)*8.);
|
//return min(1., step(1e-3, zz.x) * (np.y + pp.y + nn.y + pn.y)*8.);
|
||||||
return min(1., step(1e-2, zz.x*8.) * smoothstep(.0, .3, np.y + zp.y + pp.y + nz.y + pz.y + nn.y + zn.y + pn.y)*8.);
|
return min(1., step(1e-2, zz.x * 8.) * smoothstep(.0, .3, np.y + zp.y + pp.y + nz.y + pz.y + nn.y + zn.y + pn.y) * 8.);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main(){
|
void main() {
|
||||||
iResolution = vec2(textureSize(tex0, 0));
|
iResolution = vec2(textureSize(tex0, 0));
|
||||||
|
vec4 original = texture(tex0, v_texCoord0);
|
||||||
vec2 fragCoord = v_texCoord0 * iResolution;
|
vec2 fragCoord = v_texCoord0 * iResolution;
|
||||||
float edge = cannyEdge(fragCoord, threshold0, threshold1);
|
float edge = cannyEdge(fragCoord, threshold0, threshold1);
|
||||||
o_output = mix(foregroundColor * foregroundOpacity, backgroundColor * backgroundOpacity, 1.-edge);
|
o_output = mix(original,
|
||||||
|
mix(foregroundColor * foregroundOpacity,
|
||||||
|
backgroundColor * backgroundOpacity, 1. - edge),
|
||||||
|
fade);
|
||||||
}
|
}
|
||||||
@@ -8,27 +8,44 @@ uniform vec4 contourColor;
|
|||||||
uniform float backgroundOpacity;
|
uniform float backgroundOpacity;
|
||||||
uniform int window;
|
uniform int window;
|
||||||
uniform float bias;
|
uniform float bias;
|
||||||
|
uniform bool outputBands;
|
||||||
|
uniform float fade;
|
||||||
|
|
||||||
float calc_contour(vec2 uv) {
|
vec2 calc_contour(vec2 uv) {
|
||||||
vec4 box = texture(tex0, uv);
|
vec4 box = texture(tex0, uv);
|
||||||
float v = sin(3.1415926535 * levels * (dot(vec3(1.0 / 3.0), box.xyz) + bias));
|
float v = sin(3.1415926535 * levels * (dot(vec3(1.0 / 3.0), box.xyz) + bias));
|
||||||
float level = floor((dot(vec3(1.0 / 3.0), box.xyz) + bias) * levels) / levels;
|
float level = floor((dot(vec3(1.0 / 3.0), box.xyz) + bias) * levels);
|
||||||
float contour = 1.0 - smoothstep(0., contourWidth, 0.5 * abs(v) / fwidth(v));
|
float contour = 1.0 - smoothstep(0., contourWidth, 0.5 * abs(v) / fwidth(v));
|
||||||
return contour;
|
return vec2(contour, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 step = 1.0 / vec2(textureSize(tex0, 0));
|
vec2 step = 1.0 / vec2(textureSize(tex0, 0));
|
||||||
float contour = 0.0;
|
float contour = 0.0;
|
||||||
float weight = 0.0;
|
float weight = 0.0;
|
||||||
|
float level = 0.0;
|
||||||
|
|
||||||
for (int i = -window; i <= window; ++i) {
|
for (int i = -window; i <= window; ++i) {
|
||||||
for (int j = -window; j <= window; ++j) {
|
for (int j = -window; j <= window; ++j) {
|
||||||
contour += calc_contour(v_texCoord0 + step / (float(window) + 1.0) * vec2(float(i), float(j)));
|
vec2 c = calc_contour(v_texCoord0 + step / (float(window) + 1.0) * vec2(float(i), float(j)));
|
||||||
|
contour += c.x;
|
||||||
|
level += c.y;
|
||||||
weight += 1.0;
|
weight += 1.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
contour /= weight;
|
contour /= weight;
|
||||||
|
|
||||||
vec4 t = texture(tex0, v_texCoord0);
|
vec4 t = texture(tex0, v_texCoord0);
|
||||||
o_output = t * backgroundOpacity * (1.0 - contour) + contour * contourColor * contourOpacity * t.a;
|
|
||||||
|
if (outputBands) {
|
||||||
|
level /= weight;
|
||||||
|
|
||||||
|
level = 1.0 - max(0.0, fract(level / 2.0) * 2.0);
|
||||||
|
contour = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
o_output = mix(t,
|
||||||
|
t * backgroundOpacity * (1.0 - contour) + contour * contourColor * contourOpacity * clamp(t.a, 0.0, 1.0),
|
||||||
|
fade);
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user