OpenGL:如何确定 3D(渲染)点是否被其前面的其他 3D(渲染)图元遮挡?

发布于 2024-08-02 08:02:07 字数 817 浏览 3 评论 0原文

在我的 OpenGL 程序中,我按顺序执行以下操作:

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

为了显示点信息(例如点标识符/编号),我使用 gluProject()。我使用 glRasterPos< 在该 2D 窗口位置写入点标识符/strong>() 和 2D 字符渲染代码。

当渲染点被另一个图元遮挡时,由于 OpenGL 管道中发生的自动遮挡测试和深度测试,它会自动显示。但是,即使它被遮挡,我的点标识符文本也会显示在该点旁边,因为我没有获得此遮挡信息。

如何确定 3D(渲染)点是否被其前面的其他 3D(渲染)图元遮挡?或者是否有更好的方法在没有被遮挡时在其旁边显示点信息文本?

注意:我知道需要额外渲染通道的方法。我觉得这些对于我的目的来说是昂贵的。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

萌逼全场 2024-08-09 08:02:07

如果您不愿意使用遮挡查询第二遍,您可以尝试对 Z 缓冲区进行采样以与您的测试点进行比较。

由于您要在某个点旁边添加文本,因此请获取该点的归一化 Z 缓冲区值(例如使用 gluProject),然后将该值与该点的采样 Z 缓冲区值(使用 glReadPixels)进行比较。如果您的点落后(大于)您采样的深度值,则您的点应该被遮挡,并且您可以选择不绘制文本。

这当然要求您在文本之前渲染所有几何图形,但这不应该是问题。

示例代码:

// 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

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
难理解 2024-08-09 08:02:07

在现代硬件上,从 z 缓冲区读取数据可能非常慢。这就是遮挡查询被发明的原因。查找 ARB-occlusion-query 扩展。在您获得结果之前,它会有几帧的延迟,但这不会影响您的性能。

如果遮挡查询由于某种原因不起作用,下一个后备选项是使用 BSP 树(根本不使用 GL)执行软件光线相交世界操作。

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

病女 2024-08-09 08:02:07

除了艾伦的回答之外,您可以通过将光线从相机位置投影到您的点,并确定它是否与您的任何几何体相交,以数学方式测试遮挡。互联网上有很多关于进行光线对象相交测试的参考(例如,参见 Object/对象相交页面)。如果您有大量几何图形,那么您可能希望使用包围体或 BSP 树来加快速度。

作为奖励,您的遮挡代码应该更容易进行单元测试,因为它不依赖于从 OpenGL 中提取值。

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.

旧夏天 2024-08-09 08:02:07

Ashwin Nanjappa 的回复非常有帮助。我不是 OpenGL 专家,所以我花了一段时间才找到如何获得 MVP 矩阵。我在这里分享代码来补充他的帖子:

    GLint viewport[4];
    GLdouble modelview[16];
    GLdouble projection[16];
    glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
    glGetDoublev( GL_PROJECTION_MATRIX, projection );
    glGetIntegerv( GL_VIEWPORT, viewport );

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 );
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文