OpenGL:深度计算不连续

4
我正在使用OpenGL构建一款LIDAR模拟器。这意味着片段着色器返回光矢量的长度(距离)代替其中一个颜色通道,通过远平面到距离的归一化来实现(因此它将介于0和1之间)。换句话说,我使用红色指示光强度,蓝色指示距离;并将绿色设置为0。Alpha未使用,但我将其保留为1。
这是我的测试对象,恰好是一块岩石:

enter image description here

然后我将像素数据写入文件并加载到点云可视化器中(每个像素一个点)-基本上是默认设置。这样做之后,很明显我的所有点都位于不同深度的离散平面上:

Point cloud visualization

我尝试在R中绘制相同的数据。由于飞机密度相当高,因此默认直方图一开始不会显示出来。但是当我将断点设置为大约60时,我得到了这个结果:

Density plot of distances (about 60 breaks).

我尝试缩小近和远平面之间的距离,以防它是精度问题。起初我使用的是1-1000,现在我使用的是1-500。它可能已经减少了平面之间的距离,但我无法确定,因为这意味着相机必须更靠近物体。
我是否漏掉了什么?这是否与我禁用抗锯齿有关?(抗锯齿会导致更严重的周期性伪影,但出现在相机和物体之间。我禁用了线条平滑、多边形平滑和多重采样,解决了这个特定的问题。)
编辑
这是计算距离的两个地方:
  • 顶点着色器计算ec_pos,即相对于摄像机的顶点位置。
  • 片元着色器ec_pos和相机位置计算出light_dir0并用其计算距离。

是因为我在顶点着色器中计算了ec_pos吗?如何在片元着色器中计算ec_pos


你尝试过使用浮点深度缓冲区(默认情况下为定点数)吗?通常情况下除了一些特殊应用程序外,这样做并没有太多好处,但是在这种情况下似乎有好处。获取一个可能会有点困难,使用FBO很容易获得,但是如果使用默认的帧缓冲区,则必须查看平台的窗口系统API。我猜这种情况下使用的是CGL或NSOpenGL,因为它在OS X上运行? - Andon M. Coleman
我也不得不想知道你是如何获取这些距离值的?你是否真正关心的是深度缓冲区中存储的值,还是你计算出来的其中一个颜色分量?颜色缓冲区通常是每个组件8位定点。如果你试图将深度值塞入其中,它会表现出奇怪的事情,因为你已经放弃了至少8位的精度(假设16位深度缓冲区)。 - Andon M. Coleman
@KromStern,您能否澄清一下您的评论?我不明白您在暗示什么。 - Translunar
你是否考虑到蓝色值在0..255范围内是离散的?我很难理解你的精确计算公式,能否请您添加一下? - Kromster
是的。代码直接链接在上面。 - Translunar
显示剩余4条评论
1个回答

4
我可以想到几个可能的问题。
(1) 精度问题。远平面对分辨率影响很小,近平面很重要。请参见Learning to Love your Z-Buffer
(2) 根据您提供的信息,更有可能的解释是像素数据的转换/保存。着色器输出浮点值,但这些值存储在帧缓冲区中,通常每个通道只有8位。对于颜色而言,这意味着您的浮点数将映射到底层的8位(固定宽度的整数)表示形式,因此仅具有256个值。
如果您希望将像素数据输出为实际的浮点数,请创建一个32位浮点RGBA FBO(例如使用GL_RGBA32F或类似物)。这将存储实际的浮点数。然后,从GPU返回您的数据时,它将返回原始着色器值。
我想,如果您没有FBO实现,则可以通过一些乘法在vec4中编码单个float

你能详细解释一下如何在GLSL 120中创建这样的FBO吗?或者提供一个链接?=)谢谢。 - Translunar
FBO(帧缓冲对象)是_OpenGL_的一个特性,与GLSL无关。如果您不熟悉FBO,则这是非微不足道的OpenGL代码 - 超出了快速答案的范围。有很多在线示例。冒着自夸的风险,我的各个项目都包含一个FBO类(例如http://geometrian.com/programming/projects/index.php?project=Game%20of%20Life,用Python编写,我认为可能支持浮点渲染缓冲区)。 - geometrian
我只是想要一个例子。有很多FBO函数,我还没有弄清楚是否需要在每个渲染周期生成和绑定一个,还是只需要在设置期间进行一次即可。 - Translunar
这就是关键所在;简单的例子实际上并不存在。你应该通过谷歌搜索来找到好的用法。我上面提到的项目就是一个这样的例子。 - geometrian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接