当屏幕上有大约12000个立方体时,它的帧率降至不到20fps - 糟糕透了。
到目前为止,我所做的优化包括:视锥剔除、背面剔除(通过OpenGL的glEnable(GL_CULL_FACE)实现)、引擎仅绘制可见面(当然除了被剔除的面)并将它们放在八叉树中。
我尝试过VBO,但我不喜欢它们,而且它们并没有显著提高fps。
Minecraft的引擎怎么能跑得这么快...我在处理10000个立方体时都很吃力,而Minecraft可以轻松地以更高的fps绘制更多的立方体。
有什么想法吗?
@genpfault: 我分析了连接性并仅为外部可见表面生成面。 VBO有一个单一的立方体,我使用glTranslate()进行了平移。
我不是OpenGL专家,但据我所知,这样做节省的时间很少,因为您仍然需要将每个立方体发送到显卡。
相反,您应该为所有外部可见表面生成面,将其放入VBO中,并将其发送到显卡,直到几何形状发生变化为止,继续渲染该VBO。这样可以节省您的显卡实际上等待处理器发送几何信息的时间。
我不知道在这里是否可以“顶”一个旧问题,但有几个问题出现在我的脑海中:
如果您的体素是静态的,则可以通过使用八叉树进行视锥体裁剪等操作来加速整个渲染过程。此外,还可以将静态场景编译为八叉树中的潜在可见集。 PVS的主要原则是针对树中的每个节点预先计算哪些其他节点是潜在可见的,并在向量中存储指向它们的指针。在进行渲染时,您首先检查摄像机放置在哪个节点中,然后针对该节点的PVS向量中的所有节点运行视锥体裁剪。(Carmack在Quake引擎中使用了类似的方法,但是使用了二进制空间分割树)
如果您的体素着色方式比较复杂,则还可以执行预深度通道(Pre-Depth-Only-Pass),而无需写入颜色缓冲区,只需填充深度缓冲区。之后,您进行第二次传递:禁用对深度缓冲区的写入,并仅对颜色缓冲区进行渲染,同时检查深度缓冲区。因此,您避免了昂贵的着色器计算,这些计算稍后被更靠近观察者的新片段覆盖。(Carmack在Quake3中使用了这个技术)
另一个肯定会加速事情的方法是使用实例化。您仅将每个体素的位置以及必要时其比例和其他参数存储到纹理缓冲区对象中。在顶点着色器中,您可以读取要生成的体素的位置并创建体素的实例(即通过顶点缓冲区对象提供给着色器的立方体)。因此,您只需要一次发送8个顶点+ 8个法线(3 * sizeof(float) * 8 + 3 * sizeof(float) * 8 +浮点数用于颜色/纹理等...)到VBO中,然后只需在TBO中发送立方体的实例位置(3*sizeof(float)*体素数量)。
也许可以通过将所有3个步骤结合在2个线程间并行化GPU和CPU之间的处理,例如,在CPU线程中,您可以检查八叉树PVS并更新TBO以便在下一帧进行实例化,而GPU线程则同时执行两个传递,同时使用由CPU线程在上一步骤中创建的TBO进行实例化。之后,切换TBO。如果摄像机没有移动,则甚至无需重新进行CPU计算。
您可能还对一种称为k-d-tree的树感兴趣,它比八叉树更通用。
PS:抱歉我的英语不是很清晰...
有第三方库可以用来使渲染更加高效。例如,C++ PolyVox library 可以以高效的方式获取体积并为您生成网格。它具有内置方法来减少三角形数量,并帮助生成环境光遮蔽等内容。它拥有良好的社区支持,因此在论坛上获取支持应该很容易。