Previously the mesh for the terrain was generated on the CPU, both positions and normals. While this ‘worked’, it was extremely slow. So slow in fact, that it required the process to be split across multiple frames, usually it would take upward of 50 frames for one chunk to be ready on screen. Usually there are 9 chunks needed, so if the player pans quickly across the map then it takes a long time for the terrain to prepare. Now this would be fine for a small map size, as I could just cache the terrain mesh for each chunk. But for a large map (4096 x 4095), it would take up to much memory. Also another issue was that with CPU bound mesh generation it’s difficult to alter the mesh in real time.
The new method involves moving the mesh calculation to the GPU and having just one small flat mesh which follows the camera. The vertex shader then reads in values from a texture and calculates the correct Y position. The downside is that I can’t do greedy meshing or any kind of optimisation to reduce the verts. However the upside is that mesh generation is instant and the terrain can be updated in realtime.
Another big issue was terrain LOD, which was proving very difficult. The issue is that it’s very hard to simplify a voxel style mesh, a cube is still a cube at any distance and can not be reduced further. You can see some experiments with smooth meshing at low LOD in previous posts, I was not very happy with the results. My new solution is to show the map in strictly 2 dimensions when zoomed out. So what the player sees is actually just one quad. The interesting part is that directional light and depth still work as normal. The quad writes directly into the depth buffer the Y value at the given tile. So when the ocean is rendered in the next pass, it can discard fragments above sea level by looking at the depth. I’ve also done done some work with an adaptive LOD for grass, so the number of rendered shells decreases as you zoom out.