Shifting point sprites to prevent depth issues

I came across an old post on these forums while trying to solve an issue I encountered in my project:

The author explains he is rendering point sprites in a scene with other geometry, but wants to prevent the point sprites from partly intersecting that geometry. Since nobody mentioned the solution I found to this, I thought I’d post it here.

[ATTACH=CONFIG]1885[/ATTACH]

In this screenshot, you can see I’m using point sprites to render LEDs in a light fixture. However, the geometry and the point sprites intersect. It would be great if we could render the point sprites on top of the geometry, at least for the ones closest to us.

Instead of doing depth testing in the fragment shader, or foregoing depth testing altogether, I chose to add a little bias to the sprites to shift them slightly towards the camera. My world coordinates are in meters and I think 5 centimeters would do it. So here’s the vertex shader:


#version 330

uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
uniform vec2 uPointSize;        // in view space units (usually the same as world space) 
uniform vec2 uViewportSize;     // size of the window (or viewport) in pixels

in vec4 inPosition;  // in object space

float calcPointSize( in vec4 viewPosition, in vec2 size, in float viewportWidth )
{
    vec4 projected = uProjectionMatrix * vec4( 0.5 * size.xy, viewPosition.z, viewPosition.w );
    return viewportWidth * projected.x / projected.w;
}

void main(void)
{
    vec4 viewPosition = uModelViewMatrix * inPosition; // in view space

    // Move the vertex 5cm towards the camera by scaling the w coordinate:
    viewPosition.w *= viewPosition.z / ( viewPosition.z + 0.05 );

    gl_PointSize = calcPointSize( viewPosition, uPointSize, uViewportSize.x );
    gl_Position = uProjectionMatrix * viewPosition;
}

Note: I have omitted any textures or colors, to keep the code sample brief.

We can simply shift the point sprite along the ray from the camera position to the vertex position by changing the W coordinate. You can think of the W coordinate as a scaling factor. In world and view space, it usually is equal to 1. By setting it to 0.5, you would move the point twice as close to the camera (half the distance).

This is what it looks like with the above code active:

[ATTACH=CONFIG]1886[/ATTACH]

Hopefully this is useful to any of you.