## Runtime Selection of Chunks to Draw

With the ChunkTree available, it’s just a matter of selecting the right Chunks to draw. This happens every frame and is dependend from the camera.

First, a quick definition of the term “screen space error”: This is the approximated difference in pixel between the drawn original model and the simplified one used for level of detail [Lue02, P. 54].

The method is similar to the one of Ulrich. By traversing the tree, each Chunk gets checked. When its current screen space error of the node is smaller or equal to a defined, tolerated one, it gets drawn and the traversal stops here, the children are not visited anymore.

A screen space error gets calculated with the previously defined maximum geometric error $\delta$ of the chunk, the distance D to the camera, the height of the viewport viewportHeight and the vertical opening angle of the camera fovY [Ulr02, P. 6-7]. $\rho = \frac{\delta}{D} \cdot \frac{viewportHeight}{2 \cdot \tan \frac{fovY}{2}}$

Ulrich uses the width of the viewport and the horizontal opening angle. This is different here, because OGRE3D doesn’t offer a horizontal camera opening angle directly and it doesn’t make a difference.

In addition to Ulrich, D can’t be smaller than 1. If so, the result would be very big or even a division by zero could happen in case of zero when the camera would be exactly in the center of the Chunk.

Luebke gives the relation for the screen space error of the formula above: $\frac{\delta}{w} = \frac{\rho}{viewportWidth}$

w is the width of the Chunk. Figure 1 shows the vertical camera opening angle $\alpha$ and image width w with the camera distance D.

Given this, you can calculate w with this formula: $\tan \frac{\alpha}{2} = \frac{\frac{w}{2}}{D} \Rightarrow w = 2 \cdot D \cdot \tan \frac{\alpha}{2}$

w can be inserted in the relation which is then shifted to $\rho$ [Lue02, P. 54].

Given that, we can chose which Chunks to draw on each rendered frame. See this pseudocode of its memberfunction “setChunkTreeVisible()”:

setChunkTreeVisible() {
if (invisible) {
return true;
}
d = distance(cameraPosition);
if (d < 1.0) {
d = 1.0;
}
screenSpaceError = chunk.error / d * (camera.viewportHeight
/ (2.0 * tan(camera.fovY / 2.0)));
if (screenSpaceError <= maxPixelError) {
setVisible(true);
} else {
setVisible(false);
if (children) {
setChunkTreeVisible(children);
if (children) {
children.setChunkTreeVisible();
children.setChunkTreeVisible();
children.setChunkTreeVisible();
children.setChunkTreeVisible();
children.setChunkTreeVisible();
children.setChunkTreeVisible();
children.setChunkTreeVisible();
}
} else {
setVisible(true);
}
}
}


This is the selection of Chunks to draw depending on the camera position. First of all, the recursion is stopped, when the invisible flag of the current Chunk is true indicating this Chunk doesn’t contain any triangles.

Then, the current screen space error is calculated and tested against a maximum tolerated one. If the calculated screen space error is smaller, the Chunk is drawn and the recursion stops. Else, a check is done whether this Chunk is a leaf of the tree. If so, it is drawn. Else, the process starts recursively with it’s children. Note that there might be only one child if the current Chunk is one level above the leafs.

And that’s it, this way, the volume is drawn with a Level of Detail mechanism! If you like this work and want to support it, feel free to donate something or click on any Flattr button!