From f5e7e6a060de85a512a5f4ad12af4cbe70c15c81 Mon Sep 17 00:00:00 2001 From: Thomas Friedel Date: Tue, 11 Feb 2020 15:45:48 +0100 Subject: [PATCH] replaced the gaussian shadow shaders with box blur shaders --- backend/goglbackend/fill.go | 116 ++++++++++++++-------------- backend/goglbackend/gogl.go | 28 +------ backend/goglbackend/shaders.go | 137 +++++++++++---------------------- 3 files changed, 104 insertions(+), 177 deletions(-) diff --git a/backend/goglbackend/fill.go b/backend/goglbackend/fill.go index 053651b..34b8e3e 100644 --- a/backend/goglbackend/fill.go +++ b/backend/goglbackend/fill.go @@ -228,82 +228,78 @@ func (b *GoGLBackend) FillImageMask(style *backendbase.FillStyle, mask *image.Al } } -func (b *GoGLBackend) drawBlurred(blur float64) { - var kernel []float32 - var kernelBuf [255]float32 - var gs *gaussianShader - if blur < 3 { - gs = &b.gauss15r - kernel = kernelBuf[:15] - } else if blur < 12 { - gs = &b.gauss63r - kernel = kernelBuf[:63] - } else { - gs = &b.gauss127r - kernel = kernelBuf[:127] - } - - gaussianKernel(blur, kernel) - +func (b *GoGLBackend) drawBlurred(size float64) { + b.offscr1.alpha = true b.offscr2.alpha = true - b.enableTextureRenderTarget(&b.offscr2) - gl.Disable(gl.STENCIL_TEST) - gl.Disable(gl.BLEND) gl.BindBuffer(gl.ARRAY_BUFFER, b.shadowBuf) - data := [16]float32{0, 0, 0, float32(b.h), float32(b.w), float32(b.h), float32(b.w), 0, 0, 0, 0, 1, 1, 1, 1, 0} + data := [16]float32{ + 0, 0, 0, float32(b.h), float32(b.w), float32(b.h), float32(b.w), 0, + 0, 1, 0, 0, 1, 0, 1, 1} gl.BufferData(gl.ARRAY_BUFFER, len(data)*4, unsafe.Pointer(&data[0]), gl.STREAM_DRAW) - gl.VertexAttribPointer(gs.Vertex, 2, gl.FLOAT, false, 0, nil) - gl.VertexAttribPointer(gs.TexCoord, 2, gl.FLOAT, false, 0, gl.PtrOffset(8*4)) - gl.EnableVertexAttribArray(gs.Vertex) - gl.EnableVertexAttribArray(gs.TexCoord) + gl.UseProgram(b.bbshd.ID) + gl.Uniform1i(b.bbshd.Image, 0) + gl.Uniform2f(b.bbshd.CanvasSize, float32(b.fw), float32(b.fh)) + + gl.VertexAttribPointer(b.bbshd.Vertex, 2, gl.FLOAT, false, 0, nil) + gl.VertexAttribPointer(b.bbshd.TexCoord, 2, gl.FLOAT, false, 0, gl.PtrOffset(8*4)) + gl.EnableVertexAttribArray(b.bbshd.Vertex) + gl.EnableVertexAttribArray(b.bbshd.TexCoord) + + gl.Disable(gl.BLEND) gl.ActiveTexture(gl.TEXTURE0) + + // calculate box blur size + fsize := math.Max(1, math.Floor(size)) + sizea := int(fsize) + sizeb := sizea + sizec := sizea + if size-fsize > 0.333333333 { + sizeb++ + } + if size-fsize > 0.666666666 { + sizec++ + } + gl.BindTexture(gl.TEXTURE_2D, b.offscr1.tex) - - gl.UseProgram(gs.ID) - gl.Uniform1i(gs.Image, 0) - gl.Uniform2f(gs.CanvasSize, float32(b.fw), float32(b.fh)) - gl.Uniform2f(gs.KernelScale, 1.0/float32(b.fw), 0.0) - gl.Uniform1fv(gs.Kernel, int32(len(kernel)), &kernel[0]) - gl.DrawArrays(gl.TRIANGLE_FAN, 0, 4) - - b.disableTextureRenderTarget() - + b.enableTextureRenderTarget(&b.offscr2) + b.box3(sizea, false) + gl.BindTexture(gl.TEXTURE_2D, b.offscr2.tex) + b.enableTextureRenderTarget(&b.offscr1) + b.box3(sizeb, false) + gl.BindTexture(gl.TEXTURE_2D, b.offscr1.tex) + b.enableTextureRenderTarget(&b.offscr2) + b.box3(sizec, false) + gl.BindTexture(gl.TEXTURE_2D, b.offscr2.tex) + b.enableTextureRenderTarget(&b.offscr1) + b.box3(sizea, true) + gl.BindTexture(gl.TEXTURE_2D, b.offscr1.tex) + b.enableTextureRenderTarget(&b.offscr2) + b.box3(sizeb, true) gl.Enable(gl.BLEND) gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) - gl.BindTexture(gl.TEXTURE_2D, b.offscr2.tex) + b.disableTextureRenderTarget() + b.box3(sizec, true) - gl.Uniform2f(gs.KernelScale, 0.0, 1.0/float32(b.fh)) - gl.DrawArrays(gl.TRIANGLE_FAN, 0, 4) + gl.DisableVertexAttribArray(b.bbshd.Vertex) + gl.DisableVertexAttribArray(b.bbshd.TexCoord) - gl.DisableVertexAttribArray(gs.Vertex) - gl.DisableVertexAttribArray(gs.TexCoord) - - gl.Enable(gl.STENCIL_TEST) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) } -func gaussianKernel(stddev float64, target []float32) { - stddevSqr := stddev * stddev - center := float64(len(target) / 2) - factor := 1.0 / math.Sqrt(2*math.Pi*stddevSqr) - for i := range target { - x := float64(i) - center - target[i] = float32(factor * math.Pow(math.E, -x*x/(2*stddevSqr))) +func (b *GoGLBackend) box3(size int, vertical bool) { + gl.Uniform1i(b.bbshd.BoxSize, int32(size)) + if vertical { + gl.Uniform1i(b.bbshd.BoxVertical, 1) + gl.Uniform1f(b.bbshd.BoxScale, 1/float32(b.fh)) + } else { + gl.Uniform1i(b.bbshd.BoxVertical, 0) + gl.Uniform1f(b.bbshd.BoxScale, 1/float32(b.fw)) } - // normalizeKernel(target) -} + gl.DrawArrays(gl.TRIANGLE_FAN, 0, 4) -func normalizeKernel(kernel []float32) { - var sum float32 - for _, v := range kernel { - sum += v - } - factor := 1.0 / sum - for i := range kernel { - kernel[i] *= factor - } + gl.StencilFunc(gl.ALWAYS, 0, 0xFF) } diff --git a/backend/goglbackend/gogl.go b/backend/goglbackend/gogl.go index f589e97..a7526da 100644 --- a/backend/goglbackend/gogl.go +++ b/backend/goglbackend/gogl.go @@ -20,10 +20,8 @@ type GLContext struct { shadowBuf uint32 alphaTex uint32 - shd unifiedShader - gauss15r gaussianShader - gauss63r gaussianShader - gauss127r gaussianShader + shd unifiedShader + bbshd boxBlurShader offscr1 offscreenBuffer offscr2 offscreenBuffer @@ -60,29 +58,11 @@ func NewGLContext() (*GLContext, error) { return nil, err } - err = loadShader(gaussian15VS, gaussian15FS, &ctx.gauss15r.shaderProgram) + err = loadShader(boxVS, boxFS, &ctx.bbshd.shaderProgram) if err != nil { return nil, err } - ctx.gauss15r.shaderProgram.mustLoadLocations(&ctx.gauss15r) - if err = glError(); err != nil { - return nil, err - } - - err = loadShader(gaussian63VS, gaussian63FS, &ctx.gauss63r.shaderProgram) - if err != nil { - return nil, err - } - ctx.gauss63r.shaderProgram.mustLoadLocations(&ctx.gauss63r) - if err = glError(); err != nil { - return nil, err - } - - err = loadShader(gaussian127VS, gaussian127FS, &ctx.gauss127r.shaderProgram) - if err != nil { - return nil, err - } - ctx.gauss127r.shaderProgram.mustLoadLocations(&ctx.gauss127r) + ctx.bbshd.shaderProgram.mustLoadLocations(&ctx.bbshd) if err = glError(); err != nil { return nil, err } diff --git a/backend/goglbackend/shaders.go b/backend/goglbackend/shaders.go index 06d4760..70759cb 100755 --- a/backend/goglbackend/shaders.go +++ b/backend/goglbackend/shaders.go @@ -1,11 +1,5 @@ package goglbackend -import ( - "bytes" - "fmt" - "strings" -) - var unifiedVS = ` attribute vec2 vertex, texCoord; @@ -100,96 +94,52 @@ void main() { } ` -var gaussian15VS = ` +var boxVS = ` attribute vec2 vertex, texCoord; + uniform vec2 canvasSize; -varying vec2 v_texCoord; + +varying vec2 v_cp, v_tc; + void main() { - v_texCoord = texCoord; + v_tc = texCoord; + v_cp = vertex; vec2 glp = vertex * 2.0 / canvasSize - 1.0; gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); -}` -var gaussian15FS = ` -#ifdef GL_ES -precision mediump float; -#endif -varying vec2 v_texCoord; -uniform vec2 kernelScale; -uniform sampler2D image; -uniform float kernel[15]; -void main() { - vec4 color = vec4(0.0, 0.0, 0.0, 0.0); -_SUM_ - gl_FragColor = color; -}` - -var gaussian63VS = ` -attribute vec2 vertex, texCoord; -uniform vec2 canvasSize; -varying vec2 v_texCoord; -void main() { - v_texCoord = texCoord; - vec2 glp = vertex * 2.0 / canvasSize - 1.0; - gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); -}` -var gaussian63FS = ` -#ifdef GL_ES -precision mediump float; -#endif -varying vec2 v_texCoord; -uniform vec2 kernelScale; -uniform sampler2D image; -uniform float kernel[63]; -void main() { - vec4 color = vec4(0.0, 0.0, 0.0, 0.0); -_SUM_ - gl_FragColor = color; -}` - -var gaussian127VS = ` -attribute vec2 vertex, texCoord; -uniform vec2 canvasSize; -varying vec2 v_texCoord; -void main() { - v_texCoord = texCoord; - vec2 glp = vertex * 2.0 / canvasSize - 1.0; - gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); -}` -var gaussian127FS = ` -#ifdef GL_ES -precision mediump float; -#endif -varying vec2 v_texCoord; -uniform vec2 kernelScale; -uniform sampler2D image; -uniform float kernel[127]; -void main() { - vec4 color = vec4(0.0, 0.0, 0.0, 0.0); -_SUM_ - gl_FragColor = color; -}` - -func init() { - fstr := "\tcolor += texture2D(image, v_texCoord + vec2(%.1f * kernelScale.x, %.1f * kernelScale.y)) * kernel[%d];\n" - bb := bytes.Buffer{} - for i := 0; i < 127; i++ { - off := float64(i) - 63 - fmt.Fprintf(&bb, fstr, off, off, i) - } - gaussian127FS = strings.Replace(gaussian127FS, "_SUM_", bb.String(), -1) - bb.Reset() - for i := 0; i < 63; i++ { - off := float64(i) - 31 - fmt.Fprintf(&bb, fstr, off, off, i) - } - gaussian63FS = strings.Replace(gaussian63FS, "_SUM_", bb.String(), -1) - bb.Reset() - for i := 0; i < 15; i++ { - off := float64(i) - 7 - fmt.Fprintf(&bb, fstr, off, off, i) - } - gaussian15FS = strings.Replace(gaussian15FS, "_SUM_", bb.String(), -1) } +` +var boxFS = ` +#ifdef GL_ES +precision mediump float; +#endif + +varying vec2 v_cp, v_tc; + +uniform int boxSize; +uniform bool boxVertical; +uniform float boxScale; +uniform sampler2D image; + +void main() { + vec4 color = vec4(0.0, 0.0, 0.0, 0.0); + + vec4 sum = vec4(0.0); + if (boxVertical) { + vec2 start = v_tc - vec2(0.0, (float)(boxSize) * boxScale); + for (int i=0; i