VTK Painters

From ParaQ Wiki
Jump to navigationJump to search

The VTK Painters and associated components were developed as part of a collaborative effort between Kitware and Sandia National Laboratories.

For documentation on VTK Shaders please refer to VTK Shaders.


Overview

This document describes the implementation of the Painters in VTK. For the original design/motivation please refer to VTK Painters Design Wiki. Painters are used within a mapper. The design decomposes the tasks that a mapper needs to perform into several operations, each handled by a separate painter. The mapper creates a chain of painters, with each painter having at most one delegate painter. Each painter performs its operations and then delegate the rendering request to the delegate, if any.

Note that the current implementation is provided for poly data mapper alone, although the design should work with other data types. With some modifications to the implementation it should be possible to use the painters for other data types as well.

vtkPainter

vtkPainter is the superclass for all painters. The important public API is as follows

  // Description:
  // Get/Set the information object associated with this painter.
  vtkGetObjectMacro(Information, vtkInformation);
  virtual void SetInformation(vtkInformation*);

  // Description:
  // Set/Get the painter to which this painter should propagare its draw calls.
  vtkGetObjectMacro(DelegatePainter, vtkPainter);
  virtual void SetDelegatePainter(vtkPainter*);

 // Description:
  // Generates rendering primitives of appropriate type(s). Multiple types 
  // of primitives can be requested by or-ring the primitive flags. 
  // Default implementation calls UpdateDelegatePainter() to update the 
  // deletagate painter and then calls RenderInternal().
  virtual void Render(vtkRenderer* renderer, vtkActor* actor, 
    unsigned long typeflags);
  
  // Description:
  // Release any graphics resources that are being consumed by this painter.
  // The parameter window could be used to determine which graphic
  // resources to release. 
  // The call is propagated to the delegate painter, if any.
  virtual void ReleaseGraphicsResources(vtkWindow *);

Each painter keeps an Information object pointer. This information object is used to pass important information about the rendering pass down the painter chain. Typically the mapper fills up the information object based on user selection eg. whether user wants to use display lists, whether scalar coloring is enabled, which lookup table to use etc. and then sets it on the head painter in the painter chain. As will be explained later, this information object then gets propagates to all delegates the painter chain. Each painter only looks for those keys in the information object that it is concerned with and adapts its behaviour accordingly. Each painter may define a set of information keys that it understands.

Each painter can have a delegate painter. One can think of each painter doing its part and the delegating the rest to the delegate painter. eg. we have a display list painter that manages the creation and rendering of display lists, however it does not perform the actual primitive rendering i.e. drawing of polygons. That is delegated to the delegate painter. The delegate painter is set when the painter chain is set up. This is typically done by the mapper. However the user can create his own chain and set it on the mapper (or modify the one set up by the mapper) to customize the pipeline.

A render request is propagated to the painter using the Render method. typeflags identifies the types of primitives that primitives that we are interested in rendering eg. in case of polydata we may choose vertices, lines, polys or tstrips.

vtkPolyDataPainter

vtkPolyDataPainter is the subclass of vtkPainter that provides mechanism for propagating polydata along the painter chain. All the logic in here needs to be collapsed into the superclass (refer to Bug 2809 for details). That will make is possible for all painters to propagate a vtkDataObject which opens up the possibility for using the painters in mappers for anything other than polydata.

The only main addition provided by vtkPolyDataPainter, is that when propagating the Information object to the delegate painter, it propagates the polydata object as well. The default implementation simply passes the input polydata to the delegate. However, subclasses (such as scalars to colors painter) create a new copy of the input polydata, change some of its properties (in case of scalars to colors painters, it adds a new colors array which is colors assigned to points or cells after mapping through the lookuptable) and pass that to the delegate.

RECENT CHANGES

Bug 2809 has now been resolved. vtkPainter passes along a vtkDataObject. Hence several painters which don't need the data to be polydata such as ClipPlanesPainter, DisplayListsPainter etc. are now subclasses of vtkPainter instead of vtkPolyDataPainter.

Rendering Sequence

