JOGL:用新的细节级别替换 VBO 数据
Posted
技术标签:
【中文标题】JOGL:用新的细节级别替换 VBO 数据【英文标题】:JOGL: replacing VBO data with new level of detail 【发布时间】:2017-07-01 14:50:13 【问题描述】:我有一个 Java 应用程序,我在其中计算 CPU 上的 3D 模型。计算需要一些时间(以秒为单位 - 分钟),但发生在迭代中,如果你愿意的话,细节级别。我正在使用 JOGL 来可视化模型。我想立即可视化模型,并在准备好后用新的细节级别更新视图。我有一个可以正常工作的设置,但我感觉我做错了什么(我正在用这个项目学习 OpenGL):现在我将新 LoD 的顶点信息缓存在 FloatBuffer
中并设置一只旗。渲染循环检查这个标志,如果它被设置,它将为 VBO 分配一个新的数据存储 (glBufferData
)。我考虑使用glBufferSubData
以获得更好的性能(分配新的数据存储会导致更高级别的性能提升,至少有 1M 顶点)但问题是新的细节级别具有任意数量的顶点(不是与上一个细节级别相同)并且我无法预测,当第一次初始化 VBO 时,缓冲区应该最大有多大。我尝试分配一个非常大的缓冲区,但这让我遇到 JVM 崩溃或 GL 1281 错误(我想我正在尝试分配一个太大的缓冲区:1440*1440*4 字节)。我应该使用多个单独的 VBO 吗?我可以制作多大的 VBO?我是否应该为顶点颜色、法线和顶点位置设置一个单独的(一组)VBO?准备好新的详细程度后,最佳做法是什么?
额外信息:
在渲染循环中检查的输出带有一个新的缓冲区数据存储(使用System.currentTimeMillis()
测量的时间),以获取不同级别的细节到达,显示出明显的性能提升:
OpenGL received new data of length 0
Allocating a new data store took 0 ms
OpenGL received new data of length 0
Allocating a new data store took 0 ms
OpenGL received new data of length 360
Allocating a new data store took 3 ms
OpenGL received new data of length 6240
Allocating a new data store took 0 ms
OpenGL received new data of length 34020
Allocating a new data store took 0 ms
OpenGL received new data of length 177840
Allocating a new data store took 1 ms
OpenGL received new data of length 1018980
Allocating a new data store took 7 ms
OpenGL received new data of length 5214660
Allocating a new data store took 20 ms
OpenGL received new data of length 19392000
Allocating a new data store took 59 ms
OpenGL received new data of length 56229840
Allocating a new data store took 157 ms
实际代码:
long before = System.currentTimeMillis();
gl.glBufferData(GL_ARRAY_BUFFER, vertexData.limit() * 4, vertexData, GL_STATIC_DRAW);
System.out.println("Allocating a new data store took " + (System.currentTimeMillis() - before) + " ms");
其中vertexData
是在包含顶点数据的float[]
上使用GLBuffers.newDirectFloatBuffer(...)
分配的(这是在CPU 线程上完成的)。在旁注中,请注意最大的细节模型如何包含 5622984 个顶点(每个顶点由 10 个浮点值组成)。此代码有效,当我的电脑被要求使用这行代码分配该大小的缓冲区数据存储时,它不会抱怨。我很奇怪,因为如果我尝试通过硬编码这个字节量来直接在我的 init 例程中分配一个大小的缓冲区,JVM 就会崩溃......(#有问题的帧:
[nvoglv64.DLL+0xd16e7b])。所以改变
gl.glBufferData(
GL_ARRAY_BUFFER,
vertexData.limit() * 4,
vertexData,
GL_STATIC_DRAW);
到
gl.glBufferData(
GL_ARRAY_BUFFER,
56229840*4,
vertexData,
GL_STATIC_DRAW);
导致 JVM 崩溃。
【问题讨论】:
【参考方案1】:要绘制56229840个顶点,每个顶点由3个坐标组成,每个坐标占用4个字节和glBufferData expects a size in bytes。因此,您应该通过56229840 * com.jogamp.common.nio.Buffers.SIZEOF_FLOAT * 3
。
A VBO 是一个缓冲区。你可以在GLEventListener.display()
中多次调用glBufferData
/glBufferSubData
和glDrawElements
/glDrawArrays
,这是我在分层绘图系统(硬盘+CPU+GPU)中所做的。想象一下,您的硬盘驱动器上有一个巨大的网格,您需要多次通过来填充内存在本机堆或 Java 堆上的缓冲区,并且您将需要更多次来填充 GPU 中的缓冲区。如果 CPU 中的缓冲区占用 1 GB 而 GPU 中的缓冲区小 1000 倍,则您必须进行 1000 次传输和glBufferData
/glBufferSubData
调用才能绘制网格。
【讨论】:
我不想画56229840个顶点(我的错,我编辑了原帖),我的意思是画5622984个顶点,每个顶点由10个浮点值组成:x,y,z, r、g、b、a、nx、ny 和 nz(坐标、颜色和法线)。在我的代码示例中,56229840 是我的浮动缓冲区的长度(所以vertexData.limit()
= 56229840)。我很困惑用硬编码的等效值替换运行时值会导致崩溃。以上是关于JOGL:用新的细节级别替换 VBO 数据的主要内容,如果未能解决你的问题,请参考以下文章