views:

693

answers:

3

In my OpenGL program, I am doing the following in sequence:

// Drawing filled polyhedrons
// Drawing points using GL_POINTS
// Displaying information for each above point beside it

For displaying the point information (say a point identifier/number), I convert the 3D coordinates of the point to 2D window coordinates using gluProject(). I write the point identifier at that 2D window location using glRasterPos() and 2D character rendering code.

When a rendered point is occluded by another primitive, it is automatically not displayed due to automatic occlusion test and depth test that happens in the OpenGL pipeline. However, my point identifier text is displayed beside the point, even when it is occluded since I do not get this occlusion information.

How to determine if a 3D (rendered) point is occluded by other 3D (rendered) primitives in front of it? Or is there a better way to display the point information text beside it only when it is not occluded?

Note: I am aware of the methods that require an extra rendering pass. I feel that those are expensive for my purpose.

+3  A: 

If you're not willing to use an occlusion query second pass you can try sampling the Z-buffer to compare against your test point.

Since you are adding text next to a point, grab the normalized Z buffer value (say using gluProject) of the point, then compare that value to the sampled Z-buffer (using glReadPixels) value at that point. If your point is behind (greater than) the depth value you sampled, your point should be occluded and you can choose not to draw the text.

This of course requires that you render all your geometry before the text, but that shouldn't be an issue.

Sample code:

// Assumed to already hold 3D coordinates of point
GLdouble point3DX, point3DY, point3DZ;

// Project 3D point coordinates to 2D
GLdouble point2DX, point2DY, point2DZ;  // 2D coordinates of point
gluProject( point3DX, point3DY, point3DZ,
            mMatrix, pMatrix, vMatrix,      // MVP matrices
            &point2DX, &point2DY, &point2DZ);

// Read depth buffer at 2D coordinates obtained from above
GLfloat bufDepth = 0.0;
glReadPixels(   static_cast<GLint>( point2DX ), static_cast<GLint>( point2DY ),     // Cast 2D coordinates to GLint
                1, 1,                                                               // Reading one pixel
                GL_DEPTH_COMPONENT, GL_FLOAT,
                &bufDepth);

// Compare depth from buffer to 2D coordinate "depth"
GLdouble EPSILON = 0.0001;  // Define your own epsilon
if (fabs(bufDepth - point2DZ) < EPSILON)
    // 3D point is not occluded
else
    // 3D point is occluded by something
Ron Warholic
Thanks Sid Farkus (22780)! That worked. I have enhanced your answer with some sample code.
Ashwin
+2  A: 

Reading from the z-buffer can be very very slow on modern hardware. That's why occlusion query was invented. Look up the ARB-occlusion-query extension. It has a couple of frames of lag before you can get the results, but it won't hit your performance.

If occlusion query isn't going to work for whatever reason, the next fallback option is to do a software ray-intersect-world operation using a BSP-tree (which doesn't use GL at all).

Alan
Thanks for pointing out the occlusion query extension. I cannot afford the lag of a few renders, I need the correct answer from the first render, so this is not suitable for me.
Ashwin
Could you delay rendering the text panels until the reply from the occlusion query was available?
Alan
Occlusion query doesn't need to lag and to my experience usually doesn't. You can call glFlush() before retrieving occlusion query results, that's how I do it in one application case, and it works fine and w/o affecting frame rates of my app (3D game).
karx11erx
+2  A: 

Further to Alan's answer, you could test for occlusion mathematically by projecting a ray from your camera position to your point, and determining whether it intersects any of your geometry. There are plenty of references on the Internet for doing ray-object intersection testing (see, for example, the Object/Object Intersection Page). If you have lots of geometry then you might want to speed things up using bounding volumes or a BSP tree.

As a bonus, your occlusion code should be a lot easier to unit test, because it doesn't rely on extracting values from OpenGL.

Incredulous Monk
Thanks for suggesting this solution. This is too much for my case where I just need to display point information. But, this should be useful for anyone doing some serious occlusion testing.
Ashwin