C++ C++;,OpenGL Z缓冲区预处理

C++ C++;,OpenGL Z缓冲区预处理,c++,opengl,occlusion-culling,C++,Opengl,Occlusion Culling,我正在制作一个简单的体素引擎(想想Minecraft),目前我正处于去除遮挡人脸以获得一些珍贵fps的阶段。我对OpenGL不太熟悉,也不太了解glColorMask魔术是如何工作的 这就是我所拥有的: // new and shiny glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // this one goes without saying glEnable(GL_DEPTH_TEST); // I want to see my

我正在制作一个简单的体素引擎(想想Minecraft),目前我正处于去除遮挡人脸以获得一些珍贵fps的阶段。我对OpenGL不太熟悉,也不太了解glColorMask魔术是如何工作的

这就是我所拥有的:

// new and shiny
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// this one goes without saying
glEnable(GL_DEPTH_TEST);

// I want to see my code working, so fill the mask
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

// fill the z-buffer, or whatever
glDepthFunc(GL_LESS);
glColorMask(0,0,0,0);
glDepthMask(GL_TRUE);

// do a first draw pass
world_display();

// now only show lines, so I can see the occluded lines do not display
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

// I guess the error is somewhere here
glDepthFunc(GL_LEQUAL);
glColorMask(1,1,1,1);
glDepthMask(GL_FALSE);

// do a second draw pass for the real rendering
world_display();

这在某种程度上是可行的,但一旦我改变相机位置,世界开始褪色,我看到的线条越来越少,直到什么都看不到。

glColorMask和glDepthMask确定帧缓冲区的哪些部分实际上被写入

早期Z消隐的思想是,首先只渲染深度缓冲区部分——实际的节省来自于从近到远对几何体进行排序,以便GPU可以快速丢弃被遮挡的片段。但是,在绘制Z缓冲区时,您不希望绘制颜色组件:这允许您切换着色器、纹理,即简言之,所有计算密集的内容

警告一句:早期Z仅适用于不透明几何体。实际上,整个深度缓冲算法只适用于不透明的东西。一旦进行混合,就必须从远到近进行排序,并且不使用深度缓冲(搜索“顺序无关透明”算法以克服相关问题)

如果你有混合过的东西,把它从“早期Z”阶段移除

你在第一次传球时

glDepthMask(1); // enable depth buffer writes
glColorMask(0,0,0); // disable color buffer writes
glDepthFunc(GL_LESS); // use normal depth oder testing
glEnable(GL_DEPTH_TEST); // and we want to perform depth tests
完成Z传递后,您可以稍微更改设置

glDepthMask(0); // don't write to the depth buffer
glColorMask(1,1,1); // now set the color component

glDepthFunc(GL_EQUAL); // only draw if the depth of the incoming fragment
                       // matches the depth already in the depth buffer
GL_LEQUAL也完成了这项工作,但也让片段比深度缓冲区中的片段更接近。但由于深度缓冲区没有更新,所以每次在原点和存储的深度之间绘制内容时,原点和存储的深度之间的任何内容都将覆盖深度缓冲区

该主题的一个细微变化是使用“早期Z”填充深度缓冲区作为多个延迟着色过程中的几何缓冲区


要保存进一步的几何图形,请查看遮挡查询。使用遮挡查询,您会询问GPU有多少个片段通过了所有测试。这是一个体素引擎,你可能正在使用八叉树或Kd树。在遍历分支之前,绘制树分支的空间分割面(使用glDepthMask(0)、GLCOLORSMASK(0,0,0)),可以告诉您该分支中的任何几何体是否可见。再加上从近到远的排序遍历和树上的(粗略的)截头体剪裁,将给您带来巨大的性能优势。

听起来好像您没有清除深度缓冲区


尝试使用
glClear
清除深度缓冲区时,需要启用深度写入(通过
glDepthMask(GL_TRUE);
)。您可能仍然从上一帧禁用了它,导致所有的清除在子序列帧中都是无操作的。只需移动
glDepthMask
调用,然后
glClear

z-pre过程就可以处理半透明对象。如果它们是半透明的,请不要在预过程中渲染它们,然后Z排序并渲染。

RE:precious FPS,
world\u display()
是否已使用顶点数组(VAs)或顶点缓冲区对象(VBO)提交几何体?+1用于@genpfault。顺便说一句,你能发布一些你的案例的截图吗?除非我遗漏了一些明显的东西,否则错误可能在其他地方——上面的代码在我看来还行。非常好的评论!但是OP的代码似乎与您对early-z的描述一致。world_display()可能会做一些不幸的事情,例如使用混合,可能会改变某些状态等等。在“早期Z”的工作原理中,您需要三个单独的渲染路径:一个仅用于深度过程、不透明过程,最后用于所有半透明的对象。哦,这可能就是原因,很好的捕捉。看看孩子们:这就是为什么你总是在一个操作之前设置所有OpenGL状态的原因。我现在觉得自己很愚蠢。不幸的是,它将我的fps减半而不是翻倍,该死!对Z预过程仅在填充率绑定时有效(并且如果您有非常昂贵的每像素操作),而不是顶点绑定。