For this section we will look at vtkPolyDataPainter and see the sequence of operations performed when Render() is called.


void Render(vtkRenderer* renderer, vtkActor* actor, unsigned int typeflags)

  • ProcessInformation: First, the painter mush gather information about user preference for the rendering pass from the information object passed to the painter. A painter should read the Information object for the keys it knows and updates its ivar only by overriding the void ProcessInformation(vtkInformation*) method. The painters use ivars to avoid accessing the map during each render. After ProcessInformation() is called, vtkPainter updates a timestamp called InformationProcessTime. Next time, ProcessInformation() is called only if the information object's MTime is less than this->InformationProcessTime. This avoids processing of the information on every render pass unless the information has changed.
  • PrepareForRendering: Some painter may need to do some preprocessing before the actual rendering eg. build efficient data structures for rendering the data. This can be done here. PrepareForRendering is called during each render requests, so subclasses may want to check the data object's MTime to avoid building these data structures unless the data has changed.
  • RenderInternal: This is a virtual method that gets called to perform the actual rendering. Default implementation does the following if a delegate painter is present:
    • UpdateDelegatePainter: This updates the delegate painter. Updating a delegate painter implies passing the information object to the delegate. This is done by calling the virtual method PassInformation(vtkPainter* toPainter). Default implementation of PassInformation simply sets the information object pointer on the delegate. vtkPolyDataPainter overrides PassInformation to pass the polydata object to the delegate as well. As discussed earlier, default implementation simply passes the input polydata to the delegate, however subclasses may change that.
    • Delegate->Render: Once the delegate have been updated, we simply call this->DelegatePainter->Render(...) to pass the control to the delegate.

That's the core that drives the painters. Now, we shall cover all the subclass of vtkPolyDataPainter and understand their functionality. The classes are covered in the sequence that they are connected together to form the default painter chain in the vtkPainterPolyDataMapper.

vtkPainterPolyDataMapper

vtkPainterPolyDataMapper is concrete subclass of vtkPolyDataMapper that uses painters. It is functionally equivalent to vtkOpenGLPolyDataMapper which it replaces (there may be some improvements that got added to the PainterPolyDataMapper since the original implementation that are missing from vtkOpenGLPolyDataMapper). It keeps a vtkInformation instance called ShaderInformation. This information object is passed to the painter. All the different set methods on the mapper (such as SetScalarMode, SetImmediateModeRendering etc.) result in setting values for different keys in this map. It also keeps a pointer to the head of the painter chain that it uses for rendering. This can be changed using SetPainter. The default painter chain created is as follows:

  vtkPainterPolyDataMapper -> vtkDefaultPainter -> vtkChooserPainter

vtkDefaultPainter

This painter does not do any actual rendering, it's merely an aggregate of a chain of painters set up to mimic the vtkOpenGLPolyDataMapper processing pipeline. The chain is as follows (to get actual class names for instances created by default, prefix "vtk" and suffix "Painter" i.e. ClipPlanes => vtkClipPlanesPainter):

  ScalarsToColors -> ClipPlanes -> DisplayList -> CoincidentTopologyResolution -> Lighting -> Representation -> [DefaultPainter Delegate]

The vtkDefaultPainter is instantiated, the constructor creates a default painter type for each of these painters. All of them can then be changed by the user (set to 0 to skip a painter). The implementation takes care of connecting the painters as specified.

vtkChooserPainter

This is another one of the aggregate painters. This one choose the painter to render a primitive of the polydata i.e. verts, lines, polys, or tstrips. It uses vtkPointsPainter to render points, vtkLinesPainter to render lines, vtkPolygonsPainter to render polys and vtkTStripsPainter to render tstrips. The delegate for each of these painters is set to the vtkStandardPolyDataPainter which is generic (read slow) painter which can render any type of primitive. Generally no delegate is set for the chooser painter since all primitives will be rendered by the painters within the ChooserPainter itself.

ChooserPainter.png



Sandia is a multi-program laboratory operated by Sandia Corporation, a Lockheed Martin Company, for the United States Department of Energy under Contract DE-AC04-94AL85000.