[libGDX] Scanlines problem with OrthographicCamera

I want to display a semi-transparent texture over the top of my game to create a scanlines effect. The texture is a png with alternating black and transparent lines. To achieve this, I’ve got two problems to overcome:

  1. How to create a texture that is the size of the device’s screen resolution, then tile it with my 64x64 scanline png?

  2. My game uses an OrthographicCamera to scale the game screen to the size of whatever device it is running on. This means that I can’t simply draw the scanlines texture created in step 1 as I want to scanlines to always be 1 pixel in height of the device’s resolution.

This is what I have so far for problem 1:

Texture texScanlines = globals.spritesAtlas.findRegion("Scanlines").getTexture();
texScanlines.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat);
TextureRegion imgTextureRegion = new TextureRegion(texScanlines);
imgTextureRegion.setRegion(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

scanlines = new Sprite(imgTextureRegion);

However, this does not work. When creating the Texture using the texture atlas region, the whole texture atlas is being drawn instead of just the selected region. Any pointers?

Create an quad (mesh) covering the screen, consisting of 2 triangles.
Set the texture coordinates so that they tile the texture with 1texel:1pixel ratio, you need to compute this at runtime!
Set GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T to GL_REPEAT for tiling.

The screen has xs pixels in one direction and texture has xt texels int that direction
=> tile the image xs/xt times

Make biggest texture you need let say 2000 pixels Height,
if you have device with 1000 pixels set Texture UV 0.0 - 0.5

Also remember to use power of two textures (512,1024,2048,etc) on old/mobile gpus, cause they often don’t (properly) support non-POT textures.

I need to start at the beginning with this as I haven’t done any GL20 programming in libGDX before. I wanted to start by just drawing a quad over the top of my game, here’s what I have so far (that doesn’t work):

create()

quad = new Mesh(true, 4, 4,
				new VertexAttribute(Usage.Position, 3, "a_position"),
				new VertexAttribute(Usage.ColorPacked, 4, "a_color"));

quad.setVertices(new float[] {
				-0.5f, -0.5f, 0, Color.toFloatBits(128, 0, 0, 255),
				0.5f, -0.5f, 0, Color.toFloatBits(192, 0, 0, 255),
				-0.5f, 0.5f, 0, Color.toFloatBits(192, 0, 0, 255),
				0.5f, 0.5f, 0, Color.toFloatBits(255, 0, 0, 255) });

quad.setIndices(new short[] { 0, 1, 2, 3});

render()

Gdx.graphics.getGL20().glClearColor(0, 0, 0, 1);
Gdx.graphics.getGL20().glClear(GL20.GL_COLOR_BUFFER_BIT);

camera.update();
spriteBatch.setProjectionMatrix(camera.combined);

spriteBatch.begin();
  // draw game stuff here...
spriteBatch.end();

quad.render(SpriteBatch.createDefaultShader(), GL20.GL_TRIANGLE_STRIP, 0, 4);

It’s run OK, and my game runs normally, but the quad isn’t being displayed.

I think you mess up with colot count
i may be wrong ), but try default 4 floats colors without packing

Like this?

quad = new Mesh(true, 4, 4,
				new VertexAttribute(Usage.Position, 3, "a_position"));

quad.setVertices(new float[] {
				-0.5f, -0.5f, 0,
				0.5f, -0.5f, 0,
				-0.5f, 0.5f, 0,
				0.5f, 0.5f, 0 });

quad.setIndices(new short[] { 0, 1, 2, 3});

Still doesn’t display the quad.

You need to have texture coordinates and a texture bound before rendering too!
Try copying what you need from this example

Having looked at the tutorials, this is what I have so far:

create()

quad = new Mesh(true, 4, 6,
				new VertexAttribute(Usage.Position, 3, "a_position"),
				new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoords"));
quad.setVertices(new float[] {
				-1.0f, 0.0f, 0, 0.0f, 1.0f,             //bottom left
				1.0f,  0.0f, 0, 1.0f, 1.0f,             //bottom right
				1.0f,  1.0f, 0, 1.0f, 0.0f,             //top right
				-1.0f, 1.0f, 0, 0.0f, 0.0f });          //top left
quad.setIndices(new short[] { 0, 1, 2, 2, 3, 0});

Gdx.gl20.glEnable(GL20.GL_TEXTURE_2D);
Gdx.gl20.glEnable(GL20.GL_BLEND);
Gdx.gl20.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);

texScanlines = new Texture(Gdx.files.internal("Scanlines.png"));
texScanlines.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat);
imgTextureRegion = new TextureRegion(texScanlines);
imgTextureRegion.setRegion(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

render()

Gdx.graphics.getGL20().glClearColor(0, 0, 0, 1);
Gdx.graphics.getGL20().glClear(GL20.GL_COLOR_BUFFER_BIT);

camera.update();
		
spriteBatch.setProjectionMatrix(camera.combined);

spriteBatch.begin();
  // draw game stuff...
spriteBatch.end();

imgTextureRegion.getTexture().bind();
quad.render(SpriteBatch.createDefaultShader(), GL20.GL_TRIANGLES);

However, the quad still isn’t being rendered.

You said using opengl in libgdx is new for you, why don’t you copy every bit that is needed to run this example into your game and see if it does anything, skipping steps without understanding whether you can skip them is asking for trouble.
Also, clear the depth buffer too before rendering so that you can be sure that your quad isn’t discarded.

Gdx.gl20.glClear(GL20.GL_DEPTH_BUFFER_BIT);

If the quad is finally displayed, try supplying not only vertex coordinates, but also the texture coordinates (u,v) so that the image is laid over the screen in a pixel to pixel scale.

Agree - clean Opengl very sensitive to every mistake:
you turn on some parameter(status) - forgot send data to it (or send wrong data count 9 from 10)
and receive black screen - without any warning or debug errors.

So best way copy-past 100% working examples and line by line figurate out how they works,
and re run it after every line editing to catch moment when all goes wrong :wink: