OpenGL Alpha values having no effect in shader

Tags: , , ,



I have a simple shader to make scanlines in my 2d game which works fine and is as follows:

#ifdef GL_ES
    precision mediump float;
#endif

varying vec4 v_color;
varying vec2 v_texCoords;

uniform sampler2D u_texture;

void main() {
    vec2 p = vec2(floor(gl_FragCoord.x), floor(gl_FragCoord.y));
    if (mod(p.y, 6.0)==0.0)
        gl_FragColor = vec4(0.0,0.0,0.0, 0.1);
    else
        gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
}

But if I change the alpha value in the vec4 for the fragment colour, it has no effect, the scanlines are equally black at 0.1 as they are at 1.0. I saw some other questions regarding this which advised to enable blending, but I tried that to no avail.

This is my render method with blending enabled.

@Override
public void render(float delta) {
    Gdx.gl.glClearColor(0.0f, 0.0f, 0.0f, 0);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    Gdx.gl.glEnable(GL20.GL_BLEND);
    Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
    // batch.enableBlending(); tried this too but no effect
    batch.setProjectionMatrix(cam.combined);
    batch.setShader(shaderProgram);
    batch.begin();
    rendup.renderAll(batch);//renders all sprites, tiles etc
    batch.setShader(null);
    batch.end();
}

Answer

This isn’t a blending problem. The issue is your shader only draws either a translucent black pixel, or the color of whatever texture region is being drawn. These black pixels are just getting blended with what’s already on the screen (in this case the black clear color).

I assume what you actually want here is for the scan lines not to be pure black. So you should be drawing the color of the texture region everywhere, and just darken it slightly where the scan lines are. You don’t want to be modifying the alpha that the shader outputs, or when you have overlapping sprites, the scanline will appear darker in that area.

So change your shader like this:

#ifdef GL_ES
    precision mediump float;
#endif

varying vec4 v_color;
varying vec2 v_texCoords;

uniform sampler2D u_texture;

const float DARK_LINE_BRIGHTNESS = 0.9;

void main() {
    vec4 color = v_color * texture2D(u_texture, v_texCoords);
    vec2 p = vec2(floor(gl_FragCoord.x), floor(gl_FragCoord.y));
    if (mod(p.y, 6.0)==0.0)
        gl_FragColor = vec4(color.rgb * DARK_LINE_BRIGHTNESS, color.a);
    else
        gl_FragColor = color;
}

However, if/else should be avoided in fragment shaders because it performs significantly worse in most cases. (Exception is if the if statement evaluates to the same value for many pixels in a row, such as with if (u_someUniformBoolean).) You could rewrite it like this:

void main() {
    vec4 color = v_color * texture2D(u_texture, v_texCoords);
    vec2 p = vec2(floor(gl_FragCoord.x), floor(gl_FragCoord.y));
    gl_FragColor = (step(0.01, mod(p.y, 6.0)) * (1.0 - DARK_LINE_BRIGHTNESS) + DARK_LINE_BRIGHTNESS) * color;
}


Source: stackoverflow