Volume Rendering Primer

HUB | Up | Download | Pheedbak | Tree | Topic | A-Z | Search | Hot | New


Volume Rendering Primer

Silicon Graphics Applications Engineering
September 19, 1995

The vrp binary in this directory
was compiled on an IRIX 5.3 ALL Indigo² High Impact.


What is the Volume Rendering Primer?

Volume Rendering Primer provides an example of hardware accelerated volume rendering on the Indigo² High Impact, Maximum Impact, Reality Engine, and Infinite Reality workstations from Silicon Graphics. Although the included binary was compiled with Irix 5.3 ALL IMPACT on an Indigo² High Impact workstation, it will also compile and run on the following:

The above list describes a minimum configuration for VRP. It will compile and build under Irix 6.2 on any of the above systems.

VRP was written for the express purpose of providing an easy to understand example of hardware accelerated volume rendering. It addresses the issues of lookup tables for volume feature enhancement and using embedded geometry within a volume using the depth buffer along with the fundamental approach necessary to visualize volumetric data using the available 3D texturing extensions of OpenGL.

All code specific to volume rendering is written in OpenGL. All code specific to embedded geometry is written in OpenInventor. The source to VRP is well documented.

How is a volume of data visualized in the VRP?

Volume visualization via OpenGL requires that a 3D texture is defined to represent the volume. Applications of volume rendering often require more data than the available texture memory will hold for a given workstation. The volume must be defined piecewise as a set of 3D textures.

In the simple case of a single 3D texture the information in the texture needs to be mapped to polygons that reveal the interior details of the texture. To create the polygons a spatial representation of the volume must be determined. How was the data acquired? How much space does it occupy longitudinally and laterally?

With the space determined a bounding box is defined for the volume. A mapping must be established between the spatial coordinates of the bounding volume and 3D texture coordinate space. Typically, the spatial coordinates vary greatly from one volume to the next, so a consistent mechanism for mapping these spatial coordinates to texture coordinates is imperative.

Texture coordinates can range from 0.0 to 1.0. Specifying texture coordinate values outside of this range will cause the texture to wrap which is an undesirable complication.

To simplify this, spatial coordinates must be rotated, translated, and scaled to map into the "0 - 1 Space" of the texture. In VRP, volumes are defined piecewise as a collection of images arranged in the Z direction. Z in spatial coordinates is analogous to R in texture coordinates.

Given this "R" arrangement of a texture, the S (X) and T (Y) dimensions of the texture are fixed. VRP assumes square images (i.e. S = T). The R dimension of the 3D textures that compose a volume of data is determined by the available texture memory (i.e. how many S by T images will fit in the available texture memory).

Once the R dimension (number of slices) of the "slabs" of texture data is calculated from available texture memory, a spatial representation of the slabs may be determined. For instance, assume that the available texture memory will hold 16 256x256 images. Also assume that the entire volume to be visualized is 256 slices of image data. If the original span of the slices of data in Z is 1 unit per slice, or 256 units in our case, we have a volume that in OpenGL modelview space, occupies a unit cube.

Mapping 0.0 in R to slice 1 in Z and 1.0 in R to slice 256 in Z, similarly for S and T, will give us the one to one mapping. Each 16 slice slab would occupy 16/256 or 1/16 of texture coordinate space.

If the volume were to remained fixed in space, we would be done. The mapping from modelview space to texture coordinates would be a simple one to one mapping. A static volume, however, is not particularly useful.

The volume can of course be rotated, translated, or scaled. The problem inherent in this is that the transformed bounding vertices of the volume can easily reach outside of the desired 0-1 coordinate space of textures.

To make full use of the defined texture, texture coordinates must range from 0 to 1. The OpenGL texture matrix serves as a mechanism to map the texture coordinates to the transformed spatial coordinates of the volume. A rotation, translation, and scale are loaded onto the texture matrix. Each of these transformations effectively undoes the transformations done by the user or the inherent scale factor of the data to map the bounding coordinates of the slab back into 0-1 space.

