1

我创建了两个简单的体素引擎,实际上只是包含立方体的块。对于第一个,我使用显示列表,并且可以以 60 FPS 的速度渲染数百个块,尽管它背后的技术已经有多年历史并且现在已经过时了。使用我的 VBO 版本,我尝试渲染 27 个块,但我突然下降到低于 50 FPS。是什么赋予了?我将着色器用于我的 VBO 版本,但不用于显示列表一。如果没有 VBO 版本的着色器,我仍然可以获得相同的 FPS 速率。我将发布一些相关代码:

伊博

初始化块:

public void initGL() {
    rand = new Random();

    sizeX = (int) pos.getX() + CHUNKSIZE;
    sizeY = (int) pos.getY() + CHUNKSIZE;
    sizeZ = (int) pos.getZ() + CHUNKSIZE;

    tiles = new byte[sizeX][sizeY][sizeZ];

    vCoords = BufferUtils.createFloatBuffer(CHUNKSIZE * CHUNKSIZE * CHUNKSIZE * (3 * 4 * 6));
    cCoords = BufferUtils.createFloatBuffer(CHUNKSIZE * CHUNKSIZE * CHUNKSIZE * (4 * 4 * 6));

    createChunk();

    verticeCount = CHUNKSIZE * CHUNKSIZE * CHUNKSIZE * (4 * 4 * 6);

    vCoords.flip();
    cCoords.flip();

    vID = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, vID);
    glBufferData(GL_ARRAY_BUFFER, vCoords, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    cID = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, cID);
    glBufferData(GL_ARRAY_BUFFER, cCoords, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}
private void createChunk() {
    for (int x = (int) pos.getX(); x < sizeX; x++) {
        for (int y = (int) pos.getY(); y < sizeY; y++) {
            for (int z = (int) pos.getZ(); z < sizeZ; z++) {
                if (rand.nextBoolean() == true) {
                    tiles[x][y][z] = Tile.Grass.getId();
                } else {
                    tiles[x][y][z] = Tile.Void.getId();
                }
                vCoords.put(Shape.createCubeVertices(x, y, z, 1));
                cCoords.put(Shape.getCubeColors(tiles[x][y][z]));
            }
        }
    }
}

然后渲染:

public void render() {
    glBindBuffer(GL_ARRAY_BUFFER, vID);
    glVertexPointer(3, GL_FLOAT, 0, 0L);

    glBindBuffer(GL_ARRAY_BUFFER, cID);
    glColorPointer(4, GL_FLOAT, 0, 0L);

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);

    shader.use();
    glDrawArrays(GL_QUADS, 0, verticeCount);
    shader.release();

    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
}

我知道我使用四边形,这很糟糕,但我也将四边形用于我的显示列表引擎。着色器非常简单,它们所做的只是获取颜色并将其应用于顶点,我什至不会发布它们,它们就是那么简单。

显示列表

初始化:

public void init() {
    rand = new Random();

    opaqueID = glGenLists(1);

    tiles = new byte[(int) lPosition.x][(int) lPosition.y][(int) lPosition.z];

    genRandomWorld();
    rebuild();
}
public void rebuild() {
    glNewList(opaqueID, GL_COMPILE);
    glBegin(GL_QUADS);
    for (int x = (int) sPosition.x; x < (int) lPosition.x; x++) {
        for (int y = (int) sPosition.y; y < (int) lPosition.y; y++) {
            for (int z = (int) sPosition.z; z < (int) lPosition.z; z++) {
                if (checkCubeHidden(x, y, z)) {
                    // check if tiles hidden. if not, add vertices to
                    // display list
                    if (type != 0) {
                        Tile.getTile(tiles[x][y][z]).getVertices(x, y, z, 1, spritesheet.getTextureCoordsX(tiles[x][y][z]), spritesheet.getTextureCoordsY(tiles[x][y][z]));
                    } else {
                        Tile.getTile(tiles[x][y][z]).getVertices(x, y, z, 1);
                    }
                }
            }
        }
    }
    glEnd();
    glEndList();
    spritesheet.bind();
}

我应该注意,在我的显示列表版本中,我只添加了可见的立方体。所以,这可能是一个不公平的优势,但它不应该将 VBO 版本降低到只有 27 个块的 FPS,而显示列表版本是 500 个块。我这样渲染:

public void render() {
    if (tiles.length != -1) {
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glCallList(opaqueID);
    }
}

所以,在所有这些代码之后,我真的还是想知道为什么我的 VBO 版本这么慢?当我调用它们进行渲染时,我的显示列表版本中确实有一个一维的块列表,而我的 VBO 版本中有一个 3 维的块列表,但我认为 JVM 几乎消除了额外维度的任何滞后。那么,我做错了什么?

4

1 回答 1

0

如果没有实际项目和分析器,很难回答这样的问题,所以这些是理论:

  • 您没有详细显示您的显示列表生成代码,所以我假设您正在glColor(); glVertex3f();循环中执行类似的操作(而不是您声明了一次颜色并完成了它)。
  • 显示列表实现是特定于实现的,但通常是交错的顶点属性数组,因为这对缓存更友好(所有顶点道具都按 16 字节紧密对齐,而不是按数组大小分散)。另一方面,您使用的 VBO 分为两个非交错块 - 坐标和颜色。这可能会导致过度使用不友好的缓存(尤其是在处理大量数据的情况下)。

如评论中所述:

尝试将您的位置和颜色数据交错在一个缓冲区中。这是静态数据的通常建议,因为它在渲染期间提供了更好的内存访问模式。– GuyRT`

于 2014-07-10T05:17:56.227 回答