GLSL is the standard shader language for OpenGL so you may already be familiar with it. If not, you will find its keywords and syntax are similar to the C language, plus some features from C++ like function overloading (multiple versions of a function that have the same name). There are two important differences that you will see in almost every GLSL function. First, GLSL supports generic vector types like “vec3” and “vec4”, which can contain integer or floating point (etc) values. Second, these vector types allow one or several of their components to be addressed using the suffix notation “xyzw” or “rgba”. In other words a GLSL function can refer to the first component of a vec4 variable as “color.r”, but it can also refer to the first three components simultaneously as “position.xyz”.
The suffix notation also allows “swizzling” the order of components in an assignment statement. There are many resources available on the web for learning more about GLSL.
Similar to a C or C++ programming environment, VolumeViz provides header files for the shader API. These files provide declarations for the shader API functions and for predefined uniform and varying parameters. For example, to use the function VVizGetData() in an application shader file, add the following include directive at the top of the file:
Example : Include GLSL header file
Be sure there are no spaces (blank characters) in the string “//!oiv_include”. The parser currently does not recognize white space in include directives.
VolumeViz provides a virtual address space (also called virtual texture) for volume data on the GPU. This allows shader functions to access any voxel in the volume. For example it is possible to get the values of neighboring voxels for filtering or the values of other samples in a trace for computing seismic attributes. Voxel positions are specified in normalized volume coordinates. These are floating point values ranging from 0..1 along each axis of the volume. Since voxel positions are floating point, it is possible to request the value at any position inside the volume. Interpolation is used, if necessary, to compute the value at the requested position. Application shader code must use the VVizGetData() or VVizGetRawData() function to get voxel values.
Unlike using the Data Access API on the CPU, it is not possible to guarantee that voxel values are taken from full resolution data. However it is possible to query the resolution level for the tile containing a specific voxel. Use the GLSL methods VVizGetTileInfo() and VVizGetTileResolution().
Application shader code cannot make any assumptions about how or where data is stored on the GPU (this may change between releases or even as tiles of different resolutions are managed on the GPU).
All application shader functions should follow these guidelines:
(The application cannot make any assumptions about how/where data is stored on the GPU.)
(See the forVolumeOnly field in SoVolumeShader)
(Turn ray casting mode off if necessary using the raycasting field in SoVolumeShader)
The public shader API functions are described in the Reference Manual. Some of the most commonly used functions are listed here. As previously discussed, VVIZ_DATATYPE is a macro defined as "float" for scalar volumes and "vec4" for RGBA volumes.
Reimplement this function for the GET_DATA_FUNCTION slot.
This function is called with a data set id and a voxel coordinate and returns a voxel value. This value could be computed from the actual value in the specified data set, for example by applying a filter or a seismic attribute algorithm. To get the actual value call VVizGetRawData(). The default implementation just returns the value from VVizGetRawData().
Used in application written VVizGetData() functions.
This function is called with a data set id and a voxel coordinate and returns the interpolated, but otherwise unmodified, voxel value from the data set.
Reimplement this function for the DATA_COMBINE_FUNCTION slot.
This function is called with a voxel coordinate and returns a voxel value. This value may be a combination of values from multiple volumes. The default implementation just calls VVizGetData() on the primary volume.
Reimplement this function for the FRAGMENT_COMPUTE_COLOR slot
There are two versions of this function, one for slice primitives and one for volume rendering:
The application must re-implement both if the shader needs to apply to both slice primitives and volume rendering. The source code for both versions can be in the same source file, however the file needs to loaded in two different volume shader nodes (one with forVolumeOnly set to true). Lighting and other rendering effects are applied to the color and opacity returned from this function. Basically this function is called with a voxel value and returns a color and opacity (RGBA value). This function is often used to blend colors from multiple data sets and can also be used to implement a custom transfer function. The default implementation just calls VVizTransferFunction(). The slice version is called with the voxel value from the primary data set, but also with the voxel coordinate, so it can fetch values from additional data sets. The volume rendering version is called with voxel info for the “front” and “back” voxels of the preintegrated rendering slab. These values can simply be forwarded to the volume rendering version of VVizTransferFunction() if you just need to do a color lookup. However you can also get the voxel value and coordinate as, for example, voxelInfoFront.value and voxelInfoFront.texCoord.
Note: In the volume rendering version of this function, all the parameters are declared "in" except the voxelInfoFront parameter, which is declared "inout". "In" is the default and can be omitted. The "inout" declaration cannot be omitted or the shader will not link.
Used in application written VVizComputeFragmentColor() functions.
There are two versions of this function, one for slice primitives and one for volume rendering:
This function takes a voxel value and a transfer function id and returns the result of the color lookup. The transfer function id is a value assigned by the application in the transferFunctionId field of the SoTransferFunction node. Each transfer function should have a unique id.
VolumeViz automatically defines the following preprocessor macros when compiling shader functions:
Is true if VVizData (VolumeViz input data) contains RGBA values. In this case each value in VVizData is a vec4. Otherwise each value is a float.
A string defining the GLSL data type in the volume (VVizData). If VVIZ_DATARGBA is true, then VVIZ_DATATYPE is defined as "vec4", in all other cases it is defined as "float". You will see this macro frequently in the declaration of VViz functions.
Defines the current numbers of GL clipping planes to take in account.
Defines the type of shape that is currently being rendered. It might be useful in some cases to specialize the shader behavior depending on the shape type. This value can be tested in the shader source against the following macro values: VVIZ_VRENDER (volume rendering), VVIZ_SLICE, VVIZ_OBLSLICE, VVIZ_VGEOM, VVIZ_VSKIN or VVIZ_HEIGHTFIELD.
VolumeViz automatically creates some uniform parameters when loading the shader. These contain useful information about the volume. With the exception of VVizDataSetId (previously discussed), the application should not attempt to access these variables directly. Use the following query functions:
Returns the volume dimensions in voxels (integer)
Returns the tile dimensions in voxels (integer)
Returns the size of one voxel in normalized volume coordinates (float 0..1)
Returns the resolution level of the specified tile (0 is full resolution).
See VVizGetTileInfo to get the parameter for calling this function.
Given a voxel coordinate in normalized volume coordinates (float 0..1), returns information about the tile that contains the voxel. Specifically information about the version of the tile currently resident on the GPU. This is an opaque struct but can be used with other queries, e.g. VVizGetTileResolution().
Given a dataSetId and voxel coordinate in normalized volume coordinates (float 0..1), returns the corners of the tile that contains the voxel (in voxel IJK coordinates).