我一直在写一个实验性的应用程序,我使用VBO渲染100块16x16x16立方体。我这样做是因为有十几个人称赞VBO超出了测量标准,并告诉我它比我在实际的Minecraft风格的游戏中使用的每块显示列表表现要好得多。
这是一个痛苦的过程,试图调整许多写得不好的教程,这些教程只关注单个立方体/三角形,可以处理我需要的绘图量。我仍然完全不相信VBO对我的游戏比显示列表更好。
在大多数情况下,我最终调整了代码,以便我的交错式VBO数据只构建一次(当块加载时),然后每个render
调用,缓冲区ID被绑定并{{1调用。
我正在慢慢增加此实验性应用中的块/块的数量,以了解性能如何处理。在实际游戏中,它必须在每个块中处理16x16x128块,最多加载20x20块。其中大约60%将是渲染的实体块,因此可能有800万块。使用我开始使用的显示列表方法渲染没有太多问题。
然而,即使我现在VBO渲染性能在可容忍的水平范围内,我也无法在不达到内存限制的情况下生成10个半径的半径:
glDrawArrays
我非常有信心我的缓冲区设置需要正确的计数。我打电话给:
Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:658)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:306)
at org.lwjgl.BufferUtils.createByteBuffer(BufferUtils.java:60)
at org.lwjgl.BufferUtils.createFloatBuffer(BufferUtils.java:110)
at com.helion3.opengl.rendering.TextureQuadRenderer.<init>(TextureQuadRenderer.java:25)
at com.helion3.opengl.shapes.Chunk.<init>(Chunk.java:13)
at com.helion3.opengl.shapes.World.<init>(World.java:18)
at com.helion3.opengl.Game.start(Game.java:90)
at com.helion3.opengl.Launcher.main(Launcher.java:19)
每个立方体使用BufferUtils.createFloatBuffer(
个浮点数(3个顶点,3个颜色,2个纹理坐标乘以6个面,每个面4个顶点)乘以192
- 块中的块数块测试。
现在在真实的游戏中,我不会渲染没有曝光的块面 - 但即使我在这个测试应用程序中这样做,我仍然只渲染16x16x16块。
如何更好地管理VBO内存?我的VBO测试app rendering code,chunk code
在哪个阶段,维也纳国际组织以每个人一直在销售它们的方式发光?洛尔
P.S。我想我现在会深入了解实例,看看它有多大帮助。
答案 0 :(得分:3)
现在在真实的游戏中,我不会渲染没有曝光的块面 - 但即使我在这个测试应用程序中这样做,我仍然只渲染16x16x16块。
那非常好。我只是提到这一点,因为首先,人们在编写Minecraft风格渲染器时犯下的一个常见错误就是尝试发送OpenGL 所有块(更糟糕的是,如果他们渲染它们全部)。相反,你应该确定哪些表面实际上是可见的,只保留在VBO中。使用空间细分结构有助于此。像世界一样的“我的世界”只是充满了八月,这可以轻而易举地存储实际的东西。 (这是针对其他人来到这个Q&amp; A)。
要记住的另一件事是,由于所有内容都呈现为多维数据集,因此您无需保留数百万个(相同的)多维数据集,只需翻译即可。如果您使用实例化,单个就足够了。
通过实例化,每个块只需要4个整数来完全描述它(3个用于位置,1个用于表面,从GL_TEXTURE_2D_ARRAY加载)。整数是优选的,因为它们的种类较小(唯一的缺点是,较旧的GPU无法有效处理它们)。假设一个立方体代表1立方米。然后一个16位整数给你一个(65536m)³的世界。对于Minecraft风格的游戏,你几乎不需要超过256种表面。所以使用8位整数来表示。然后,当你只考虑可见表面,那么块,你的很多卷不必驻留在VBO中。
这可以是真正的内存保护程序。从32位浮点数到16位整数可以节省50%的内存。使用单个8位整数作为材料索引而不是3×32位浮动颜色可以将内存需求降低到1/12。
为了进一步降低渲染负载,您可以利用世界上所有立方体都是并行的。这使得即使被处理也可以很容易地消除隐藏的表面:有8 + 6个主要方向可以看到一个立方体:8个共享一个角的3个面是可见的,6个方向只有你正在看的表面直接可见。从当前的角度来看,确定每种情况适用的世界主要平面相当容易。因此,您有14个多维数据集基本模板的变体,并在特定情况下对每个子卷进行实例化调用。八叉树再次帮助您选择哪个实例获得哪个变体。
你应该想到的另一件事是缓存一致性。您的多维数据集的数据在VBO中的排列和对齐方式以及访问它的顺序是一个大问题。通常,您希望您的数据能够很好地对齐和合并(尽管使用当前的多路径存储器架构,分离的数据布局也可以提供相当好的性能)。但是,您的访问模式不应该“遍布整个地方”,可以这么说。保持您的访问很好地分组。这是显示列表优于VBO的主要原因:内容是不变的,驱动程序可以将其内容重新排列为最佳对齐和有序的结构。你必须尝试这个。
为了让您了解当前最先进的游戏引擎所做的事情:DICE最近的一份报告指出,在即将推出的“战地4”游戏中,即使是最复杂的场景,也只会产生一个帧。 2000绘制API调用。这是一个非常低的数字。