仅使用模板测试的遮挡查询
Posted
技术标签:
【中文标题】仅使用模板测试的遮挡查询【英文标题】:Occlusion queries with stencil test only 【发布时间】:2014-10-16 17:40:21 【问题描述】:如果事先知道障碍物集严格位于相机和要测试的对象之间,如果我完全禁用深度测试,遮挡查询是否仍然有效? 这是一种提高性能的尝试,因为从逻辑上讲,如果没有遮挡物位于被遮挡物后面,我不需要复杂的 z 测试。
我正在使用以下命令来初始化颜色/深度/模板缓冲区:
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 0);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 0);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 0);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1);
...
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glEnable(GL_STENCIL_TEST);
glStencilMask(0x00000001);
...
glClear(GL_STENCIL_BUFFER_BIT);
【问题讨论】:
为什么不试试看呢? 遮挡查询只计算通过深度测试的样本;模板缓冲区无关紧要。 opengl.org/wiki/Occlusion_Query#Occlusion_queries @ColonelThirtyTwo 我不小心发布了之前的评论。将在几秒钟内重写它。 @ColonelThirtyTwo 因为我不知道 Opengl 是如何处理这种情况的。它可能有效,可能无效,有时可能有效......而且谷歌并没有告诉我“嘿,你不能使用禁用深度测试的查询”,所以我最好在互联网上询问人们。 我发现这个页面指出:“它返回通过深度和模板测试的样本数量作为结果”。 opengl.org/registry/specs/ARB/occlusion_query.txt 在该页面的多个场合中,看起来模板和深度都在合作计算结果。 【参考方案1】:最具决定性的文档是最新的 OpenGL 规范。来自 OpenGL 4.5 规范,第 476 页的“17.3.7 遮挡查询”部分(重点由我添加):
遮挡查询使用查询对象来跟踪通过深度测试的片段或样本的数量。
当遮挡查询处于活动状态时,每个通过深度测试的片段的通过样本计数都会增加。
因此,真正的问题变成了:“通过深度测试”是什么意思?如果没有深度测试,像素是否通过深度测试?模板测试是如何发挥作用的?
关键是模板测试在深度测试之前应用,这是规范中定义的行为。所以只有通过模板测试的片段才会通过深度测试,因此会被计入遮挡查询。或者换句话说,只有通过同时模板和深度测试的片段才会被计算在内。
一种绝对可行的方法是启用深度测试,并让所有片段通过深度测试。这将计算所有通过模板测试的片段。用于此的设置是:
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
glEnable(GL_STENCIL_TEST);
...
现在,在没有深度缓冲区或禁用深度缓冲区的情况下,它是否也能正常工作?第一部分在“17.3.6 深度缓冲测试”小节末尾回答:
如果没有深度缓冲,就好像深度缓冲测试总是通过。
在这种情况下,答案是肯定的,您可以使用没有深度缓冲区的遮挡查询,它会计算通过模板测试的片段。
第二种情况在前面的“17.3.6 深度缓冲测试”一节中有介绍:
禁用时,将绕过深度比较和随后可能更新的深度缓冲区值,片段被传递到下一个操作。
规范中的图 17.1 显示“遮挡查询”作为“深度缓冲测试”之后的下一个操作。因此,如果深度测试被禁用,所有通过早期测试的片段(包括模板)都将被遮挡查询计算在内。
最后的答案是:是的,您可以通过模板测试使用遮挡查询。
致谢:根据@jozxyqk 和@user2464424 的反馈修改最新版本
【讨论】:
我喜欢你的直通深度测试解决方案,只是为了让文档满意:p 我认为它会起作用。唯一的考虑,正如jozxyqk所说:“关闭深度测试,我假设所有片段都通过了”这在平均对象显示场景中是正确的(我在我的系统中尝试过,三角形仍然被渲染,但是在随机z-命令)。这完全取决于遮挡查询的编码方式。他们是否将禁用的深度缓冲区视为等效的 glDepthFunc(GL_ALWAYS)?它依赖于制造商吗?人类永远不会知道。那我去测试一下。 @user2464424 我的假设是在深度测试之后将计数器插入到渲染管道中。无论是否启用了深度测试或计数器之前的任何先前测试,如果在管道的深度测试部分之后片段仍然存在,它就会被计算在内。或许these pipeline diagrams 可以提供更好的图片。 @jozxyqk 经过更多的思考和挖掘,这听起来完全正确。而且我相信我找到了所有规范语言来支持这确实是行为。请参阅上面答案的彻底修订版。 @RetoKoradi 做得很好。现在我接受你的回答,但我还没有进行现场测试,如果出现问题会报告。 @RetoKoradi 是的,它确实有效。仅仅为了显示和调试该模板而拆除我的一半代码是一场噩梦,但最终它奏效了。为了科学。【参考方案2】:来自www.opengl.org/registry/specs/ARB/occlusion_query.txt
此扩展解决了这两个 [HP_occlusion_test] 问题。它作为它的返回 结果通过深度和模板测试的样本数
...
我们在管道的哪个阶段对样本进行计数?
已解决:我们在 深度和 模板测试,即通过两者的样本。注意深度 测试在模板测试之后,所以说它是 通过深度测试的人数就足够了;虽然它经常 在概念上有助于将深度和模板测试视为 被合并,因为深度测试的结果会影响 使用的模板操作。
来自www.opengl.org/registry/specs/ARB/occlusion_query2.txt
这个扩展简单地添加了一个布尔遮挡查询到
ARB_occlusion_query
关闭深度测试后,我假设所有片段都通过了。 从上面看来,您可以仅依靠模板测试来影响遮挡查询结果,这与opengl.org/wiki 的以下内容不一致。
模板测试、alpha 测试或片段着色器丢弃与查询无关
扩展名没有提到discard
。 GL 4.5 core/compat 规范中的遮挡查询部分仅提及通过深度测试的计数片段。 如果片段没有通过深度测试,那么我猜它不被认为是通过它。
有点旁注,但我认为early fragment test 也值得一提。
【讨论】:
以上是关于仅使用模板测试的遮挡查询的主要内容,如果未能解决你的问题,请参考以下文章
原创 我的OpenGL学习进阶之旅介绍一下OpenGL ES的 遮挡查询
原创 我的OpenGL学习进阶之旅介绍一下OpenGL ES的 遮挡查询