In the process of integrating vtk with the CAVE environment, we found that vtk was not designed to be able to render the same geometry multiple times simultaneously to different channels (views). At first, I addressed this problem by modifying the source code for certain vtk classes in order to get them to work in the CAVE environment. This worked, but it was not a good design decision. Whenever the vtk library would change, as it did, I would have to redo the whole process. The solution was also very inefficient. It produced four identical yet separate vtk pipelines, one for each wall.
This initial experience taught me the importance of encapsulation. By breaking encapsulation and changing some of the vtk implementation, I lost some of the benefits of object oriented design.
We found that a better solution was to make use of another package to do the rendering. SGI distributes a toolkit called Perfomer that is widely used for 3D graphics (See Performer section). There is even a Performer version of the CAVE library (See pfCAVE section). Using vtk and Performer together allows the developer to get all of the visualization algorithms from vtk and all of the rendering advantages of Performer, such as multi-process rendering to multiple channels (views).
Plugging these two components together is not trivial. On the one hand, there is a vtk pipeline that generates geometry and on the other hand there is a Performer scene graph which is traversed whenever it is time to render. These two structures know nothing about each other. Then there is another issue about which component should control execution.
The solution is to develop a translator that translates the vtk geometry and creates a corresponding Performer structure and attaches it to the scene-graph. Vtk geometry is organized into an object called a vtkActor. Performer geometry is stored in a pfGeode. As for the issue of control of execution, vtk has an implicit control model, meaning that it updates the pipeline only when it is time to render and only re-executes the segments of the pipeline that are no longer valid. Since vtk is no longer doing the rendering itself, the Performer component has the control of execution and it is responsible for telling the vtk pipeline to update itself.
One approach is to use a function that explicitly translates a vtkActor to a pfGeode. While this works well, the function must be called explicitly whenever the Performer geometry needs to be updated in order to make it consistent with the vtk geometry.
A better approach is to create a translator object. This translator object knows about a particular vtkActor and a particular pfGeode. Since it is an object rather than a function, it can store state. In this case, the time of the last translation is stored so that it can be compared with the modification time of the vtkActor. Whenever the vtkActor changes, the pfGeode is automatically retranslated. The way this is accomplished is that the translator registers a callback with Performer that is called (on behalf of the pfGeode) before rendering. The callback checks to see if in fact the vtkActor did change since the last rendering, and retranslates if this is the case.
Figure 6.6: Diagram of how vtkActorToPFTranslator object works. The object has access
to a particular vtkActor and a particular pfGeode. The translator accesses the vtk
geometry through the actor's mapper. It deposits geometry into the pfGeoSets stored
in the geode.
Using this approach preserves vtk's implicit model of execution. For instance, you can simply change the iso value of an isosurface filter in the pipeline and you know that the change will cause the vtk pipeline to update itself and re-execute the isosurface algorithm. Then, before rendering, the new vtk geometry will automatically be translated and plugged into the Performer scene-graph.
This approach emphasizes object composition, making this a very flexible and reusable solution. The two toolkits work together simply by creating new types of objects (translators) that bridge the gap. After creating these objects, the toolkits work together and the translation is transparent.
The source code and examples can be obtained at the following web address:
http://brighton.ncsa.uiuc.edu/~prajlich/vtkActorToPF/