遮挡查询和实例化渲染

nil*_*ils 0 opengl

我面临的问题是需要将遮挡查询与实例渲染结合使用。

据我了解,类似的东西

glBeginQuery(GL_ANY_SAMPLES_PASSED, occlusionQuery);
glDrawArraysInstanced(mode, i, j, countInstances);
glEndQuery(GL_ANY_SAMPLES_PASSED);
Run Code Online (Sandbox Code Playgroud)

只会告诉我是否绘制了任何实例。我需要知道的是,绘制了哪组实例(给我所有可见实例的 ID)。在自己的调用中绘制每个实例对我来说是没有选择的。

另一种方法是对实例进行颜色编码并手动检测可见实例。但是真的没有办法通过查询命令来解决这个问题吗?为什么不可以呢?

Nic*_*las 5

由于多种原因这是不可能的。

  1. 查询对象仅包含单个计数器值。您想要的将需要为每个实例提供单独的样本传递计数。

  2. 即使查询对象存储了样本计数数组,您也可以在查询的开始/结束范围内发出多个绘制调用。那么OpenGL如何知道哪个绘制调用的哪一部分属于数组中的哪个查询值呢?您甚至可以更改查询范围内的其他状态;统一的绑定、程序,几乎任何东西。

  3. 样本传递计数完全由 GPU 上的光栅化器硬件决定。并且光栅化器既不知道也不关心哪个实例生成了三角形。

    实例化是顶点处理和/或顶点规范阶段的函数;当光栅化器看到它时,该信息就消失了。请注意,片段着色器甚至不会获取实例 ID 作为输入,除非您通过从顶点处理阶段传递实例 ID 来显式创建实例 ID。

但是,如果您确实想这样做,您可以使用图像加载/存储及其原子操作。也就是说,将相关实例传递给片段着色器(作为int数据类型,进行flat插值)。这个FS还使用了uimageBuffer缓冲纹理,它使用的GL_R32UI格式(或者你可以使用SSBO无界数组)。然后,它imageAtomicAdd使用作为缓冲区索引传入的实例值来执行 。哦,您需要让 FS明确要求早期测试,以便片段测试失败的样本将不会执行。

然后使用计算着色器为数组中具有非零值的实例构建渲染命令列表。然后使用间接渲染调用来绘制此计算的结果。现在显然,您需要正确同步这些不同操作之间的访问。因此,您需要glMemoryBarrier在每个之间使用适当的调用。

即使查询按照您希望的方式工作,总体来说这也比使用查询对象要好得多。除非您将查询读入缓冲区对象,否则读取查询对象需要某种形式的 GPU/CPU 同步。虽然上面需要一些同步和屏障操作,但它们都是 GPU 上的操作,而不是与 CPU 同步。