The primary purpose of the built-in terrain system in the SpeedTree SDK is not necessarily to be a state-of-the-art/cutting-edge terrain engine, rather it is to provide client applications with a simple, efficient 3D terrain system that's useful for rapid prototyping.
Note that the terrain engine does not support more than one height value point (i.e. no overhangs).
The terrain system divides the world into a series of square cells. As the camera roams the world, new cells are created and old ones are destroyed. Each time a new cell is created, the client application will be given the parameters necessary to populate it based on whatever data or algorithm is controlling the terrain geometry.
The core functionality of the terrain system is housed in the Forest library, which contains the initialization, roaming, and culling code. The Render Interface library contains the code necessary to render it within the SpeedTree framework.
While the terrain vertex data is populated cell by cell, the system uses a series of index buffers composited into one large index buffer. LOD is handled by rendering a particular cell with different index buffer, depending on its distance from the camera as well as its neighbors. This allows the system to drop triangles (by skipping over more and more vertices in success index buffers) and to ensure that adjacent cells match by using index buffers where lower LOD cells use higher tesselated edges to match their higher LOD neighbors. This also has the added advantage of only having to populate a given cell once, albeit at the highest LOD. Watch the reference application in wireframe mode to observe the effect.
To get started, simply #include “Forest/Terrain.h” to get the core, non-graphical terrain system functionality. Under the namespace SpeedTree, it defines a class called CTerrain which can be initialized using the CTerrain::Init() function:
st_bool CTerrain::InitGeometry(st_int32 nNumLods, st_int32 nMaxTileRes, st_float32 fCellSize);
The parameters are:
Generally speaking, you should just need to have one CTerrain object in your world. Note that if you want to have the SpeedTree SDK handle rendering chores for your application, you can use the CTerrainRI, which derives from the CTerrain class. See the terrain rendering page for details.
For the terrain culling system to work properly, it must be able to predict when a new terrain tile will be visible before it can know its complete extents. That is, if the cell's geometry is being provided by the application, but the application can't provide it until it exists, some a priori knowledge is necessary. The terrain system can know the width and length of the tiles since they are easily computed and the same for each, but the height of the terrain is unknown. To assist with this, CTerrain::SetHeightHints() is provided so that the client application can provide the expected low and high points for the terrain, allowing the culling/roaming algorithm to complete the 3D extents of the cells before they have been created.
The roaming system can use dynamic allocation while it's running. To prevent this, and account for all of its heap allocation up front, use CTerrain::SetHint(). The only hint currently supported is CTerrain::HINT_MAX_NUM_VISIBLE_CELLS. Once set properly, the terrain system will not make any additional heap allocation calls.