What optimizations do you have in place? How fast is your game for loading/average FPS? I’m making my own voxel engine and I was just wondering what you have right now!
I have a render distance (fog). I also have face culling. My culling only shows the outside of the chunk. I will change the culling to only show viewable things(but not right now). My average FPS is around 35-40 FPS, so that’s good.
Damn, I only render 18 chunks and my FPS drops down below 60. I’m using display lists also, so I wonder what the issue is!
Edit: Never mind, I was doing something horribly wrong. Now I’m back to a good FPS! How many chunks do you actively render? I don’t imagine all 484.
Oh I get over 100 FPS while playing minecraft. Just tested my game, I get a perfect 60 FPS with vSync on while rendering over 60 chunks. Awesome.
Edit: Now I’m up to 150 chunks. I’m trying to find the max… this is insane I don’t know why its working so well!
Edit 2: Found the limit before the program crashes from heap errors! I can get up to 174 chunks at one time
The only thing I don’t do on your list right now is view frustum culling, but that’s because I’m to lazy to get into all that math My voxel face culling can also be improved to only render faces, and I still need to check for cubes that are touching in different chunks, but that won’t be that difficult I hope. What do you use VAOs for? And what do you mean by cached texture UV’s? I just create one instance of the texture coordinates in a spritesheet and then pass them into my renderer. My only issue is that I run out of heap space at about 175 chunks Looks like I need to reduce the amount of geometry by a lot!
It is extremely easy to check if a face needs to be rendered, may it be over chunk-borders or inside a single chunk.
(pseudocode)
when renderVoxel DEFAULT_VOXEL Voxel{x,y,z,ID} of CHUNK
{
for_each SIDE of VOXEL
{
int3 coord = SIDE.getCoordinatesOfNeighborRelative(VOXEL.x,VOXEL.y,VOXEL.z);
int neighborData = 0;
if(CHUNK.isCoordInside(coord))
neighborData = CHUNK.get(coord);
else
neighborData.WORLD.get(coord);
Do-Occlusion-Checks-For-Neigbor-And-Stuff (neighborData);
}
}
This is just about how I go about it, with the exception that I am doing some fancy caching behind the scenes to speed things up.
Notable is that my World consists of chunks and is infinite in all directions.
Also:
- Use ByteBuffers for your chunks, not int[] or byte[] or short[] or Voxel[(This-Is-The-Worst)].
- Do as much packing as possible. If needed on a bit-wise level. My voxels each take up 3 bytes, or none.
- Never store more than one istance of a Block.
- Never return Voxels as Objects over 'return'.
- Never create Objects inside the loop that renders the blocks.
- Never try to render voxels in real-time if you want a lot of them.
- Use FACC-Rendering if possible. (FarAwayCompressedChunk-Rendering)
- Face Cull all Voxel-faces that cant be visible.
- Do View Frustum Culling on the chunks.
- Render Chunks based on DisplayLists and VAOs. This is THE fastest way. Nothing is faster. Believe me in that. (Needs a lot of trickery though)
- Use stitched TextureMaps to support an 'infinite' amount of textures on your voxels.
- Cache all the Texture-UVs for the Voxels. Never recalculate them each time you render stuff.
- Cache all the chunks around a chunk to speed up the access when generating the mesh (aka: Rendering the Chunk).
- Z-Sort your Chunks and render them (opaque) Front-To-Back, then (transparenzy) Back-To-Front. This can double your FPS, if done right.
- Do not use glCallList(int) to render your display-lists! Use glCallList(IntBuffer) instead, its a lot faster.
- ...etc.etc.
- ALWAYS USE A DAMN PROFILER! Seriosly... do it!
There are so many things to speed up rendering.
I don’t even know how many of them I found out about by just experimenting.
Interesting talk about performance. I thought my little project for my game class was very slow but I guess not so bad. I can get around 500k cubes (not chunks) at 20+ fps. Not fantastic but I do not use any chunking system or anything fancy.
Look at the last post.
All I do is per-compute the culled faces and use a face batcher via GL11 stuff. The cubes are stored in a hashmap with their location as the key. Adding and removing blocks is basically free for recomputing which faces are culled. Because everything is make dynamically every frame, things could get faster with a chunk system, static VBOs, and frustum culling on non-visible chunks. From what I know, frustum culling on each cube is not worth the computational cost.