0

I am creating an iOS app for drawing / sketching and right now encountering a problem when I draw GL_POINTS indirectly to an FBO that then this FBO is stamped onto a final FBO.

Here is the result when I draw the GL_POINTS DIRECTLY to an FBO

Direct Drawing

And here is the result when I draw the points INDIRECTLY by drawing to an FBO and then draw this FBO onto another FBO

Drawing Indirectly

As you can see, the indirect method didn't blend quite right. I don't know if the problem is because of my blend mode is wrong or because there's a loss precision when drawing indirectly.

Here is my algorithm :

I. Drawing the points to an offscreen FBO named drawingFramebuffer:

// pre-multiplied alpha
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glBindFramebuffer(GL_FRAMEBUFFER, drawingFramebuffer);
// clear drawing FBO
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
... 
// draw the points
glDrawArrays(GL_POINTS, 0, totalPoints);

in the fragment shader

uniform sampler2D brushTexture;
uniform highp vec4 brushColor;
void main()
{
    highp vec4 textureAlpha = texture2D(brushTexture, gl_PointCoord.xy);
    gl_FragColor = vec4(brushColor.rgb * textureAlpha.a, textureAlpha.a);      
}

II. And then, stamping the drawingFramebuffer onto final Framebuffer by using a quad

// draw the texture using pre-multiplied alpha
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glBindFramebuffer(GL_FRAMEBUFFER, finalFramebuffer);
... 
// draw the quad vertices using triangle strip
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

in the fragment shader

uniform sampler2D texture;
varying highp vec2 textureCoord;
void main()
{
    highp vec4 textureColor = texture2D(texture, textureCoord);
    gl_FragColor = textureColor;      
}

I'm utterly confused, how can drawing directly and indirectly yields different results when the blend modes are the same.

Thanks guys/girls for any help!

--- Edited to Add ---

After some calculations with excel, I found out that my blending is already correct, so I suspect the problem is the loss of precision that's happening when reading the drawing FBO

Coolant
  • 448
  • 6
  • 13
  • 1
    It looks a little to me like one of your framebuffers lacks a depth buffer, or you forgot to clear it. That said, I kind of like the look of the second; it looks like a finger painting. Maybe make the second one an optional draw mode and call it a feature? :) – Andon M. Coleman Sep 07 '13 at 02:22
  • Hehe, thanks for the input. I never thought about depth buffer before. Ok, I'll check it out and hopefully that's the reason why. – Coolant Sep 07 '13 at 04:24
  • 1
    My original thinking was that this was an order-dependent issue related to your blend function. But upon closer inspection that should not matter, and thus depth buffering should not be to blame. But the clear value of your FBO could be to blame. If you could show how you clear your draw buffer in your code that would help. – Andon M. Coleman Sep 07 '13 at 04:32
  • Oh, right, I forgot about that :) I cleared the drawing FBO using glClearColor(0, 0, 0, 0). Should it be another value, though? I figured, it should be a transparent color and pre-multiplied...? – Coolant Sep 07 '13 at 08:01
  • I did some calculations with excel to differentiate between the two modes and the results are the same, so my blending is already correct, so I think this is the loss of precision issue :( – Coolant Sep 07 '13 at 14:58

1 Answers1

0

Okay, I've finally fixed it by :

  1. Disregarding the RGB calculation when drawing the GL_POINTS. Bottom line is, rgb value is the culprit. So I'm only focusing on the alpha calculation when drawing GL_POINTS (by using default pre-multiplied blending).

  2. When 'stamping' the drawing FBO, this is when I applied the coloring. By inserting the color value as a uniform and set the fragment color as this color value multiplied by alpha.

I think this is a method that Procreate or other drawing apps use. Although now I have a problem of what would happen if the color value is varied (not a uniform)...

Coolant
  • 448
  • 6
  • 13