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(); }
Advertisement
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; }