Quadtree LOD subdivisions

The terrain mesh is using a quadtree lod mesh to sustain performance and detail across large terrain.

Concept

The terrain starts as one entity which represents the entire terrains. This terrain entity has a grid mesh that us being used to present the terrain. When the camera gets close enough to the terrain’s bounds, the terrain gets disabled and four child terrains are created instead. Each child terrain has the same mesh resolution as the “parent” terraub, effectivly quadrupling the total resolution. Each newly created terrain fills up a quarter of the parent terrain, leaving no gaps between. When the camera gets far enough away again, the four child nodes are removed again and the source node gets enabled.

This whole process gets repeated for the child nodes, allowing them to also be split up when the camera gets close enough to them, creating a detail mesh only where the camera is close enough. With each subdisivion, the lod level is increased, until the maxLOD property value has been reached.

Implementation

The lod level increases/decreases are handly by the QuadtreeLODSubdivisionSystem. At the start of the game, the distance at which each terrain node/chunk is being split up is gather. The distances are defined as a list in the OrbisInterface.

The center of where the terrain should be at it’s highest resolution if using the camera position (which is gather by calling Camera.main. If not main camera is defined, you’ll need to implement another approach, as the system will run into errors.

Subdividing

If the distance between the camera and the bounds of a terrain chunk is lower than the lod distance defined for the chunk’s lod level, the terrain chunk will be split up into four smaller chunks, and the renderer of the original will be disabled. The newly created chunks are copies of the parent, with slightly altered paremeters. If custom components are added to the root terrain entity, they’ll also be present on all child chunks of that terrain entity.

Merging

When a chunk has already been split up, and the camera gets far enough away from it again, the chunk will be enabled again. The children that were created from that chunk will also be removed. To avoid flickering when moving at the edge of a LOD distance, the distance threshold to merge meshes is multiplied by 1.05.

Collision invokers

To allow physics on the terrain to work even if the camera is not close enough for the collision LODs to be generated, Orbis uses collision invokers. A collision invoker is an entity with a CollisionInvokerTag on it. Collision invoker are handled by the terrain subdivision system like another camera. The chunks will always use the closest collision invoker or camera to calculate whether they need to be split up or merged again.

To keep the performance overhead of collision invokers low without them forcing large areas of the terrain to unneseccarily get generated, the distance thresholds are lowered for distance checks with collision invokers. This value can be modified to fit a projects needs. It can be found in the File QuadtreeLODSubdivisionSystem.cs, with the default value:

private const float collisionInvokerDistanceMultiplier = 0.15f;

Keep in mind that this is a DOTS asset, collider are integrated as DOTS physics mesh collider, and will only interact with dots physics bodies. GameObjects that are using RigidBody and Colliders based on MonoBehaviours will not work.