OpenGL: How to determine if a 3D (rendered) point is occluded by other 3D (rendered) primitives in front of it?

删除回忆录丶 提交于 2019-12-03 16:17:47
Ron Warholic

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

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).

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.

Reply from Ashwin Nanjappa was very helpful. I'm not an OpenGL expert, so it took me a while to find out how to get MVP matrices. I'm sharing the code here to complement his post:

    GLint viewport[4];
    GLdouble modelview[16];
    GLdouble projection[16];
    glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
    glGetDoublev( GL_PROJECTION_MATRIX, projection );
    glGetIntegerv( GL_VIEWPORT, viewport );
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!