[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.9.10 Level of Detail

Written by Jorrit Tyberghein, jorrit.tyberghein@gmail.com. Last updated 13 August 2003.

In a 3D engine there are typically two major ways that can be used to optimize performance (aside from getting better hardware and making better use of hardware). Those two ways are Visibility Culling (see section Visibility Culling In Detail) and Level of Detail. In this section we will talk about the latter.

Level of Detail (or LOD) is the technique of reducing high polygon models with a simpler representation that renders faster. In contrast with visibility culling, level of detail can performance even if there are a lot of objects visible at the same time. Level of Detail is practically the only way to improve performance in situations where there is not much culling opportunity (like in a space game).

Crystal Space currently supports three kinds of LOD:

In future we will also support other kinds of LOD like imposters.

Also in future there will be a LOD manager. At this moment LOD is purely distance based but for a given distance the level of detail will not change. A LOD manager can decide to reduce the lod levels for certain objects in order to improve overall performance.

Static LOD From Map File

Using static LOD from a map file is fairly easy. Here is an example:

 
<meshobj name="loddy">
  <nullmesh>
    <min x="-1" y="0" z="-1" />
    <max x="1" y="2" z="1" />
  </nullmesh>
  <staticlod>
    <distance d0="100" d1="10" />
  </staticlod>
  <meshobj name="loddy_lowdetail">
    <lodlevel>0</lodlevel>
    ...
  </meshobj>
  <meshobj name="loddy_mediumdetail">
    <lodlevel>1</lodlevel>
    ...
  </meshobj>
  <meshobj name="loddy_highdetail_upper">
    <lodlevel>2</lodlevel>
    ...
  </meshobj>
  <meshobj name="loddy_highdetail_lower">
    <lodlevel>2</lodlevel>
    ...
  </meshobj>
  <move>
    ...
  </move>
</meshobj>

Let's explain what this example does in more detail. First we define a mesh object called `loddy'. This is the parent mesh which represents the actual model but on itself contains no geometry. So that's why we use `nullmesh'. The box given in the nullmesh is important as it is used for visibility culling. So you should make the box larger then any of the objects inside it. Also the center of the box is used for calculating the distance between the box and the camera.

Internally LOD uses a function to calculate a detail value betwen 0 and 1 (0 meaning lowest detail, 1 meaning highest):

 
float lod = m * distance + a;

The result of this function is capped so it is always between 0 and 1.

Inside the `staticlod' block you can directly specify the `m' and `a' values but it is often easier to use a short-cut and specify `d0' and `d1' instead. In the example above we set `d0' equal to 100 which means that at distance 100 and beyond we will go to lowest possible detail. We also set `d1' equal to 10 which means that at distance 10 or less the object will use highest detail. Internally `d0' and `d1' are transformed to `m' and `a' using the following equation:

 
float m = 1.0 / (d1-d0);
float a = -m * d0;

After this we have four child meshes representing the different detail levels. Using the `lodlevel' keyword one can place a child mesh at a LOD index. These indices always start at 0 for lowest detail and can go as high as you want. The maximum index that is used will be represented by detail level equal to 1.

Interesting in the example above is that there are two meshes for level 2. This means that at the highest detail level we actually use two sub-meshes to represent our mesh. Using this trick one can also use static lod to replace individual trees with collections of trees.

Note that it is also possible to define static LOD on a hierarchical mesh factory using the same syntax as described above. In that case one can use `meshref' to make an instance of that hierarchical factory (or use iMeshFactoryWrapper->CreateMeshWrapper()).

Note that it is also possible to use variables for `m' and `v'. One can do that like this:

 
<variables>
  <variable name="Lod M" value="-.1" />
  <variable name="Lod A" value=".5" />
</variables>
...
<staticlod>
  <distance varm="Lod M" vara="Lod A" />
</staticlod>

The advantage of this technique is that one can then use the same LOD values for different objects and modify them easily. Also one can modify the variables at runtime too with an immediate effect.

Static LOD From Code

Using static LOD from code is very easy. One basically has to create a hierarchical mesh, followed by a static LOD object and then the children which should be added to the right LOD level. Here follows an example which roughly does the same as our map example in the previous section:

 
csRef<iMeshWrapper> loddy_mesh = Engine->CreateMeshWrapper (
  "crystalspace.mesh.object.null", "loddy");
csRef<iNullMeshState> nullmesh = scfQueryInterface<iNullMeshState> (
  loddy_mesh->GetMeshObject ());
nullmesh->SetBoundingBox (csBox3 (
  csVector3 (-1, 0, -1), csVector3 (1, 2, 1)));

iLODControl* lodctrl = loddy_mesh->CreateStaticLOD ();
float d0 = 100;
float d1 = 10;
float m = 1.0 / (d1-d0);
float a = -m * d0;
lodctrl->SetLOD (m, a);

csRef<iMeshWrapper> loddy_lowdetail = ...
loddy_mesh->GetChildren ()->Add (loddy_lowdetail);
loddy_mesh->AddMeshToStaticLOD (0, loddy_lowdetail);
...
csRef<iMeshWrapper> loddy_meddetail = ...
loddy_mesh->GetChildren ()->Add (loddy_meddetail);
loddy_mesh->AddMeshToStaticLOD (1, loddy_meddetail);
...

Progressive LOD

To-Do... @@@


[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated using texi2html 1.76.