Last week I mention that my next goal with Crimild was to tackle several issues regarding the Terrain Library. And that’s what I’m doing. The goal that I’m trying to accomplish with this code review is to ensure not only a cleaner and more developer-friendly API for terrains, but also to improve some optimization that were implemented in the past but never actually completed. But before discussing about the optimization details let me explain how the Terrain library is composed of:
As its name suggests, the HeightMap class store the elevation information that is later used to build the landscape. But since elevation data might come in different forms, the HeightMap class only declares a common interface for all the actual implementations. As I’m writing this post the library already suports elevation data in the form of raw data files, image files (with support for both 8-bit and 24-bit images) and even a procedural heightmap generated through the use of fractal calculations.
This class is one of the two terrain implementations available in Crimild. In particular, this is the brute force approach. It just read through all the information contained in the heightmap and creates the entire landscape with the maximum level of detail. Although there is no mesh optimization, this class does provide a couple of tricks in order to speed up rendering. The terrain is divided into several patches and group them in order to create a node hierarchy, allowing for fast culling. For those of you wandering, a patch is just a geometry node that contains only the graphical data for the particular portion of the terrain it represents.
The following picture shows the TerrainNode class in action
Notice that all patches have the same amount of detail regarding their actual position relative to the camera view point.
In contrast with TerrainNode, the CLODTerrainNode class does provide a mesh optimization in order to reduce the amount of vertex information sent to the graphics card. The algorithm I’m using is based on Geomipmapping (see references) and ensures that the level of detail for a given patch increases as the camera moves closer to it. A LOD value is assigned to each patch based on the viewer’s distance and the patch is tessellated whenever that value changes. The amount of patches that are tessellated between each frame depends on the subdivision policy and the camera movement, but during my testings it was always below ten.
Here’s an example of the the CLODTerrainNode works.
As the camera moves closer to the terrain, the patches at the bottom of the screen gain more detail.
Cracks will appear on the borders between patches with different level of details. In this iteration I’m using vertical skirts along the patch border to prevent those holes in the terrain. Instead of avoiding the formation of cracks in the surface, the skirt just fill the blanks.
I still need to perform further tests, but the results so far are optimistic in both performance and memory requirements. Improving the terrain library is imperative for the iPhone extensions due to the hardware limitations. I’m going to freeze any further change in the optimization algorithms in order to make some progress in the remaining subjects. The next step is to provide some lighting for our landscapes as well as improving the texture generator.