是否可以在间接绘图调用中清除模板缓冲区?

Posted

技术标签:

【中文标题】是否可以在间接绘图调用中清除模板缓冲区?【英文标题】:Is it possible to clear stencil buffer within indirect draw call? 【发布时间】:2021-02-24 16:33:13 【问题描述】:

我想实现模板阴影,而不必在 CPU 端使用单个灯光(记录缓冲区,为每个灯光交替管道) - 我想一次性完成所有灯光。我认为使用计算着色器是可能的;但是我无法从他们那里访问 ROP,虽然应该可以使用原子,但感觉不对(将 R32UINT 图像转换为 B8G8R8A8UNORMvkGetPhysicalDeviceSurfaceFormatsKHR 可能输出的任何内容)。不得不对影子卷进行软件光栅化也感觉不对。简单地使用模板,并在绘制阴影体积时输出 0 颜色,然后做一个四边形的实际光很好,但是我看不到任何方法可以在两次绘制之间清除它。我也考虑过使用混合和 alpha 值,但我能想到的唯一方法需要特殊的钳位行为:不是钳位混合输入,而是钳位输出。据我所知,在同一个绘图调用中,不可能从帧缓冲区中读取像素。

【问题讨论】:

如何将多个灯放在一个模板缓冲区中?我对模板阴影算法的理解是正面增加模板值,背面减少它。这似乎排除了在单个模板缓冲区中拥有多个阴影投射灯。如果你不能在一个模板缓冲区中有多个灯,那么你剩下的问题就是诡辩了。 我打算一个一个地绘制灯光:用一个draw填充模板缓冲区,在第二次绘制时从同一个draw inderect命令绘制一个灯光四边形,以某种方式清除它,然后继续。但是,如果不“退出”drawIndirect 并切换管道,我看不到这样做的方法。我使用 alpha 的方法是填充 alpha 缓冲区,通过将其相乘来“验证”它,以便任何非 0 变为 1(使用双 src 混合),并在光照绘制时将其归零。然而,这些值在混合之前被钳制...... 【参考方案1】:

我打算一个一个地绘制灯光:用一个draw填充模板缓冲区,在第二次绘制时从同一个draw inderect命令绘制一个灯光四边形,以某种方式清除它,然后继续。

在“以某种方式清除它”部分之前你有一个问题。即,绘制“光四边形”需要将模板参数从写入模板值更改为测试它们。这当然不能在绘图命令中执行。

虽然将几何图形捆绑到几个绘制命令中总是好的,但重要的是要记住 Vulkan 不是 OpenGL。状态更改不是免费的,完整的管道更改也不是非常便宜,但它们不像在 OpenGL 下那样昂贵。因此,您不必为不得不以这种方式中断绘图命令而感到难过。

【讨论】:

据我所知,可以同时启用测试和编写模板;并且因为照明通常使用加法混合,所以在填充模板时,我们可以简单地输出 0 以不改变任何内容并在之后计算实际颜色;我们还可以为通过模板测试和失败指定模板操作,所以我认为这里不需要更改模板状态。我想快速清除模板(没有 255 个屏幕四边形)是不可能的。哦,我尝试捆绑的原因是我个人面临的挑战是将尽可能多的工作转移到 gpu 上 - 剔除等。【参考方案2】:

无法在绘图命令中清除模板缓冲区;但是,我能够通过特殊的模板状态、后期深度模板测试、discard 以及着色器中的一些额外工作来实现所需的结果,但代价是做这些事情和灵活性。

在我的情况下它是如何工作的(深度失败阴影):

    为了区分通行证,我使用GL_ARB_shader_draw_parameters 代替gl_DrawID,但应该可以通过其他方式实现 暗影传球:
      在片段着色器中,如果要传递深度,则丢弃 // 因此,从未完成任何颜色写入 在模板状态下,正面失败(深度和模板)-> 递增;背面失败->递减; // 计算数量
    光通道:
      如果光三角形是背面,则输出零;模板状态,背面通过 -> 替换为参考; // 有模板被清除 否则,计算颜色;模板状态,正面通过 -> 无关紧要。

【讨论】:

以上是关于是否可以在间接绘图调用中清除模板缓冲区?的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL:清除模板缓冲区,除了某些位?

问绘图缓冲区的模板缓冲区会增加性能成本(WebGL)吗?

WebGL:在带有深度模板纹理附件的帧缓冲区上未清除颜色

webgl 绘图顺序,模板缓冲区

在仅触及深度缓冲区的openGL中进行绘图调用

使用缓冲区的 Windows AlphaBlend