Efficient Chunk Loading.

Lets say I want to load a Map that is 20x20 chunks, each chunk is 10x10x2 blocks, that is a lot of blocks (80,000). So, in a small map, I would just initiate all of the chunks before the game starts, but now, I am interested in more efficient ways. I have tried to only initiate the chunks within a 2x2 area of the player, but RAM keeps stacking (from ~52mb to ~250mb) by the time I trek the whole map. Here is some code I have tried to implement. If anyone can give me a better suggestion, please do so.

private void setView() {
        int lowX = (getChunk((int) position.x, (int) position.z)[0]) - 2;
        int highX = (getChunk((int) position.x, (int) position.z)[0]) + 2;

        int lowY = (getChunk((int) position.x, (int) position.z)[1]) - 2;
        int highY = (getChunk((int) position.x, (int) position.z)[1]) + 2;

        if (lowX < 0) {
            lowX = 0;
        }

        if (highX > width) {
            highX = width;
        }

        if (lowY < 0) {
            lowY = 0;
        }

        if (highY > height) {
            highY = height;
        }

        if (view[0] != lowX || view[1] != highX || view[2] != lowY || view[3] != highY) {
            view[0] = lowX;
            view[1] = highX;
            view[2] = lowY;
            view[3] = highY;
            loadChunks();
        }
    }

    private void loadChunks() {
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                if (x >= view[0] && x <= view[1] && y >= view[2] && y <= view[3]) {
                    chunk[x][y] = new Chunk(x, y);
                    chunk[x][y].setTexAmount(4);
                } else {
                    chunk[x][y] = null;
                }
            }
        }
    }

private void renderChunks() {
        int lowX = view[0];
        int highX = view[1];

        int lowY = view[2];
        int highY = view[3];

        for (int x = lowX; x < highX; x++) {
            for (int y = lowY; y < highY; y++) {
                chunk[x][y].renderChunk();
            }
        }
    }

If it matters, I am using Vertex Buffer Objects for all of my 3D rendering.

Also, a sub question: Would it be worth the code for me to convert my 2D HUD from immediate mode to VBO?

First off, why the random choice in chunk size? I believe it is actually less efficient not to use a power of two chunk size, but I don’t know where I read that.

In my YouTube tutorial series, I can load literally millions of blocks at one time. How do I do it? Well, for one I use display lists. Second, I do a far amount of optimizations.

1.) Frustum culling. VERY IMPORTANT! The game would run very very slow without it.
2.) I create one static instance of every block type in my world instead of creating separate instances for every block. I have a feeling this is what you’re doing, and its a very, very bad way of doing it!
3.) All your standard culling (back face culling, face removal, block removal)
4.) Unload chunks not in view, and load them back in when in view.

I’m sure I missed a couple, but with these pretty basic optimizations I can hold around 1000 chunks in memory at once. Not great, but Its decent I think. So far I’ve yet to actually hit a limit on how many chunks can be rendered at once. display lists are amazing for this kind of work though, I would quite honestly recommend arrays objects instead of buffer objects if you don’t like the idea of display lists and want to stay “modern”.

Remember, just because buffer objects are the modern way of holding vertices it doesn’t mean it’s the best way. I found that buffer objects could barely render 16 chunks before slowing down, whereas I can render literally a 1000 display lists at once and see no performance hit. Sure, I probably didn’t optimize the buffer objects well enough, but it seems display lists are doing the job, so what the hell! Might as well do something I enjoy.

Thanks for the response. And yes, I am making a new instance of every block, unfortunately. By the way, you never got back to me on that private message. I will definitely try out some of your optimizations though.

EDIT: I misread you, I do not make a new instance for every block. Only every chunk. The only data I keep per block is in an array of Vector4f, x, y, z and texture.

Oh sorry! I’ve been very busy lately!

You shouldn’t keep an instance of every texture. Your renderer should take parameters corresponding to what texture you want to render. I also assume you are using a spritesheet? If not, definitely do that right away! But yes, storing a new texture per chunk would add up eventually.

Really, if you want to be very efficient, you shouldn’t be creating any new objects at all after the initial start up of the game. For instance, I make a single block for each block type, I make all the chunks, I make the entities and mobs and player and then I don’t create new objects at all after that. Later on I will need to, but I really do believe that’s one reason its running faster.

I forgot to mention that I handle textures by number, not by instance. Yes I use a spritesheet. I will make a version of my 3D rendering in display lists. I have never used them for large scale 3D before.

For voxels it seems they work very well. What do you mean by number though?

I would assume texture handle.

Ah I see, I understand now. Why keep a texture handle per chunk though? I create a single static spritesheet in a spritesheet class then reference it whenever I need it. No point in having every chunk keep their own.

I am sorry for my miss wording. I load the sheet and set each texture within the sheet to a number, lets say I have 5 textures, the numbers would be 0-5. I then I can change the texture by putting a different number in for the coords of the cube in an array, I then re buffer the chunk, applying the changes. I never load the sheet more than once.

Ah I see, that makes sense. Can you profile your code? That would be greatly helpful to see why you have such a high memory usage.

What do you mean by profile? And wow man, thanks for the tip on display lists. Literally exponentially more efficient. But the RAM is still stacking, nevertheless.

Profiling basically means to monitor the JVM while it is running. You can see exactly (sort of) what is happening. How much memory is used, how much this thread is being used etc… I don’t know of any good profilers, but a quick Google search should turn you up one!

No problem for the display list idea by the way! Just remember to only rebuild them once every time a chunk is changed and not ever else!

Only common sense my friend. Haha, I enabled the basic GL_CULL_FACE, and that seems to save some RAM, but nothing extreme.

EDIT: I fixed my chunk loading method to initialize all of the chunks at the start, it seems like the display lists load almost instantanious compared to VBOs which take around 4 seconds to load 400 chunks. I am sitting at 80mb RAM with 80,000 tiles, the RAM is no longer stacking, at least I think so.

To solve your ram problem, just unload the chunks once they are far enough away from the player.

Describe ‘unload’. As in setting the chunk to null, so the GC can take care of it? If so, I did that, it sucked. If you mean ‘don’t render them when they get a distance away’, I do that.

No no, just save them to disk when they are far away. Then remove the chunks from your array. You’re using an array correct? I actually use an arraylist so I can literally remove the chunk from memory after I save it, then add it back when I load it back in.

By save to disk, do you literally mean save it to my hard disk? I was planning on map loading, but not at this point, though it can be done in like 5 minutes.

Yes, save it to the hard drive. Trust me, it’ll get rid of a lot of your issues, especially with memory management.

Ok, I will do that tomorrow, and do you think storing an array of integer arrays is more efficient that storing an array of Vertex4fs?

Are you storing the voxel positions? Don’t do that. It probably actually is the reason you have such high memory usage! You can just extract the voxel positions from the array they sit in. I keep a byte of tile ids in each of my chunks, and my renderer then renders the appropriate texture from the id. I never ever store a voxel position. Its just a huge waste of memory!