It highly depends on rasterization of the depth at the vertex positions, and how accurate your ‘world to screen coordinate’ projection function is (but to a lesser degree). If the depth changes alot between frames, the tags may flicker.
I’ve implemented something similar before. Slight differences in the rasterized vs. projected depth coordinates caused the tags to flicker, because the depth value would one frame be deeper (invisible), and the next to be exactly the same or larger (visible). Because the distribution of the depth buffer is non-linear, you can’t simply add a depth margin to counter this.
I did not use the projected winZ component returned by gluProject, as it is in linear space, and the depth buffer is non-linear. You could probably use winZ to calculate it proper, but you have to get the exact formula that the GL implementation uses or add a margin.
If I recall correctly, I did it like this:
- render visible scene
- disable color buffer rendering (glColorMask) and clear depth buffer
- glPointSize(3), to take in account inaccuracy of project function and badly implemented rasterization (read Intel graphics drivers)
- render vertices as GL_POINTS to depth buffer
- loop through vertices and project these to get the screen coordinates, store these
- loop through vertices and read back depth from z-buffer, store this
- render occluder (e.g. solid cube)
- loop through vertices second time, and read back depth, store as well
- setup 2d view projection (for 2d font/tag drawing etc)
- loop through vertices and do the depth compare, if visible draw tag, if invisible skip
I had a structure for each vertex something like this:
struct vert
{
vec3 pos; // world space position
int screen_x; // projected screen space X
int screen_y; // projected screen space Y
float depth_1; // read back depth at screen space X,Y before occluder is drawn
float depth_2; // read back depth at screen space X,Y after occluder is drawn
};
Keep in mind this way vertices may also occlude other vertices (in my case this was desirable), but can be avoided if you dot he whole process for vertices individually (not recommended!).
As you can see, lots of glReadPixels with means lots of stalls. In my application this was ok, as it wasn’t real-time.
IMO, better to draw the tags into the 3d scene, if that is ok for your purposes. It is faster and relies less on the assumed correctness of the GL implementation. You just need to make sure the tags are scaled properly with respect to the eye position and it will work efficiently.