diff --git a/src/webgl/p5.RendererGL.js b/src/webgl/p5.RendererGL.js index 258040a7ac..88ac6eaf16 100644 --- a/src/webgl/p5.RendererGL.js +++ b/src/webgl/p5.RendererGL.js @@ -1078,7 +1078,8 @@ p5.RendererGL = class RendererGL extends p5.Renderer { pg.shader(this.filterShader); this.filterShader.setUniform('texelSize', texelSize); - this.filterShader.setUniform('steps', Math.max(1, filterParameter)); + this.filterShader.setUniform('canvasSize', [this.width, this.height]); + this.filterShader.setUniform('radius', Math.max(1, filterParameter)); // horiz pass this.filterShader.setUniform('direction', [1, 0]); diff --git a/src/webgl/shaders/filters/blur.frag b/src/webgl/shaders/filters/blur.frag index f7aca92ed4..2823043b1f 100644 --- a/src/webgl/shaders/filters/blur.frag +++ b/src/webgl/shaders/filters/blur.frag @@ -8,24 +8,53 @@ precision highp float; uniform sampler2D tex0; varying vec2 vTexCoord; uniform vec2 direction; -uniform vec2 texelSize; -uniform float steps; +uniform vec2 canvasSize; +uniform float radius; -void main(){ - const float maxIterations = 100.0; +float random(vec2 p) { + vec3 p3 = fract(vec3(p.xyx) * .1031); + p3 += dot(p3, p3.yzx + 33.33); + return fract((p3.x + p3.y) * p3.z); +} +// This isn't a real Gaussian weight, it's a quadratic weight. It's what the +// CPU mode's blur uses though, so we also use it here to match. +float quadWeight(float x, float e) { + return pow(e-abs(x), 2.); +} + +void main(){ vec2 uv = vTexCoord; - vec4 tex = texture2D(tex0, uv); - float sum = 1.0; + // A reasonable maximum number of samples + const float maxSamples = 64.0; + + float numSamples = floor(7. * radius); + if (fract(numSamples / 2.) == 0.) { + numSamples++; + } + vec4 avg = vec4(0.0); + float total = 0.0; + + // Calculate the spacing to avoid skewing if numSamples > maxSamples + float spacing = 1.0; + if (numSamples > maxSamples) { + spacing = numSamples / maxSamples; + numSamples = maxSamples; + } + + float randomOffset = (spacing - 1.0) * mix(-0.5, 0.5, random(gl_FragCoord.xy)); + for (float i = 0.0; i < maxSamples; i++) { + if (i >= numSamples) break; + + float sample = i * spacing - (numSamples - 1.0) * 0.5 * spacing + randomOffset; + vec2 sampleCoord = uv + vec2(sample, sample) / canvasSize * direction; + float weight = quadWeight(sample, (numSamples - 1.0) * 0.5 * spacing); - vec2 offset = direction * texelSize; - for(float i = 1.0; i <= maxIterations; i++) { - if( i > steps) break; - tex += texture2D(tex0, uv + i * offset); - tex += texture2D(tex0, uv - i * offset); - sum += 2.0; + avg += weight * texture2D(tex0, sampleCoord); + total += weight; } - gl_FragColor = tex / sum; + avg /= total; + gl_FragColor = avg; }