Wednesday, January 3, 2024

Notes on creating large landscapes in Unreal Engine 5.3

I'm currently working on my next project, a skiing VR game using Unreal Engine. Note there's no .net or F# involved in this post.

The process of creating a large landscape in Unreal Engine 5.3 wasn't a smooth experience for me for the following reasons:

  • Shadow issues when moving around the terrain. Someone else has encountered that problem and described it here.
  • Low-resolution textures, even after increasing the streaming pool size
  • Falling through the floor, or missing landscape sections

The first issue I can't seem to fix. The other two issues were due to a bug or lack of precision in the mechanism that loads and unloads far sections of the landscape, and I fixed them as described in the rest of this post.

Create new open world level

You can also create an empty level, but the open world template level has atmosphere and light already set up.

Import landscape from heightmap

To do this, switch to landscape edit mode, go to the manage tab, choose to create a new landscape, select heightmap file to import.

Side note: Use The Gimp to edit heightmaps, it can work with 16bit graylevel PNGs, which Unreal can use. Be careful to avoid software that is limited to 8 bits per color component such as Paint.NET. It's not suitable for manipulating heightmaps.

Delete initial landscape

To do this, you must be in selection mode, select all proxys under the landscape node, delete them, them delete the landscape node itself. One would expect that selecting the landscape node and deleting it would take care of the subnodes, but that doesn't work.

Set up world partition grid

A world partition grid controls how actors are loaded and displayed as the view point approaches them. By default, it's set for a small landscape. In particular, the range outside of which landscape components are not loaded is set to less than 1km by default. Initially, I didn't notice because the HLOD system (see below) filled in outside that range, but there would be issues with low quality of textures, lack of physics (the controlled character can fall below the ground) and issues with shadows.

In the world settings, create a grid with suitable sizes, i.e. a kilometer or so (1e5 units) for the cell size and a multiple of that for the load range. Name that grid something suitable, e.g. LandscapeGrid.

Use that grid for the imported landscape.

Build hierarchical levels of detail (HLODs)

Landscape proxy nodes are loaded and displayed according to the world partition grid. Nodes that are outside the loading range can display simplified meshes and materials instead to fill in the empty space and avoid mountains popping up suddenly as the view point moves forward. The problem is that since version 5, the editor creates the simplified mesh using the most detailed level of detail, i.e. LOD 0.

To work around this issue, in the LOD settings, set the screen size of the LOD 0 to something coarse, e.g. 1 instead of 0.5. This will (temporarily) force LOD 0 to a level of detail that would normally be more suitable for something like LOD 2.

Delete and then build the HLODs

Reset the LOD 0 screen size back to the smaller value (e.g. 0.5).

I got these steps from the video below.


An alternative is to delete the HLODs and force loading of all landscape proxy components. In my case, I don't see any benefits in using HLODs, although that might change as the project advances, I suppose.