I am rendering 2 triangles to make a square, using a single draw call with GL_TRIANGLE_STRIP.
I calculate position and uv in the shader with:
vec2 uv = vec2(gl_VertexID >> 1, gl_VertexID & 1);
vec2 position = uv * 333.0f;
float offset = 150.0f;
mat4 model = mat4(1.0f);
model[3][1] = offset;
gl_Position = projection * model * position;
projection is a regular orthographic projection that matches screen size.
In the fragment shader I want to draw each first line of pixels with blue and each second line of pixels with red color.
int v = int(uv.y * 333.0f);
if (v % 2 == 0) {
color = vec4(1.0f, 0.0f, 0.0f, 1.0f);
} else {
color = vec4(0.0f, 0.0f, 1.0f, 1.0f);
}
This works ok, however if I use offset that will give me a subpixel translation:
offset = 150.5f;
The 2 triangles don't get matching uvs as seen in this picture:
What am I doing wrong?
Attribute interpolation is done only with a finite precision. This implies that due to round-off errors, even a difference in 1 ulp
(unit-last-place, i.e. least significant digit) can cause the result to be rounded in the other direction. Since the order of operations in the hardware interpolation unit can be different between the two triangles, the values prior to rounding can be slightly different. OpenGL does not provide any guarantees about that.
For example you might be getting 1.499999
in the upper triangle and 1.50000
in the lower triangle. Consequently when you add an offset of 0.5
then 1.99999
will be rounded down to 1.00000
but 2.000000
will be rounded to 2.00000
.
If pixel perfect results are important to you I suggest you calculate uv
coordinates manually from the gl_FragCoord.xy
. In a case of an axis-aligned rectangle, as in your example, it is straightforward to do.