2012-09-17 41 views
0

我想在我的OpenGL场景中跟踪被建模为高度图的世界地面上的鼠标坐标。目前没有像硬件镶嵌那样的花哨的东西。请注意,这个问题是不是对象采摘。如何在OpenGL中高效实现“点对高度图”拾取?

目前我在做这显然是因为下降一回读操作的性能如下:

  • 渲染世界(地面)
  • 在回读的深度值鼠标坐标
  • 渲染场景的其余
  • 交换缓冲区和渲染下一帧

回读介于两个渲染步骤之间,因为我需要地面的深度值,前面没有任何物体。它使用以下命令完成:

GLfloat depth; 
glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); 

我的应用程序将帧速率限制为每秒60帧。在没有回读操作的情况下渲染场景时,我的CPU使用率低于5%,但是在回读时,它会增加到75%左右,尽管我没有做太多渲染场景或更新任何游戏模型或者这样的事情。

临时解决方案是缓存鼠标下像素的深度值,并仅在每5或10帧更新一次,这会导致CPU使用率回落到10%以下。但显然不能成为问题的最佳解决方案。

如何有效地执行拾取(不是对象拾取,因为我想要表面上的(浮点)坐标)?

我已经想过读回前端缓冲区的深度值而不是后台缓冲区,但是当用谷歌搜索的方式时,我只发现人们抱怨glRead *方法最好避免。但我怎么能读东西(做采摘)没有读东西(使用glRead *)?

我很困惑。其他人如何实施采摘?


一个完全不同的方法是在软件中实现世界曲面拾取。重建从相机“进入深度”的3D射线应该没什么大不了的,它代表在目标像素处呈现的空间中的点。然后我可以实现一个交集算法来找到曲面上最前面的点。

回答

3

你通常在CPU上实现它!在高度图坐标中找到你的拾取光线,并在高度图上做一个简单的线迹。这与线画非常相似。在相交的每个单元格中,测试用于对其进行三角化的三角形。

在完成之前避免从GPU读取数据很重要。由于您通常会提前几个画图命令(GL会自动执行此操作),这意味着您也只会得到结果 - 或者在CPU停滞前暂停CPU。但是不要为了这样简单的事情而做到这一点!

+0

当这个想法第一次出现在我的脑海里时,它听起来是“错误的方式”。但是,当越来越多地了解GPU性能时,特别是考虑命令队列时,在CPU上执行操作确实听起来像是“正确的方式”。其他人确认这一点真的很有帮助。谢谢。 – leemes

+0

但是,是否有可能有效地读取当前处于GPU中的深度缓冲区,而不是当执行当前正在队列中的命令时将存在的值?如果这还不算太旧,那么使用旧的深度值也是一种解决方案。 – leemes

+0

是的,那是可能的。或者更准确地说,您可以提前安排阅读时间并检查完成时间。阅读同步和像素缓冲区对象 – ltjax