LOD chunked rendering

by in A game engine
Tagged: LOD | Octree

A naive approach in rendering the chunks in a view frustum would result in this example in about 230 chunks.


We can take advantage of the perspective, and render chunks at different level of details based on the distance to the camera.

In the above example, we can considerably reduce the number of chunks to 17.

Because of the perspective, each chunk will have the same width on screen (one chunk wide in the example), so we should have a constant chunk density on screen space.


An Octree structure seems the perfect choice in building the chunk render list.

template <typename Data>
struct Octree {
    Data* value;
    vec3 center;
    float size;

    Octree<Data> *parent;
    Octree<Data> *children[8];

    int level; 
    int index; // child index in parent
    bool leaf;
};

Building the octree

  1. start from the biggest cell that contains the complete view frustum
  2. determine LOD based on distance to frustum
  3. if current cell level == computed LOD, then add chunk to render list
  4. if current cell level < computed LOD, iterate children

1. Determine the start cell

For the first time, we start from an arbitrary cell in the octree.

From here, we keep zooming out the octree (by navigating the parents) until our cell contains the whole view frustum.

while (!chunkContainsCube(chunk, cameraPos, viewDistance)) {
    c = c->getOrMakeParent(CHILD_LEFT_DOWN_BACK);
    c = c->getOrMakeParent(CHILD_RIGHT_UP_FRONT);
}

While zooming out, we create 2 levels in the Octree, to ensure that we enlarge on all dimensions:


Next, we check if we can zoom in, by checking if any of the children contains the frustum completely.

again:
for (Chunk* c : chunk->children) {
    if (cubeContainsChunk(cameraPos, viewDistance, c)) {
        chunk = c;
        goto again;
    }
}

Now we have determined our start octree cell for building our render list.


Results

Here are the chunks rendered in our engine:

Only the chunks crossing the y=0 plane.
All chunks

Also read:

  • So, I've been having fun with some OpenGL, I'm working on a terrain engine, we'll see where it goes... So far, I've got: voxel terrain renderer, tesselated with marching cubes. the signed density function is generated from a few octaves of simplex noise. multithreaded chunk generation and tesselation with no world bounds. triplanar mapping...