如何在 OpenGL 中将不透明对象与透明对象分开

How to separate opaque from transparent objects in OpenGL

我正在尝试在 OpenGL 中实现透明度,据我所知,有必要首先渲染所有不透明对象,然后以正确的顺序渲染透明对象。

我的问题是如何在场景图中将不透明对象与透明对象分开,以便我可以首先渲染不透明对象。我的场景图由一堆可以附加实体的节点组成,每个实体可以由多个具有不同材质的网格组成,每个网格具有一个或多个纹理。

如果我将场景加载到我的图表中,我需要知道哪些材料是部分或完全透明的,这意味着我需要检查加载的纹理是否有任何小于 1 的 alpha 值。我目前正在使用 Assimp 来处理加载 models/scenes 和 SOiL 来读取纹理,但我还没有找到任何简单的方法来将透明材料与不透明材料分开。

这可能有一个非常简单的解决方案,因为我还没有发现其他人有同样的问题,但我仍然从 OpenGL 开始,并且在过去的几个小时里我一直被困在这个问题上。

透明度通常是如何完成的?不透明对象如何与部分或完全透明的对象分开,以便它们可以先渲染?

对于大多数渲染方法,您不必严格地将不透明对象与透明对象分开。如果您考虑一下,透明度(或不透明度)是一种持续的品质。在 OpenGL 中,alpha 分量通常用于定义不透明度。不透明物体的 alpha 值为 1.0,但这只是连续光谱中的一个值。能够正确处理所有 alpha 值的方法不会因为 alpha 值恰好是 1.0 就突然失败。

换句话说:alpha 值为 0.9 的对象是不透明的吗?如果 alpha 值为 0.99,你能证明将其与 alpha 值 1.0 区别对待吗?它真的是连续的,而不是二元决定。

话虽如此,以不同方式对待不透明对象是有原因的。我能想到的主要有:

  1. 由于non-opaque对象必须对常见的简单透明渲染方法进行排序,您可以通过排序 [=43]来节省工作=] 对象。排序并不便宜,您可以通过这种方式减少处理时间。对于大多数这些方法,您可以通过对 所有 对象进行排序来获得完美的结果,但代价是效率较低。

  2. 很多时候,对象无法完美排序,或者至少做到这一点并不容易。一个明显的问题是当对象重叠时,但挑战超出了这种情况(请在此处查看我的回答以更深入地说明有问题的情况:Some questions about OpenGL transparency)。在这些情况下,您会从不正确的排序中得到伪像。通过在启用深度测试的情况下绘制不透明对象,您可以避免这些对象出现伪影的可能性,并减少明显伪影的总体发生率。

您不知道哪些对象包含透明度的情况似乎有些不寻常。在大多数情况下,您知道哪些对象是不透明的,因为您可以控制渲染和内容。因此,拥有一个指定对象是否不透明的属性通常是免费的。

如果您真的无法定义哪些对象是不透明的,可以考虑几个选项。第一个是对所有对象进行排序,并按顺序渲染它们。根据上面的解释,您可能会遇到性能或质量下降的情况,但值得一试。

有一些方法可以使用透明渲染而不需要排序或分离不透明和透明对象。想到的一个简单的是 alpha-to-coverage。特别是如果您无论如何都使用 MSAA 进行渲染,则不会产生任何开销。缺点是质量可能很一般,具体取决于场景的性质。但同样,值得一试。

你可以在我对这个问题的回答中找到alpha-to-coverage的基本解释,以及其他一些简单的透明渲染方法:OpenGL ES2 Alpha test problems.

有更高级的透明渲染方法,部分依赖于最新的硬件功能。覆盖它们超出了这里 post 的范围(并且在很大程度上超出了我的知识......),但你应该能够通过搜索 "order independent transparency".[=12 找到 material =]