A number of OpenGL Volumizer application examples are included in /usr/share/Volumizer/demos/Volumizer. They include an extensive set of OpenGL, Open Inventor, and IRIS Performer samples. In addition, a set of utilities for voxel data manipulation is provided in /usr/share/Volumizer/util as described earlier.
It should be noted that all the examples were intended as an illustration of a specific feature of the API and are thus kept rather simple. No full-featured viewer is provided at this time.
There are a number of examples provided here that illustrate the use of Volumizer in the framework of an OpenGL application. They all share a common structure and much of the source. For example, most of the examples share the same main() routine (to be found in voglMain.cxx). This is done in order to emphasize the similarities and differences, to facilitate code reuse, and to provide consistent user interface for all examples. The next section discusses the common structural elements.
All the programs define five functions: my_InitAppearance(), my_InitGeometry(), my_InitGfx(), my_DrawVolume(), and my_Cleanup(). The contents of these functions vary from application to application, but their purpose remains the same:
my_InitAppearance() parses the command line arguments for input file name, selects optimal parameters for representing voxel data, creates an instance of voBrickSetCollection, reads and converts the data. It is called from main().
my_InitGeometry() creates an instance of voIndexedTetraSet to represent the region of interest of the volumetric object to be rendered. It also allocates storage for transient geometry (voIndexedFaceSet) produced during the polygonization stage. It is called from main().
my_InitGfx() performs certain types of initialization and optimization on the voxel data (e.g., creation of texture objects) that require the graphics context to be present. This is also where the lookup tables get initialized. It is called once the connection to the server is established (e.g., from the Expose callback).
my_DrawVolume() is called for every frame to polygonize the volumetric shape and draw the resulting geometry.
my_Cleanup() is called once the application is done with the volume and wants to reclaim the system resources (e.g., memory, texture objects, etc.).
For example, voglSimpleMain.cxx and voglSimpleVolume.cxx illustrate the above routines in action in a minimalist fashion. This is the smallest self-contained example. However, the resulting application, voglSimple, has very limited capabilities.
All the remaining examples share a substantial amount of code. In particular, they share much of the implementation of the user interface. For example, dragging the left mouse button causes all applications to rotate the scene around its center. Similarly, middle mouse button will modify the current transfer function using the cursor position to determine the center and width of a grayscale linear ramp (-lutFile on the command line disables this feature, as described below).
All the applications, except as noted below, take a single command line argument, which is the name of the 3D TIFF file containing the voxel data. Sample data sets in this format are provided in Volumizer/data/volumes/. Look in Volumizer/data/volumes/*/README for detailed format description. voglRaw takes as argument a list of file names of a sequence of 2D images stored as raw voxel streams. A sample data set in this common format is provided in Volumizer/data/volumes/*/raw.
It is also possible to generate a simple 3D test pattern consisting of an array of cubes with varying density. Volumizer/util/mkcubes was provided for this purpose. It creates output in form of a 3D TIFF file. For example:
mkcubes 128 128 128 32 |
will create a volume 128 units on the side filled with a series of 8 cubes (each 32 units on a side) of varying density.
All sample applications take the same set of command line options. These are:
-2D -- render using 2D textures (default is 3D if supported)
-3D -- render using 3D textures
-color -- render in RGBA mode (default is monochrome)
-dataRange %d %d --specify the dynamic range of your data
-lut %d %d -- generate a grayscale linear ramp with center and width
-lutFile %s -- read in the transfer function from a file
-monochrome -- render in grayscale mode (saves memory and bandwidth)
-tessellationSize %d -- for voglSpaceLeap the size of the adaptive subdivision
The options can come anywhere on the command line and can be abbreviated (ambiguity resolved in lexicographic order, e.g., -lu expands to -lut not -lutFile). Individual programs are discussed below. All programs are executed with the following command:
program volume.tif |
unless indicated otherwise. Consult the README file in the demo directory for specific instructions and options use.
voglBasic is a version of voglSimple extended to use a lookup table, parse the command line arguments, and select different options. Typical invocations include:
voglBasic volume.tif voglBasic volume.tif -2D voglBasic volume.tif -color voglBasic volume.tif -color -lutFile lookup.table |
Sample lookup tables are provided in Volumizer/data/tables.
voglCache replaces the contents of the basic my_DrawVolume() modifying it to use transient geometry caching from frame to frame in order to amortize the cost of polygonization. In addition, it uses a call to voGeometryAction::drawUtility() which is a high level utility function that will try to draw the volumetric object efficiently. While this utility simplifies the volume rendering code even further it has one drawback: drawUtility() does not have precise semantics associated with it and may change in future releases. Applications that rely on the specifics of the rendering process may want to exercise more control by adopting the more explicit version provided by voglBasic.
This application provides functionality identical to that of voglCache. However, it accepts input from a list of files of raw 2D images, instead of a single 3D tiff file. By a “raw” 2D file, we mean a voxel stream in row-major order possibly proceeded with a fixed length header. File names, image sizes, header length, and voxel data type are specified on the command line:
voglRaw 0 256 256 128 ushort -dataRange 0 4095 -lut 135 155 vol*.ima |
All the previous examples use a single cube matching the voxel array in size as geometry. voglSpaceLeap replaces the content of my_InitGeometry() to tessellate the volume into a large number of small sub-cubes. The sub-cubes that are empty (outside of the data range of interest) are discarded, and the adjacent non-empty sub-cubes are coalesced to reduce the number of tetrahedra in the scene (each cube is still represented as 5 tetrahedra). The size of the sub-cubes and the voxel range are specified on the command line:
voglSpaceLeap volume.tif -tess 8 40 255 |
The results are shown below.
All the previous examples specified the vertex data in V3F format, thus implicitly assuming that the voxel and vertex coordinates be identical. voglMorph replaces the contents of my_InitGeometry() to explicitly specify the voxel coordinates on per-vertex basis. If the mapping between the vertex and voxel coordinates is not an identity, the rendered volume appears warped. Consult the figures below.
voglSphere replaces the content of my_InitGeometry() to define a spherical region of interest. Extended volumetric primitives are used for that purpose.
voglPick illustrates Volumizer's ability to pick individual voxels from within the volume. Press the right mouse button to select the line of sight through the cursor. A signal corresponding to the values of voxels along this line is drawn at the bottom of the screen. See the figure below.
voglShade modifies the my_DrawVolume() routine to apply per voxel shading using the tangent space method (Brian Cabral, SIGGRAPH97). Each slice is drawn twice using slightly different texture coordinates to effectively compute the component of the gradient along the light vector. Use the right mouse button to move the light vector around.
voglUnstructured virtually eliminates my_InitAppearance() in order to render unstructured grids: a tetrahedral tessellation with per-vertex colors but no texture associated with it.
voglMirror illustrates multi-pass rendering of a heterogeneous scene containing both surface and volume objects in order to accomplish special effects such as reflection and refraction. The scene is rendered twice, once from the imaginary and again from the actual eye position and the results are combined. Use the left mouse button to tilt the scene and the middle button to move the sphere around.
These two programs illustrate drawing of Multi-Planar Reconstructions (MPRs) or cross sectional images on stacks of 2D images. This code is useful for efficiently computing oblique slices through volumes on machines that do not support 3D texture mapping efficiently. voglMPR1 slices the volume with a plane, while voglMPR2 with a couple of polygons.
A set of examples that use Open Inventor as the underlying software platform is also provided. Their main purpose is to illustrate how to integrate the functionality provided by Volumizer with the retained mode framework of Open Inventor. Note that this is not an endorsement of Open Inventor as a viable development environment for new applications; these examples are provided solely to illuminate Volumizer to existing and past Open Inventor users.
OpenGL Volumizer operates in the immediate mode characteristic of OpenGL. In order to take advantage of its volume rendering capabilities in an Open Inventor environment we have to extend the core set of classes and traversal methods provided by Inventor.
In the simplest case, we have to implement two classes to represent a volumetric object: one to represent geometry, the other, appearance. These are voivGeometry and voivAppearance respectively. voivGeometry will be subclassed from soShape, and voivAppearance from soNode, becoming a part of the current state. In addition, we will also need voivAppearanceElement which will be derived from SoReplacedElement and which will be used to get the volume appearance from the current state.
voivViewer is an application that uses these two classes to implement a simple volume viewer. It is essentially identical to ivview (it is possible to build a shared library from the objects provided and convince ivview to load them as well) capable of displaying volumetric objects. voivViewer takes a single command line argument that is a file in an Open Inventor format. Sample input files were provided in /usr/share/Volumizer/data/Inventor. For example:
voivViewer Simple.IV |
voivFreeFormDeform is another application that builds on the Open Inventor classes previously described. It illustrates Volumizer's ability to clip the volumetric model to arbitrarily shaped surfaces and to accomplish free form deformations of volumes. In order to grab on a vertex press ESCAPE key or click on the “arrow” button in the upper part of the right panel on the viewer.
In the first mode of operation, voivViewer takes as input the same input file as voivViewer (i.e., V3F vertex format):
voivFreeFormDeform Simple.IV |
Grab one of the vertices outlining the volume's geometry (drawn as a yellow wireframe) and drag it around. If you move the vertex towards the center, the surfaces of the distorted geometry will act as clipping planes as shown above.
In the second example, the input volume uses T3F_V3F per-vertex data:
voivFreeFormDeform UniformT3F.IV |
Dragging a vertex will cause the volume to morph:
A sample implementation of a Performer volume node is also provided. The executable takes a single command line argument that is the path to a 3D TIFF file containing the voxel data.
perfvol volume.tif |
Use the left, middle, and right mouse buttons to translate, rotate, and scale the model respectively.