[vtk-developers] How to emulate the SetCompositeMethodToClassifyFirst behaviour in hardware (vtkOpenGLGPUVolumeRayCastMapper)...

AGPX agpxnet at yahoo.it
Mon Dec 27 05:19:15 EST 2010

Hello everybody,

I need to render a volume (of scalar values)  that have some regions fully 
transparent. To avoid the problem that arise from trilinear interpolation of the 
scalars (that show wrong boundary scalars), I have to use the software volume 
rendering mapper (vtkVolumeRayCastMapper) where you can customize the composite 
function. In more details, you can invoke the very useful method 
SetCompositeMethodToClassifyFirst() of the vtkVolumeRayCastCompositeFunction to 
obtain the correct result. Unfortunately the software version is slow compared 
to the hardware one (vtkOpenGLGPUVolumeRayCastMapper). So I have extended the 
hardware version, rewriting a GLSL shader (starting from 
vtkGPUVolumeRayCastMapper_CompositeFS.glsl) in order to emulate the behaviour of 
the vtkVolumeRayCastMapper when you invoke the 
SetCompositeMethodToClassifyFirst() method. The shader is the following 
(vtkGPUVolumeRayCastMapper_CompositeFS2.glsl) and you have to add it to the 
vtkOpenGLGPUVolumeRayCastMapper class:


  Program:   Visualization Toolkit
  Module:    vtkGPUVolumeRayCastMapper_CompositeFS2.glsl

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.


// Fragment program part with ray cast and composite method.

#version 110

uniform sampler3D dataSetTexture;
uniform sampler1D opacityTexture;

uniform vec3 lowBounds;
uniform vec3 highBounds;
uniform int textureWidth;
uniform int textureHeight;
uniform int textureDepth;

// Entry position (global scope)
vec3 pos;
// Incremental vector in texture space (global scope)
vec3 rayDir;

float tMax;

// from cropping vs no cropping
vec4 initialColor();

// from 1 vs 4 component shader.
float scalarFromValue(vec4 value);
vec4 colorFromValue(vec4 value);

// from noshade vs shade.
void initShade();
vec4 shade(vec4 value);

void trace(void)
  vec4 destColor=initialColor();
  float remainOpacity=1.0-destColor.a;

  bool inside=true;
  vec3 color;
  vec4 opacity;

  float t=0.0;
  // We NEED two nested while loops. It is trick to work around hardware
  // limitation about the maximum number of loops.

  vec3 textureSize = vec3(textureWidth, textureHeight, textureDepth);
  vec3 texelSize = vec3(1.0, 1.0, 1.0) / textureSize;
      vec3 texelpos=textureSize*pos;
      vec3 lerps = fract(texelpos);
      vec4 sourcevals[8]; 
      sourcevals[0] = texture3D(dataSetTexture, pos + vec3(0,           
0,           0));
      sourcevals[1] = texture3D(dataSetTexture, pos + vec3(texelSize.x, 
0,           0));
      sourcevals[2] = texture3D(dataSetTexture, pos + vec3(0,           
texelSize.y, 0));
      sourcevals[3] = texture3D(dataSetTexture, pos + vec3(texelSize.x, 
texelSize.y, 0));
      sourcevals[4] = texture3D(dataSetTexture, pos + vec3(0,           
0,           texelSize.z));
      sourcevals[5] = texture3D(dataSetTexture, pos + vec3(texelSize.x, 
0,           texelSize.z));
      sourcevals[6] = texture3D(dataSetTexture, pos + vec3(0,           
texelSize.y, texelSize.z));
      sourcevals[7] = texture3D(dataSetTexture, pos + vec3(texelSize.x, 
texelSize.y, texelSize.z));
      vec3 m = vec3(1, 1, 1) - lerps;
      float weights[8];
      weights[0] = m.x * m.y * m.z;
      weights[1] = lerps.x * m.y * m.z;
      weights[2] = m.x * lerps.y * m.z;
      weights[3] = lerps.x * lerps.y * m.z;
      weights[4] = m.x * m.y * lerps.z;
      weights[5] = lerps.x * m.y * lerps.z;
      weights[6] = m.x * lerps.y * lerps.z;
      weights[7] = lerps.x * lerps.y * lerps.z;
      float weight, totalOpacity;
      totalOpacity  = weight = 
      color  = shade(sourcevals[0]).xyz*weight;
      totalOpacity += weight = 
      color += shade(sourcevals[1]).xyz*weight;
      totalOpacity += weight = 
      color += shade(sourcevals[2]).xyz*weight;
      totalOpacity += weight = 
      color += shade(sourcevals[3]).xyz*weight;
      totalOpacity += weight = 
      color += shade(sourcevals[4]).xyz*weight;
      totalOpacity += weight = 
      color += shade(sourcevals[5]).xyz*weight;
      totalOpacity += weight = 
      color += shade(sourcevals[6]).xyz*weight;
      totalOpacity += weight = 
      color += shade(sourcevals[7]).xyz*weight;
      destColor.xyz += remainOpacity*color;
      remainOpacity *= (1.0 - totalOpacity);
      inside=t<tMax && all(greaterThanEqual(pos,lowBounds))
        && all(lessThanEqual(pos,highBounds))
        && (remainOpacity>=0.0039); // 1/255=0.0039
  gl_FragColor = destColor;
  gl_FragColor.a = 1.0-remainOpacity;

The algorithm performs trilinear interpolation manually so you have to call 
SetInterpolationTypeToNearest() when you use this shader. In addition you have 3 
new uniform variables:

uniform int textureWidth;
uniform int textureHeight;
uniform int textureDepth;

that maintains the dimensions of the 3D texture. You have to modify the class 
vtkOpenGLGPUVolumeRayCastMapper to provide these additional informations to the 

I hope that this could be helpful for other guys and that (one day) this feature 
will be added to the VTK library :)


Gianluca Arcidiacono (AGPX)

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/vtk-developers/attachments/20101227/3a0ecedf/attachment.html>

More information about the vtk-developers mailing list