8
\$\begingroup\$

I am working on an old-school platformer in libgdx and I want it to have a "scanline" effect, like this:

maldita castilla scanline effect

My first attempt was to make a little texture and draw it on a full-screen quad. I used two different orthographic camera modes (one for the main tilemap of the game, and a second to render the scanline texture). Sometime the texture is stuck on the tilemap and sometime it is too large, and covers the whole screen in black.

Is my approach using two cameras and a texture reasonable? What's a good solution to achieve this effect?

\$\endgroup\$
0

2 Answers 2

4
\$\begingroup\$

The problem with naively rendering a small scanline texture onto a large full-screen quad is that the texture will scale up, making what was a set of single-pixel scanlines in the texture much thicker, blurrier (depending on your interpolation method), and generally uglier.

You should instead tile the texture across the quad in such a way as to preserve a 1:1 pixel-to-texel ratio. This involves adjusting the quad's texture coordinates so that they are greater than 1 at the furthest extent, and also setting your textures wrap parameter to repeat instead of clamp. If your texture is 64x64 pixels, and your screen is 1024x768 pixels, you can figure that in the X axis you must tile the texture 16 times (1024 / 64). Similarly, on the Y axis you must tile it 12 times (768 / 64). You can adjust this math for the actual bounds of your texture and screen. Use those numbers (16 and 12) as the maximum extents of your quad's texture coordinates, and you'll get a much better result. Depending on how your orthographic projection is currently set up for the tiles, you may not even need to change it to render this.

Alternatively, you can take a shader approach: render your regular scene to a texture, then render that texture as a fullscreen quad, but omit every odd line of pixels. If you know the bounds of the screen in the shader, you can do this pretty easily (this is pseudo-code, vaguely HLSL-ish, but should translate easily):

float2    screenSize;
sampler2D textureSampler;
float2    textureCoordinate;

float4 main () { 
   // Interpolation of texture coordinates means that we don't get nice
   // integer boundaries we could take the modulus of.
   float half_y = textureCoordinate.y * screenSize.y * 0.5;
   float delta = round(half_y) - half_y;
   float delta_squared = delta * delta;
   if (delta_squared < 0.1) {
      return texture2D(textureSampler, textureCoordinate);
   } 

   return float4(0,0,0,0);
}
\$\endgroup\$
0
\$\begingroup\$

The problem with using a camera is that it will scale the image. What you essentially want is to always draw the same image at the same size (100%). I assume it's big enough to always cover the entire screen.

If this is the case, one solution would be to apply the inverse transformation of the camera on the image so that it draws at a "pixel perfect" size.

The easier option would be to scale it yourself. Eg. if your camera is zoomed to 75%, your image would be scaled to 133% (1/0.75).

\$\endgroup\$
4
  • \$\begingroup\$ you say that the image have to be big enought to cover the entire screen, isn't it possible to fill a bit rect with a small texture? \$\endgroup\$ Oct 27, 2013 at 6:56
  • \$\begingroup\$ @AlexandreGUIDET I'm not sure. I use a texture for fading in and out, and it's a 1x1 pixel that's scaled. For scanlines, you want it to repeat. You should check if libGDX has an option for this. \$\endgroup\$
    – ashes999
    Oct 27, 2013 at 11:46
  • \$\begingroup\$ @AlexandreGUIDET did you try this? \$\endgroup\$
    – ashes999
    Dec 5, 2013 at 21:54
  • \$\begingroup\$ I choose a different approach using another camera and drawing the scanline effect above the scene. I am not yet satisfied with the result because the scene seems to slip behind the scanlines. What do you think about using a shader instead? \$\endgroup\$ Dec 6, 2013 at 8:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .