diff --git a/orx-fx/src/main/kotlin/blur/ApproximateGaussianBlur.kt b/orx-fx/src/main/kotlin/blur/ApproximateGaussianBlur.kt index e98a475f..a52bfa77 100644 --- a/orx-fx/src/main/kotlin/blur/ApproximateGaussianBlur.kt +++ b/orx-fx/src/main/kotlin/blur/ApproximateGaussianBlur.kt @@ -44,6 +44,7 @@ class ApproximateGaussianBlur : Filter(Shader.createFromCode(Filter.filterVertex private var intermediateCache = mutableMapOf() + init { window = 5 spread = 1.0 diff --git a/orx-fx/src/main/kotlin/blur/MipBloom.kt b/orx-fx/src/main/kotlin/blur/MipBloom.kt new file mode 100644 index 00000000..87913a45 --- /dev/null +++ b/orx-fx/src/main/kotlin/blur/MipBloom.kt @@ -0,0 +1,154 @@ +package org.openrndr.extra.fx.blur + +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.* +import org.openrndr.extra.fx.filterFragmentCode +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.filter.color.delinearize +import org.openrndr.filter.color.linearize + +class BloomDownscale : Filter(Shader.createFromCode(filterVertexCode, filterFragmentCode("blur/bloom-downscale.frag"))) { + +} + +class BloomUpscale : Filter(Shader.createFromCode(filterVertexCode, filterFragmentCode("blur/bloom-upscale.frag"))) { + var gain:Double by parameters + var shape:Double by parameters + var seed:Double by parameters + + init { + gain = 1.0 + shape = 1.0 + seed = 1.0 + } +} + +class BloomCombine: Filter(Shader.createFromCode(filterVertexCode, filterFragmentCode("blur/bloom-combine.frag"))) { + var gain: Double by parameters + var bias: ColorRGBa by parameters + + init { + bias = ColorRGBa.BLACK + gain = 1.0 + } +} + +@Description("MipBloom") +open class MipBloom(val blur:T) : Filter(Shader.createFromCode(filterVertexCode, filterFragmentCode("blur/bloom-combine.frag"))) { + var passes = 6 + + @DoubleParameter("shape", 0.0, 4.0) + var shape: Double = 1.0 + + @DoubleParameter("gain", 0.0, 4.0) + var gain: Double = 1.0 + + @BooleanParameter("sRGB") + var sRGB = true + + var intermediates = mutableListOf() + var sourceCopy: ColorBuffer? = null + + val upscale = BloomUpscale() + val downScale = BloomDownscale() + val combine = BloomCombine() + + override fun apply(source: Array, target: Array) { + + sourceCopy?.let { + if (it.width != source[0].width || it.height != source[0].height) { + it.destroy() + sourceCopy = null + } + } + + if (sourceCopy == null) { + sourceCopy = colorBuffer(source[0].width, source[0].height, type = ColorType.FLOAT16) + } + + source[0].copyTo(sourceCopy!!) + + upscale.shape = shape + if (intermediates.size != passes + || (intermediates.isNotEmpty() && (intermediates[0].width!=target[0].width || intermediates[0].height != target[0].height) )) { + intermediates.forEach { + it.destroy() + } + intermediates.clear() + + for (pass in 0 until passes) { + val tdiv = 1 shl (pass+1) + val cb = colorBuffer(target[0].width / tdiv, target[0].height / tdiv, type = ColorType.FLOAT16) + intermediates.add(cb) + } + } + + + if (sRGB) { + linearize.apply(sourceCopy!!, sourceCopy!!) + } + + downScale.apply(sourceCopy!!, intermediates[0]) + blur.apply(intermediates[0], intermediates[0]) + + for (pass in 1 until passes) { + downScale.apply(intermediates[pass-1], intermediates[pass]) + blur.apply(intermediates[pass], intermediates[pass]) + } + + upscale.apply(intermediates.toTypedArray(), arrayOf(target[0])) + combine.gain = gain + combine.apply(arrayOf(sourceCopy!!, target[0]), target) + + if (sRGB) { + delinearize.apply(target[0], target[0]) + } + } +} + +@Description("Hash bloom") +class HashBloom : MipBloom(blur = HashBlur()) { + + /** + * Blur radius in pixels, default is 5.0 + */ + @DoubleParameter("blur radius", 1.0, 25.0) + var radius: Double = 5.0 + + /** + * Number of samples, default is 30 + */ + @IntParameter("number of samples", 1, 100) + var samples: Int = 30 + + override fun apply(source: Array, target: Array) { + blur.radius = radius + blur.samples = samples + super.apply(source, target) + } +} + +@Description("Gaussian bloom") +class GaussianBloom : MipBloom(blur = GaussianBlur()) { + + /** + * blur sample window, default value is 5 + */ + @IntParameter("window size", 1, 25) + var window: Int = 5 + + /** + * blur sigma, default value is 1.0 + */ + @DoubleParameter("kernel sigma", 0.0, 25.0) + var sigma: Double = 1.0 + + override fun apply(source: Array, target: Array) { + blur.window = window + blur.sigma = sigma + super.apply(source, target) + } +} \ No newline at end of file diff --git a/orx-fx/src/main/kotlin/color/SetBackground.kt b/orx-fx/src/main/kotlin/color/SetBackground.kt new file mode 100644 index 00000000..ea2ba977 --- /dev/null +++ b/orx-fx/src/main/kotlin/color/SetBackground.kt @@ -0,0 +1,24 @@ +package org.openrndr.extra.fx.color + +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.Filter +import org.openrndr.draw.Shader +import org.openrndr.extra.fx.filterFragmentCode +import org.openrndr.extra.parameters.ColorParameter +import org.openrndr.extra.parameters.Description +import org.openrndr.extra.parameters.DoubleParameter + +@Description("Set background") +class SetBackground : Filter(Shader.createFromCode(Filter.filterVertexCode, filterFragmentCode("color/set-background.frag"))) { + + @ColorParameter("background color") + var background: ColorRGBa by parameters + + @DoubleParameter("background opacity", 0.0, 1.0) + var backgroundOpacity: Double by parameters + + init { + background = ColorRGBa.GRAY + backgroundOpacity = 1.0 + } +} diff --git a/orx-fx/src/main/kotlin/distort/Tiles.kt b/orx-fx/src/main/kotlin/distort/Tiles.kt new file mode 100644 index 00000000..377f83b5 --- /dev/null +++ b/orx-fx/src/main/kotlin/distort/Tiles.kt @@ -0,0 +1,37 @@ +package org.openrndr.extra.fx.distort + +import org.openrndr.draw.* +import org.openrndr.extra.fx.filterFragmentCode +import org.openrndr.extra.parameters.Description +import org.openrndr.extra.parameters.DoubleParameter +import org.openrndr.extra.parameters.IntParameter + +@Description("Tiles") +class Tiles : Filter(Shader.createFromCode(filterVertexCode, filterFragmentCode("distort/tiles.frag"))) { + + @DoubleParameter("rotation", -180.0, 180.0, order = 2) + var rotation: Double by parameters + + @IntParameter("x segments", 0, 256, order = 0) + var xSegments: Int by parameters + + @IntParameter("y segments", 0, 256, order = 0) + var ySegments: Int by parameters + + + + init { + rotation = 0.0 + xSegments = 32 + ySegments = 32 + } + + var bicubicFiltering = false + override fun apply(source: Array, target: Array) { + if (bicubicFiltering && source.isNotEmpty()) { + source[0].generateMipmaps() + source[0].filter(MinifyingFilter.LINEAR_MIPMAP_LINEAR, MagnifyingFilter.LINEAR) + } + super.apply(source, target) + } +} diff --git a/orx-fx/src/main/kotlin/edges/Contour.kt b/orx-fx/src/main/kotlin/edges/Contour.kt new file mode 100644 index 00000000..6788a81c --- /dev/null +++ b/orx-fx/src/main/kotlin/edges/Contour.kt @@ -0,0 +1,41 @@ +package org.openrndr.extra.vfx + +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.Filter +import org.openrndr.draw.Shader +import org.openrndr.draw.filterShaderFromUrl +import org.openrndr.extra.fx.filterFragmentCode +import org.openrndr.extra.parameters.ColorParameter +import org.openrndr.extra.parameters.Description +import org.openrndr.extra.parameters.DoubleParameter +import org.openrndr.extra.parameters.IntParameter +import org.openrndr.resourceUrl + +@Description("Contour") +class Contour : Filter(Shader.createFromCode(Filter.filterVertexCode, filterFragmentCode("edges/contour.frag"))) { + @DoubleParameter("levels", 1.0, 16.0) + var levels: Double by parameters + + + @DoubleParameter("contour width", 0.0, 4.0) + var contourWidth: Double by parameters + + @DoubleParameter("contour opacity", 0.0, 1.0) + var contourOpacity: Double by parameters + + @DoubleParameter("background opacity", 0.0, 1.0) + var backgroundOpacity: Double by parameters + + + @ColorParameter("contour color") + var contourColor: ColorRGBa by parameters + + + init { + levels = 6.0 + contourWidth = 0.4 + contourColor = ColorRGBa.BLACK + backgroundOpacity = 1.0 + contourOpacity = 1.0 + } +} diff --git a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blur/approximate-gaussian-blur.frag b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blur/approximate-gaussian-blur.frag index 56377ffb..0c77731c 100644 --- a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blur/approximate-gaussian-blur.frag +++ b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blur/approximate-gaussian-blur.frag @@ -11,9 +11,11 @@ uniform float sigma; uniform float spread; uniform float gain; +uniform int sourceLevel; + out vec4 o_color; void main() { - vec2 s = 1.0 / textureSize(tex0, 0).xy; + vec2 s = 1.0 / textureSize(tex0, sourceLevel).xy; int w = window; vec4 sum = vec4(0.0); @@ -21,7 +23,7 @@ void main() { for (int x = -w; x <= w; ++x) { float lw = exp( -(x*x) / (2 * sigma * sigma) ) ; vec2 tc = v_texCoord0 + x * blurDirection * s;// * spread; - sum += texture(tex0, tc) * lw; + sum += textureLod(tex0, tc, sourceLevel) * lw; weight += lw; } o_color = (sum / weight) * gain; diff --git a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blur/bloom-combine.frag b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blur/bloom-combine.frag new file mode 100644 index 00000000..a8438ac2 --- /dev/null +++ b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blur/bloom-combine.frag @@ -0,0 +1,15 @@ +#version 330 core + +out vec4 o_output; +in vec2 v_texCoord0; + +uniform sampler2D tex0; +uniform sampler2D tex1; + +uniform float gain; +uniform vec4 bias; + +void main() { + o_output = texture(tex0, v_texCoord0) + texture(tex1, v_texCoord0)*gain; + o_output.a = clamp(o_output.a, 0.0, 1.0); +} \ No newline at end of file diff --git a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blur/bloom-downscale.frag b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blur/bloom-downscale.frag new file mode 100644 index 00000000..44372aad --- /dev/null +++ b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blur/bloom-downscale.frag @@ -0,0 +1,21 @@ +#version 330 + +out vec4 o_output; +in vec2 v_texCoord0; +uniform sampler2D tex0; + + +// -- based on https://github.com/excess-demogroup/even-laster-engine/blob/a451a89f6bd6d3c6017d5890b92d9f72823bc742/src/shaders/bloom.fra +void main() +{ + float centerWeight = 0.16210282163712664; + vec2 diagonalOffsets = vec2(0.3842896354828526, 1.2048616327242379); + vec4 offsets = vec4(-diagonalOffsets.xy, +diagonalOffsets.xy) / textureSize(tex0, 0).xyxy; + float diagonalWeight = 0.2085034734347498; + + o_output = textureLod(tex0, v_texCoord0, 0) * centerWeight + + textureLod(tex0, v_texCoord0 + offsets.xy, 0) * diagonalWeight + + textureLod(tex0, v_texCoord0 + offsets.wx, 0) * diagonalWeight + + textureLod(tex0, v_texCoord0 + offsets.zw, 0) * diagonalWeight + + textureLod(tex0, v_texCoord0 + offsets.yz, 0) * diagonalWeight; +} \ No newline at end of file diff --git a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blur/bloom-upscale.frag b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blur/bloom-upscale.frag new file mode 100644 index 00000000..6ced4502 --- /dev/null +++ b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/blur/bloom-upscale.frag @@ -0,0 +1,81 @@ +#version 330 + +float nrand(vec2 n) { + return fract(sin(dot(n.xy, vec2(12.9898, 78.233))) * 43758.5453); +} + +// -- based on https://github.com/excess-demogroup/even-laster-engine/blob/a451a89f6bd6d3c6017d5890b92d9f72823bc742/src/shaders/bloom_upscale.frag +uniform float seed; +uniform float shape; +uniform float gain; + +in vec2 v_texCoord0; +out vec4 o_output; + +uniform sampler2D tex0; +uniform sampler2D tex1; +uniform sampler2D tex2; +uniform sampler2D tex3; +uniform sampler2D tex4; +uniform sampler2D tex5; + +vec4 sampleBloom(vec2 pos, float shape) { + vec4 sum = vec4(0); + float total = 0; + + { + float weight = pow(0.0, shape); + vec2 rnd = vec2(nrand(3 + 0.0 + pos.xy + seed), + nrand(5 + 0.0 + pos.yx - seed)); + rnd = (rnd * 2 - 1) / textureSize(tex0, 0); + sum += textureLod(tex0, pos + rnd * 0.25, 0.0) * weight; + total += weight; + } + { + float weight = pow(1.0, shape); + vec2 rnd = vec2(nrand(3 + 0.0 + pos.xy + seed), + nrand(5 + 0.0 + pos.yx - seed)); + rnd = (rnd * 2 - 1) / textureSize(tex1, 0); + sum += textureLod(tex1, pos + rnd * 0.25, 0.0) * weight; + total += weight; + } + { + float weight = pow(2.0, shape); + vec2 rnd = vec2(nrand(3 + 0.0 + pos.xy + seed), + nrand(5 + 0.0 + pos.yx - seed)); + rnd = (rnd * 2 - 1) / textureSize(tex2, 0); + sum += textureLod(tex2, pos + rnd * 0.25, 0.0) * weight; + total += weight; + } + + { + float weight = pow(3.0, shape); + vec2 rnd = vec2(nrand(3 + 0.0 + pos.xy + seed), + nrand(5 + 0.0 + pos.yx - seed)); + rnd = (rnd * 3 - 1) / textureSize(tex3, 0); + sum += textureLod(tex3, pos + rnd * 0.25, 0.0) * weight; + total += weight; + } + { + float weight = pow(4.0, shape); + vec2 rnd = vec2(nrand(3 + 0.0 + pos.xy + seed), + nrand(5 + 0.0 + pos.yx - seed)); + rnd = (rnd * 3 - 1) / textureSize(tex3, 0); + sum += textureLod(tex4, pos + rnd * 0.25, 0.0) * weight; + total += weight; + } + { + float weight = pow(5.0, shape); + vec2 rnd = vec2(nrand(3 + 0.0 + pos.xy + seed), + nrand(5 + 0.0 + pos.yx - seed)); + rnd = (rnd * 3 - 1) / textureSize(tex3, 0); + sum += textureLod(tex5, pos + rnd * 0.25, 0.0) * weight; + total += weight; + } + + return sum / total; +} + +void main() { + o_output = sampleBloom(v_texCoord0, shape) * gain; +} \ No newline at end of file diff --git a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/color/set-background.frag b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/color/set-background.frag new file mode 100644 index 00000000..323591a2 --- /dev/null +++ b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/color/set-background.frag @@ -0,0 +1,12 @@ +#version 330 core + +uniform vec4 background; +uniform float backgroundOpacity; +in vec2 v_texCoord0; +uniform sampler2D tex0; + +out vec4 o_color; +void main() { + vec4 c = texture(tex0, v_texCoord0); + o_color = c + (1.0 - c.a) * background * backgroundOpacity; +} \ No newline at end of file diff --git a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/distort/tiles.frag b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/distort/tiles.frag new file mode 100644 index 00000000..78ea0b31 --- /dev/null +++ b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/distort/tiles.frag @@ -0,0 +1,37 @@ +#version 330 core + +in vec2 v_texCoord0; +uniform sampler2D tex0; // input +uniform float rotation; +uniform int xSegments; +uniform int ySegments; + +out vec4 o_color; + +uniform int segments; +float truncate(float x, int segments) { + if (segments == 0) { + return x; + } else { + return floor(x*segments) / segments; + } +} + +void main() { + vec2 uv = v_texCoord0 - vec2(0.5); + float cr = cos(radians(rotation)); + float sr = sin(radians(rotation)); + + mat2 rm = mat2(cr, -sr, sr, cr); + + vec2 ruv = rm * uv; + vec2 truv = vec2( truncate(ruv.x, xSegments), truncate(ruv.y, ySegments)); + vec2 tuv = transpose(rm) * truv + vec2(0.5); + + vec4 c = vec4(0.0); + tuv.x = clamp(tuv.x, 0.0, 1.0); + tuv.y = clamp(tuv.y, 0.0, 1.0); + c = texture(tex0, tuv); + + o_color = c * texture(tex0, v_texCoord0).a; +} diff --git a/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/edges/contour.frag b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/edges/contour.frag new file mode 100644 index 00000000..6d09caab --- /dev/null +++ b/orx-fx/src/main/resources/org/openrndr/extra/fx/gl3/edges/contour.frag @@ -0,0 +1,27 @@ +#version 330 core +uniform sampler2D tex0; +in vec2 v_texCoord0; +out vec4 o_output; +uniform float levels; +uniform float contourWidth; +uniform float contourOpacity; +uniform vec4 contourColor; +uniform float backgroundOpacity; + +void main() { + vec2 step = 1.0 / textureSize(tex0, 0); + vec4 box = vec4(0.0); + for (int j = -1; j <=1; ++j) { + for (int i = -1; i <= 1; ++i) { + box += texture(tex0, v_texCoord0 + step * vec2(i, j)); + } + } + box /= 9.0; + float v = sin(3.1415926535 * levels * dot(vec3(1.0/3.0),box.xyz)); + float level = floor(dot(vec3(1.0/3.0),box.xyz) * levels) / levels; + //int plateauIndex = min(levels-1, int(level * levels)); + float contour = 1.0 - smoothstep(0., contourWidth, 0.5 * abs(v) / fwidth(v)); + + vec4 t = texture(tex0, v_texCoord0); + o_output = t * backgroundOpacity * (1.0-contour) + contour * contourColor * contourOpacity * t.a; +} \ No newline at end of file