【问题标题】:OpenGL: Rendering thousands of cubes with Vertex Arrays, not working too wellOpenGL:使用顶点数组渲染数千个立方体,效果不太好
【发布时间】:2013-01-27 18:58:07
【问题描述】:

我正在尝试使用顶点数组通过 LWJGL 渲染大约 2097152 个立方体(不是一次全部渲染)。我已经实现了多种类型的多边形剔除,以将我的性能从大约 2 FPS 提高到大约 60 FPS。在整个项目中,我一直在使用即时模式渲染,我认为是时候升级了。这就是顶点数组的用武之地。

我不想使用 VBO,所以我现在一直在尝试 VAO。我似乎无法找到一种实用(或有效)的渲染方法。可悲的是,我尝试的一切都给我带来了比即时模式更差的 FPS。每一帧我都会为每个具有可见多边形的立方体加载一个 FloatBuffer,然后使用常见的顶点数组方法绘制它们。这种设置让我很头疼,因为我得到的 FPS 比使用即时模式且不剔除任何多边形时要少。

我认为我做错了什么。那么在你们这些聪明、有抱负的 OpenGL/LWJGL 程序员中,有谁知道如何以更有效和高效的方式完成这项工作?

这是我的渲染代码(被截断以免太乱):

for(int z = 0; z < chunk.bpc; z++) {
for(int y = 0; y < chunk.bpc; y++) {
    for(int x = 0; x < chunk.bpc; x++) {
        if(((z == chunk.bpc - 1 || z == 0) || (y == chunk.bpc - 1 || y == 0) || (x == chunk.bpc - 1 || x == 0)) 
            && chunk.data[(x * chunk.bpc + z) * chunk.bpc + y] == i) {

                List<Float> vertices = new ArrayList<Float>();

                float xp = x + locX, yp = y + locY, zp = z + locZ;

            if(z == chunk.bpc - 1 && chunk.z$ == null) {
                vertices.add(xp); vertices.add(yp); vertices.add(zp + size);
                vertices.add(xp + size); vertices.add(yp); vertices.add(zp + size);
                vertices.add(xp + size); vertices.add(yp + size); vertices.add(zp + size);
                vertices.add(xp); vertices.add(yp + size); vertices.add(zp + size);
            }

            if(z == 0 && chunk.z_ == null) {
                vertices.add(xp); vertices.add(yp); vertices.add(zp);
                vertices.add(xp); vertices.add(yp + size); vertices.add(zp);
                vertices.add(xp + size); vertices.add(yp + size); vertices.add(zp);
                vertices.add(xp + size); vertices.add(yp); vertices.add(zp);
            }

            if(y == chunk.bpc - 1 && chunk.y$ == null) {
                vertices.add(xp); vertices.add(yp + size); vertices.add(zp);
                vertices.add(xp); vertices.add(yp + size); vertices.add(zp + size);
                vertices.add(xp + size); vertices.add(yp + size); vertices.add(zp + size);
                vertices.add(xp + size); vertices.add(yp + size); vertices.add(zp);
            }

            if(y == 0 && chunk.y_ == null) {
                vertices.add(xp); vertices.add(yp); vertices.add(zp);
                vertices.add(xp + size); vertices.add(yp); vertices.add(zp);
                vertices.add(xp + size); vertices.add(yp); vertices.add(zp + size);
                vertices.add(xp); vertices.add(yp); vertices.add(zp + size);
            }

            if(x == chunk.bpc - 1 && chunk.x$ == null) {
                vertices.add(xp + size); vertices.add(yp); vertices.add(zp);
                vertices.add(xp + size); vertices.add(yp + size); vertices.add(zp);
                vertices.add(xp + size); vertices.add(yp + size); vertices.add(zp + size);
                vertices.add(xp + size); vertices.add(yp); vertices.add(zp + size);
            }

            if(x == 0 && chunk.x_ == null) {
                vertices.add(xp); vertices.add(yp); vertices.add(zp);
                vertices.add(xp); vertices.add(yp); vertices.add(zp + size);
                vertices.add(xp); vertices.add(yp + size); vertices.add(zp + size);
                vertices.add(xp); vertices.add(yp + size); vertices.add(zp);
            }

            float[] verts = new float[vertices.size()];
            for(int a = 0; a < verts.length; a++) {
                verts[a] = vertices.get(a);
            }

            FloatBuffer cubeBuffer = BufferUtils.createFloatBuffer(verts.length);
            cubeBuffer.put(verts);
            cubeBuffer.flip();

            GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);

            GL11.glVertexPointer(3, 0, cubeBuffer);

            GL11.glDrawArrays(GL11.GL_QUADS, 0, verts.length / 3);

            GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
        }
    }
}
}

