Well, it seems to work for you, but I’ll say that this is a bit of a hack
The center of pixels have non-integer coordinates, e.g. when rendering to a viewport of width W the pixel centers have x coordinates of 0.5, 1.5, ..., W - 0.5.
Correspondingly in clip coordinates (the output coordinate system of the vertex shader), the bottom left pixel’s center is at (-1.0 + 1.0/W, -1.0 + 1.0/W) and the top right is at (1.0 - 1.0/W, 1.0 - 1.0/W).
The vertices are on the corners between pixels, so the lines run along the edges of the pixels, exactly mid-way between pixel centres. Which means that it’s unspecified which pixels get affected (if the viewport doesn’t cover the entire window, pixels outside the viewport may be affected).
If you want to be certain which pixels are affected, inset the vertices slightly. If you’re trying to draw a one-pixel border around the inside of a w×h rectangle, the lines should ideally be w-1 and h-1 pixels apart (i.e. a half-pixel inset from each edge).
There’s no way to avoid having the coordinates depend upon the resolution. If you want one edge of a single-pixel line to touch the edge of the viewport, the line needs to get closer to ±1 (in NDC) as the resolution increases.
GClements, thank for explanation.
Look at the two lines on screenshot: line at right, line at bottom.
Both lines has coords 1.0, -1.0.
Both lines rendered.
Top and left lines has same definition, but not rendered.
Right and bottom lines has 1.0, but rendered.
If a line is exactly half-way between pixel centres (i.e. window-space coordinates are integers), it’s unspecified which pixels are rendered. For the left and right edges, you might get one or the other or both or neither. The exact behaviour may vary depending upon hardware and window size.
Yes. Or more generally, ±(1-1/size) where size is the window size in pixels.
More generally still, if the viewport bounds are [l,r]×[b,t] and the combination of the model-view-projection matrices and viewport transformation maps (x0,y0) to (b,l) and (x1,y1) to (r,t), then a change in object coordinates of (x1-x0)/(r-l) or (y1-y0)/(t-b) results in a change in window coordinates of one pixel.
For x0=y0=-1, x1=y1=1, l=b=0, r=t=100, (1-(-1))/(100-0) = 2/100 is one pixel and 1/100 is half a pixel. So add 0.01 to the left and bottom and subtract 0.01 from the right and top.