I am trying to implement a post-processing blur effect on a map drawn using openGL on my android app project.
What I try to do is render my map in a texture, then render the texture on screen using a fragment shader that apply my gaussian blur in a single pass. I have successfully render the texture making a passthrough shader, however applying a simple gaussian blur gives my a 5 pixel line in the middle of my screen, and I cannot figure it out (been trying for several hours)
Here are my shaders:
var vertexShaderCode = "" +
"precision mediump float;" +
"attribute vec2 inPos;" +
"varying vec2 pos;" +
"void main()" +
"{" +
" pos = inPos;" +
" gl_Position = vec4( inPos, 0.0, 1.0 );" +
"}"
var fragmentShaderCode = "" +
"precision mediump float;" +
"uniform sampler2D sample_texture;" +
"uniform vec2 u_textureSize;" +
"varying vec2 pos;" +
"float normpdf(in float x, in float sigma)" +
"{" +
" return 0.39894*exp(-0.5*x*x/(sigma*sigma))/sigma;" +
"}" +
"void main()" +
"{" +
" /* Return colour. */" +
" vec2 texC = pos.st * 0.5 + 0.5;" +
" vec4 texCol = texture2D(sample_texture, texC);" +
"int mSize = 11;" +
"int kSize = int((float(mSize) - 1.0) / 2.0);" +
"float kernel[11];" +
"vec3 final_color = vec3(0.0, 0, 0);" +
// Create the kernel
"float sigma = 10.0;" +
"float Z = 0.0;" +
"for (int j = 0; j <= kSize; ++j)" +
"{" +
" kernel[kSize + j] = kernel[kSize - j] = normpdf(float(j), sigma);" +
"}" +
//get the normalization factor (as the gaussian has been clamped)
"for (int j = 0; j < mSize; ++j)" +
"{" +
" Z += kernel[j];" +
"}" +
//read out the texels
"for (int i = -kSize; i <= kSize; ++i)" +
"{" +
" for (int j = -kSize; j <= kSize; ++j)" +
" {" +
" vec2 tmp = texC + vec2(float(i), float(j)) / u_textureSize;" +
" final_color += kernel[kSize + j] * kernel[kSize + i] * texture2D(sample_texture, tmp).rgb;" +
" }" +
"}" +
"gl_FragColor = vec4(final_color / (Z*Z), 1.0);" +
// This gives my a working passthrough shader
//" gl_FragColor = texCol;" +
"}"
Here is how I create the texture and use it back after rendering the scene:
/* Generate objects. */
GLES20.glGenFramebuffers(1, framebufferObjectIdPtr)
GLES20.glGenTextures (1, originalTextureObjectIdPtr)
/* Bind generated framebuffer and texture objects to specific binding points. */
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, framebufferObjectIdPtr[0])
GLES20.glBindTexture (GLES20.GL_TEXTURE_2D, originalTextureObjectIdPtr[0])
GLES20.glTexImage2D (GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR)
/* attach generated texture objects to the framebuffer object at specific binding points. */
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, originalTextureObjectIdPtr[0], 0)
/* Clear the framebuffer's content. */
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT or GLES20.GL_DEPTH_BUFFER_BIT)
/* Draw scene. */
/* Get texture sample uniform location. */
var sampleTextureUniformLocation = GLES20.glGetUniformLocation(mProgram, "sample_texture");
val locTexSize: Int = glGetUniformLocation(mProgram, "u_textureSize")
val texSize = ByteBuffer.allocateDirect(8).run {
order(ByteOrder.nativeOrder())
asFloatBuffer().apply {
put(floatArrayOf(width.toFloat(), height.toFloat()))
position(0)
}
}
/* Set uniform value. */
GLES20.glUniform1i(sampleTextureUniformLocation, 0);
GLES20.glUniform2fv(locTexSize, 1, texSize)
GLES20.glUseProgram(mProgram)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, originalTextureObjectIdPtr[0]);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0)
GLES20.glEnableVertexAttribArray(quadPositionHandle)
GLES20.glDrawArrays( GLES20.GL_TRIANGLE_STRIP, 0, 4 )
GLES20.glDisableVertexAttribArray(quadPositionHandle)
I was thinking that my error would be in the fragment shader line where I compute the final color, but computing wrongly the adjacent texture coordinates should give me wrong result but everywhere on the screen, what I get is an horizontal 5 pixel brown line in the middle of the screen. Did I miss something in the framebuffer init that may cause a wrong layout ? On the other hand, the passthrough works...
Can someone point me on the right direction ?