2
$\begingroup$

I'm looking for a way to make my surface semitransparent, and for now i ended up using this configuration:

eglChooseConfig(eglDisplay, new int[] {
            EGL10.EGL_ALPHA_SIZE,   8,
            EGL10.EGL_RED_SIZE,     8,
            EGL10.EGL_GREEN_SIZE,   8,
            EGL10.EGL_BLUE_SIZE,    8,
            EGL10.EGL_NONE
}

My default configuration was:

eglChooseConfig(eglDisplay, new int[] {
            EGL10.EGL_RED_SIZE,     8,
            EGL10.EGL_GREEN_SIZE,   8,
            EGL10.EGL_BLUE_SIZE,    8,
            EGL10.EGL_DEPTH_SIZE    16,
            EGL10.EGL_NONE
}

As you can see, i added EGL_ALPHA_SIZE attribute and removed EGL_DEPTH_SIZE, since my application is a simple 2D drawing on a surface and it doesn't need a depth buffer. It works, but for some reason results in somewhat unexpected results for this simple fragment shader:

precision mediump float;
uniform sampler2D uSampler;
varying vec2 vTextureCoord;
void main() {
    vec4 originalColor = texture2D(uSampler, vTextureCoord);
    gl_FragColor = originalColor + vec4(0, 0, 0, -0.5);
}

The alpha component seems to be affecting rest of the parts of the color and changes it at some extent. The first image below is the original one, second is what I have, and the last one is what I want to achieve.

Original image What i have What i want to achieve

Any advice is appreciated, thanks!

For the sake of clarity

OpenGL ES Version: 2.0

$\endgroup$
  • $\begingroup$ "The alpha component seems to be affecting rest of the parts of the color and changes it at some extent." How are you detecting those changes? That is, how do you know that the color is being changed? Have you read the pixels back? Or is this what you're seeing in some window? If it's a window, which OS and windowing compositor are you using? Is it one that supports transparency natively? $\endgroup$ – Nicol Bolas Dec 10 '18 at 0:30
  • $\begingroup$ What blend mode are you using, this looks like a case of pre-multiplied alpha. $\endgroup$ – PaulHK Dec 10 '18 at 2:23
2
$\begingroup$

It looks like you're drawing with pre-multiplied alpha. This means that the red, green, and blue channels have been multiplied by the alpha channel. So your shader should look more like this:

precision mediump float;
uniform sampler2D uSampler;
varying vec2 vTextureCoord;
void main() {
    vec4 originalColor = texture2D(uSampler, vTextureCoord);
    vec4 tempColor = originalColor + vec4(0, 0, 0, -0.5);
    tempColor.rgb *=  tempColor.a;
    gl_FragColor = tempColor;
}

I believe you also need to set glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) to get the correct blending (and of course, glEnable(GL_BLEND)).

$\endgroup$
  • $\begingroup$ Thank you, sir, it works as expected. One question - why the DST equation is GL_ONE_MINUS_SRC_ALPHA? It looks to me that the fragment shader already performs required computation, so it should not be any further changed? $\endgroup$ – The Dreams Wind Dec 10 '18 at 18:17
  • $\begingroup$ The destination is for blending the results of your fragment shader with whatever is already in the framebuffer. So it happens after your fragment shader runs. Your fragment shader isn't touching the destination in any way. $\endgroup$ – user1118321 Dec 11 '18 at 2:11
  • 1
    $\begingroup$ The Dreams Wind: The source.rgb * source.alpha is already computed in your texture. You still need to blend it with your destination. The full blending formula becomes frag = source.rgb + dest.rgb * (1-source.a); because source.rgb is "pre-multipled" already, saving your GPU some calculation. That is what the glBlendFunc is doing. $\endgroup$ – PaulHK Dec 13 '18 at 3:58

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.