howto... scanlines? :>

Seriously… I don’t have a clue ::slight_smile:

What’s the fastest way to produce a scanline effect?

Description of scanlines (for those who don’t know):
Every second line of the screen is black (100% scanlines) or blended (75%, 50% and 25% are common values).

Should I draw lines (640x480 would mean 240 lines) or should I use a texture? I would guess that using a 2x2 pixel texture mapped on a quad would be the best.

So if I do that - how do I have to setup the screen in order to hit the pixels exactly?

Ok… just tried some stuff…


private final static void drawScanlines()
{
      gl.disable(GL.DEPTH_TEST);
      gl.blendFunc(GL.ONE,GL.DST_COLOR);
      gl.viewport(0,0,800,600);

      gl.matrixMode(GL.PROJECTION);
      gl.pushMatrix();
      gl.loadIdentity();

      gl.ortho(0.0f,800,600,0.0f,-1.0f,1.0f);

      gl.matrixMode(GL.MODELVIEW);
      gl.pushMatrix();
      gl.loadIdentity();

      gl.color3f(0,0,0);
      for(float i=0;i<=600;i+=2)
      {
            gl.begin(GL.LINES);
            gl.vertex3f(0,i,0);
            gl.vertex3f(800,i,0);
            gl.end();
      }
      gl.matrixMode(GL.PROJECTION);
      gl.popMatrix();
      gl.matrixMode(GL.MODELVIEW);
      gl.popMatrix();
      gl.enable(GL.DEPTH_TEST);
}

It works somehow… but it cut’s my fps down to ~110 (from 125). Oh and it’s not really a “micro benchmark” there are ~8000 lines and ~2000 quads :>

Well something is kinda odd… the scanline effect doesnt appear “over” other lines (the scanlines are drawn at last).

How to make your overlay texture match up exactly: http://developer.nvidia.com/view.asp?IO=Mapping_texels_Pixels (Yes it says D3D, but the idea is the same either way).

If you want simple on/off with no blending, then glPolygonStipple may be faster.

Actually the most sure-fire way to do this is to draw black lines over the top of everything at the end. Seems obvious with hindsight dunnit?

Cas :slight_smile:

@Orangy Tang

Ah… I guess that explains something (and I’m more confused than ever :)). At the beginning I had a “<600”-loop for drawing the lines and the last one didn’t show up (everything was shifted). Do I have to change something at ortho/viewport or the coords? ._o

@Cas

Yea… well that’s what I did. So can’t I blend over other lines ???

The fastest way is certainly drawing one big quad covering the whole screen, with a tiled 2x2 texture.

After you’ve drawn everything setup an orthognal projection like so:


        gl.matrixMode(GL.PROJECTION);
        gl.loadIdentity();
        glu.ortho2D(0, width_, height_, 0);
        gl.matrixMode(GL.MODELVIEW);
        gl.loadIdentity();

Now you can use 2d coordinates, and 1 coordinate increment corresponds to 1 pixel exactly. Whenever you want to draw anything in ‘screen’ space you should setup your matrices like the above, and then you can just draw as you would in 2d.

Now setup your 2x2 texture which looks like:


     XX
     00

Where you use color/alpha as appropriate for your texture blending mode.

Then do:


        gl.begin(GL.QUADS);
        gl.texCoord2f(0, 0);
        gl.vertex2i(left, top);
        gl.texCoord2f(0, (top-bottom)/2);
        gl.vertex2i(left, bottom);
        gl.texCoord2f(1, (top-bottom)/2);
        gl.vertex2i(right, bottom);
        gl.texCoord2f(1, 0);
        gl.vertex2i(right, top);
        gl.end();

The key here is that you wrap the 2 pixels horizontally across the whole quad, and the 2 pixels vertically you repeat (top-bottom)/2 times down the whole quad.

Just tried this and it works fine.

@TheRedRabbit

Thanks for your reply. That’s the way I wanted to do it, because it seems to be the fastest way. Well have you read the doc mentioned by Orangy Tang?

I setup the screen in a similar way for doing the effect with lines and surprisingly it doesnt hit line 0 exactly. Infact line 0 (coords) was one pixel above pixel-line 0.

Therefore I guess that you need a 0.5 unit shift for the quad coords in order to make the work for the rasterizer obvious. This way it should be reproducable for all 3d-cards and the result will always look the same.

Well I guess I should simply try it for myself :slight_smile:

Using the quad as described above with the texture will line up exactly with screen pixels.

The reason your lines fail is because of the way that OpenGL rasterizes.

If you draw a rectangle from 0,0 to 1,1 it fills exactly 1 pixel. The 0 and 1 don’t represent row/column 0 and 1 on the screen, they represent infinitely thin lines around row/column 0.

If you draw a line and want it to rasterize on one pixel you should use a 0.5 offset coordinate. If you look in the Red Book (OpenGL Programming Guide 3rd Ed.) P677 (OpenGL Correctness Tips) you’ll find more details about exact two dimensional rasterization.