Level of Detail
When an object is far away from the camera, it inefficiently loads and renders a high resolution object just to get a few pixels on the screen. RenderMan provides us with a powerful level of detail tool that blends between multiple versions of a model, as it gets larger on the screen. This is an important tool for efficiently rendering large scenes with dense geometry.

The procedure for setting up level of detail is slightly involved, but boils down to deciding what resolution of model to show, at what size. The mechanism used for determining "size" is called RiDetailRange. RiDetailRange is specified as the total number of pixels the model's bounding box takes up on screen. A level of detail setup takes a series of overlapping RiDetailRanges which determine how the model transitions as it gets bigger on screen. An example LOD setup is shown below using Ri for MEL .
RiAttributeBegin;
RiDetail *bounding box values*;
RiDetailRange 0 0 1000 1600;
RiProcedural "DelayedReadArchive" "RIB_Archive/lowRes.rib" *bounding box values of low res*;
RiDetailRange 1000 1600 8000 20000;
RiProcedural "DelayedReadArchive" "RIB_Archive/medRes.rib" *bounding box values of med res*;
RiDetailRange 8000 20000 1e38 1e38;
RiShadingRate 1;
RiProcedural "DelayedReadArchive" "RIB_Archive/highRes.rib" *bounding box values of high res*;
RiAttributeEnd;
Inside an attribute block we first specify an overall RiDetail; the bounding box of our object in the current coordinate system. Then we have three levels of detail, hence three RiDetailRange calls. For each RiDetailRange, there is a call to a DelayedReadArchive that loads in the appropriate model. Also notice that we can modify attributes inside a RiDetailRange call. This allows us to change things such as shading rate or shaders for certain levels of detail.
Getting RiDetail
To calculate our RiDetail we need to find the bounding box of our high-res object. We need this to set up a ruler between the size of the object in render, so we know how big an object actually is versus how big it appears on screen.
There are two ways to get this: For single objects you can generate the scene RIB (Viewing Your Scene Rib) and steal the bounding box information from the DelayedReadArchive call which Studio generates automatically (see A RIB file line by line):
rman genrib
Then look for something similar to below:
TransformBegin
ReadArchive "renderman/paperclipObjs/rib/job/paperclipShape_0_attr.job.rib"
Procedural "DelayedReadArchive" ["file path to rib"] [-1.30112 1.38557 -0.11137 0.11137 -5.06764 4.95191]
TransformEnd
The bounding box is the set of six numbers at the end of the DelayedReadArchive call.
This is fine for single objects, but when you have multiple objects that may be in groups, it can be difficult to find a single collective bounding box from the RIB file. What you can do is run this script on the top node of the selected object. Make sure the transform is at the origin and has its scale frozen.
string $sel[] = `ls -sl`;
for($object in $sel)
{
string $curUnit = `currentUnit -q -linear`;
currentUnit -linear "cm"; // temporarily change to centimeters
float $bbSize[3] = `getAttr ($object + ".boundingBoxSize")`;
float $bbMin[3], $bboxMax[3];
$bbMin[0] = -$bbSize[0]/2;
$bbMin[1] = -$bbSize[1]/2;
$bbMin[2] = -$bbSize[2]/2;
$bbMax[0] = $bbSize[0]/2;
$bbMax[1] = $bbSize[1]/2;
$bbMax[2] = $bbSize[2]/2;
currentUnit -linear $curUnit;
print ($bbMin[0] + " " + $bbMax[0] + " " + $bbMin[1] + " " + $bbMax[1] + " " + $bbMin[2] + " " + $bbMax[2]);
}
Calculating RiDetailRange
This is the total number of pixels the object takes up on screen. If you have a model in the render view at the largest size you want the model to appear (before it blends to the next), you can save out the image, then take it into an editing program. Draw a marquee box around the object and note the number of pixels in both the width and height fields. Multiply these two numbers together. This will give you the number for one of your RiDetailRange values.

From the image above we see the marquee selection takes up 38 x 40 pixels; so in total we have 38 x 40 = 1520. This could be where we want the transition to begin. Hence in the RiDetailRange call we enter this as one of the numbers. We would then go further in our animation, repeating the process of taking a screen grab and calculating the number of pixels on screen.
Now let's dissect the command:
RiDetailRange[ minvisible lowertransition uppertransition maxvisible ]

So looking at two lines from the first block of code above, we can copy the numbers into the graph and tally them up.
RiDetailRange 0 0 1000 1600; RiProcedural "DelayedReadArchive Call"; RiDetailRange 1000 1600 8000 20000; RiProcedural "DelayedReadArchive Call"; RiDetailRange 8000 20000 1e38 1e38;
See Also
HowTos - Level Of Detail and Brickmaps For LOD
Production Examples - Working with Fur in Ratatouille
Library - Level Of Detail

