Terrain Tessellation Sample

Category:  Performance   Visuals
Min PC GPU: Fermi-based (GTX 4xx)
Min Tegra Device: Tegra K1


This sample shows how OpenGL hardware tessellation support can be used to implement a highly-efficient terrain engine that supports high geometric detail.

APIs Used

Shared User Interface

The OpenGL samples all share a common app framework and certain user interface elements, centered around the "Tweakbar" panel on the left side of the screen, 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.

Device Input Result
touch 1-Finger Drag Rotate the camera
2-Finger Drag Move forward (also controls rotation/heading)
mouse Any-Button Drag Rotate the camera
keyboard Escape Quit the application
  Tab Toggle Tweakbar visibility
  W/S, A/D Move forward/backward. Slide left/right.
gamepad Start Toggle Tweakbar visibility
  Right Thumbstick Rotate the camera
  Left Thumbstick Move forward/backward. Slide left/right
  Left/Right Triggers Move up/down

Technical Details

This sample demonstrates how to render a procedural terrain using OpenGL tessellation shaders, including automatic level of detail and culling.

It is not intended to show the optimal way of rendering terrain, but more to serve as a testbed for experimenting with tessellation shaders and different terrain heightfield functions.

Rendering Process

The code renders the terrain as a grid of patches, each of which can generate a grid of up to 64 x 64 triangles (this is the limit for the current tessellation hardware). The patches are rendered using instancing, using the glDrawArraysInstanced() function with a dummy vertex buffer. This means the whole terrain is rendered with a single draw call. The actual patch origin positions are then calculated from the gl_InstanceID in the vertex shader.

Level of detail (determining the tessellation level) and view frustum culling are performed in the tessellation control shader. Level of detail is calculated based on the projected screen size of a sphere fitted to each patch edge (as described in NVIDIA's DirectX 11 terrain tessellation sample, see link below). Culling is performed by testing the bounding sphere of the patch against the view frustum planes.

The terrain height is calculated procedurally for each generated vertex in the tessellation evaluation shader. Procedural noise is calculated based on a small 2D texture containing random values. The GLSL textureGather() function is used to read the neighboring texels in a single pass, so that custom smooth interpolation can be performed. Using hardware linear interpolation does not look as good, and has stepping artifacts at low frequencies due to the limited hardware precision (9 bits sub-texel).

The noise function is used is based on an advanced perlin noise article by Inigo Quilez (see link below). It uses the derivatives of the noise function to weight the noise octaves.

Surface normals for the terrain can be calculated in two ways: either by evaluating the terrain function at two additional neighboring points in the tessellation evaluation shader (if the "smooth normals" option is enabled), or per-triangle using the geometry shader (if "smooth normals" is disabled). The geometry shader method is usually slower on current hardware, and only calculates a flat surface normal.

Finally, the terrain color is calculated in the fragment shader, based on the height and normal.


The Tweakbar has several options and sliders to control various parameters.

See Also



NVIDIA® GameWorks™ Documentation Rev. 1.0.200608 ©2014-2020. NVIDIA Corporation. All Rights Reserved.