This sample demonstrates how to use a Texture Array to render a terrain with visually-complex texturing at high performance. The texture array is similar to a 3D texture, allowing for multiple 'slices' or sub-textures bound to a single texture ID, but arrays are much higher performance due to disallowing trivial filtering across the slices. We get great terrain rendering performance by eliminating the need to perform multiple, blended passes over the geometry, and improved quality by avoiding boundary issues that would occur with 2D atlas texturing.
glTexSubImage3D
GL_NV_map_buffer_range
glMapBufferRange
glUnmapBuffer
The GameWorks OpenGL samples all share a common app framework and certain user interface elements, centered around the "Tweakbar" panel which lets you interactively control certain variables in each sample.
To show and hide the Tweakbar, simply click or touch the triangular button positioned in the top-left of the view.
Other controls are listed below:
The sample loads multiple terrain texture images into a single texture array. Multiple images are loaded from individual texture files. The texture array is populated with calls to glTexImage3D
and glTexSubImage3D
.
The vertex program computes the texture co-ordinates. It computes a texture array slice based on the height of the terrain. It also computes a factor that represents a cliff texture on steeper slopes.
The fragment program samples the texture array twice to fetch two adjacent array slices and linearly interpolates between them. It also fetches the cliff texture slice and interpolates between the cliff and the previous result.
Figure 1 illustrates the blending, most obviously in the foreground at the right hand edge. There is a blend between three layers based on height: green grass, brown dirt and white snow; the snow doesn't blend in fully in the foreground and the result is mid-grey. The dark grey cliff texture is also visible at the top-right of the image where the terrain angle is more vertical.
The terrain rendering could be further optimized in several ways:
GL_HALF_FLOAT_OES values
. There would probably be no loss of visual fidelity for a significant reduction in bandwidth.There is a significant amount of sample code that exists to generate a terrain height field. This is not strictly necessary to enable the texture array technique. However, a plausibly realistic height field is required. We have not made strenuous efforts for true realism.
The height field and normal vertex attributes are technically dynamic because they change in response to changes in the GUI sliders. If this code were being deployed in a game terrain engine, the terrain would be strictly static (in the absence of terrain deformation which we are not attempting to demonstrate). Hence, we do not attempt to optimize for the case of dynamic terrain updates beyond keeping the app interactive. Optimal dynamic VBO updates would be double-buffered so that the graphics driver does not stall waiting for the CPU to finish updating.
The TerrainSim
class is responsible for generating the height field, using fBm and ridge noise. The TerrainSimRenderer
class owns vertex buffer objects (VBOs) and the corresponding indices. The TerrainSimThread
class manages multiple threads, taking advantage of Tegra's multiple CPU cores to accelerate the height field generation in response to adjustment's on the GUI sliders.
NVIDIA® GameWorks™ Documentation Rev. 1.0.220830 ©2014-2022. NVIDIA Corporation and affiliates. All Rights Reserved.