【问题标题】:OpenGL: How to determine if a 3D (rendered) point is occluded by other 3D (rendered) primitives in front of it?OpenGL:如何确定一个 3D(渲染)点是否被它前面的其他 3D(渲染)图元遮挡?
【发布时间】:2010-11-21 15:55:40
【问题描述】:

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

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

为了显示点信息(比如点标识符/编号),我使用gluProject() 将点的 3D 坐标转换为 2D 窗口坐标。我使用 glRasterPos() 和 2D 字符渲染代码在该 2D 窗口位置写入点标识符。

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

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

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

【问题讨论】:

  • 除了第二遍,你还尝试过什么?
  • Kyle:除了多遍方法,我没有想到任何其他方法。

标签: opengl occlusion


【解决方案1】:

如果您不愿意使用遮挡查询第二遍,您可以尝试对 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

【讨论】:

  • 感谢 Sid Farkus (22780)!那行得通。我用一些示例代码增强了你的答案。
【解决方案2】:

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

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

【讨论】:

  • 感谢您指出遮挡查询扩展。我无法承受几次渲染的延迟,我需要第一次渲染的正确答案,所以这不适合我。
  • 能否延迟渲染文本面板,直到遮挡查询的回复可用?
  • 遮挡查询不需要滞后,根据我的经验通常不会。您可以在检索遮挡查询结果之前调用 glFlush(),这就是我在一个应用案例中的做法,它工作正常且不影响我的应用程序(3D 游戏)的帧速率。
【解决方案3】:

进一步了解 Alan 的回答,您可以通过将光线从相机位置投射到您的点并确定它是否与您的任何几何体相交,以数学方式测试遮挡。 Internet 上有很多关于进行射线-对象相交测试的参考资料(例如,参见Object/Object Intersection Page)。如果您有很多几何体,那么您可能希望使用包围体或 BSP 树来加快速度。

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

【讨论】:

  • 感谢您提出此解决方案。这对于我只需要显示点信息的情况来说太多了。但是,这对任何进行严重遮挡测试的人都应该有用。
【解决方案4】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-21
    相关资源
    最近更新 更多