Atlas terrains are very efficient because they simply stream data describing chunks of precalculated levels of detail from the disk. These files are generated in a preprocessing step which is done offline, as it can potentially take a bit of time to process a heightfield (a 4097x4097 heightfield recently took 5-10 minutes to process).
The geometry processing is done by a console function called generateChunkFileFromRaw16. This interface will be extended for later milestones (or you can refer to the code contained at the end of engine/atlas/chunkGen.cpp and write your own variant of the function), but currently only loads from a raw unsigned 16bit heightfield, such as Terragen produces.
The values from the .RAW file are signed 16 bit integers. They go from about -32767 to +32767. In whole numbers. Atlas works in whole meter units, so that means you get from -32km to +32km, in whole meter increments. This might be useful in some cases but for a terrain you walk on is way too much!
So we have a scaling factor. The raw integer values are multiplied by the scaling factor to convert to floating point values that are more useful for realistic terrains.
The error metric is applied after the scaling factor. So if you change the scaling factor you probably have to change the error metric. If the error metric isn't big enough it will crash. If it's too big you'll get an undetailed terrain. There is another parameter for horizontal spacing, the squareSize, but it just affects how values are written out, and won't affect processing time or crashes/accuracy.
The mesh generation works via a quadtree. Each vertex is descended and a delta is calculated from that vertex's real position to where (essentially) the mesh would be at that point if the vertex was present. The distance is divided by the error metric. The resulting number is rounded down to a whole number. That number is the LOD at which that vertex will show up. When the quadtree is generated, it works up from the lowest levels of detail.
A general note: when working with tree depths, bear in mind that 2treeDepth-1 is the number of nodes on a side that tree will be. This becomes important when working with the TQT generator, for instance, when you implicitly describe the size of the input texture by treeDepth and leafSize. This means that 2treeDepth-1 * leafSize = imageSize.
So, the idea when you're setting up your LOD parameters is to get a good number of vertices on the highest detail chunks without maxing out (ie, exceeding the 65k limit) on the lower detail chunks
The simplest way to ensure that is to set a really high error metric. What's high and low? Well, if you're multiplying all the incoming points by 1.0/256.0, you have a working range of heights from -128 to positive 128 meters (we multiply the min/max values for heights, -32767 and +32767, by the scale factor). Depending on how jagged your terrain is, you might need quite a high error metric to avoid maxing out.
You might start with an error metric of 50 or 100 in this case, note that you get a very undetailed terrain, and start lowering it. Most of the time the error metric is going to be around 1% of your working range, but it depends on what sort of terrain you're feeding it.
// Calling generateChunkFileFromRaw16.
4096, 2.0, 1.0 / 256.0,
"demo/data/terrains/large.chu", 2.0, 6);
Filename of the source raw 16 bit heightfield we wish to
generate data for. Example: "demo/data/terrains/test_16_4097.raw".
Size of the heightfield, which is assumed to be square.
The heightfield will be expected to be ONE MORE THAN THIS.
Integer. Size must be a power of 2. Example: 4096.
Spacing between sample points, in meters. The default in
legacy was 8 meters. This is a floating point number.
There are no limitations on this value, although high
polygon density may result in reduced frame rates.
Vertical scale factor. Incoming raw data comes in as a
whole number between -32,765 and +32,765, and is scaled
by this factor to convert to meters.
Factors are commonly of the form 1.0 / 2.0n,
n often being between 1 and 8. 1.0 / 256.0 gives you a
workable range of about 256 meters in the vertical range.
File to which generated data is written. This file should
end in .chu for TGEA's resource
manager to properly load it. Example: "demo/data/terrains/large.chu".
Floating point number indicating the acceptable amount
of error for each LOD to possess compared to the
previous. This directly and dramatically impacts the
number of polygons that will be rendered. Example: 2.0.
Integer indicating how deep the quadtree of chunks is
to be. Example: 6.
Generating Texture Trees
Similarly, textures are generated from a single large source texture.
Consumer hardware cannot support textures much larger than 4096x4096,
so it is necessary to slice the source texture into smaller pieces so
that they may be loaded piecemeal to the card. In addition, detail levels
are precalculated, and the textures are compressed (currently with DXT).
// Generating a TQT.
"demo/data/terrains/large.tqt", 5, 512);
Run Time Reference
This section discusses three major aspects of the Atlas engine runtime: the script interface, the runtime parameters, and the C++ code layout. Together, knowledge of these sections will result in familiarity with how the runtime operates.
The Atlas engine resides in the Atlas sub-directory. The header files are annotated with Doxygen-compatible comments, which fully explain the functioning of the various classes and components of the terrain. The terrain itself is self-contained, and should not require any modifications to existing objects to work properly.
If you should require a C++ reference, simply run doxygen on the TGEA codebase and refer to the appropriate sections. Or, you can read the comments, which are what the Doxygen documentation is generated from. The offline documentation covering the Atlas system is also a useful reference.
There is only one class exposed to the script system, AtlasInstance. Beyond the position and rotation fields,
these are the other important fields:
- Path to the .TQT file for this instance.
- Path to the .CHU file for this instance.>
- Detail texture for the terrain.
- Name of the CustomMaterial used to render this instance. "AtlasMaterial" by default, and recommended to stay default.
Do not change this variable if you do not know what you are doing. This will not work except with custom shaders
- Detail texture for the terrain.
Run time Parameter Reference
Runtime parameters can be access from the console to control various aspects of the runtime behavior of the Atlas engine. They have global, immediate effect, and are not networked.
Atlas Engine Runtime Parameters
- Render bounding boxes showing the extents of each currently loaded geometry chunk in the hierarchy.
Color of the box ranges from yellow to red to black, indicating the relative amount of paging activity occurring on that node. Boolean, default is false.
- Draw all Atlas geometry in wireframe mode. Boolean, default is false.
- If true, performs all loading each frame in the main thread. If false, performs all loading in a background thread. Boolean, default is false.
- Debug parameter. Locks the camera position for testing LOD and culling code. Boolean, default is false.
- Debug parameter. For raycasts, treats chunks as big boxes. Useful for debugging raycast code. Boolean, default is false.
- Debug parameter. For raycasts, treats the nodes of the collision quadtree in a chunk as big boxes. Useful for debugging raycast code. Boolean, default is false.
Now that you have a stronger technical understanding of the Atlas terrain system, this might be a good time to experiment. Check out the following tutorials for creating terrains:
- Using Terragen With Atlas
- Using L3Dt With Atlas