我创建了两个简单的体素引擎,实际上只是容纳立方体的 block 。对于第一个,我使用显示列表,并且可以毫无问题地以 60 FPS 渲染数百个 block ,尽管其背后的技术已经存在多年且现已弃用。在我的 VBO 版本中,我尝试渲染 27 个 block ,但突然下降到低于 50 FPS。是什么赋予了?我将着色器用于我的 VBO 版本,但不用于显示列表一。如果没有 VBO 版本的着色器,我仍然可以获得相同的 FPS 速率。我将发布一些相关代码:
VBO
block 的初始化:
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 个 block 的 FPS,而显示列表版本则为 500 个 block 。 我这样渲染:
public void render() {
if (tiles.length != -1) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glCallList(opaqueID);
}
}
所以,在完成所有这些代码之后,我真的仍然想知道为什么我的 VBO 版本这么慢?当我调用它们进行渲染时,我的显示列表版本中确实有一维 block 列表,而我的 VBO 版本中有一个 3 维 block 列表,但我认为 JVM 几乎消除了额外维度带来的任何滞后。那么,我做错了什么?
最佳答案
如果没有实际的项目和分析器,很难回答这样的问题,所以这些都是理论:
- 您没有详细显示显示列表生成代码,因此我假设您正在执行类似的操作
glColor(); glVertex3f();
在循环中(不是您声明一次颜色并完成它)。 - 显示列表实现是特定于实现的,但通常是顶点属性的交错数组,因为这对缓存更友好(所有顶点属性都按 16 字节紧密对齐,而不是按数组大小分散)。另一方面,您使用的 VBO 包含两个非交错的 block - 坐标和颜色。这可能会导致过度不友好的缓存使用(尤其是在处理大量数据时)。
正如评论中所述:
try interleaving your position and colour data in a single buffer. That is the usual recommendation for static data as it gives better memory access patterns during rendering. – GuyRT`
关于java - 为什么我的 VBO 比显示列表慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20231456/