(忽略其中一些变量,它们只是剔除不同的多边形)

所以我不知道是否有更有效的方法来做到这一点,但如果有的话,如果我能得到一些指示会很好​​。提前致谢!哦,还有……

我的渲染方式存在严重错误。

【问题讨论】:

    标签: java opengl rendering lwjgl vertex-array


    【解决方案1】:

    虽然我读过关于 LWJGL 和 VAO 的文章,但我从未亲自使用过它们,但 VBO 总是为我解决问题。但是,如果我查看您的代码 sn-p,您似乎每帧都调用这个 sn-p。所以,本质上你是在改变每一帧的数据,创建一个新的缓冲区,将数据从缓冲区传输到缓冲区,然后在缓冲区中渲染数据。每帧创建一个新的缓冲区是昂贵的,所以这样做一次,然后重用你的缓冲区。如果您每帧都更改数据,那么 VAO 和 VBO 可能不会为您提供比立即模式更高的性能。原因在于,在即时模式下,您将每帧数据传输到 GPU 内存并进行渲染,这种传输成本很高。另一方面,如果数据没有改变每一帧,那么 VAO 和 VBO(以及更早的显示列表)通过允许您将数据存储在 GPU 内存中来为您提供加速,因此您不必每次都从 RAM 传输它通过 PCI-E 总线到 GPU 内存。

    【讨论】:

    • 我可以有一个缓冲区来存储所有顶点的数据,而不是为每个立方体创建一个新缓冲区吗?
    • 是的。您应该在缓冲区中放置更多的立方体。您应该在缓冲区中存储多少个顶点有一定的最佳值,但是您可以在其中存储数百万个顶点,这比您现在存储在其中的少数顶点要多得多。
    • 你能在任何地方给我指点一个教程或例子来说明如何做到这一点吗?我已经尝试添加更多顶点,但仍然失败,因为它只渲染了一个立方体。
    • 我什么都不知道,但是尝试在网上搜索一下,这是相当基本的 OpenGL 东西,所以我猜网上有几个示例/教程。选择一个适合您的专业水平的。 OpenGL 关于缓冲区对象和顶点规范的 wiki 也可能对您有用:opengl.org/wiki/Buffer_Object 和 opengl.org/wiki/Vertex_Specification
    【解决方案2】:

    不要重新生成你的几何体每一帧。内部渲染循环中的动态内存分配通常是一个坏主意。

    当一个块进入视野时以及如果/当​​该块被修改时,为一个块生成几何一次。

    也许使用 LRU 缓存来存储几何图形,以便不可见的块慢慢地从缓存中清除。

    【讨论】:

    • 我想我现在的主要问题是我是否可以将所有几何图形的所有顶点加载到一个缓冲区中,然后从该缓冲区而不是每个立方体的新缓冲区进行渲染...?
    • @MrDoctorProfessorTyler:您真的是在问我们如何将您的代码移出我们的渲染循环并进入一些初始化代码?
    • 我对此完全陌生,是的,我是。或者至少为我指明正确的方向
    猜你喜欢
    • 1970-01-01
    • 2015-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-21
    • 1970-01-01
    • 1970-01-01
    • 2015-08-12
    相关资源
    最近更新 更多