Add HashBloom, GaussianBloom, SetBackground, Contour and Tiles to orx-fx

This commit is contained in:
Edwin Jakobs
2020-02-13 15:12:22 +01:00
parent 9f34101716
commit 47c7b20da2
12 changed files with 454 additions and 2 deletions

View File

@@ -44,6 +44,7 @@ class ApproximateGaussianBlur : Filter(Shader.createFromCode(Filter.filterVertex
private var intermediateCache = mutableMapOf<ColorBufferDescription, ColorBuffer>()
init {
window = 5
spread = 1.0

View File

@@ -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<T:Filter>(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<ColorBuffer>()
var sourceCopy: ColorBuffer? = null
val upscale = BloomUpscale()
val downScale = BloomDownscale()
val combine = BloomCombine()
override fun apply(source: Array<ColorBuffer>, target: Array<ColorBuffer>) {
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<HashBlur>(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<ColorBuffer>, target: Array<ColorBuffer>) {
blur.radius = radius
blur.samples = samples
super.apply(source, target)
}
}
@Description("Gaussian bloom")
class GaussianBloom : MipBloom<GaussianBlur>(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<ColorBuffer>, target: Array<ColorBuffer>) {
blur.window = window
blur.sigma = sigma
super.apply(source, target)
}
}

View File

@@ -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
}
}

View File

@@ -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<ColorBuffer>, target: Array<ColorBuffer>) {
if (bicubicFiltering && source.isNotEmpty()) {
source[0].generateMipmaps()
source[0].filter(MinifyingFilter.LINEAR_MIPMAP_LINEAR, MagnifyingFilter.LINEAR)
}
super.apply(source, target)
}
}

View File

@@ -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
}
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}