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

大兔子大兔子 提交于 2019-12-05 02:01:37

问题


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.


回答1:


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



回答2:


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




回答3:


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.




回答4:


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


来源:https://stackoverflow.com/questions/1311869/opengl-how-to-determine-if-a-3d-rendered-point-is-occluded-by-other-3d-rende

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!