OpenGL中的像素间隙来自哪里?

Posted

技术标签:

【中文标题】OpenGL中的像素间隙来自哪里?【英文标题】:Where do pixel gaps come from in OpenGL? 【发布时间】:2016-10-10 12:12:30 【问题描述】:

我遇到的问题是,我渲染的场景中有一些像素 似乎丢失/不可见,因此与我的透明颜色相同 颜色。有趣的是,只有在关闭 MSAA 时才会发生这种情况。

我的第一个想法是,这可能与以下事实有关,即所有三角形都重叠并以某种方式被投影矩阵扭曲,但这些伪影似乎只出现在线条上而不是边缘上。

我在另一个问题中读到了仅将 1.00001 的比例应用于所有内容,但这对我来说似乎是一种廉价的黑客攻击,可能会导致其他问题。虽然使用硬件多重采样时这些伪影似乎减少了,但我想知道是否有其他方法可以解决这个问题。

编辑:

Nicol Bolas 解决这个问题的方法:

OpenGL(和所有其他硬件光栅化器)仅在边缘完全匹配的情况下保证两个三角形之间的边缘的无间隙渲染。这意味着你不能只让一个三角形紧挨着另一个三角形。两个三角形的共享边上的顶点必须相同。

所以如果你在一个短三角形旁边有一个长三角形,你要做的就是把长三角形分成几个三角形,这样边的共享部分就可以在两个三角形之间正确共享。

如上所述,一种可能的解决方案是将大三角形分割成小三角形,以确保所有重叠的顶点相同(即取消贪婪网格)。但就我而言,由于性能方面的原因,我想保持贪婪的网格。

【问题讨论】:

16 位浮点数 - 讨厌他们 作为低精度机器,您真的不希望您的几何图形边对边放置(正如您在实践中或 CAD 绘图中所希望的那样),因为近似错误最终会表现为图形伪影。通常情况下,你会有一个平面用于地板,它会稍微进入墙壁等等。 您有 T 形路口。这是***.com/questions/18523231/… 的完全相同的副本——因为有人重新打开了它(为什么?) 链接问题的答案不是我想要的。那里的问题似乎与应用的着色器有关,但与几何本身无关。 @DieEidechse12:你错了。仔细阅读:OP 认为它与他的片段着色器有关,但实际上建议的解决方案是调整顶点着色器中的几何图形以隐藏工件。这样你就不需要废除贪婪的网格——不像尼科尔建议的那样。 【参考方案1】:

OpenGL(和所有其他硬件光栅化器)仅在边缘完全匹配的情况下保证两个三角形之间的边缘的无间隙渲染。这意味着你不能只让一个三角形紧挨着另一个三角形。两个三角形的共享边上的顶点必须相同。

所以如果你在一个短三角形旁边有一个长三角形,你要做的就是把长三角形分成几个三角形,这样边的共享部分就可以在两个三角形之间正确共享。

由于您似乎在构建一个由立方体组成的世界,这对您来说应该相当容易。

您必须做的另一件事是确保两个三角形之间的两个共享顶点二进制相同。顶点着色器的gl_Position 输出必须是完全相同的值。因此,如果您在 VS 中计算立方体顶点的位置,则需要以一种能保证二进制结果相同的方式进行。

但就我而言,由于性能方面的原因,我想保持贪婪的网格。

然后你需要决定哪个更重要:性能,或正确性。因为没有办法强制光栅化器允许这样的边缘是无间隙的。这是浮点精度等问题,在不同的硬件上总是不同的。

【讨论】:

禁用我的贪婪网格修复它(正如你建议将大三角形分成小三角形),但这不是我想要解决的方法。我编辑了我的问题,有没有另一种方法不放弃顶点合并? @DieEidechse12:已编辑。 谢谢。你知道现代游戏引擎是如何解决这个问题的吗? @DieEidechse12:大多数游戏引擎渲染由游戏制造商构建的网格。如果这些网格没有正确连接,那么垃圾进,垃圾出。由创建网格的人来确保它们正常工作。【参考方案2】:

这叫做“缝合”。光栅化器与三角形不完全匹配,并且缺少一些像素。其他人已经解释了如何设置三角形,以便 OpenGL 知道它们共享和边缘。然而,随着您的模型构建逻辑变得越来越复杂,有时拼接很难避免。解决方法是清除为黑色或深灰色,然后缝线几乎看不见。

【讨论】:

【参考方案3】:

这是由于存在两个多边形接触边缘的问题,但存在一些小错误。 (很可能是用于估计边缘的浮点单元中的舍入误差)理论上它们也应该有重叠边缘的时候,但这不会那么明显。设置一个非常小的放大系数,或者只是将多边形本身向彼此移动一小部分应该可以解决它。它仅在 MSAA 关闭时发生的原因通常有助于防止此类问题。 (这是因为它以更高的分辨率运行所有计算,但随后将所有内容缩小到较低的分辨率,因此不会那么明显。问题实际上仍然存在,但由于缩小,丢失的像素会当它们混合到周围的像素中时消失。)

【讨论】:

以上是关于OpenGL中的像素间隙来自哪里?的主要内容,如果未能解决你的问题,请参考以下文章

OSX 上的 AVFoundation:来自视频的 OpenGL 纹理,无需访问像素数据

如何在OpenGL中将像素作为纹理绘制到多边形?

opengl 动态贝塞尔曲线有间隙 - glEvalCoord1f();

OpenGL 像素在内存中的排列方式

OpenGL 3.x / 4x 中的纹素/像素匹配

为现代 opengl 创建立体环境