I’m doing level of detail (LOD) handling using a straightforward distance-based reduction of polygons each chunk has. The picture describes this approach:
The green rings represent LOD boundaries, and can be configured from the editor. The player’s location is not visible here, but it’s in the middle of the green square (of course). Chunk resolution on each LOD can also be configured, although this can only be done explicitly for the first LOD, and every subsequent LOD has a chunk resolution equal to the chunk resolution of the LOD level before it, multiplied by the “LOD reduction factor”. Currently it’s set to 2, so that each LOD has half the resolution of the LOD before it. The number of LOD levels is also configurable.
If you’re familiar with volumetric LOD algorithms, you know about the “crack” problem that occurs on the boundary between two LODs:
I’m planning to solve this using (a heavily modified version of) Eric Lengyel’s Transvoxel algorithm. It’s going to take a couple of days of work, so I’m struggling to find the time to sit down and dig into the meat of the algorithm. No excuses though, it has to be done at some point.
Back to LOD handling. As the player moves across the map, some chunks and their LODs have to be recalculated. For example, imagine that the player moves from his current chunk to the chunk on the right, on the picture given above. There are a couple of things that have to be done:
- for each LOD level, all rightmost chunks have to have their LOD increased
- for the lowest LOD, its rightmost chunks have to be loaded, since the player has moved to the right and those chunks do not yet exist
- for each LOD level, all leftmost chunks have to have their LOD decreased
- for the lowes LOD, its leftmost chunks have to be unloaded, since the player has moved to the right and those chunks are now outside of the LOD range
Initially, I did this all on the main Unity thread, which worked fine. However, there was a slight hiccup (as you would imagine) when loading new chunks, so I decided to make it multithreaded. Currently, every LOD level has its own dedicated thread and processes all its chunks sequentially, which works nicely. I still have to perform all Unity stuff on the main thread, so I’m using kind of a producer-consumer architecture and performing the setting of actual mesh data on the main thread, while all the heavy calculations are performed on separate threads.