Skip to content

Terrain

The Alire crate orka_plugins_terrain provides packages to render adaptively tessellated terrain of a planet on the GPU.

  • Updates and renders multiple terrain tiles.

  • Supports flattened spheroids with warping to reduce RMSE when projecting cubes on spheres.

  • Can optionally display a wireframe on top of the rendered terrain.

Info

The various objects described on this page are declared in the package Orka.Features.Terrain and its child packages.

Creating the terrain

To render the terrain, first create a location object to find the height map and shader to render the terrain:

Location_Data : constant Locations.Location_Ptr :=
  Locations.Directories.Create_Location ("data");

The location Location_Data should contain the directory terrain/. This directory should contain the file terrain-dmap.ktx, a height map, and the file terrain-render-atmosphere.frag, a fragment shader to render the terrain. This fragment shader should implement the function vec4 ShadeFragment(vec2 texCoord, vec4 worldPos). The height map should contain a red channel of type Unsigned_16.

Next, create a Terrain_Planet object by calling the functions Create_Terrain_Planet in the package Orka.Features.Terrain.Planets:

Atmosphere_Manager : Orka.Features.Atmosphere.Rendering.Atmosphere :=
  Orka.Features.Atmosphere.Rendering.Create_Atmosphere
    (Context, Earth, Atmosphere_Textures, Location_Precomputed, Earth_Parameters);

Terrain_Manager : Planets.Terrain_Planet := Planets.Create_Terrain_Planet
  (Context           => Context,
   Min_Depth         => 6,
   Max_Depth         => 20,
   Wireframe         => True,
   Initialize_Render => null,
   Data              => Earth,
   Parameters        => Earth_Parameters,
   Atmosphere        => Atmosphere_Manager,
   Location_Data     => Location_Data,
   Height_Scale      => 8848.0 + 11_000.0,
   Height_Offset     => 11_000.0);

See Atmosphere on how to create the parameters used in the call of function Create_Atmosphere.

The maximum tessellation is controlled by the parameter Max_Depth. Increase this constant to further subdivide the terrain. However, older GPUs might not be able to handle values greater than 20.

If Wireframe is True, then optionally a wireframe can be displayed when rendering the terrain. In production, this parameter should be set to False to avoid invoking a geometry shader.

The parameters Height_Scale and Height_Offset should be adjusted depending on the height map which is used.

A maximum depth of 20 might be too low

Intel GPUs cannot handle very large max terrain subdivision levels, which limits the maximum terrain resolution. Discrete GPUs might be able to handle larger values. A value of 20 gives a resolution of about 2 km per triangle for Earth.

Configuration

To adaptively tessellate terrain, some parameters are needed which specify how much the terrain should be tessellated:

Terrain_Parameters : constant Subdivision_Parameters :=
  (Meshlet_Subdivision  => 3,
   Edge_Length_Target   => 16,
   Min_LoD_Standard_Dev => 0.00);

Rendering

To render the terrain, create a frame graph with the function Create_Graph and connect it to your main frame graph:

Terrain_Graph : constant Orka.Frame_Graphs.Frame_Graph :=
  Terrain_Manager.Create_Graph (Resource_Color.Description, Resource_Depth.Description);

Resources_Terrain : constant Orka.Frame_Graphs.Resource_Array :=
  Main_Graph.Connect (Terrain_Graph, [Resource_Color, Resource_Depth]);

The variable Resources_Terrain contains two resources to which yet another frame graph can be connected. Finally, create a Renderable_Graph and call its procedure Render to render the whole frame graph.

See Frame graph for more information on how to build and render a frame graph.

Updating the state

Each frame, before presenting one of the resources of the frame graph, update the state of the terrain by calling the procedure Set_Data:

use Orka.Transforms.Singles.Matrices;

Terrain_Manager.Set_Data
  (Rotation      => Rz (-Orka.Float_32 (Earth_Parameters.Axial_Tilt)),
   Center        => Translate_From_Camera_To_Planet,
   Camera        => Camera,
   Star          => Direction_From_Planet_To_Star,
   Parameters    => Terrain_Parameters,
   Freeze        => Enable_Terrain_Freeze,
   Wires         => Enable_Terrain_Wires);

The parameter Rotation should be a Matrix4 describing the desired rotation of the planet. The parameter Center should be a Matrix4 describing the translation from the camera's view position to the center of the planet, divided by Earth_Data.Length_Unit_In_Meters:

T ((Planet.Position - Camera.View_Position) * (1.0 / Earth_Data.Length_Unit_In_Meters)`

See Transformations for more information.

The parameters Freeze and Wires control whether the terrain must be updated when the camera changes its position and whether a wireframe must be shown.

Querying visible tiles

The function Visible_Tiles of Terrain_Manager can be called to query which tiles are visible and which are hidden. The function returns an array of six booleans.

Screenshots

Triangle culling of terrain is based on the frustum and the distance from camera:

Culled terrain

Increase the minimum level of detail (LoD) variance to reduce the number of triangles on flat terrain:

LoD