gpt4 book ai didi

java - 提高使用 VBO 时所需的内存

转载 作者:行者123 更新时间:2023-12-01 23:22:34 24 4
gpt4 key购买 nike

我一直在编写一个实验性应用程序,其中使用 VBO 渲染 100 个 16x16x16 立方体 block 。我这样做是因为有十几个人对 VBO 赞不绝口,并告诉我它的性能比我在实际的 Minecraft 风格游戏中使用的按 block 显示列表要好得多。

这是一个痛苦的过程,试图将许多只关注单个立方体/三角形的写得不好的教程改编成可以处理我需要的绘图量的东西。我仍然不相信 VBO 比显示列表更适合我的游戏。

在很大程度上,我最终调整了代码,以便我的交错 VBO 数据仅构建一次(当 block 加载时),然后每次 render 调用,缓冲区 ID 被绑定(bind)并调用 glDrawArrays

我正在慢慢增加这个实验性应用程序中的 block / block 的数量,以了解性能如何处理。在实际游戏中,它必须处理每个 block 中的 16x16x128 个 block ,最多加载 20x20 个 block 。其中大约 60% 将是渲染的实心 block ,因此可能有 800 万个 block 。使用我开始使用的显示列表方法,渲染没有太多问题。

但是,即使我现在的 VBO 渲染性能在可容忍的水平内,我也无法在不达到内存限制的情况下生成 10 个 block 的半径:

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( 使用 192 每个立方体的 float (3 个顶点、3 个颜色、2 个纹理坐标乘以 6 个面,每个面 4 个顶点)乘以 4096 - block 测试中的 block 数。

现在在真正的游戏中,我不会渲染未暴露在空气中的 block 面 - 但即使我在这个测试应用程序中这样做,我仍然只渲染 16x16x16 block 。

如何更好地管理 VBO 内存?我的VBO测试app rendering code , chunk code

VBO 在什么时候会像大家所宣传的那样大放异彩?哈哈

附注我想我现在会深入实例化,看看这有什么帮助。

最佳答案

Now in the real game, I'm not rendering the block faces that aren't exposed to air - but even if I do that in this test application, I'm still only rendering 16x16x16 blocks.

这非常好。我只是提到这一点,因为首先也是最重要的,人们在编写 Minecraft 风格渲染器时常犯的一个错误是尝试发送 OpenGL 所有 block (如果他们渲染所有 block ,情况会更糟) )。相反,您应该确定哪些表面实际上可见,并且只将它们保留在 VBO 中。使用空间分割结构对此有所帮助。类似《我的世界》的世界充满了八叉树,它可以轻松存储实际的东西。 (这是供其他人在这里遇到此问答的)。

<小时/>

要记住的另一件事是,由于所有内容都渲染为立方体,因此您不必保留数百万个(相同的)立方体,只需翻译即可。如果您使用实例,单个就足够了。

通过实例化,每个 block 只需要 4 个整数即可完整描述它(3 个表示位置,1 个表示表面,从 GL_TEXTURE_2D_ARRAY 加载)。整数更可取,因为它们的种类更小(唯一的缺点是旧的 GPU 无法有效地处理它们)。假设一个立方体代表 1 立方米。那么一个 16 位整数给你一个 (65536m)³ 的世界。此外,对于 Minecraft 风格的游戏,您几乎不需要超过 256 种表面。所以用8位整数来表示。然后,当您只考虑可见表面(即 block )时,许多体积不必驻留在 VBO 中。

这可以真正节省内存。从 32 位 float 转换为 16 位整数可以节省 50% 的内存。使用单个 8 位整数代替 3×32 位浮点颜色作为 Material 索引,可将内存需求减少到 1/12。

<小时/>

为了进一步减少渲染负载,您可以利用世界上所有立方体都是并行的。这使得消除隐藏表面变得非常容易,甚至不进行处理:有 8 + 6 个主要方向可以用来查看立方体:8 个方向中共享一个角的 3 个面可见,6 个方向中只有您正在查看的表面直接可见。从当前的角度来看,确定每种情况适用的世界主要平面是相当容易的。因此,您有 14 个多维数据集基础模板的变体,并针对特定情况对每个子卷进行实例调用。八叉树再次帮助您选择哪些实例获得哪个变体。

<小时/>

您应该考虑的另一件事是缓存一致性。多维数据集数据在 VBO 中的排列和对齐方式以及访问数据的顺序非常重要。一般来说,您希望数据能够很好地对齐和合并(尽管使用当前的多路径内存架构,分离的数据布局也可以提供相当好的性能)。然而,可以这么说,您的访问模式不应该“到处跳跃”。让您的访问保持良好的分组。这是显示列表优于 VBO 的主要原因:内容是恒定的,驱动程序可以将其内容重新排列成最佳对齐和有序的结构。您必须对此进行试验。

<小时/>

为了让您了解当前最先进的游戏引擎的功能:DICE 最近的一份报告指出,在即将推出的“战地 4”游戏中,即使是最复杂的场景,生成的单个帧也不超过大约2000 次绘图 API 调用。这是一个非常低的数字。

关于java - 提高使用 VBO 时所需的内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20448929/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com