1.8.2. Shader framework

VolumeViz applications still use the SoVertexShader( C++ | Java | .NET ) and/or SoFragmentShader( C++ | Java | .NET ) nodes to load the actual shader function source. This makes it easy to load and reload shader functions. The application can provide shader source code as a character string in memory or as a file on disk.

However instead of using the SoShaderProgram( C++ | Java | .NET ) node to create a shader program, applications will normally use one of its derived classes specific to VolumeViz. For slice rendering, the SoVolumeShader( C++ | Java | .NET ) node provides the basic “slots” for replacing steps in the rendering process. For volume rendering, it’s derived class SoVolumeRenderingQuality( C++ | Java | .NET ) integrates these slots with the advanced rendering effects like lighting and edge detection . VolumeViz automatically creates some “uniform” parameters to give the shaders general information about the volume. Generally application shaders should access this information through the VolumeViz shader API functions provided because details of these parameters may change in future releases of Open Inventor. The application can pass other information to shaders using application defined uniform parameters. There is an Open Inventor node for each type of parameter supported by GLSL, for example the SoShaderParameter1f( C++ | Java | .NET ) node passes a single named float value to the shader. If the application changes one of these parameters, for example the blend factor for combining two volumes, Open Inventor will automatically re-render the scene just as for any scene graph change.

Most applications will be creating fragment shaders. The fragment shader stage of the OpenGL pipeline is where most of the work is done for slice and volume rendering. This stage is responsible for computing gradients, color lookup, lighting, blending, clipping and many other things. The following shows how to load a shader function as a fragment shader:


SoVolumeShader( C++ | Java | .NET ) and SoVolumeRenderingQuality( C++ | Java | .NET ) inherit the SoMFNode( C++ | Java | .NET ) field shaderObject from SoShaderProgram( C++ | Java | .NET ). The application can add SoFragmentShader( C++ | Java | .NET ) (and SoVertexShader( C++ | Java | .NET ) and so on) objects to this field. VolumeViz takes care of linking all the shader functions into a shader program. There are two important differences from SoShaderProgram( C++ | Java | .NET ). First, OpenGL still requires that one of the shader functions is named “main”, but this function is automatically provided by VolumeViz, not (usually) by the application. Second, instead of being an unordered list of shader objects, as in SoShaderProgram( C++ | Java | .NET ), the VolumeViz shaderObject field is an ordered list of named “slots”. Each slot has a specific purpose in the rendering pipeline and the application can supply a replacement function by setting a fragment shader object using the name of the slot as the index. For example, to replace the computation of fragment color:


or


The shader function supplied by the application must implement the corresponding function in the VolumeViz shader framework that it is replacing. For example, the shader function set in the FRAGMENT_COMPUTE_COLOR slot must implement VVizComputeFragmentColor(). All the VolumeViz shader framework function names begin with the string “VViz”. Applications should not use this prefix except to specifically replace a VolumeViz framework function. The slots and corresponding shader framework functions are listed below. Implementing the actual GLSL code for the shader functions is discussed in the next subsection.

SoVolumeShader( C++ | Java | .NET ) and SoVolumeRenderingQuality( C++ | Java | .NET ) are property nodes that apply to volume primitives following them in the scene graph. They should be added to the scene graph after the volume data node(s), but before the rendering nodes. Note that the shaders loaded by these nodes will affect core Open Inventor rendering nodes (usually in a bad way), so normally Open Inventor geometry and VolumeViz geometry should be kept under separate SoSeparator( C++ | Java | .NET ) nodes.

The slot names are defined in the enumeration ShaderPosition.

Slot name GLSL function name
DATA_COMBINE_FUNCTION VVizCombineData
GET_DATA_FUNCTION VVizGetData
FRAGMENT_COMPUTE_COLOR VVizComputeFragmentColor
VERTEX_POSTPROCESSING VVizVertexPostProcessin
CUSTOM_SHADER,CUSTOM_SHADER+1,... Any application function

NOTE that there are named slots for the geometry, vertex and fragment “main” functions, for example “FRAGMENT_MAIN”. However replacing the vertex or fragment "main" is not compatible with the raycasting mode for volume rendering. If you must use one of these slots for volume rendering, set the raycasting field to false. Replacing the vertex or fragment "main" is possible for slice rendering, but not recommended.

The following list explains the purpose of each named slot. An example for each slot is shown later.