A good example of one of these "undo" operations is loading the inverse of the modelview matrix onto the texture matrix to undo the rotation of the volume. Another example, in our case of the 16 slice slab, is a scale factor of 16 to be loaded on the texture matrix. If this scale factor was not loaded on the texture matrix, the spatial to texture coordinate mapping would only use 1/16 of the defined texture resulting in a partial rendering of the volume.

Once the volume is mapped into 0-1 space a set of polygons can be created to render the volume. Typically, a volume is visualized from back to front in z. A set of simple plane equations in the form; z = 1.00, z = 0.99 ... z = 0.00 is used to intersect the volume at small intervals in z. The intersection of these planes with the transformed bounding box of the volume creates the defining polygons for the volume. VRP handles this intersection of polygons on a per slab basis.

Once the work is done up front to prepare the texture matrix, rendering the volume is a simple matter of drawing the set of intersection polygons and applying the same texture coordinate for each vertex as the spatial coordinate for that same vertex.

Features of the VRP

VRP will render 1 or 4 channel volumetric data stored in SGI image format along with embedded geometry in Open Inventor .iv format. One channel image data is interpreted as medical CT data and a corresponding set of medical lookup tables are employed with such volumes. Four channel data has an associated set of lookup table controls in the from of a red, green, blue, and alpha gain.

Three compositing modes are supported; Blend, Maximum Intensity Projection, and Minimum Intensity Projection.

The two interpolation types: Nearest Neighbor and Linear are provided for comparison.

VRP allows control of the number of defining polygons for the volume. The quality and speed of the volume rendering is directly tied to the number of defining polygons which is determined by the size of the intervals in Z. These polygons may be displayed along with the volume rendering by selecting "Show Polygons" from the options menu.

A performance test option is provided because it is expected that users of VRP will be modifying the source, recompiling, and executing on a variety of platforms.

All of the transformation fields will activate a rendering of the volume when "Enter" is pressed when they have focus. This becomes a very important feature with large volumes where interactivity in the rendering window is poor. The cadaver data set is a good example of such volume.

Using VRP

Loading Volume Data

VRP includes three volume data sets and two geometry files. The volume data sets are: headData, cadaverData, and rainSphere. The geometry files are flyer.iv and mauler.iv. HeadData and cadaverData are single channel medical computed tomography scans. RainSphere is a four channel computer generated data set.

The rainSphere data set was created by a small program called createRGBA that is included with VRP. See the createRGBA directory and associated README.

To load a volume into VRP select "Volume..." from the file menu. Select from one of the 3 available volume files that are suffixed with ".vrp". These are ASCII files with a list of file names included in the data set. When a volume is going to be loaded, VRP will request the number of slices desired and the span in Z units in which the data was acquired. VRP will make a guess that the span in Z is the same as the total number of slices in the .vrp file, or a 1:1 ratio. A 1:1 ratio of slices to span will work for both the cadaver and rainSphere datasets. HeadData requires a ratio of 1:2 so the default span of 64 should be changed to 128.

Loading Geometry Data

To load a geometry file into VRP, select "Geometry..." from the file menu. VRP understands geometry files that are Inventor's ".iv" format.

Manipulation of volume/model Each of the three mouse buttons plays a part in manipulation of the volume. The left mouse button will tumble the volume. The middle button will translate the volume. The right button will scale the volume.

Options

Performance test will pass the volume through 360 degrees of rotation in 4 degree increments. A full revolution is necessary because the viewing angle will determine the number of intersecting polygons in the volume. Therefore to get a good representative sample of performance, a full rotation is required. Note that this can take up to a few minutes depending on the size of the volume and the hardware used to render it.

Show Polygons will render the outlines of the polygons that define the volume. Increase and decrease the number of slices to see the affect on the polygon outlines. The slab outlines will be drawn in a dark blue and the polygon outlines will be drawn in a lighter transparent blue.

Source Description

There are 9 source files included in the Volume Rendering Primer:

vrp.c++

Contains the main routine, drawing area widget creation/callbacks/input, and coordination of slab definitions for reading volume data.

slab.c++

