Isometric tiles and heights...can I modify?

I have an isometric 2D Engine that has capability of generating different heights.


http://i.imgur.com/4BKlkuCl.png

It runs at 20~30 FPS with grid layers, 55~60 FPS without grid layers.
And I started to think about improving it’s performance much higher(though I have enough fps for smooth scrolling).

The way it generates the world is by dividing entire world by chunks(The engine itself can generate maximum map size of 2048x2048).
I have single tile vertices saved in vbo, and when it is time to render a tile, I map out the buffer and change the vertex location based on its height, flip the buffer, then ummap it.

But now I’m thinking about putting a single chunk into vbo, then render it.
However, if I put single chunk(which contains vertices for tiles) into vbo, it will be impossible to unmap the buffer, pin-point the tile, then change it’s height value.

So my question is, is there a way to “store all tiles in one chunk, into one vbo, then modify individual tile as it needs”?


Tile[][] tile = new Tile[xMax][yMax][zMax];
for (int x = 0; x < tile.lenght; x++){
	for (int y = 0; y < tile[0].lenght; y++){
		for (int z = 0; z < tile[0][0].lenght; z++){
			vbo.add(tile[x][y][z]);
		}
	}
}

Maybe ??? :confused: ???

For this example, I am going to assume that each vertex comprises of 3 floats (x, y, z) and you store them in the vbo in row major order.

This means that for the tile at position X, Z (relative to the chunk it is in) the four vertices begin at offsets:
( ( Z * CHUNK_WIDTH ) + X ) * 3
( ( ( Z + 1 ) * CHUNK_WIDTH ) + X ) * 3
( ( ( Z + 1 ) * CHUNK_WIDTH ) + ( X + 1 ) ) * 3
( ( Z * CHUNK_WIDTH ) + ( X + 1 ) ) * 3

which we must not forget to times by 4 to get the byte offset.

So the following method will update the height of a specific tile. (I don’t know if you LWJGL or what but that is the format I’ll give it in)



static FloatBuffer fb = BufferUtils.createFloatBuffer(4); //We will reuse the buffer since this is about efficiency.

public static updateTile(int bufferId, int x, int z, int newHeight) {
    glBindBuffer(GL_ARRAY_BUFFER, bufferId);
    
    fb.flip();
    int offset1 = ( ( ( ( z * CHUNK_WIDTH ) + x ) * 3 ) + 1 ) * 4; //+1 since we will start updating at the y coord
    fb.put(newHeight);
    fb.put(z);
    fb.put(x + 1);
    fb.put(newHeight);
    fb.flip();
    glBufferSubData(GL_ARRAY_BUFFER, offset1, fb);

    fb.flip();
    int offset2 = ( ( ( ( ( z + 1) * CHUNK_WIDTH ) + x ) * 3 ) + 1 ) * 4;
    fb.put(newHeight);
    fb.put(z + 1);
    fb.put(x + 1);
    fb.put(newHeight);
    fb.flip();
    glBufferSubData(GL_ARRAY_BUFFER, offset2, fb);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
}


In this example I updated it with 2 calls to glBufferSubData. That meant that I was needlessly updating 2 other values, but I suspect that it would still be quicker than 4 calls, but you can try it out to your hearts content.

I’m sure there are probably some other optimizations (perhaps caching buffer offsets or working them out more efficiently), but I shall leave that up to you.

I have made some assumptions about your system, but you’re a smart guy, I’m sure you’ll figure out anything I got wrong. Saying that I didn’t comment much so feel free to ask about the code.

Here’s hoping I got that all right (would be a miracle)