Drawing small anti-aliased points with shaders

I want to draw what are essentially single-pixel points in world-space of arbitrary luminance and color with sub-pixel precision, so effectively quads with appropriately distributed brightness summing up to RGB values of choice.
What steps should be taken to implement this while avoiding any potential precision issues and aliasing?

Read section 14.4 of the OpenGL 4.6 specification for the details of how points are rasterised.

Having the weights sum exactly to one will be easier without multi-sampling. If you set the point size to 2, you’ll get a 2x2 block where one half has gl_PointCoord.x in [0,1/2] and the other in [1/2,1] with the difference exactly 1/2. Likewise for Y. So given gl_PointCoord for one fragment, you know what the values will be for the other 3.

If you choose weights according to:

vec2 d = abs(gl_PointCoord - 0.5) - 1;
float w = d.x*d.y*4/9;

then the four weights will sum to 1.0.

If you want to keep the total observed intensity constant, you’ll need to do this in a linear colour space.

You can use other weighting functions. In order for the weights to sum to a constant, you need w(u+1/2,v)=C-w(u,v), i.e. the function for u>1/2 needs to be a vertically-mirrored version of the function for u<1/2 (likewise for v). You probably also want it to be symmetric, i.e. w(1/2+du,v)=w(1/2-du,v).

This would work:

vec2 d = (gl_PointCoord - 0.5)*2*pi;
float w = cos(d.x)*cos(d.y);

As would:

vec2 d = abs(gl_PointCoord - 0.5);
float w = (1-smoothstep(0.0,0.5,d.x))*(1-smoothstep(0.0,0.5,d.y));
1 Like