gl_Position Pixel-shift

Hi guys,

I am calculating the final on-screen projected values in the vertex shader like so:


vec4 projectedpos = mvpmatrix * vec4(in_Position, 1.0);
FinalPos = vec2(projectedpos.xy) / projectedpos.w;
FinalPos = (FinalPos * 0.5 + 0.5) * vec2(Viewportwidth,Viewportheight);
   gl_Position = projectedpos;

Then, in the fragment shader:


     if(truncate(FinalPos.x+0.5) == 10)
        out_Color = vec4(1.0,0.0,0.0,1.0);

FinalPos is an out variable to the vertex shader, and in to the fragment. ViewportWidth and ViewportHeight are obivously uniforms providing the window width and window height.

This should give me a vertical line at x=10. I dont see a straight line. The line seems to ‘jitter’ around x=10, i.e, often it will draw a red dot at x=11, or not draw one at all.


     if(truncate(FinalPos.x) == 10)
        out_Color = vec4(1.0,0.0,0.0,1.0);

This is better, but its still not a completely straight line.

I had this working when I used ftransform(), but in Opengl 3 it refuses to work. I also tried an ‘invariant’ for gl_Position, but nope…

Why don’t you use gl_FragCoord ? Doesn’t that contain the same value, that you compute in the vertex-shader?

Jan.

Actually I need the equivalent of gl_FragCoord in the vertex shader. I only use it in the fragment shader to test it.

Come to think of it, comparing that value with gl_FragCoord should tell me wether I am computing the correct value or not!

This, in the fragment shader, (correctly) produces a red screen:


     if(int(FinalPos.x+0.5) >= (gl_FragCoord.x-0.5) && trunc(FinalPos.x+0.5) <= (gl_FragCoord.x+0.5))
        out_Color = vec4(1.0,0.0,0.0,1.0);

It seems FinalPos is being computed ok in general but there is a precision loss somewhere. Darn…

Just a stab in the dark: Your vertex-position is “smooth” (i.e. every vertex is somewhere inside a pixel) and you interpolate that across the triangle. Maybe you need to truncate the “FinalPos” variable already in the vertex-shader, before it is interpolated across the fragments.

But i am not sure about that, at all, i would assume your given formula is correct already. But i could imagine there being precision issues. I mean the rasterization is, AFAIK, done by specialized hardware, so there might be slight differences.

Jan.

This should give me a vertical line at x=10. I dont see a straight line. The line seems to ‘jitter’ around x=10, i.e, often it will draw a red dot at x=11, or not draw one at all.

You’re doing multisampling, aren’t you?

Multisample samples are allowed to be from arbitrary locations within the area of the pixel. Technically, even from outside of the pixel. This means that the sample can actually lie outside the area of the triangle. If you need to ensure that an interpolated value is always calculated from within the area of the triangle, you need to use the “centroid” qualifier.

Not really, unless SDL 1.3 likes to turn it on automatically. In fact I made sure I even turned off anti-aliasing from the NVidia control centre.

I’m puzzled to say the least, because it works with ftransform(), i.e, old OpenGL, on the same hardware.

My vertex position is indeed smooth, but that is precisely what I am trying to find, i.e, the sub-pixel offset of each vertex in screen-space. Thats why I have to calculate it in the vertex-shader. The fragment shader operates on integer pixel coordinates only. BTW, its a point-renderer (no triangles) so their shouldn’t be any interpolation.
Good point about truncating FinalPos in the vertex shader. I’ll try that just to see if it makes a difference.

I’m puzzled to say the least, because it works with ftransform(), i.e, old OpenGL, on the same hardware.

What worked with ftransform, exactly?

The fragment shader operates on integer pixel coordinates only.

gl_FragCoord is a vec4, not an ivec4. It gets floating-point values in window coordinates.

It does get floating point values, but they are truncated. There is no sub-pixel information. Its in the specs. In short, fract(gl_FragCoord.x-0.5) is always 0.

With ftransform, I was able to find out the screen-space sub-pixel location in the vertex shader. i.e, replacing the first line in the previous code with something like this worked in my old pre-opengl 3 code:


gl_Position = ftransform();
vec4 projectedpos = gl_Position;

In the vertex shader I was able to find exactly where the pixel would be drawn by the fragment shader. Drawing a line at a particular column or row of the screen produced a straight line, rather than one that straddles between lines like now.