Defines a class for slabs in the volume. Slab methods include: reading, polygon intersection, texture initialization/definition, and drawing. Slab.c++ contains the core of the logic required to do volume rendering through OpenGL.

geometry.c++

Has initialization and drawing routines for the Inventor scenegraph created from the specified geometry file.

drawScene.c++

Coordinates the drawing of volume data and geometric data. Calls the appropriate slab methods to prepare a slab for rendering.

tlut.c++

Handles lookup table functionality for one channel and four channel data. Tlut.c++ has logic to account for differences between Impact texture lookups and RE/IR texture lookups.

ui.c++

Has all user interface and callback routines.

menu.c++

Convenience class for creation of Motif menus.

matrix.c++

Contains one function for inversion of matrices.

progress.c++

Convenience class for providing progress status of lengthy operations.

Headers:

Compilation Notes

Three macro definitions are present in the source to VRP: IMPACT, USE_GEOMETRY, and USE_BIND.

IMPACT is used primarily to account for differences in texture lookups between RE / IR and IMPACT. On RE and IR, there are texture lookup tables for Red, Green, Blue, and Alpha. On Impact there are texture lookup tables for Red, Green, and Blue only. The Alpha lookup on Impact is handled through the geometry engines via the glPixelMap interface. This type of lookup requires the textures to be downloaded from host to texture memory in the event that the alpha lookup table is changed.

USE_GEOMETRY is defined because embedded geometry requires depth buffering. Depth buffering requires a different visual than the standard doublebuffered RGBA visual without depth buffering. On High Impact, color bits may be sacrificed for depth bits so the color depth without embedded geometry will be higher than that with embedded geometry.

USE_BIND employs the glTextureBind extension to improve the performance of the volume rendering. Texture binding creates a copy of voxel data in host memory. Host voxel memory can then be freed. There is one catch to this however, alpha lookups require a download from host to texture memory. If bindings are used along with alpha lookups, the original host copy of the voxel data may not be freed. In this case, the binding must be established via glBindTextureEXT and a download must be forced subsequently with glTexImage3DEXT or glTexSubImage3DEXT.

A considerable performance difference can be realized on Reality Engine 2 and Infinite Reality systems by building vrp with USE_BIND defined.

General Notes

VRP assumes that voxel image data is stored as square images. These images may be up to 512x512 on Impact or larger on RE/IR. The 512x512 constraint on Impact is present because of the method that VRP uses to handle seams between slabs of voxel data. The seaming strategy is to share a slice of image data from an adjacent slab in the volume therefore requiring a minimum slab size of 2. The largest single channel texture on Impact can be 1 MB in size. Two images that are 1024x1024 x some number of channels will exceed this limit.

The seaming strategy for hardware accelerated volume rendering is required to prevent interpolation with zero texture data. On the outside boundaries of the 3D texture there is one side of the texture that will get interpolated with zero texture data (i.e. the border pixels) if no seaming strategy is employed. This causes a darkened region or seam between each set of adjacent slabs.

To counter this seaming effect, each slab shares a single slice from one adjacent slab. This shared slice is used to interpolate across on both edges of the adjacency to prevent seams. Each slab is scaled down in texture coordinate space 1/(the number of slices in the slab). The texture is then biased by 1/2 the scale amount to center it. These scale and bias values are applied to the OpenGL texture matrix.

Scaling and biasing the texture values via the texture matrix has the effect of constraining the range of texture coordinate values to some subrange of 0.0 and 1.0 depending on the size of the slab. By constraining this range, textures are interpolated across defined texture values and not with the zero border pixels.

Author: John Rosasco, jdr@sgi.com



Files of interest from "src/exampleCode/volumeRendering/vrp" directory

Documentation

Reference

Subdirectories


Select any combo of files you'd like to send yourself a compressed tar image of. Executables/scripts are indicated with a trailing `*' character. (Depending upon the browser, it may be necessary to hold down the Ctrl key to select/deselect disjoint items.) a compressed tar image of the above-selected items.
OR, ...
a compressed tar image of the entire vrp directory.

Copyright © 1996, Silicon Graphics, Inc.