From 004eab4fae26929346fb03c9ee75862807e9cdfd Mon Sep 17 00:00:00 2001 From: Edwin Jakobs Date: Sat, 2 Nov 2019 12:47:30 +0100 Subject: [PATCH] Add orx-poisson-fill --- .../src/main/kotlin/ConvolutionPyramid.kt | 122 ++++++++++++++++++ .../src/main/kotlin/LaplacianIntegrator.kt | 46 +++++++ .../src/main/kotlin/PoissonBlender.kt | 55 ++++++++ .../src/main/kotlin/PoissonFiller.kt | 32 +++++ .../shaders/gl3/poisson/alpha-to-bitmap.frag | 11 ++ .../shaders/gl3/poisson/blend-boundary.frag | 37 ++++++ .../shaders/gl3/poisson/blend-combine.frag | 45 +++++++ .../resources/shaders/gl3/poisson/clamp.frag | 25 ++++ .../shaders/gl3/poisson/downscale.frag | 50 +++++++ .../shaders/gl3/poisson/fill-boundary.frag | 63 +++++++++ .../shaders/gl3/poisson/fill-combine.frag | 25 ++++ .../resources/shaders/gl3/poisson/filter.frag | 41 ++++++ .../shaders/gl3/poisson/laplacian.frag | 52 ++++++++ .../gl3/poisson/passthrough-noalpha.frag | 20 +++ .../shaders/gl3/poisson/remove-alpha.frag | 18 +++ .../shaders/gl3/poisson/upscale.frag | 60 +++++++++ 16 files changed, 702 insertions(+) create mode 100644 orx-poisson-fill/src/main/kotlin/ConvolutionPyramid.kt create mode 100644 orx-poisson-fill/src/main/kotlin/LaplacianIntegrator.kt create mode 100644 orx-poisson-fill/src/main/kotlin/PoissonBlender.kt create mode 100644 orx-poisson-fill/src/main/kotlin/PoissonFiller.kt create mode 100644 orx-poisson-fill/src/main/resources/shaders/gl3/poisson/alpha-to-bitmap.frag create mode 100644 orx-poisson-fill/src/main/resources/shaders/gl3/poisson/blend-boundary.frag create mode 100644 orx-poisson-fill/src/main/resources/shaders/gl3/poisson/blend-combine.frag create mode 100644 orx-poisson-fill/src/main/resources/shaders/gl3/poisson/clamp.frag create mode 100644 orx-poisson-fill/src/main/resources/shaders/gl3/poisson/downscale.frag create mode 100644 orx-poisson-fill/src/main/resources/shaders/gl3/poisson/fill-boundary.frag create mode 100644 orx-poisson-fill/src/main/resources/shaders/gl3/poisson/fill-combine.frag create mode 100644 orx-poisson-fill/src/main/resources/shaders/gl3/poisson/filter.frag create mode 100644 orx-poisson-fill/src/main/resources/shaders/gl3/poisson/laplacian.frag create mode 100644 orx-poisson-fill/src/main/resources/shaders/gl3/poisson/passthrough-noalpha.frag create mode 100644 orx-poisson-fill/src/main/resources/shaders/gl3/poisson/remove-alpha.frag create mode 100644 orx-poisson-fill/src/main/resources/shaders/gl3/poisson/upscale.frag diff --git a/orx-poisson-fill/src/main/kotlin/ConvolutionPyramid.kt b/orx-poisson-fill/src/main/kotlin/ConvolutionPyramid.kt new file mode 100644 index 00000000..a1372c1a --- /dev/null +++ b/orx-poisson-fill/src/main/kotlin/ConvolutionPyramid.kt @@ -0,0 +1,122 @@ +package org.openrndr.poissonfill + +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.* +import org.openrndr.filter.blend.passthrough +import org.openrndr.math.IntVector2 +import org.openrndr.resourceUrl +import kotlin.math.ceil +import kotlin.math.log2 +import kotlin.math.min + +internal class Downscale(filterUrl: String = "/shaders/gl3/poisson/downscale.frag") + : Filter(filterShaderFromUrl(resourceUrl(filterUrl))) { + var h1: FloatArray by parameters + init { + h1 = floatArrayOf(0.0f, 0.0f, 0.0f, 0.0f, 0.0f) + } +} + +internal class Upscale(filterUrl: String = "/shaders/gl3/poisson/upscale.frag") + : Filter(filterShaderFromUrl(resourceUrl(filterUrl))) { + var h1: FloatArray by parameters + var h2: Float by parameters + var g: FloatArray by parameters + + init { + h1 = floatArrayOf(0.0f, 0.0f, 0.0f, 0.0f, 0.0f) + h2 = 0.0f + g = floatArrayOf(0.0f, 0.0f, 0.0f) + } +} + +internal class Convolution(filterUrl: String = "/shaders/gl3/poisson/filter.frag") + : Filter(filterShaderFromUrl(resourceUrl(filterUrl))) { + var g: FloatArray by parameters + + init { + g = floatArrayOf(0.0f, 0.0f, 0.0f) + } +} + +internal class ConvolutionPyramid(width: Int, height: Int, + private val padding: Int = 0, cutOff: Int = 10000, + private val downscale: Downscale = Downscale(), + private val upscale: Upscale = Upscale(), + private val filter: Convolution = Convolution(), + val type: ColorType = ColorType.FLOAT32) { + var h1 = floatArrayOf(0.0f, 0.0f, 0.0f, 0.0f, 0.0f) + var h2 = 0.0f + var g = floatArrayOf(0.0f, 0.0f, 0.0f) + + private val size = 5 + private val resolution = IntVector2(width + 2 * padding, height + 2 * padding) + private val minResolution = min(resolution.x, resolution.y) + private val depth = min(cutOff, ceil(log2(minResolution.toDouble())).toInt()) + + private val levelsIn = mutableListOf() + private val levelsOut = mutableListOf() + + private val result = colorBuffer(width, height, type = type) + + init { + var levelWidth = resolution.x + 2 * size + var levelHeight = resolution.y + 2 * size + + for (i in 0 until depth) { + levelsIn.add(renderTarget(levelWidth, levelHeight) { + colorBuffer(type = type) + }) + + levelsOut.add(renderTarget(levelWidth, levelHeight) { + colorBuffer(type = type) + }) + + levelWidth /= 2 + levelHeight /= 2 + levelWidth += 2 * size + levelHeight += 2 * size + } + } + + fun process(input: ColorBuffer): ColorBuffer { + for (l in levelsIn) { + l.clearColor(0, ColorRGBa.TRANSPARENT) + } + + for (l in levelsOut) { + l.clearColor(0, ColorRGBa.TRANSPARENT) + } + + downscale.h1 = h1 + + upscale.g = g + upscale.h1 = h1 + upscale.h2 = h2 + + filter.g = g + + passthrough.padding = (levelsIn[0].width - input.width) / 2 + passthrough.apply(input, levelsIn[0].colorBuffer(0)) + passthrough.padding = 0 + + for (i in 1 until levelsIn.size) { + downscale.padding = 0 + downscale.apply(levelsIn[i - 1].colorBuffer(0), + levelsIn[i].colorBuffer(0) + ) + } + + filter.apply(levelsIn.last().colorBuffer(0), levelsOut.last().colorBuffer(0)) + + for (i in levelsOut.size - 2 downTo 0) { + upscale.padding = 0 + upscale.apply(arrayOf(levelsIn[i].colorBuffer(0), levelsOut[i + 1].colorBuffer(0)), arrayOf(levelsOut[i].colorBuffer(0))) + } + + passthrough.padding = -size - padding + passthrough.apply(levelsOut[0].colorBuffer(0), result) + passthrough.padding = 0 + return result + } +} \ No newline at end of file diff --git a/orx-poisson-fill/src/main/kotlin/LaplacianIntegrator.kt b/orx-poisson-fill/src/main/kotlin/LaplacianIntegrator.kt new file mode 100644 index 00000000..c793bb38 --- /dev/null +++ b/orx-poisson-fill/src/main/kotlin/LaplacianIntegrator.kt @@ -0,0 +1,46 @@ +package org.openrndr.poissonfill + +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.* +import org.openrndr.resourceUrl + +internal class PassthroughNoAlpha : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/poisson/passthrough-noalpha.frag"))) + +/** + * Laplacian filter + */ +class Laplacian : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/poisson/laplacian.frag"))) + +class LaplacianIntegrator(width: Int, height: Int, downscaling: Int = 1, type: ColorType = ColorType.FLOAT32) { + private val pyramid = ConvolutionPyramid(2 + width / downscaling, 2 + height / downscaling, type = type) + private val h1 = floatArrayOf(0.15f, 0.5f, 0.7f, 0.5f, 0.15f) + private val h2 = 1.0f + private val g = floatArrayOf(0.175f, 0.547f, 0.175f) + private val preproc = colorBuffer(width + 2, height + 2, type = type) + private val combined = colorBuffer(width, height) + private val passthrough = PassthroughNoAlpha() + + init { + pyramid.h1 = h1 + pyramid.g = g + pyramid.h2 = h2 + } + + fun process(input: ColorBuffer): ColorBuffer { + preproc.fill(ColorRGBa.TRANSPARENT) + + pyramid.h1 = h1 + pyramid.g = g + pyramid.h2 = h2 + + passthrough.padding = 1 + passthrough.apply(input, preproc) + passthrough.padding = 0 + + val result = pyramid.process(preproc) + passthrough.padding = -1 + passthrough.apply(result, combined) + passthrough.padding = 0 + return combined + } +} \ No newline at end of file diff --git a/orx-poisson-fill/src/main/kotlin/PoissonBlender.kt b/orx-poisson-fill/src/main/kotlin/PoissonBlender.kt new file mode 100644 index 00000000..c90fe4bb --- /dev/null +++ b/orx-poisson-fill/src/main/kotlin/PoissonBlender.kt @@ -0,0 +1,55 @@ +package org.openrndr.poissonfill + +import org.openrndr.draw.* +import org.openrndr.filter.blend.subtract +import org.openrndr.resourceUrl + +internal class BlendBoundary : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/poisson/blend-boundary.frag"))) +class AlphaToBitmap : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/poisson/alpha-to-bitmap.frag"))) + +internal class BlendCombine : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/poisson/blend-combine.frag"))) { + var softMaskGain: Double by parameters + init { + softMaskGain = 1.0 + } +} + +internal class Clamp : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/poisson/clamp.frag"))) { + var minValue: Double by parameters + var maxValue: Double by parameters +} + +class PoissonBlender(width: Int, height: Int, type: ColorType = ColorType.FLOAT32) { + private val pyramid = ConvolutionPyramid(width, height, 0, type = type) + private val preprocess = colorBuffer(width, height, type = type) + private val combined = colorBuffer(width, height, type = type) + + private val fillBoundary = BlendBoundary() + private val fillCombine = BlendCombine() + + private val difference = colorBuffer(width, height, type = type) + + private val h1 = floatArrayOf(0.1507146f, 0.6835785f, 1.0334191f, 0.6836f, 0.1507f) + private val h2 = 0.0269546f + private val g = floatArrayOf(0.0311849f, 0.7752854f, 0.0311849f) + + private val clamp = Clamp() + + init { + pyramid.h1 = h1 + pyramid.g = g + pyramid.h2 = h2 + } + + fun process(target: ColorBuffer, source: ColorBuffer, mask: ColorBuffer, + softMask: ColorBuffer = mask, softMaskGain: Double = 1.0): ColorBuffer { + subtract.apply(arrayOf(target, source), difference) + clamp.minValue = -0.50 + clamp.maxValue = 0.50 + fillBoundary.apply(arrayOf(difference, mask), preprocess) + val result = pyramid.process(preprocess) + fillCombine.softMaskGain = softMaskGain + fillCombine.apply(arrayOf(result, target, source, mask, softMask), arrayOf(combined)) + return combined + } +} \ No newline at end of file diff --git a/orx-poisson-fill/src/main/kotlin/PoissonFiller.kt b/orx-poisson-fill/src/main/kotlin/PoissonFiller.kt new file mode 100644 index 00000000..f4f06f5d --- /dev/null +++ b/orx-poisson-fill/src/main/kotlin/PoissonFiller.kt @@ -0,0 +1,32 @@ +package org.openrndr.poissonfill + +import org.openrndr.draw.* +import org.openrndr.resourceUrl + +internal class FillBoundary : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/poisson/fill-boundary.frag"))) +internal class FillCombine : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/poisson/fill-combine.frag"))) + +class PoissonFiller(width: Int, height: Int, type: ColorType = ColorType.FLOAT32) { + private val pyramid = ConvolutionPyramid(width, height, 0, type = type) + private val preproc = colorBuffer(width, height, type = type) + private val combined = colorBuffer(width, height, type = type) + private val fillBoundary = FillBoundary() + private val fillCombine = FillCombine() + + private val h1 = floatArrayOf(0.1507146f, 0.6835785f, 1.0334191f, 0.6836f, 0.1507f) + private val h2 = 0.0269546f + private val g = floatArrayOf(0.0311849f, 0.7752854f, 0.0311849f) + + init { + pyramid.h1 = h1 + pyramid.g = g + pyramid.h2 = h2 + } + + fun process(input: ColorBuffer): ColorBuffer { + fillBoundary.apply(input, preproc) + val result = pyramid.process(preproc) + fillCombine.apply(arrayOf(result, input), arrayOf(combined)) + return combined + } +} \ No newline at end of file diff --git a/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/alpha-to-bitmap.frag b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/alpha-to-bitmap.frag new file mode 100644 index 00000000..afc1fa1b --- /dev/null +++ b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/alpha-to-bitmap.frag @@ -0,0 +1,11 @@ +#version 330 + +in vec2 v_texCoord0; +uniform sampler2D tex0; +out vec4 o_output; + +void main(){ + vec4 c = texture(tex0, v_texCoord0); + o_output.rgb = vec3(step(1.0, c.a)); + o_output.a = 1.0; +} \ No newline at end of file diff --git a/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/blend-boundary.frag b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/blend-boundary.frag new file mode 100644 index 00000000..d6829ee5 --- /dev/null +++ b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/blend-boundary.frag @@ -0,0 +1,37 @@ +// adapted from https://github.com/kosua20/Rendu/blob/master/resources/common/shaders/screens/convolution-pyramid/fill-boundary.frag + +#version 330 + +in vec2 v_texCoord0; +uniform sampler2D tex0; // input image +uniform sampler2D tex1; // mask + +out vec4 o_output; + +/** Output color only on the edges of the black regions in the input image, along with a 1.0 alpha. */ +void main(){ + + o_output = vec4(0.0); + + vec4 fullColor = textureLod(tex0, v_texCoord0, 0.0); + float maskColor = textureLod(tex1, v_texCoord0, 0.0).r; + + float isInMask = maskColor == 1.0 ? 1.0 : 0.0; + + float maskLaplacian = -4.0 * isInMask; + float mask110 = textureLodOffset(tex1, v_texCoord0, 0.0, ivec2( 1, 0)).r; + float mask101 = textureLodOffset(tex1, v_texCoord0, 0.0, ivec2( 0, 1)).r; + float mask010 = textureLodOffset(tex1, v_texCoord0, 0.0, ivec2(-1, 0)).r; + float mask001 = textureLodOffset(tex1, v_texCoord0, 0.0, ivec2( 0,-1)).r; + + maskLaplacian += mask110 == 1.0 ? 1.0 : 0.0; + maskLaplacian += mask101 == 1.0 ? 1.0 : 0.0; + maskLaplacian += mask010 == 1.0 ? 1.0 : 0.0; + maskLaplacian += mask001 == 1.0 ? 1.0 : 0.0; + + if(maskLaplacian > 0.0){ + o_output.rgb = fullColor.rgb; + o_output.a = 1.0; + } + +} \ No newline at end of file diff --git a/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/blend-combine.frag b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/blend-combine.frag new file mode 100644 index 00000000..3ccfef85 --- /dev/null +++ b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/blend-combine.frag @@ -0,0 +1,45 @@ +#version 330 + +in vec2 v_texCoord0; + +uniform sampler2D tex0; // membrane +uniform sampler2D tex1; // target image +uniform sampler2D tex2; // source image +uniform sampler2D tex3; // mask +uniform sampler2D tex4; // soft mask + +uniform float softMaskGain; +out vec4 o_output; + +void main(){ + + vec4 targetColor = textureLod(tex1, v_texCoord0, 0.0).rgba; + float maskColor = textureLod(tex3, v_texCoord0, 0.0).r; + float mask = maskColor == 1.0 ? 1.0 : 0.0; + float softMask = textureLod(tex4, v_texCoord0, 0.0).r; + + float maskLaplacian = -4.0 * mask; + float mask110 = textureLodOffset(tex3, v_texCoord0, 0.0, ivec2( 1, 0)).r; + float mask101 = textureLodOffset(tex3, v_texCoord0, 0.0, ivec2( 0, 1)).r; + float mask010 = textureLodOffset(tex3, v_texCoord0, 0.0, ivec2(-1, 0)).r; + float mask001 = textureLodOffset(tex3, v_texCoord0, 0.0, ivec2( 0,-1)).r; + + maskLaplacian += mask110 == 1.0 ? 1.0 : 0.0; + maskLaplacian += mask101 == 1.0 ? 1.0 : 0.0; + maskLaplacian += mask010 == 1.0 ? 1.0 : 0.0; + maskLaplacian += mask001 == 1.0 ? 1.0 : 0.0; + + if (maskLaplacian > 0) { + mask = 1; + } + { + vec4 sourceColor = textureLod(tex2, v_texCoord0, 0.0); + vec4 membraneColor = textureLod(tex0, v_texCoord0, 0.0); + membraneColor.rgb /= membraneColor.a; + + vec3 blend = membraneColor.rgb + sourceColor.rgb; + + o_output.rgb = mix(targetColor.rgb, blend, mask*max(0.0,min(1.0, softMask * softMaskGain))); + o_output.a = 1.0; + } +} \ No newline at end of file diff --git a/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/clamp.frag b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/clamp.frag new file mode 100644 index 00000000..f70628a3 --- /dev/null +++ b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/clamp.frag @@ -0,0 +1,25 @@ +// from https://github.com/kosua20/Rendu/blob/master/resources/common/shaders/screens/convolution-pyramid/fill-boundary.frag + +#version 330 + +in vec2 v_texCoord0; +uniform sampler2D tex0; +uniform int levels; +out vec4 o_output; +uniform float scale; +uniform float phase; + +uniform float minValue; +uniform float maxValue; + +void main(){ + + vec4 c = texture(tex0, v_texCoord0); + + c.rgb = clamp(c.rgb, vec3(minValue), vec3(maxValue)); + + o_output = c; + + + +} \ No newline at end of file diff --git a/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/downscale.frag b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/downscale.frag new file mode 100644 index 00000000..ec074939 --- /dev/null +++ b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/downscale.frag @@ -0,0 +1,50 @@ +// from https://github.com/kosua20/Rendu/blob/master/resources/common/shaders/screens/convolution-pyramid/downscale.frag + +#version 330 + +in vec2 v_texCoord0; + +uniform vec2 targetSize; +uniform sampler2D tex0; +out vec4 o_output; +uniform vec2 padding; +uniform float h1[5]; ///< h1 filter parameters. + +/** Denotes if a pixel falls outside an image. + \param pos the pixel position + \param size the image size + \return true if the pixel is outside of the image + */ +bool isOutside(ivec2 pos, ivec2 size){ + + return (pos.x < 0 || pos.y < 0 || pos.x > size.x || pos.y > size.y); +} + +/** Apply the h1 filter and downscale the input data by a factor of 2. */ +void main(){ + + vec4 accum = vec4(0.0); + + ivec2 size = textureSize(tex0, 0).xy; + + ivec2 ts = size; + + //ivec2 ts = ivec2(targetSize - 2 * padding); + + // Our current size is half this one, so we have to scale by 2. + + ivec2 coords = ivec2(floor( targetSize * v_texCoord0)) * 2 - ivec2(10); + + + for(int dy = -2; dy <=2; dy++){ + for(int dx = -2; dx <=2; dx++){ + ivec2 newPix = coords+ivec2(dx,dy); + if(isOutside(newPix, size)){ + continue; + //accum = vec4(1.0, 0.0, 0.0, 1.0); + } + accum += h1[dx+2] * h1[dy+2] * texelFetch(tex0, newPix,0); + } + } + o_output = accum; +} \ No newline at end of file diff --git a/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/fill-boundary.frag b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/fill-boundary.frag new file mode 100644 index 00000000..faa8a563 --- /dev/null +++ b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/fill-boundary.frag @@ -0,0 +1,63 @@ +// from https://github.com/kosua20/Rendu/blob/master/resources/common/shaders/screens/convolution-pyramid/fill-boundary.frag + +#version 330 + +in vec2 v_texCoord0; +uniform sampler2D tex0; + +//layout(binding = 0) uniform sampler2D screenTexture; ///< Image to process. + +//layout(location = 0) out vec4 fragColor; ///< Color. + +out vec4 o_output; + +/** Denotes if a pixel falls outside an image. + \param pos the pixel position + \param size the image size + \return true if the pixel is outside of the image + */ + +/** Output color only on the edges of the black regions in the input image, along with a 1.0 alpha. */ +void main(){ + + o_output = vec4(0.0); + + vec4 fullColor = textureLod(tex0, v_texCoord0, 0.0); + + float isInMask = fullColor.a == 1.0 ? 0.0 : 1.0; //float(all(equal(fullColor.rgb, vec3(0.0)))); + float maskLaplacian = -4.0*(1.0-fullColor.a); + +// float maskLaplacian = -4.0 * isInMask; + vec4 cola110 = textureLodOffset(tex0, v_texCoord0, 0.0, ivec2( 1, 0)); + vec4 cola101 = textureLodOffset(tex0, v_texCoord0, 0.0, ivec2( 0, 1)); + vec4 cola010 = textureLodOffset(tex0, v_texCoord0, 0.0, ivec2(-1, 0)); + vec4 cola001 = textureLodOffset(tex0, v_texCoord0, 0.0, ivec2( 0,-1)); + + vec3 col110 = cola110.rgb; // cola110.a; + vec3 col101 = cola101.rgb; // cola101.a; + vec3 col010 = cola010.rgb; // cola010.a; + vec3 col001 = cola001.rgb; // cola001.a; +// maskLaplacian += float(all(equal(col110, vec3(0.0)))); +// maskLaplacian += float(all(equal(col101, vec3(0.0)))); +// maskLaplacian += float(all(equal(col010, vec3(0.0)))); +// maskLaplacian += float(all(equal(col001, vec3(0.0)))); + +// maskLaplacian += cola110.a == 1.0 ? 0.0 : 1.0; +// maskLaplacian += cola101.a == 1.0 ? 0.0 : 1.0; +// maskLaplacian += cola010.a == 1.0 ? 0.0 : 1.0; +// maskLaplacian += cola001.a == 1.0 ? 0.0 : 1.0; + + maskLaplacian += (1.0-cola110.a); + maskLaplacian += (1.0-cola101.a); + maskLaplacian += (1.0-cola010.a); + maskLaplacian += (1.0-cola001.a); + + if(maskLaplacian > 0.0){ + o_output.rgb = fullColor.rgb;///fullColor.a;; + o_output.a = fullColor.a; + + } + + + +} \ No newline at end of file diff --git a/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/fill-combine.frag b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/fill-combine.frag new file mode 100644 index 00000000..9436db54 --- /dev/null +++ b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/fill-combine.frag @@ -0,0 +1,25 @@ +// from https://github.com/kosua20/Rendu/blob/master/resources/common/shaders/screens/convolution-pyramid/fill-combine.frag + +#version 330 + +in vec2 v_texCoord0; + +uniform sampler2D tex0; // result of pyramid convolution +uniform sampler2D tex1; // input image + +out vec4 o_output; + +/** Composite the initial image and the filled image in the regions where the initial image is black. */ +void main(){ + + vec4 inputColor = textureLod(tex1, v_texCoord0, 0.0).rgba; + //float mask = float(all(equal(inputColor, vec3(0.0)))); + //float mask = inputColor.a == 1.0? 0.0 : 1.0; + float mask = 1.0 - inputColor.a; + + vec4 fillColor = textureLod(tex0, v_texCoord0, 0.0); + fillColor.rgb /= fillColor.a; + + o_output.rgb = fillColor.rgb * (mask) + inputColor.rgb; //mix(inputColor.rgb, fillColor.rgb, mask); + o_output.a = 1.0; +} \ No newline at end of file diff --git a/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/filter.frag b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/filter.frag new file mode 100644 index 00000000..203d3a8a --- /dev/null +++ b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/filter.frag @@ -0,0 +1,41 @@ +// from https://github.com/kosua20/Rendu/blob/master/resources/common/shaders/screens/convolution-pyramid/filter.frag + +#version 330 + +//layout(binding = 0) uniform sampler2D screenTexture; ///< Level to filter. + +uniform sampler2D tex0; +in vec2 v_texCoord0; +out vec4 o_output; + +uniform float g[3]; ///< g filter parameters. + +/** Denotes if a pixel falls outside an image. + \param pos the pixel position + \param size the image size + \return true if the pixel is outside of the image + */ +bool isOutside(ivec2 pos, ivec2 size){ + return (pos.x < 0 || pos.y < 0 || pos.x >= size.x || pos.y >= size.y); +} + +/** Apply the g filter to the input data. */ +void main(){ + vec4 accum = vec4(0.0); + ivec2 size = textureSize(tex0, 0).xy; + + ivec2 coords = ivec2(v_texCoord0 * size); + + for(int dy = -1; dy <=1; dy++){ + for(int dx = -1; dx <=1; dx++){ + + ivec2 newPix = coords + ivec2(dx,dy); + + if(isOutside(newPix, size)){ + continue; + } + accum += g[dx+1] * g[dy+1] * texelFetch(tex0, newPix,0 ); + } + } + o_output = accum; +} \ No newline at end of file diff --git a/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/laplacian.frag b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/laplacian.frag new file mode 100644 index 00000000..9df11eca --- /dev/null +++ b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/laplacian.frag @@ -0,0 +1,52 @@ +// adapted from https://github.com/kosua20/Rendu/blob/master/resources/common/shaders/screens/convolution-pyramid/laplacian.frag +#version 330 + +in vec2 v_texCoord0; +uniform sampler2D tex0; +out vec4 o_output; + +/** Denotes if UV coordinates falls outside an image. + \param pos the UV coordinates + \return true if the UV are outside of the image + */ +bool isOutside(vec2 pos){ + return (pos.x < 0.0 || pos.y < 0.0 || pos.x > 1.0 || pos.y > 1.0); +} + +/** Compute the Laplacian field of an input RGB image, adding a 1px black border around it before computing the gradients and divergence. */ +void main(){ + vec3 div = vec3(0.0); + ivec2 size = textureSize(tex0, 0).xy; + + vec3 pixelShift = vec3(0.0); + pixelShift.xy = 1.0/vec2(size); + + vec2 uvs = v_texCoord0; + if(!isOutside(uvs)){ + vec3 col = textureLod(tex0, uvs, 0.0).rgb; + div = 4.0 * col; + } + + vec2 uvs110 = uvs + pixelShift.xz; + if(!isOutside(uvs110)){ + vec3 col110 = textureLod(tex0, uvs110, 0.0).rgb; + div -= col110; + } + vec2 uvs101 = uvs + pixelShift.zy; + if(!isOutside(uvs101)){ + vec3 col101 = textureLod(tex0, uvs101, 0.0).rgb; + div -= col101; + } + vec2 uvs010 = uvs - pixelShift.xz; + if(!isOutside(uvs010)){ + vec3 col010 = textureLod(tex0, uvs010, 0.0).rgb; + div -= col010; + } + vec2 uvs001 = uvs - pixelShift.zy; + if(!isOutside(uvs001)){ + vec3 col001 = textureLod(tex0, uvs001, 0.0).rgb; + div -= col001; + } + o_output.rgb = div; + o_output.a = 1.0f; +} \ No newline at end of file diff --git a/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/passthrough-noalpha.frag b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/passthrough-noalpha.frag new file mode 100644 index 00000000..16a5cac6 --- /dev/null +++ b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/passthrough-noalpha.frag @@ -0,0 +1,20 @@ +#version 330 + +in vec2 v_texCoord0; +uniform sampler2D tex0; + +out vec4 o_output; + +/** Denotes if a pixel falls outside an image. + \param pos the pixel position + \param size the image size + \return true if the pixel is outside of the image + */ + +/** Output an image translated by a fixed number of pixels on each axis. useful for padding when rendering in a larger framebuffer. */ +void main(){ + vec4 c = texture(tex0, v_texCoord0); + + o_output.rgb = c.rgb; + o_output.a = 1.0; +} \ No newline at end of file diff --git a/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/remove-alpha.frag b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/remove-alpha.frag new file mode 100644 index 00000000..99378517 --- /dev/null +++ b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/remove-alpha.frag @@ -0,0 +1,18 @@ +// from https://github.com/kosua20/Rendu/blob/master/resources/common/shaders/screens/convolution-pyramid/fill-boundary.frag + +#version 330 + +in vec2 v_texCoord0; +uniform sampler2D tex0; + +out vec4 o_output; + +void main(){ + o_output = vec4(0.0); + vec4 fullColor = textureLod(tex0, v_texCoord0, 0.0); + + if (fullColor.a == 1.0) { + o_output = fullColor; + } + +} \ No newline at end of file diff --git a/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/upscale.frag b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/upscale.frag new file mode 100644 index 00000000..392bdbad --- /dev/null +++ b/orx-poisson-fill/src/main/resources/shaders/gl3/poisson/upscale.frag @@ -0,0 +1,60 @@ +// from https://github.com/kosua20/Rendu/blob/master/resources/common/shaders/screens/convolution-pyramid/upscale.frag + +#version 330 + +in vec2 v_texCoord0; + +uniform sampler2D tex0; ///< Current h1 filtered level. +uniform sampler2D tex1; ///< Previous h1+g filtered level. + +out vec4 o_output; ///< Color. + +uniform float h1[5]; ///< h1 filter parameters. +uniform float h2; ///< h2 scaling parameter. +uniform float g[3]; ///< g filter parameters. + +/** Denotes if a pixel falls outside an image. + \param pos the pixel position + \param size the image size + \return true if the pixel is outside of the image + */ +bool isOutside(ivec2 pos, ivec2 size){ + return (pos.x < 0 || pos.y < 0 || pos.x >= size.x || pos.y >= size.y); +} + +/** Combine previous level filtered with h2 (applying a 0-filled upscaling) and the current level filtered with g. + */ +void main(){ + vec4 accum = vec4(0.0); + ivec2 size = textureSize(tex0, 0).xy; + ivec2 coords = ivec2(v_texCoord0 * size); + + for(int dy = -1; dy <=1; dy++){ + for(int dx = -1; dx <=1; dx++){ + ivec2 newPix = coords+ivec2(dx,dy); + if(isOutside(newPix, size)){ + continue; + } + accum += g[dx+1] * g[dy+1] * texelFetch(tex0, newPix,0); + } + } + + ivec2 sizeSmall = textureSize(tex1, 0).xy; + + for(int dy = -2; dy <=2; dy++){ + for(int dx = -2; dx <=2; dx++){ + ivec2 newPix = coords+ivec2(dx,dy); + // The filter is applied to a texture upscaled by inserting zeros. + if(newPix.x%2 != 0 || newPix.y%2 != 0){ + continue; + } + newPix /= 2; + newPix += 5; + if(isOutside(newPix, sizeSmall)){ + accum = vec4(0.0, 0.0, 1.0, 1.0); + } + accum += h2 * h1[dx+2] * h1[dy+2] * texelFetch(tex1, newPix, 0); + } + } + o_output = accum; +} \ No newline at end of file