[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;
initShade();
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;
while(inside)
{
while(inside)
{
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 =
texture1D(opacityTexture,scalarFromValue(sourcevals[0])).a*weights[0];
color = shade(sourcevals[0]).xyz*weight;
totalOpacity += weight =
texture1D(opacityTexture,scalarFromValue(sourcevals[1])).a*weights[1];
color += shade(sourcevals[1]).xyz*weight;
totalOpacity += weight =
texture1D(opacityTexture,scalarFromValue(sourcevals[2])).a*weights[2];
color += shade(sourcevals[2]).xyz*weight;
totalOpacity += weight =
texture1D(opacityTexture,scalarFromValue(sourcevals[3])).a*weights[3];
color += shade(sourcevals[3]).xyz*weight;
totalOpacity += weight =
texture1D(opacityTexture,scalarFromValue(sourcevals[4])).a*weights[4];
color += shade(sourcevals[4]).xyz*weight;
totalOpacity += weight =
texture1D(opacityTexture,scalarFromValue(sourcevals[5])).a*weights[5];
color += shade(sourcevals[5]).xyz*weight;
totalOpacity += weight =
texture1D(opacityTexture,scalarFromValue(sourcevals[6])).a*weights[6];
color += shade(sourcevals[6]).xyz*weight;
totalOpacity += weight =
texture1D(opacityTexture,scalarFromValue(sourcevals[7])).a*weights[7];
color += shade(sourcevals[7]).xyz*weight;
destColor.xyz += remainOpacity*color;
remainOpacity *= (1.0 - totalOpacity);
pos=pos+rayDir;
t+=1.0;
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
shader.
I hope that this could be helpful for other guys and that (one day) this feature
will be added to the VTK library :)
-------------- 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