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/glBufferSubDataglDrawElements/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 数据的主要内容,如果未能解决你的问题,请参考以下文章

使用 JOGL 使用 VBO 渲染随机引发异常

在 jogl 中渲染大型 VBO 对象

在 JOGL 中跨多个 QWidget 共享 VBO

在 netbeans 7.4 上运行 jogl VBO

用新的URL替换本地数据库

用新的小部件替换 QTabWidget 的页面