对于体素渲染,更有效的方法是:预制的VBO或几何着色器?


26

给定一个相当静态的体素数组,效率更高:使用CPU预先生成VBO来渲染体素面(暂时忽略更高级的渲染形式,如行进立方体),或在GPU上使用几何体着色器生成脸上苍蝇?

我不是担心更新变化的体素,但是这当然是GPU版本的好处,因为您不必重建VBO。另外,GS方法感觉更现代了:)

另一方面,我还没有研究过GS如何真正与现代GPU中的栅格化管道一起工作的细节。它是将顶点输出到某种流缓存中,还是将顶点写入两者之间的普通GPU内存中?如果是后者,那么即时生成可能会减少我猜想的其余GPU任务的可用带宽和处理能力,然后在CPU上进行将更为有益。

Answers:


9

我正在考虑一个我的世界(Minecraft)类型的场景,在这里用体素表示一个实际上是使用多边形渲染的块的世界:

如果使用几何体着色器,将很难避免每个体素恰好具有三个面(或其他任何面)。

如果您有许多相邻的块具有相同的纹理,则可以使用纹理的平铺,以VBO方法在(退化的)条中使用更少的三角形。我的意思是,如果有一个很好的6x6的大平面草体素区域,则可以仅用2个三角形而不是64个三角形绘制整个顶部。

使用GS方法,您无法对相邻体素所遮挡的面进行琐碎的剔除,而这对于VBO方法而言也非常简单。

我没有尝试过GS方法,但是我可以说VBO方法与重复相邻图块的组合效果很好。我发现弄乱元素索引比仅仅重复顶点要慢得多。如果将世界分割成漂亮的小立方体,则通常每个顶点每个组件只能使用一个字节,甚至可以将纹理信息和法线打包(轴对齐的立方体上的一个面只有3个可能的法线),等等,到第四字节即可每个顶点4个字节,这是很好且快速的。

我为6个面中的每个面使用了单独的VBO-显然,您最多只需要绘制3个即可。这非常适合通常用于Minecraft样式体素顶部的不同纹理。因为对于每个集合,法线等都是统一的。

通过GL_REPEAT在水平轴的地图集中使用垂直平铺的像素图,并在同一地图集中使用像素图的90度旋转版本,我发现可以在同一调用中使用相同的VBO绘制大量明显不同的块。在6x6的草地区域示例中,我将其分成12个三角形,因为我只在地图集中的一个维度上进行重复。

我主要是在集成显卡芯片和移动设备的低端工作,而GS只是我有一天可以玩的梦想。


3
每个体素最多只需要绘制3个面,但是根据视点,每个体素可能需要绘制不同的面,所以优化不是那么容易吗?预制的VBO将包含多个体素。如果您的视点在体素之间,则将看到一个的东侧和另一个的西侧。唯一有帮助的方法是,您可以琐碎剔除实际的背面,但是最坏的情况是仍然在一组体素中渲染6个侧面中的5个。如果您的视点不在 VBO的轴向范围之内,则只需渲染3个面。
比约恩·韦森

比约恩现货,它可行。(但我会根据需要为块创建VBO,并重新考虑我在摄像机移动时所构建的内容,而不是一直将整个世界都放在VBO中;因此,我自然有时间做出这些选择)
Will

10

使用实例数组的第三种选择呢?基本上,您可以通过一次绘制调用来绘制许多框(由一个简单的8顶点的多维数据集制成),并从体素数据VBO(glVertexAttribDivisor在OpenGL中使用)确定每个实例的位置(以及其他数据)的位置(和其他数据)DX也有)。尽管应用程序代码(非着色器)应该非常相似,但是这可能比几何着色器方法要快,因为我记得几何着色器以其速度较慢而著称,尽管我仍然没有使用它们的经验(或实例化)在2.1硬件上。

但是无论如何,几何体着色器或实例化数组都应该比CPU构建的体素几何体更适合,尤其是当体素数据可能发生变化时。结合转换反馈(DX中的流输出?),您可以设置一些基于GPU的良好剔除技术。


是的,这是解决此问题的最佳方法。为什么没有发生在我身上?:)
Notabene 2011年

经过一番实验之后,我必须告诉您,烘焙的几何图形远远胜过任何实例化。我还没有尝试过几何着色器。
Jari Komppa

@JariKomppa您能详细说明烘焙几何的含义吗?
史蒂文·卢

实例已预先翻译并复制到单个网格。就像有一个代表一百个立方体的网格物体一样。
Jari Komppa '02

@JariKomppa我看到了相同的结果,但是创建网格的速度要快得多。但是,在gtx 680上,实例化选项的工作速度似乎更快,很奇怪。
Levi H

1

几何着色器版本对我来说听起来要好得多。您只能动态运行vbo点和构造框(输入点,输出三角形流)。它会更快(如果您在5 eq。DX11着色器模型中使用曲面细分单元,甚至会更快),并且会极大地减少带宽,这将是一个很好的解决方案。

关于GS。将其放在顶点着色器和像素着色器之间,并修改输出的顶点(基元)流。虽然顶点着色器仅对顶点起作用,但是几何着色器对整个图元起作用。该流的输出仅到达像素着色器(并在偏离路线之前被光栅化:)),并且无法保存它。(也许通过疯狂地渲染到纹理然后解析它……但是没有真正简单的可能性)

性能说明:您应该能够访问几何着色器中的所有内容并跳过(仅传递数据)顶点着色器。但这不是最好的方法。更好(更快)的方法是在顶点着色器上进行大多数可能的转换,并尝试最小化几何着色器程序。如果需要,不要害怕用于循环(例如,用于创建盒子)。编译器将为您展开它。


2
检查几何体和/或顶点着色器中的相邻体素,并丢弃顶点或跳过面(如果它们被遮挡)可能是一个好主意。否则,GS解决方案将增加使用的带宽。
Tamschi 2011年

从我的经验来看,Bandwith并不是什么大问题,但是当然是这样。而且您不能在GS中搜索其他原语(我知道:))。
Notabene 2011年

@Tamschi:是的,在写完这个问题之后我就出现了这个问题..对于CPU版本,固体中间的体素被抑制了,但是如果没有预通过,那么在GPU上这可能是不可能的。差异..
比约恩·韦森

1
您可以将顶点缓冲区绑定到着色器中的isamplerBuffer或usamplerBuffer制服,然后使用texture(name_of_uniform,index)进行查找。另一个选择是将缓冲区绑定到一个统一的数组,这样可以为您提供更多使用所需顶点格式的自由。
Tamschi 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.