You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2536 lines
84 KiB
2536 lines
84 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkVolumeRayCastCompositeFunction.cxx,v $
|
|
|
|
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.
|
|
|
|
=========================================================================*/
|
|
#include "vtkVolumeRayCastCompositeFunction.h"
|
|
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkPiecewiseFunction.h"
|
|
#include "vtkVolume.h"
|
|
#include "vtkVolumeProperty.h"
|
|
#include "vtkVolumeRayCastMapper.h"
|
|
|
|
#include <math.h>
|
|
|
|
vtkCxxRevisionMacro(vtkVolumeRayCastCompositeFunction, "$Revision: 1.1 $");
|
|
vtkStandardNewMacro(vtkVolumeRayCastCompositeFunction);
|
|
|
|
#define VTK_REMAINING_OPACITY 0.02
|
|
|
|
// This is the templated function that actually casts a ray and computes
|
|
// The composite value. This version uses nearest neighbor interpolation
|
|
// and does not perform shading.
|
|
template <class T>
|
|
void vtkCastRay_NN_Unshaded( T *data_ptr, vtkVolumeRayCastDynamicInfo *dynamicInfo,
|
|
vtkVolumeRayCastStaticInfo *staticInfo )
|
|
{
|
|
int value=0;
|
|
unsigned char *grad_mag_ptr = NULL;
|
|
float accum_red_intensity;
|
|
float accum_green_intensity;
|
|
float accum_blue_intensity;
|
|
float remaining_opacity;
|
|
float opacity=0.0;
|
|
float gradient_opacity;
|
|
int loop;
|
|
int xinc, yinc, zinc;
|
|
int voxel[3];
|
|
float ray_position[3];
|
|
int prev_voxel[3];
|
|
float *SOTF;
|
|
float *CTF;
|
|
float *GTF;
|
|
float *GOTF;
|
|
int offset;
|
|
int steps_this_ray = 0;
|
|
int grad_op_is_constant;
|
|
float gradient_opacity_constant;
|
|
int num_steps;
|
|
float *ray_start, *ray_increment;
|
|
|
|
num_steps = dynamicInfo->NumberOfStepsToTake;
|
|
ray_start = dynamicInfo->TransformedStart;
|
|
ray_increment = dynamicInfo->TransformedIncrement;
|
|
|
|
SOTF = staticInfo->Volume->GetCorrectedScalarOpacityArray();
|
|
CTF = staticInfo->Volume->GetRGBArray();
|
|
GTF = staticInfo->Volume->GetGrayArray();
|
|
GOTF = staticInfo->Volume->GetGradientOpacityArray();
|
|
|
|
// Get the gradient opacity constant. If this number is greater than
|
|
// or equal to 0.0, then the gradient opacity transfer function is
|
|
// a constant at that value, otherwise it is not a constant function
|
|
gradient_opacity_constant = staticInfo->Volume->GetGradientOpacityConstant();
|
|
grad_op_is_constant = ( gradient_opacity_constant >= 0.0 );
|
|
|
|
// Move the increments into local variables
|
|
xinc = staticInfo->DataIncrement[0];
|
|
yinc = staticInfo->DataIncrement[1];
|
|
zinc = staticInfo->DataIncrement[2];
|
|
|
|
// Initialize the ray position and voxel location
|
|
ray_position[0] = ray_start[0];
|
|
ray_position[1] = ray_start[1];
|
|
ray_position[2] = ray_start[2];
|
|
voxel[0] = vtkRoundFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkRoundFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkRoundFuncMacro( ray_position[2] );
|
|
|
|
// So far we haven't accumulated anything
|
|
accum_red_intensity = 0.0;
|
|
accum_green_intensity = 0.0;
|
|
accum_blue_intensity = 0.0;
|
|
remaining_opacity = 1.0;
|
|
|
|
// Get a pointer to the gradient magnitudes for this volume
|
|
if ( !grad_op_is_constant )
|
|
{
|
|
grad_mag_ptr = staticInfo->GradientMagnitudes;
|
|
}
|
|
|
|
|
|
// Keep track of previous voxel to know when we step into a new one
|
|
// set it to something invalid to start with so that everything is
|
|
// computed first time through
|
|
prev_voxel[0] = voxel[0]-1;
|
|
prev_voxel[1] = voxel[1]-1;
|
|
prev_voxel[2] = voxel[2]-1;
|
|
|
|
// Two cases - we are working with a gray or RGB transfer
|
|
// function - break them up to make it more efficient
|
|
if ( staticInfo->ColorChannels == 1 )
|
|
{
|
|
// For each step along the ray
|
|
for ( loop = 0;
|
|
loop < num_steps && remaining_opacity > VTK_REMAINING_OPACITY;
|
|
loop++ )
|
|
{
|
|
// We've taken another step
|
|
steps_this_ray++;
|
|
|
|
// Access the value at this voxel location
|
|
if ( prev_voxel[0] != voxel[0] ||
|
|
prev_voxel[1] != voxel[1] ||
|
|
prev_voxel[2] != voxel[2] )
|
|
{
|
|
offset = voxel[2] * zinc + voxel[1] * yinc + voxel[0] * xinc;
|
|
value = *(data_ptr + offset);
|
|
opacity = SOTF[value];
|
|
|
|
if ( opacity )
|
|
{
|
|
if ( grad_op_is_constant )
|
|
{
|
|
gradient_opacity = gradient_opacity_constant;
|
|
}
|
|
else
|
|
{
|
|
gradient_opacity = GOTF[*(grad_mag_ptr + offset)];
|
|
}
|
|
opacity *= gradient_opacity;
|
|
}
|
|
|
|
prev_voxel[0] = voxel[0];
|
|
prev_voxel[1] = voxel[1];
|
|
prev_voxel[2] = voxel[2];
|
|
}
|
|
|
|
// Accumulate some light intensity and opacity
|
|
accum_red_intensity += ( opacity * remaining_opacity *
|
|
GTF[(value)] );
|
|
remaining_opacity *= (1.0 - opacity);
|
|
|
|
// Increment our position and compute our voxel location
|
|
ray_position[0] += ray_increment[0];
|
|
ray_position[1] += ray_increment[1];
|
|
ray_position[2] += ray_increment[2];
|
|
voxel[0] = vtkRoundFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkRoundFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkRoundFuncMacro( ray_position[2] );
|
|
}
|
|
accum_green_intensity = accum_red_intensity;
|
|
accum_blue_intensity = accum_red_intensity;
|
|
}
|
|
else if ( staticInfo->ColorChannels == 3 )
|
|
{
|
|
// For each step along the ray
|
|
for ( loop = 0;
|
|
loop < num_steps && remaining_opacity > VTK_REMAINING_OPACITY;
|
|
loop++ )
|
|
{
|
|
// We've taken another step
|
|
steps_this_ray++;
|
|
|
|
// Access the value at this voxel location
|
|
if ( prev_voxel[0] != voxel[0] ||
|
|
prev_voxel[1] != voxel[1] ||
|
|
prev_voxel[2] != voxel[2] )
|
|
{
|
|
offset = voxel[2] * zinc + voxel[1] * yinc + voxel[0] * xinc;
|
|
value = *(data_ptr + offset);
|
|
opacity = SOTF[value];
|
|
|
|
if ( opacity )
|
|
{
|
|
if ( grad_op_is_constant )
|
|
{
|
|
gradient_opacity = gradient_opacity_constant;
|
|
}
|
|
else
|
|
{
|
|
gradient_opacity = GOTF[*(grad_mag_ptr + offset)];
|
|
}
|
|
opacity *= gradient_opacity;
|
|
}
|
|
|
|
prev_voxel[0] = voxel[0];
|
|
prev_voxel[1] = voxel[1];
|
|
prev_voxel[2] = voxel[2];
|
|
}
|
|
|
|
|
|
// Accumulate some light intensity and opacity
|
|
accum_red_intensity += ( opacity * remaining_opacity *
|
|
CTF[(value)*3] );
|
|
accum_green_intensity += ( opacity * remaining_opacity *
|
|
CTF[(value)*3 + 1] );
|
|
accum_blue_intensity += ( opacity * remaining_opacity *
|
|
CTF[(value)*3 + 2] );
|
|
remaining_opacity *= (1.0 - opacity);
|
|
|
|
// Increment our position and compute our voxel location
|
|
ray_position[0] += ray_increment[0];
|
|
ray_position[1] += ray_increment[1];
|
|
ray_position[2] += ray_increment[2];
|
|
voxel[0] = vtkRoundFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkRoundFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkRoundFuncMacro( ray_position[2] );
|
|
}
|
|
}
|
|
|
|
// Cap the intensity value at 1.0
|
|
if ( accum_red_intensity > 1.0 )
|
|
{
|
|
accum_red_intensity = 1.0;
|
|
}
|
|
if ( accum_green_intensity > 1.0 )
|
|
{
|
|
accum_green_intensity = 1.0;
|
|
}
|
|
if ( accum_blue_intensity > 1.0 )
|
|
{
|
|
accum_blue_intensity = 1.0;
|
|
}
|
|
|
|
if( remaining_opacity < VTK_REMAINING_OPACITY )
|
|
{
|
|
remaining_opacity = 0.0;
|
|
}
|
|
|
|
// Set the return pixel value. The depth value is the distance to the
|
|
// center of the volume.
|
|
dynamicInfo->Color[0] = accum_red_intensity;
|
|
dynamicInfo->Color[1] = accum_green_intensity;
|
|
dynamicInfo->Color[2] = accum_blue_intensity;
|
|
dynamicInfo->Color[3] = 1.0 - remaining_opacity;
|
|
dynamicInfo->NumberOfStepsTaken = steps_this_ray;
|
|
|
|
}
|
|
|
|
|
|
// This is the templated function that actually casts a ray and computes
|
|
// the composite value. This version uses nearest neighbor and does
|
|
// perform shading.
|
|
template <class T>
|
|
void vtkCastRay_NN_Shaded( T *data_ptr, vtkVolumeRayCastDynamicInfo *dynamicInfo,
|
|
vtkVolumeRayCastStaticInfo *staticInfo )
|
|
{
|
|
int value;
|
|
unsigned char *grad_mag_ptr = NULL;
|
|
float accum_red_intensity;
|
|
float accum_green_intensity;
|
|
float accum_blue_intensity;
|
|
float remaining_opacity;
|
|
float opacity = 0.0;
|
|
float gradient_opacity;
|
|
int loop;
|
|
int xinc, yinc, zinc;
|
|
int voxel[3];
|
|
float ray_position[3];
|
|
int prev_voxel[3];
|
|
float *SOTF;
|
|
float *CTF;
|
|
float *GTF;
|
|
float *GOTF;
|
|
float *red_d_shade, *green_d_shade, *blue_d_shade;
|
|
float *red_s_shade, *green_s_shade, *blue_s_shade;
|
|
unsigned short *encoded_normals;
|
|
float red_shaded_value = 0.0;
|
|
float green_shaded_value = 0.0;
|
|
float blue_shaded_value = 0.0;
|
|
int offset;
|
|
int steps_this_ray = 0;
|
|
int grad_op_is_constant;
|
|
float gradient_opacity_constant;
|
|
int num_steps;
|
|
float *ray_start, *ray_increment;
|
|
|
|
num_steps = dynamicInfo->NumberOfStepsToTake;
|
|
ray_start = dynamicInfo->TransformedStart;
|
|
ray_increment = dynamicInfo->TransformedIncrement;
|
|
|
|
// Get diffuse shading table pointers
|
|
red_d_shade = staticInfo->RedDiffuseShadingTable;
|
|
green_d_shade = staticInfo->GreenDiffuseShadingTable;
|
|
blue_d_shade = staticInfo->BlueDiffuseShadingTable;
|
|
|
|
// Get specular shading table pointers
|
|
red_s_shade = staticInfo->RedSpecularShadingTable;
|
|
green_s_shade = staticInfo->GreenSpecularShadingTable;
|
|
blue_s_shade = staticInfo->BlueSpecularShadingTable;
|
|
|
|
// Get a pointer to the encoded normals for this volume
|
|
encoded_normals = staticInfo->EncodedNormals;
|
|
|
|
// Get the scalar opacity transfer function for this volume (which maps
|
|
// scalar input values to opacities)
|
|
SOTF = staticInfo->Volume->GetCorrectedScalarOpacityArray();
|
|
|
|
// Get the color transfer function for this volume (which maps
|
|
// scalar input values to RGB values)
|
|
CTF = staticInfo->Volume->GetRGBArray();
|
|
GTF = staticInfo->Volume->GetGrayArray();
|
|
|
|
// Get the gradient opacity transfer function for this volume (which maps
|
|
// gradient magnitudes to opacities)
|
|
GOTF = staticInfo->Volume->GetGradientOpacityArray();
|
|
|
|
// Get the gradient opacity constant. If this number is greater than
|
|
// or equal to 0.0, then the gradient opacity transfer function is
|
|
// a constant at that value, otherwise it is not a constant function
|
|
gradient_opacity_constant = staticInfo->Volume->GetGradientOpacityConstant();
|
|
grad_op_is_constant = ( gradient_opacity_constant >= 0.0 );
|
|
|
|
// Get a pointer to the gradient magnitudes for this volume
|
|
if ( !grad_op_is_constant )
|
|
{
|
|
grad_mag_ptr = staticInfo->GradientMagnitudes;
|
|
}
|
|
|
|
// Move the increments into local variables
|
|
xinc = staticInfo->DataIncrement[0];
|
|
yinc = staticInfo->DataIncrement[1];
|
|
zinc = staticInfo->DataIncrement[2];
|
|
|
|
// Initialize the ray position and voxel location
|
|
ray_position[0] = ray_start[0];
|
|
ray_position[1] = ray_start[1];
|
|
ray_position[2] = ray_start[2];
|
|
|
|
voxel[0] = vtkRoundFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkRoundFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkRoundFuncMacro( ray_position[2] );
|
|
|
|
// So far we haven't accumulated anything
|
|
accum_red_intensity = 0.0;
|
|
accum_green_intensity = 0.0;
|
|
accum_blue_intensity = 0.0;
|
|
remaining_opacity = 1.0;
|
|
|
|
// Keep track of previous voxel to know when we step into a new one
|
|
prev_voxel[0] = voxel[0]-1;
|
|
prev_voxel[1] = voxel[1]-1;
|
|
prev_voxel[2] = voxel[2]-1;
|
|
|
|
// Two cases - we are working with a gray or RGB transfer
|
|
// function - break them up to make it more efficient
|
|
if ( staticInfo->ColorChannels == 1 )
|
|
{
|
|
// For each step along the ray
|
|
for ( loop = 0;
|
|
loop < num_steps && remaining_opacity > VTK_REMAINING_OPACITY;
|
|
loop++ )
|
|
{
|
|
// We've taken another step
|
|
steps_this_ray++;
|
|
|
|
// Access the value at this voxel location and compute
|
|
// opacity and shaded value
|
|
if ( prev_voxel[0] != voxel[0] ||
|
|
prev_voxel[1] != voxel[1] ||
|
|
prev_voxel[2] != voxel[2] )
|
|
{
|
|
offset = voxel[2] * zinc + voxel[1] * yinc + voxel[0] * xinc;
|
|
value = *(data_ptr + offset);
|
|
|
|
// Get the opacity contributed by the scalar opacity transfer function
|
|
opacity = SOTF[value];
|
|
|
|
// Multiply by the opacity contributed by the gradient magnitude
|
|
// transfer function (don't both if opacity is already 0)
|
|
if ( opacity )
|
|
{
|
|
if ( grad_op_is_constant )
|
|
{
|
|
gradient_opacity = gradient_opacity_constant;
|
|
}
|
|
else
|
|
{
|
|
gradient_opacity = GOTF[*(grad_mag_ptr + offset)];
|
|
}
|
|
|
|
opacity *= gradient_opacity;
|
|
|
|
}
|
|
|
|
// Compute the red shaded value (only if there is some opacity)
|
|
// This is grey-scale so green and blue are the same as red
|
|
if ( opacity )
|
|
{
|
|
red_shaded_value = opacity * remaining_opacity *
|
|
( red_d_shade[*(encoded_normals + offset)] * GTF[value] +
|
|
red_s_shade[*(encoded_normals + offset)] );
|
|
}
|
|
else
|
|
{
|
|
red_shaded_value = 0.0;
|
|
}
|
|
|
|
prev_voxel[0] = voxel[0];
|
|
prev_voxel[1] = voxel[1];
|
|
prev_voxel[2] = voxel[2];
|
|
}
|
|
|
|
|
|
// Accumulate the shaded intensity and opacity of this sample
|
|
accum_red_intensity += red_shaded_value;
|
|
remaining_opacity *= (1.0 - opacity);
|
|
|
|
// Increment our position and compute our voxel location
|
|
ray_position[0] += ray_increment[0];
|
|
ray_position[1] += ray_increment[1];
|
|
ray_position[2] += ray_increment[2];
|
|
voxel[0] = vtkRoundFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkRoundFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkRoundFuncMacro( ray_position[2] );
|
|
}
|
|
accum_green_intensity = accum_red_intensity;
|
|
accum_blue_intensity = accum_red_intensity;
|
|
}
|
|
else if ( staticInfo->ColorChannels == 3 )
|
|
{
|
|
// For each step along the ray
|
|
for ( loop = 0;
|
|
loop < num_steps && remaining_opacity > VTK_REMAINING_OPACITY; loop++ )
|
|
{
|
|
// We've taken another step
|
|
steps_this_ray++;
|
|
|
|
// Access the value at this voxel location and compute
|
|
// opacity and shaded value
|
|
if ( prev_voxel[0] != voxel[0] ||
|
|
prev_voxel[1] != voxel[1] ||
|
|
prev_voxel[2] != voxel[2] )
|
|
{
|
|
offset = voxel[2] * zinc + voxel[1] * yinc + voxel[0] * xinc;
|
|
value = *(data_ptr + offset);
|
|
|
|
// Get the opacity contributed by the scalar opacity transfer function
|
|
opacity = SOTF[value];
|
|
|
|
// Multiply by the opacity contributed by the gradient magnitude
|
|
// transfer function (don't both if opacity is already 0)
|
|
if ( opacity )
|
|
{
|
|
if ( grad_op_is_constant )
|
|
{
|
|
gradient_opacity = gradient_opacity_constant;
|
|
}
|
|
else
|
|
{
|
|
gradient_opacity = GOTF[*(grad_mag_ptr + offset)];
|
|
}
|
|
|
|
opacity *= gradient_opacity;
|
|
}
|
|
|
|
// Compute the red, green, and blue shaded value (only if there
|
|
// is some opacity)
|
|
if ( opacity )
|
|
{
|
|
red_shaded_value = opacity * remaining_opacity *
|
|
( red_d_shade[*(encoded_normals + offset)] * CTF[value*3] +
|
|
red_s_shade[*(encoded_normals + offset)] );
|
|
green_shaded_value = opacity * remaining_opacity *
|
|
( green_d_shade[*(encoded_normals + offset)] * CTF[value*3 + 1] +
|
|
green_s_shade[*(encoded_normals + offset)] );
|
|
blue_shaded_value = opacity * remaining_opacity *
|
|
( blue_d_shade[*(encoded_normals + offset)] * CTF[value*3 + 2] +
|
|
blue_s_shade[*(encoded_normals + offset)] );
|
|
}
|
|
else
|
|
{
|
|
red_shaded_value = 0.0;
|
|
green_shaded_value = 0.0;
|
|
blue_shaded_value = 0.0;
|
|
}
|
|
|
|
prev_voxel[0] = voxel[0];
|
|
prev_voxel[1] = voxel[1];
|
|
prev_voxel[2] = voxel[2];
|
|
}
|
|
|
|
|
|
// Accumulate the shaded intensity and opacity of this sample
|
|
accum_red_intensity += red_shaded_value;
|
|
accum_green_intensity += green_shaded_value;
|
|
accum_blue_intensity += blue_shaded_value;
|
|
remaining_opacity *= (1.0 - opacity);
|
|
|
|
// Increment our position and compute our voxel location
|
|
ray_position[0] += ray_increment[0];
|
|
ray_position[1] += ray_increment[1];
|
|
ray_position[2] += ray_increment[2];
|
|
voxel[0] = vtkRoundFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkRoundFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkRoundFuncMacro( ray_position[2] );
|
|
}
|
|
}
|
|
|
|
// Cap the intensities at 1.0
|
|
if ( accum_red_intensity > 1.0 )
|
|
{
|
|
accum_red_intensity = 1.0;
|
|
}
|
|
if ( accum_green_intensity > 1.0 )
|
|
{
|
|
accum_green_intensity = 1.0;
|
|
}
|
|
if ( accum_blue_intensity > 1.0 )
|
|
{
|
|
accum_blue_intensity = 1.0;
|
|
}
|
|
|
|
if( remaining_opacity < VTK_REMAINING_OPACITY )
|
|
{
|
|
remaining_opacity = 0.0;
|
|
}
|
|
|
|
// Set the return pixel value. The depth value is the distance to the
|
|
// center of the volume.
|
|
dynamicInfo->Color[0] = accum_red_intensity;
|
|
dynamicInfo->Color[1] = accum_green_intensity;
|
|
dynamicInfo->Color[2] = accum_blue_intensity;
|
|
dynamicInfo->Color[3] = 1.0 - remaining_opacity;
|
|
dynamicInfo->NumberOfStepsTaken = steps_this_ray;
|
|
|
|
}
|
|
|
|
// This is the templated function that actually casts a ray and computes
|
|
// the composite value. This version uses trilinear interpolation and
|
|
// does not compute shading
|
|
template <class T>
|
|
void vtkCastRay_TrilinSample_Unshaded( T *data_ptr, vtkVolumeRayCastDynamicInfo *dynamicInfo,
|
|
vtkVolumeRayCastStaticInfo *staticInfo )
|
|
{
|
|
unsigned char *grad_mag_ptr = NULL;
|
|
unsigned char *gmptr;
|
|
float accum_red_intensity;
|
|
float accum_green_intensity;
|
|
float accum_blue_intensity;
|
|
float remaining_opacity;
|
|
float red_value, green_value, blue_value;
|
|
float opacity;
|
|
int loop;
|
|
int xinc, yinc, zinc;
|
|
int voxel[3];
|
|
float ray_position[3];
|
|
float A, B, C, D, E, F, G, H;
|
|
int Binc, Cinc, Dinc, Einc, Finc, Ginc, Hinc;
|
|
T *dptr;
|
|
float *SOTF;
|
|
float *CTF;
|
|
float *GTF;
|
|
float *GOTF;
|
|
float x, y, z, t1, t2, t3;
|
|
int offset;
|
|
int steps_this_ray = 0;
|
|
float gradient_value;
|
|
float scalar_value;
|
|
int grad_op_is_constant;
|
|
float gradient_opacity_constant;
|
|
int num_steps;
|
|
float *ray_start, *ray_increment;
|
|
|
|
num_steps = dynamicInfo->NumberOfStepsToTake;
|
|
ray_start = dynamicInfo->TransformedStart;
|
|
ray_increment = dynamicInfo->TransformedIncrement;
|
|
|
|
// Get the scalar opacity transfer function which maps scalar input values
|
|
// to opacities
|
|
SOTF = staticInfo->Volume->GetCorrectedScalarOpacityArray();
|
|
|
|
// Get the color transfer function which maps scalar input values
|
|
// to RGB colors
|
|
CTF = staticInfo->Volume->GetRGBArray();
|
|
GTF = staticInfo->Volume->GetGrayArray();
|
|
|
|
// Get the gradient opacity transfer function for this volume (which maps
|
|
// gradient magnitudes to opacities)
|
|
GOTF = staticInfo->Volume->GetGradientOpacityArray();
|
|
|
|
// Get the gradient opacity constant. If this number is greater than
|
|
// or equal to 0.0, then the gradient opacity transfer function is
|
|
// a constant at that value, otherwise it is not a constant function
|
|
gradient_opacity_constant = staticInfo->Volume->GetGradientOpacityConstant();
|
|
grad_op_is_constant = ( gradient_opacity_constant >= 0.0 );
|
|
|
|
// Get a pointer to the gradient magnitudes for this volume
|
|
if ( !grad_op_is_constant )
|
|
{
|
|
grad_mag_ptr = staticInfo->GradientMagnitudes;
|
|
}
|
|
|
|
// Move the increments into local variables
|
|
xinc = staticInfo->DataIncrement[0];
|
|
yinc = staticInfo->DataIncrement[1];
|
|
zinc = staticInfo->DataIncrement[2];
|
|
|
|
// Initialize the ray position and voxel location
|
|
ray_position[0] = ray_start[0];
|
|
ray_position[1] = ray_start[1];
|
|
ray_position[2] = ray_start[2];
|
|
voxel[0] = vtkFloorFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkFloorFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkFloorFuncMacro( ray_position[2] );
|
|
|
|
// So far we have not accumulated anything
|
|
accum_red_intensity = 0.0;
|
|
accum_green_intensity = 0.0;
|
|
accum_blue_intensity = 0.0;
|
|
remaining_opacity = 1.0;
|
|
|
|
// Compute the increments to get to the other 7 voxel vertices from A
|
|
Binc = xinc;
|
|
Cinc = yinc;
|
|
Dinc = xinc + yinc;
|
|
Einc = zinc;
|
|
Finc = zinc + xinc;
|
|
Ginc = zinc + yinc;
|
|
Hinc = zinc + xinc + yinc;
|
|
|
|
// Two cases - we are working with a gray or RGB transfer
|
|
// function - break them up to make it more efficient
|
|
if ( staticInfo->ColorChannels == 1 )
|
|
{
|
|
// For each step along the ray
|
|
for ( loop = 0;
|
|
loop < num_steps && remaining_opacity > VTK_REMAINING_OPACITY;
|
|
loop++ )
|
|
{
|
|
// We've taken another step
|
|
steps_this_ray++;
|
|
|
|
offset = voxel[2] * zinc + voxel[1] * yinc + voxel[0];
|
|
dptr = data_ptr + offset;
|
|
|
|
A = *(dptr);
|
|
B = *(dptr + Binc);
|
|
C = *(dptr + Cinc);
|
|
D = *(dptr + Dinc);
|
|
E = *(dptr + Einc);
|
|
F = *(dptr + Finc);
|
|
G = *(dptr + Ginc);
|
|
H = *(dptr + Hinc);
|
|
|
|
// Compute our offset in the voxel, and use that to trilinearly
|
|
// interpolate the value
|
|
x = ray_position[0] - (float) voxel[0];
|
|
y = ray_position[1] - (float) voxel[1];
|
|
z = ray_position[2] - (float) voxel[2];
|
|
|
|
t1 = 1.0 - x;
|
|
t2 = 1.0 - y;
|
|
t3 = 1.0 - z;
|
|
|
|
scalar_value =
|
|
A * t1 * t2 * t3 +
|
|
B * x * t2 * t3 +
|
|
C * t1 * y * t3 +
|
|
D * x * y * t3 +
|
|
E * t1 * t2 * z +
|
|
F * x * t2 * z +
|
|
G * t1 * y * z +
|
|
H * x * y * z;
|
|
|
|
if ( scalar_value < 0.0 )
|
|
{
|
|
scalar_value = 0.0;
|
|
}
|
|
else if ( scalar_value > staticInfo->Volume->GetArraySize() - 1 )
|
|
{
|
|
scalar_value = staticInfo->Volume->GetArraySize() - 1;
|
|
}
|
|
|
|
opacity = SOTF[(int)(scalar_value)];
|
|
|
|
if ( opacity )
|
|
{
|
|
if ( !grad_op_is_constant )
|
|
{
|
|
gmptr = grad_mag_ptr + offset;
|
|
|
|
A = *(gmptr);
|
|
B = *(gmptr + Binc);
|
|
C = *(gmptr + Cinc);
|
|
D = *(gmptr + Dinc);
|
|
E = *(gmptr + Einc);
|
|
F = *(gmptr + Finc);
|
|
G = *(gmptr + Ginc);
|
|
H = *(gmptr + Hinc);
|
|
|
|
gradient_value =
|
|
A * t1 * t2 * t3 +
|
|
B * x * t2 * t3 +
|
|
C * t1 * y * t3 +
|
|
D * x * y * t3 +
|
|
E * t1 * t2 * z +
|
|
F * x * t2 * z +
|
|
G * t1 * y * z +
|
|
H * x * y * z;
|
|
|
|
if ( gradient_value < 0.0 )
|
|
{
|
|
gradient_value = 0.0;
|
|
}
|
|
else if ( gradient_value > 255.0 )
|
|
{
|
|
gradient_value = 255.0;
|
|
}
|
|
|
|
opacity *= GOTF[(int)(gradient_value)];
|
|
}
|
|
else
|
|
{
|
|
opacity *= gradient_opacity_constant;
|
|
}
|
|
red_value = opacity * GTF[(int)(scalar_value)];
|
|
|
|
// Accumulate intensity and opacity for this sample location
|
|
accum_red_intensity += remaining_opacity * red_value;
|
|
remaining_opacity *= (1.0 - opacity);
|
|
}
|
|
|
|
// Increment our position and compute our voxel location
|
|
ray_position[0] += ray_increment[0];
|
|
ray_position[1] += ray_increment[1];
|
|
ray_position[2] += ray_increment[2];
|
|
voxel[0] = vtkFloorFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkFloorFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkFloorFuncMacro( ray_position[2] );
|
|
}
|
|
accum_green_intensity = accum_red_intensity;
|
|
accum_blue_intensity = accum_red_intensity;
|
|
}
|
|
else if ( staticInfo->ColorChannels == 3 )
|
|
{
|
|
// For each step along the ray
|
|
for ( loop = 0;
|
|
loop < num_steps && remaining_opacity > VTK_REMAINING_OPACITY;
|
|
loop++ )
|
|
{
|
|
// We've taken another step
|
|
steps_this_ray++;
|
|
|
|
offset = voxel[2] * zinc + voxel[1] * yinc + voxel[0];
|
|
dptr = data_ptr + offset;
|
|
|
|
A = *(dptr);
|
|
B = *(dptr + Binc);
|
|
C = *(dptr + Cinc);
|
|
D = *(dptr + Dinc);
|
|
E = *(dptr + Einc);
|
|
F = *(dptr + Finc);
|
|
G = *(dptr + Ginc);
|
|
H = *(dptr + Hinc);
|
|
|
|
// Compute our offset in the voxel, and use that to trilinearly
|
|
// interpolate the value
|
|
x = ray_position[0] - (float) voxel[0];
|
|
y = ray_position[1] - (float) voxel[1];
|
|
z = ray_position[2] - (float) voxel[2];
|
|
|
|
t1 = 1.0 - x;
|
|
t2 = 1.0 - y;
|
|
t3 = 1.0 - z;
|
|
|
|
scalar_value =
|
|
A * t1 * t2 * t3 +
|
|
B * x * t2 * t3 +
|
|
C * t1 * y * t3 +
|
|
D * x * y * t3 +
|
|
E * t1 * t2 * z +
|
|
F * x * t2 * z +
|
|
G * t1 * y * z +
|
|
H * x * y * z;
|
|
|
|
if ( scalar_value < 0.0 )
|
|
{
|
|
scalar_value = 0.0;
|
|
}
|
|
else if ( scalar_value > staticInfo->Volume->GetArraySize() - 1 )
|
|
{
|
|
scalar_value = staticInfo->Volume->GetArraySize() - 1;
|
|
}
|
|
|
|
opacity = SOTF[(int)(scalar_value)];
|
|
|
|
if ( opacity )
|
|
{
|
|
if ( !grad_op_is_constant )
|
|
{
|
|
gmptr = grad_mag_ptr + offset;
|
|
|
|
A = *(gmptr);
|
|
B = *(gmptr + Binc);
|
|
C = *(gmptr + Cinc);
|
|
D = *(gmptr + Dinc);
|
|
E = *(gmptr + Einc);
|
|
F = *(gmptr + Finc);
|
|
G = *(gmptr + Ginc);
|
|
H = *(gmptr + Hinc);
|
|
|
|
gradient_value =
|
|
A * t1 * t2 * t3 +
|
|
B * x * t2 * t3 +
|
|
C * t1 * y * t3 +
|
|
D * x * y * t3 +
|
|
E * t1 * t2 * z +
|
|
F * x * t2 * z +
|
|
G * t1 * y * z +
|
|
H * x * y * z;
|
|
|
|
if ( gradient_value < 0.0 )
|
|
{
|
|
gradient_value = 0.0;
|
|
}
|
|
else if ( gradient_value > 255.0 )
|
|
{
|
|
gradient_value = 255.0;
|
|
}
|
|
|
|
opacity *= GOTF[(int)(gradient_value)];
|
|
}
|
|
else
|
|
{
|
|
opacity *= gradient_opacity_constant;
|
|
}
|
|
|
|
red_value = opacity * CTF[(int)(scalar_value) * 3 ];
|
|
green_value = opacity * CTF[(int)(scalar_value) * 3 + 1];
|
|
blue_value = opacity * CTF[(int)(scalar_value) * 3 + 2];
|
|
|
|
// Accumulate intensity and opacity for this sample location
|
|
accum_red_intensity += remaining_opacity * red_value;
|
|
accum_green_intensity += remaining_opacity * green_value;
|
|
accum_blue_intensity += remaining_opacity * blue_value;
|
|
remaining_opacity *= (1.0 - opacity);
|
|
}
|
|
|
|
// Increment our position and compute our voxel location
|
|
ray_position[0] += ray_increment[0];
|
|
ray_position[1] += ray_increment[1];
|
|
ray_position[2] += ray_increment[2];
|
|
voxel[0] = vtkFloorFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkFloorFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkFloorFuncMacro( ray_position[2] );
|
|
}
|
|
}
|
|
|
|
// Cap the intensity value at 1.0
|
|
if ( accum_red_intensity > 1.0 )
|
|
{
|
|
accum_red_intensity = 1.0;
|
|
}
|
|
if ( accum_green_intensity > 1.0 )
|
|
{
|
|
accum_green_intensity = 1.0;
|
|
}
|
|
if ( accum_blue_intensity > 1.0 )
|
|
{
|
|
accum_blue_intensity = 1.0;
|
|
}
|
|
|
|
if( remaining_opacity < VTK_REMAINING_OPACITY )
|
|
{
|
|
remaining_opacity = 0.0;
|
|
}
|
|
|
|
// Set the return pixel value. The depth value is the distance to the
|
|
// center of the volume.
|
|
dynamicInfo->Color[0] = accum_red_intensity;
|
|
dynamicInfo->Color[1] = accum_green_intensity;
|
|
dynamicInfo->Color[2] = accum_blue_intensity;
|
|
dynamicInfo->Color[3] = 1.0 - remaining_opacity;
|
|
dynamicInfo->NumberOfStepsTaken = steps_this_ray;
|
|
|
|
|
|
}
|
|
|
|
// This is the templated function that actually casts a ray and computes
|
|
// the composite value. This version uses trilinear interpolation, and
|
|
// does perform shading.
|
|
template <class T>
|
|
void vtkCastRay_TrilinSample_Shaded( T *data_ptr, vtkVolumeRayCastDynamicInfo *dynamicInfo,
|
|
vtkVolumeRayCastStaticInfo *staticInfo )
|
|
{
|
|
unsigned char *grad_mag_ptr = NULL;
|
|
unsigned char *gmptr;
|
|
float accum_red_intensity;
|
|
float accum_green_intensity;
|
|
float accum_blue_intensity;
|
|
float remaining_opacity;
|
|
float opacity;
|
|
int loop;
|
|
int xinc, yinc, zinc;
|
|
int voxel[3];
|
|
float ray_position[3];
|
|
float A, B, C, D, E, F, G, H;
|
|
int A_n, B_n, C_n, D_n, E_n, F_n, G_n, H_n;
|
|
float final_rd, final_gd, final_bd;
|
|
float final_rs, final_gs, final_bs;
|
|
int Binc, Cinc, Dinc, Einc, Finc, Ginc, Hinc;
|
|
T *dptr;
|
|
float *SOTF;
|
|
float *CTF;
|
|
float *GTF;
|
|
float *GOTF;
|
|
float x, y, z, t1, t2, t3;
|
|
float tA, tB, tC, tD, tE, tF, tG, tH;
|
|
float *red_d_shade, *green_d_shade, *blue_d_shade;
|
|
float *red_s_shade, *green_s_shade, *blue_s_shade;
|
|
unsigned short *encoded_normals, *nptr;
|
|
float red_shaded_value, green_shaded_value, blue_shaded_value;
|
|
int offset;
|
|
int steps_this_ray = 0;
|
|
int gradient_value;
|
|
int scalar_value;
|
|
float r, g, b;
|
|
int grad_op_is_constant;
|
|
float gradient_opacity_constant;
|
|
int num_steps;
|
|
float *ray_start, *ray_increment;
|
|
|
|
|
|
num_steps = dynamicInfo->NumberOfStepsToTake;
|
|
ray_start = dynamicInfo->TransformedStart;
|
|
ray_increment = dynamicInfo->TransformedIncrement;
|
|
|
|
// Get diffuse shading table pointers
|
|
red_d_shade = staticInfo->RedDiffuseShadingTable;
|
|
green_d_shade = staticInfo->GreenDiffuseShadingTable;
|
|
blue_d_shade = staticInfo->BlueDiffuseShadingTable;
|
|
|
|
|
|
// Get diffuse shading table pointers
|
|
red_s_shade = staticInfo->RedSpecularShadingTable;
|
|
green_s_shade = staticInfo->GreenSpecularShadingTable;
|
|
blue_s_shade = staticInfo->BlueSpecularShadingTable;
|
|
|
|
// Get a pointer to the encoded normals for this volume
|
|
encoded_normals = staticInfo->EncodedNormals;
|
|
|
|
// Get the scalar opacity transfer function which maps scalar input values
|
|
// to opacities
|
|
SOTF = staticInfo->Volume->GetCorrectedScalarOpacityArray();
|
|
|
|
// Get the color transfer function which maps scalar input values
|
|
// to RGB values
|
|
CTF = staticInfo->Volume->GetRGBArray();
|
|
GTF = staticInfo->Volume->GetGrayArray();
|
|
|
|
// Get the gradient opacity transfer function for this volume (which maps
|
|
// gradient magnitudes to opacities)
|
|
GOTF = staticInfo->Volume->GetGradientOpacityArray();
|
|
|
|
// Get the gradient opacity constant. If this number is greater than
|
|
// or equal to 0.0, then the gradient opacity transfer function is
|
|
// a constant at that value, otherwise it is not a constant function
|
|
gradient_opacity_constant = staticInfo->Volume->GetGradientOpacityConstant();
|
|
grad_op_is_constant = ( gradient_opacity_constant >= 0.0 );
|
|
|
|
// Get a pointer to the gradient magnitudes for this volume
|
|
if ( !grad_op_is_constant )
|
|
{
|
|
grad_mag_ptr = staticInfo->GradientMagnitudes;
|
|
}
|
|
|
|
// Move the increments into local variables
|
|
xinc = staticInfo->DataIncrement[0];
|
|
yinc = staticInfo->DataIncrement[1];
|
|
zinc = staticInfo->DataIncrement[2];
|
|
|
|
// Initialize the ray position and voxel location
|
|
ray_position[0] = ray_start[0];
|
|
ray_position[1] = ray_start[1];
|
|
ray_position[2] = ray_start[2];
|
|
voxel[0] = vtkFloorFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkFloorFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkFloorFuncMacro( ray_position[2] );
|
|
|
|
// So far we haven't accumulated anything
|
|
accum_red_intensity = 0.0;
|
|
accum_green_intensity = 0.0;
|
|
accum_blue_intensity = 0.0;
|
|
remaining_opacity = 1.0;
|
|
|
|
// Compute the increments to get to the other 7 voxel vertices from A
|
|
Binc = xinc;
|
|
Cinc = yinc;
|
|
Dinc = xinc + yinc;
|
|
Einc = zinc;
|
|
Finc = zinc + xinc;
|
|
Ginc = zinc + yinc;
|
|
Hinc = zinc + xinc + yinc;
|
|
|
|
// Two cases - we are working with a gray or RGB transfer
|
|
// function - break them up to make it more efficient
|
|
if ( staticInfo->ColorChannels == 1 )
|
|
{
|
|
// For each step along the ray
|
|
for ( loop = 0;
|
|
loop < num_steps && remaining_opacity > VTK_REMAINING_OPACITY;
|
|
loop++ )
|
|
{
|
|
// We've taken another step
|
|
steps_this_ray++;
|
|
|
|
offset = voxel[2] * zinc + voxel[1] * yinc + voxel[0];
|
|
dptr = data_ptr + offset;
|
|
nptr = encoded_normals + offset;
|
|
|
|
A = *(dptr);
|
|
B = *(dptr + Binc);
|
|
C = *(dptr + Cinc);
|
|
D = *(dptr + Dinc);
|
|
E = *(dptr + Einc);
|
|
F = *(dptr + Finc);
|
|
G = *(dptr + Ginc);
|
|
H = *(dptr + Hinc);
|
|
|
|
// Compute our offset in the voxel, and use that to trilinearly
|
|
// interpolate a value
|
|
x = ray_position[0] - (float) voxel[0];
|
|
y = ray_position[1] - (float) voxel[1];
|
|
z = ray_position[2] - (float) voxel[2];
|
|
|
|
t1 = 1.0 - x;
|
|
t2 = 1.0 - y;
|
|
t3 = 1.0 - z;
|
|
|
|
tA = t1 * t2 * t3;
|
|
tB = x * t2 * t3;
|
|
tC = t1 * y * t3;
|
|
tD = x * y * t3;
|
|
tE = t1 * t2 * z;
|
|
tF = x * t2 * z;
|
|
tG = t1 * y * z;
|
|
tH = x * y * z;
|
|
|
|
scalar_value = (int) (
|
|
A * tA + B * tB + C * tC + D * tD +
|
|
E * tE + F * tF + G * tG + H * tH );
|
|
|
|
if ( scalar_value < 0 )
|
|
{
|
|
scalar_value = 0;
|
|
}
|
|
else if ( scalar_value > staticInfo->Volume->GetArraySize() - 1 )
|
|
{
|
|
scalar_value = (int)(staticInfo->Volume->GetArraySize() - 1);
|
|
}
|
|
|
|
opacity = SOTF[scalar_value];
|
|
|
|
// If we have some opacity based on the scalar value transfer function,
|
|
// then multiply by the opacity from the gradient magnitude transfer
|
|
// function
|
|
if ( opacity )
|
|
{
|
|
if ( !grad_op_is_constant )
|
|
{
|
|
gmptr = grad_mag_ptr + offset;
|
|
|
|
A = *(gmptr);
|
|
B = *(gmptr + Binc);
|
|
C = *(gmptr + Cinc);
|
|
D = *(gmptr + Dinc);
|
|
E = *(gmptr + Einc);
|
|
F = *(gmptr + Finc);
|
|
G = *(gmptr + Ginc);
|
|
H = *(gmptr + Hinc);
|
|
|
|
gradient_value = (int) (
|
|
A * tA + B * tB + C * tC + D * tD +
|
|
E * tE + F * tF + G * tG + H * tH );
|
|
if ( gradient_value < 0 )
|
|
{
|
|
gradient_value = 0;
|
|
}
|
|
else if ( gradient_value > 255 )
|
|
{
|
|
gradient_value = 255;
|
|
}
|
|
|
|
opacity *= GOTF[gradient_value];
|
|
}
|
|
else
|
|
{
|
|
opacity *= gradient_opacity_constant;
|
|
}
|
|
}
|
|
|
|
// If we have a combined opacity value, then compute the shading
|
|
if ( opacity )
|
|
{
|
|
A_n = *(nptr);
|
|
B_n = *(nptr + Binc);
|
|
C_n = *(nptr + Cinc);
|
|
D_n = *(nptr + Dinc);
|
|
E_n = *(nptr + Einc);
|
|
F_n = *(nptr + Finc);
|
|
G_n = *(nptr + Ginc);
|
|
H_n = *(nptr + Hinc);
|
|
|
|
final_rd =
|
|
red_d_shade[ A_n ] * tA + red_d_shade[ B_n ] * tB +
|
|
red_d_shade[ C_n ] * tC + red_d_shade[ D_n ] * tD +
|
|
red_d_shade[ E_n ] * tE + red_d_shade[ F_n ] * tF +
|
|
red_d_shade[ G_n ] * tG + red_d_shade[ H_n ] * tH;
|
|
|
|
final_rs =
|
|
red_s_shade[ A_n ] * tA + red_s_shade[ B_n ] * tB +
|
|
red_s_shade[ C_n ] * tC + red_s_shade[ D_n ] * tD +
|
|
red_s_shade[ E_n ] * tE + red_s_shade[ F_n ] * tF +
|
|
red_s_shade[ G_n ] * tG + red_s_shade[ H_n ] * tH;
|
|
|
|
r = GTF[(scalar_value)];
|
|
|
|
// For this sample we have do not yet have any opacity or
|
|
// shaded intensity yet
|
|
red_shaded_value = opacity * ( final_rd * r + final_rs );
|
|
|
|
// Accumulate intensity and opacity for this sample location
|
|
accum_red_intensity += red_shaded_value * remaining_opacity;
|
|
remaining_opacity *= (1.0 - opacity);
|
|
}
|
|
|
|
// Increment our position and compute our voxel location
|
|
ray_position[0] += ray_increment[0];
|
|
ray_position[1] += ray_increment[1];
|
|
ray_position[2] += ray_increment[2];
|
|
voxel[0] = vtkFloorFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkFloorFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkFloorFuncMacro( ray_position[2] );
|
|
}
|
|
accum_green_intensity = accum_red_intensity;
|
|
accum_blue_intensity = accum_red_intensity;
|
|
}
|
|
else if ( staticInfo->ColorChannels == 3 )
|
|
{
|
|
// For each step along the ray
|
|
for ( loop = 0;
|
|
loop < num_steps && remaining_opacity > VTK_REMAINING_OPACITY;
|
|
loop++ )
|
|
{
|
|
// We've taken another step
|
|
steps_this_ray++;
|
|
|
|
offset = voxel[2] * zinc + voxel[1] * yinc + voxel[0];
|
|
dptr = data_ptr + offset;
|
|
nptr = encoded_normals + offset;
|
|
|
|
A = *(dptr);
|
|
B = *(dptr + Binc);
|
|
C = *(dptr + Cinc);
|
|
D = *(dptr + Dinc);
|
|
E = *(dptr + Einc);
|
|
F = *(dptr + Finc);
|
|
G = *(dptr + Ginc);
|
|
H = *(dptr + Hinc);
|
|
|
|
// Compute our offset in the voxel, and use that to trilinearly
|
|
// interpolate a value
|
|
x = ray_position[0] - (float) voxel[0];
|
|
y = ray_position[1] - (float) voxel[1];
|
|
z = ray_position[2] - (float) voxel[2];
|
|
|
|
t1 = 1.0 - x;
|
|
t2 = 1.0 - y;
|
|
t3 = 1.0 - z;
|
|
|
|
tA = t1 * t2 * t3;
|
|
tB = x * t2 * t3;
|
|
tC = t1 * y * t3;
|
|
tD = x * y * t3;
|
|
tE = t1 * t2 * z;
|
|
tF = x * t2 * z;
|
|
tG = t1 * y * z;
|
|
tH = x * y * z;
|
|
|
|
scalar_value = (int) (
|
|
A * tA + B * tB + C * tC + D * tD +
|
|
E * tE + F * tF + G * tG + H * tH );
|
|
|
|
if ( scalar_value < 0 )
|
|
{
|
|
scalar_value = 0;
|
|
}
|
|
else if ( scalar_value > staticInfo->Volume->GetArraySize() - 1 )
|
|
{
|
|
scalar_value = (int)(staticInfo->Volume->GetArraySize() - 1);
|
|
}
|
|
|
|
opacity = SOTF[scalar_value];
|
|
|
|
if ( opacity )
|
|
{
|
|
if ( !grad_op_is_constant )
|
|
{
|
|
gmptr = grad_mag_ptr + offset;
|
|
|
|
A = *(gmptr);
|
|
B = *(gmptr + Binc);
|
|
C = *(gmptr + Cinc);
|
|
D = *(gmptr + Dinc);
|
|
E = *(gmptr + Einc);
|
|
F = *(gmptr + Finc);
|
|
G = *(gmptr + Ginc);
|
|
H = *(gmptr + Hinc);
|
|
|
|
gradient_value = (int) (
|
|
A * tA + B * tB + C * tC + D * tD +
|
|
E * tE + F * tF + G * tG + H * tH );
|
|
if ( gradient_value < 0 )
|
|
{
|
|
gradient_value = 0;
|
|
}
|
|
else if ( gradient_value > 255 )
|
|
{
|
|
gradient_value = 255;
|
|
}
|
|
|
|
opacity *= GOTF[gradient_value];
|
|
}
|
|
else
|
|
{
|
|
opacity *= gradient_opacity_constant;
|
|
}
|
|
}
|
|
|
|
// If we have a combined opacity value, then compute the shading
|
|
if ( opacity )
|
|
{
|
|
A_n = *(nptr);
|
|
B_n = *(nptr + Binc);
|
|
C_n = *(nptr + Cinc);
|
|
D_n = *(nptr + Dinc);
|
|
E_n = *(nptr + Einc);
|
|
F_n = *(nptr + Finc);
|
|
G_n = *(nptr + Ginc);
|
|
H_n = *(nptr + Hinc);
|
|
|
|
final_rd =
|
|
red_d_shade[ A_n ] * tA + red_d_shade[ B_n ] * tB +
|
|
red_d_shade[ C_n ] * tC + red_d_shade[ D_n ] * tD +
|
|
red_d_shade[ E_n ] * tE + red_d_shade[ F_n ] * tF +
|
|
red_d_shade[ G_n ] * tG + red_d_shade[ H_n ] * tH;
|
|
|
|
final_gd =
|
|
green_d_shade[ A_n ] * tA + green_d_shade[ B_n ] * tB +
|
|
green_d_shade[ C_n ] * tC + green_d_shade[ D_n ] * tD +
|
|
green_d_shade[ E_n ] * tE + green_d_shade[ F_n ] * tF +
|
|
green_d_shade[ G_n ] * tG + green_d_shade[ H_n ] * tH;
|
|
|
|
final_bd =
|
|
blue_d_shade[ A_n ] * tA + blue_d_shade[ B_n ] * tB +
|
|
blue_d_shade[ C_n ] * tC + blue_d_shade[ D_n ] * tD +
|
|
blue_d_shade[ E_n ] * tE + blue_d_shade[ F_n ] * tF +
|
|
blue_d_shade[ G_n ] * tG + blue_d_shade[ H_n ] * tH;
|
|
|
|
final_rs =
|
|
red_s_shade[ A_n ] * tA + red_s_shade[ B_n ] * tB +
|
|
red_s_shade[ C_n ] * tC + red_s_shade[ D_n ] * tD +
|
|
red_s_shade[ E_n ] * tE + red_s_shade[ F_n ] * tF +
|
|
red_s_shade[ G_n ] * tG + red_s_shade[ H_n ] * tH;
|
|
|
|
final_gs =
|
|
green_s_shade[ A_n ] * tA + green_s_shade[ B_n ] * tB +
|
|
green_s_shade[ C_n ] * tC + green_s_shade[ D_n ] * tD +
|
|
green_s_shade[ E_n ] * tE + green_s_shade[ F_n ] * tF +
|
|
green_s_shade[ G_n ] * tG + green_s_shade[ H_n ] * tH;
|
|
|
|
final_bs =
|
|
blue_s_shade[ A_n ] * tA + blue_s_shade[ B_n ] * tB +
|
|
blue_s_shade[ C_n ] * tC + blue_s_shade[ D_n ] * tD +
|
|
blue_s_shade[ E_n ] * tE + blue_s_shade[ F_n ] * tF +
|
|
blue_s_shade[ G_n ] * tG + blue_s_shade[ H_n ] * tH;
|
|
|
|
r = CTF[(scalar_value) * 3 ];
|
|
g = CTF[(scalar_value) * 3 + 1];
|
|
b = CTF[(scalar_value) * 3 + 2];
|
|
|
|
// For this sample we have do not yet have any opacity or
|
|
// shaded intensity yet
|
|
red_shaded_value = opacity * ( final_rd * r + final_rs );
|
|
green_shaded_value = opacity * ( final_gd * g + final_gs );
|
|
blue_shaded_value = opacity * ( final_bd * b + final_bs );
|
|
|
|
// Accumulate intensity and opacity for this sample location
|
|
accum_red_intensity += red_shaded_value * remaining_opacity;
|
|
accum_green_intensity += green_shaded_value * remaining_opacity;
|
|
accum_blue_intensity += blue_shaded_value * remaining_opacity;
|
|
remaining_opacity *= (1.0 - opacity);
|
|
}
|
|
|
|
// Increment our position and compute our voxel location
|
|
ray_position[0] += ray_increment[0];
|
|
ray_position[1] += ray_increment[1];
|
|
ray_position[2] += ray_increment[2];
|
|
voxel[0] = vtkFloorFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkFloorFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkFloorFuncMacro( ray_position[2] );
|
|
}
|
|
}
|
|
|
|
// Cap the accumulated intensity at 1.0
|
|
if ( accum_red_intensity > 1.0 )
|
|
{
|
|
accum_red_intensity = 1.0;
|
|
}
|
|
if ( accum_green_intensity > 1.0 )
|
|
{
|
|
accum_green_intensity = 1.0;
|
|
}
|
|
if ( accum_blue_intensity > 1.0 )
|
|
{
|
|
accum_blue_intensity = 1.0;
|
|
}
|
|
|
|
if( remaining_opacity < VTK_REMAINING_OPACITY )
|
|
{
|
|
remaining_opacity = 0.0;
|
|
}
|
|
|
|
// Set the return pixel value. The depth value is the distance to the
|
|
// center of the volume.
|
|
dynamicInfo->Color[0] = accum_red_intensity;
|
|
dynamicInfo->Color[1] = accum_green_intensity;
|
|
dynamicInfo->Color[2] = accum_blue_intensity;
|
|
dynamicInfo->Color[3] = 1.0 - remaining_opacity;
|
|
dynamicInfo->NumberOfStepsTaken = steps_this_ray;
|
|
|
|
|
|
}
|
|
|
|
// Description:
|
|
// This is the templated function that actually casts a ray and computes
|
|
// the composite value. This version uses trilinear interpolation and
|
|
// does not compute shading
|
|
template <class T>
|
|
void vtkCastRay_TrilinVertices_Unshaded( T *data_ptr, vtkVolumeRayCastDynamicInfo *dynamicInfo,
|
|
vtkVolumeRayCastStaticInfo *staticInfo )
|
|
{
|
|
unsigned char *grad_mag_ptr = NULL;
|
|
unsigned char *goptr;
|
|
float accum_red_intensity;
|
|
float accum_green_intensity;
|
|
float accum_blue_intensity;
|
|
float remaining_opacity;
|
|
float red_value, green_value, blue_value;
|
|
float opacity;
|
|
int loop;
|
|
int xinc, yinc, zinc;
|
|
int voxel[3];
|
|
float ray_position[3];
|
|
int prev_voxel[3];
|
|
float A, B, C, D, E, F, G, H;
|
|
float Ago, Bgo, Cgo, Dgo, Ego, Fgo, Ggo, Hgo;
|
|
int Binc, Cinc, Dinc, Einc, Finc, Ginc, Hinc;
|
|
T *dptr;
|
|
float *SOTF;
|
|
float *CTF;
|
|
float *GTF;
|
|
float *GOTF;
|
|
float x, y, z, t1, t2, t3;
|
|
float weight;
|
|
int offset;
|
|
int steps_this_ray = 0;
|
|
int num_steps;
|
|
float *ray_start, *ray_increment;
|
|
int grad_op_is_constant;
|
|
float gradient_opacity_constant;
|
|
|
|
num_steps = dynamicInfo->NumberOfStepsToTake;
|
|
ray_start = dynamicInfo->TransformedStart;
|
|
ray_increment = dynamicInfo->TransformedIncrement;
|
|
|
|
// Get the scalar opacity transfer function which maps scalar input values
|
|
// to opacities
|
|
SOTF = staticInfo->Volume->GetCorrectedScalarOpacityArray();
|
|
|
|
// Get the color transfer function which maps scalar input values
|
|
// to RGB colors
|
|
CTF = staticInfo->Volume->GetRGBArray();
|
|
GTF = staticInfo->Volume->GetGrayArray();
|
|
|
|
// Get the gradient opacity transfer function for this volume (which maps
|
|
// gradient magnitudes to opacities)
|
|
GOTF = staticInfo->Volume->GetGradientOpacityArray();
|
|
|
|
// Get the gradient opacity constant. If this number is greater than
|
|
// or equal to 0.0, then the gradient opacity transfer function is
|
|
// a constant at that value, otherwise it is not a constant function
|
|
gradient_opacity_constant = staticInfo->Volume->GetGradientOpacityConstant();
|
|
grad_op_is_constant = ( gradient_opacity_constant >= 0.0 );
|
|
|
|
// Get a pointer to the gradient magnitudes for this volume
|
|
if ( !grad_op_is_constant )
|
|
{
|
|
grad_mag_ptr = staticInfo->GradientMagnitudes;
|
|
}
|
|
|
|
// Move the increments into local variables
|
|
xinc = staticInfo->DataIncrement[0];
|
|
yinc = staticInfo->DataIncrement[1];
|
|
zinc = staticInfo->DataIncrement[2];
|
|
|
|
// Initialize the ray position and voxel location
|
|
ray_position[0] = ray_start[0];
|
|
ray_position[1] = ray_start[1];
|
|
ray_position[2] = ray_start[2];
|
|
voxel[0] = vtkFloorFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkFloorFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkFloorFuncMacro( ray_position[2] );
|
|
|
|
// So far we have not accumulated anything
|
|
accum_red_intensity = 0.0;
|
|
accum_green_intensity = 0.0;
|
|
accum_blue_intensity = 0.0;
|
|
remaining_opacity = 1.0;
|
|
|
|
// Compute the increments to get to the other 7 voxel vertices from A
|
|
Binc = xinc;
|
|
Cinc = yinc;
|
|
Dinc = xinc + yinc;
|
|
Einc = zinc;
|
|
Finc = zinc + xinc;
|
|
Ginc = zinc + yinc;
|
|
Hinc = zinc + xinc + yinc;
|
|
|
|
// Compute the values for the first pass through the loop
|
|
offset = voxel[2] * zinc + voxel[1] * yinc + voxel[0];
|
|
dptr = data_ptr + offset;
|
|
|
|
A = SOTF[(*(dptr))];
|
|
B = SOTF[(*(dptr + Binc))];
|
|
C = SOTF[(*(dptr + Cinc))];
|
|
D = SOTF[(*(dptr + Dinc))];
|
|
E = SOTF[(*(dptr + Einc))];
|
|
F = SOTF[(*(dptr + Finc))];
|
|
G = SOTF[(*(dptr + Ginc))];
|
|
H = SOTF[(*(dptr + Hinc))];
|
|
|
|
if ( !grad_op_is_constant )
|
|
{
|
|
goptr = grad_mag_ptr + offset;
|
|
Ago = GOTF[(*(goptr))];
|
|
Bgo = GOTF[(*(goptr + Binc))];
|
|
Cgo = GOTF[(*(goptr + Cinc))];
|
|
Dgo = GOTF[(*(goptr + Dinc))];
|
|
Ego = GOTF[(*(goptr + Einc))];
|
|
Fgo = GOTF[(*(goptr + Finc))];
|
|
Ggo = GOTF[(*(goptr + Ginc))];
|
|
Hgo = GOTF[(*(goptr + Hinc))];
|
|
}
|
|
else
|
|
{
|
|
Ago = Bgo = Cgo = Dgo = Ego = Fgo = Ggo = Hgo = 1.0;
|
|
}
|
|
|
|
// Keep track of previous voxel to know when we step into a new one
|
|
prev_voxel[0] = voxel[0];
|
|
prev_voxel[1] = voxel[1];
|
|
prev_voxel[2] = voxel[2];
|
|
|
|
// Two cases - we are working with a gray or RGB transfer
|
|
// function - break them up to make it more efficient
|
|
if ( staticInfo->ColorChannels == 1 )
|
|
{
|
|
// For each step along the ray
|
|
for ( loop = 0;
|
|
loop < num_steps && remaining_opacity > VTK_REMAINING_OPACITY;
|
|
loop++ )
|
|
{
|
|
// We've taken another step
|
|
steps_this_ray++;
|
|
|
|
// Have we moved into a new voxel? If so we need to recompute A-H
|
|
if ( prev_voxel[0] != voxel[0] ||
|
|
prev_voxel[1] != voxel[1] ||
|
|
prev_voxel[2] != voxel[2] )
|
|
{
|
|
offset = voxel[2] * zinc + voxel[1] * yinc + voxel[0];
|
|
dptr = data_ptr + offset;
|
|
|
|
A = SOTF[(*(dptr))];
|
|
B = SOTF[(*(dptr + Binc))];
|
|
C = SOTF[(*(dptr + Cinc))];
|
|
D = SOTF[(*(dptr + Dinc))];
|
|
E = SOTF[(*(dptr + Einc))];
|
|
F = SOTF[(*(dptr + Finc))];
|
|
G = SOTF[(*(dptr + Ginc))];
|
|
H = SOTF[(*(dptr + Hinc))];
|
|
|
|
if ( !grad_op_is_constant )
|
|
{
|
|
goptr = grad_mag_ptr + offset;
|
|
Ago = GOTF[(*(goptr))];
|
|
Bgo = GOTF[(*(goptr + Binc))];
|
|
Cgo = GOTF[(*(goptr + Cinc))];
|
|
Dgo = GOTF[(*(goptr + Dinc))];
|
|
Ego = GOTF[(*(goptr + Einc))];
|
|
Fgo = GOTF[(*(goptr + Finc))];
|
|
Ggo = GOTF[(*(goptr + Ginc))];
|
|
Hgo = GOTF[(*(goptr + Hinc))];
|
|
}
|
|
else
|
|
{
|
|
Ago = Bgo = Cgo = Dgo = Ego = Fgo = Ggo = Hgo = 1.0;
|
|
}
|
|
|
|
prev_voxel[0] = voxel[0];
|
|
prev_voxel[1] = voxel[1];
|
|
prev_voxel[2] = voxel[2];
|
|
}
|
|
|
|
// Compute our offset in the voxel, and use that to trilinearly
|
|
// interpolate the value
|
|
x = ray_position[0] - (float) voxel[0];
|
|
y = ray_position[1] - (float) voxel[1];
|
|
z = ray_position[2] - (float) voxel[2];
|
|
|
|
t1 = 1.0 - x;
|
|
t2 = 1.0 - y;
|
|
t3 = 1.0 - z;
|
|
|
|
// For this sample we have do not yet have any opacity
|
|
opacity = 0.0;
|
|
red_value = 0.0;
|
|
|
|
// Now add the opacity in vertex by vertex. If any of the A-H
|
|
// have a non-transparent opacity value, then add its contribution
|
|
// to the opacity
|
|
if ( A && Ago )
|
|
{
|
|
weight = t1*t2*t3 * A * Ago;
|
|
opacity += weight;
|
|
red_value += weight * GTF[((*dptr))];
|
|
}
|
|
|
|
if ( B && Bgo )
|
|
{
|
|
weight = x*t2*t3 * B * Bgo;
|
|
opacity += weight;
|
|
red_value += weight * GTF[((*(dptr + Binc)))];
|
|
}
|
|
|
|
if ( C && Cgo )
|
|
{
|
|
weight = t1*y*t3 * C * Cgo;
|
|
opacity += weight;
|
|
red_value += weight * GTF[((*(dptr + Cinc)))];
|
|
}
|
|
|
|
if ( D && Dgo )
|
|
{
|
|
weight = x*y*t3 * D * Dgo;
|
|
opacity += weight;
|
|
red_value += weight * GTF[((*(dptr + Dinc)))];
|
|
}
|
|
|
|
if ( E && Ego )
|
|
{
|
|
weight = t1*t2*z * E * Ego;
|
|
opacity += weight;
|
|
red_value += weight * GTF[((*(dptr + Einc)))];
|
|
}
|
|
|
|
if ( F && Fgo )
|
|
{
|
|
weight = x*t2*z * F * Fgo;
|
|
opacity += weight;
|
|
red_value += weight * GTF[((*(dptr + Finc)))];
|
|
}
|
|
|
|
if ( G && Ggo )
|
|
{
|
|
weight = t1*y*z * G * Ggo;
|
|
opacity += weight;
|
|
red_value += weight * GTF[((*(dptr + Ginc)))];
|
|
}
|
|
|
|
if ( H && Hgo )
|
|
{
|
|
weight = x*z*y * H * Hgo;
|
|
opacity += weight;
|
|
red_value += weight * GTF[((*(dptr + Hinc)))];
|
|
}
|
|
|
|
// Accumulate intensity and opacity for this sample location
|
|
accum_red_intensity += remaining_opacity * red_value;
|
|
remaining_opacity *= (1.0 - opacity);
|
|
|
|
// Increment our position and compute our voxel location
|
|
ray_position[0] += ray_increment[0];
|
|
ray_position[1] += ray_increment[1];
|
|
ray_position[2] += ray_increment[2];
|
|
voxel[0] = vtkFloorFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkFloorFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkFloorFuncMacro( ray_position[2] );
|
|
}
|
|
accum_green_intensity = accum_red_intensity;
|
|
accum_blue_intensity = accum_red_intensity;
|
|
}
|
|
else if ( staticInfo->ColorChannels == 3 )
|
|
{
|
|
// For each step along the ray
|
|
for ( loop = 0;
|
|
loop < num_steps && remaining_opacity > VTK_REMAINING_OPACITY;
|
|
loop++ )
|
|
{
|
|
// We've taken another step
|
|
steps_this_ray++;
|
|
|
|
// Have we moved into a new voxel? If so we need to recompute A-H
|
|
if ( prev_voxel[0] != voxel[0] ||
|
|
prev_voxel[1] != voxel[1] ||
|
|
prev_voxel[2] != voxel[2] )
|
|
{
|
|
offset = voxel[2] * zinc + voxel[1] * yinc + voxel[0];
|
|
dptr = data_ptr + offset;
|
|
|
|
A = SOTF[(*(dptr))];
|
|
B = SOTF[(*(dptr + Binc))];
|
|
C = SOTF[(*(dptr + Cinc))];
|
|
D = SOTF[(*(dptr + Dinc))];
|
|
E = SOTF[(*(dptr + Einc))];
|
|
F = SOTF[(*(dptr + Finc))];
|
|
G = SOTF[(*(dptr + Ginc))];
|
|
H = SOTF[(*(dptr + Hinc))];
|
|
|
|
if ( !grad_op_is_constant )
|
|
{
|
|
goptr = grad_mag_ptr + offset;
|
|
Ago = GOTF[(*(goptr))];
|
|
Bgo = GOTF[(*(goptr + Binc))];
|
|
Cgo = GOTF[(*(goptr + Cinc))];
|
|
Dgo = GOTF[(*(goptr + Dinc))];
|
|
Ego = GOTF[(*(goptr + Einc))];
|
|
Fgo = GOTF[(*(goptr + Finc))];
|
|
Ggo = GOTF[(*(goptr + Ginc))];
|
|
Hgo = GOTF[(*(goptr + Hinc))];
|
|
}
|
|
else
|
|
{
|
|
Ago = Bgo = Cgo = Dgo = Ego = Fgo = Ggo = Hgo = 1.0;
|
|
}
|
|
|
|
prev_voxel[0] = voxel[0];
|
|
prev_voxel[1] = voxel[1];
|
|
prev_voxel[2] = voxel[2];
|
|
}
|
|
|
|
// Compute our offset in the voxel, and use that to trilinearly
|
|
// interpolate the value
|
|
x = ray_position[0] - (float) voxel[0];
|
|
y = ray_position[1] - (float) voxel[1];
|
|
z = ray_position[2] - (float) voxel[2];
|
|
|
|
t1 = 1.0 - x;
|
|
t2 = 1.0 - y;
|
|
t3 = 1.0 - z;
|
|
|
|
// For this sample we have do not yet have any opacity
|
|
opacity = 0.0;
|
|
red_value = 0.0;
|
|
green_value = 0.0;
|
|
blue_value = 0.0;
|
|
|
|
// Now add the opacity in vertex by vertex. If any of the A-H
|
|
// have a non-transparent opacity value, then add its contribution
|
|
// to the opacity
|
|
if ( A && Ago )
|
|
{
|
|
weight = t1*t2*t3 * A * Ago;
|
|
opacity += weight;
|
|
red_value += weight * CTF[((*dptr)) * 3 ];
|
|
green_value += weight * CTF[((*dptr)) * 3 + 1];
|
|
blue_value += weight * CTF[((*dptr)) * 3 + 2];
|
|
}
|
|
|
|
if ( B && Bgo )
|
|
{
|
|
weight = x*t2*t3 * B * Bgo;
|
|
opacity += weight;
|
|
red_value += weight * CTF[((*(dptr + Binc))) * 3 ];
|
|
green_value += weight * CTF[((*(dptr + Binc))) * 3 + 1];
|
|
blue_value += weight * CTF[((*(dptr + Binc))) * 3 + 2];
|
|
}
|
|
|
|
if ( C && Cgo )
|
|
{
|
|
weight = t1*y*t3 * C * Cgo;
|
|
opacity += weight;
|
|
red_value += weight * CTF[((*(dptr + Cinc))) * 3 ];
|
|
green_value += weight * CTF[((*(dptr + Cinc))) * 3 + 1];
|
|
blue_value += weight * CTF[((*(dptr + Cinc))) * 3 + 2];
|
|
}
|
|
|
|
if ( D && Dgo )
|
|
{
|
|
weight = x*y*t3 * D * Dgo;
|
|
opacity += weight;
|
|
red_value += weight * CTF[((*(dptr + Dinc))) * 3 ];
|
|
green_value += weight * CTF[((*(dptr + Dinc))) * 3 + 1];
|
|
blue_value += weight * CTF[((*(dptr + Dinc))) * 3 + 2];
|
|
}
|
|
|
|
if ( E && Ego )
|
|
{
|
|
weight = t1*t2*z * E * Ego;
|
|
opacity += weight;
|
|
red_value += weight * CTF[((*(dptr + Einc))) * 3 ];
|
|
green_value += weight * CTF[((*(dptr + Einc))) * 3 + 1];
|
|
blue_value += weight * CTF[((*(dptr + Einc))) * 3 + 2];
|
|
}
|
|
|
|
if ( F && Fgo )
|
|
{
|
|
weight = x*t2*z * F * Fgo;
|
|
opacity += weight;
|
|
red_value += weight * CTF[((*(dptr + Finc))) * 3 ];
|
|
green_value += weight * CTF[((*(dptr + Finc))) * 3 + 1];
|
|
blue_value += weight * CTF[((*(dptr + Finc))) * 3 + 2];
|
|
}
|
|
|
|
if ( G && Ggo )
|
|
{
|
|
weight = t1*y*z * G * Ggo;
|
|
opacity += weight;
|
|
red_value += weight * CTF[((*(dptr + Ginc))) * 3 ];
|
|
green_value += weight * CTF[((*(dptr + Ginc))) * 3 + 1];
|
|
blue_value += weight * CTF[((*(dptr + Ginc))) * 3 + 2];
|
|
}
|
|
|
|
if ( H && Hgo )
|
|
{
|
|
weight = x*z*y * H * Hgo;
|
|
opacity += weight;
|
|
red_value += weight * CTF[((*(dptr + Hinc))) * 3 ];
|
|
green_value += weight * CTF[((*(dptr + Hinc))) * 3 + 1];
|
|
blue_value += weight * CTF[((*(dptr + Hinc))) * 3 + 2];
|
|
}
|
|
|
|
// Accumulate intensity and opacity for this sample location
|
|
accum_red_intensity += remaining_opacity * red_value;
|
|
accum_green_intensity += remaining_opacity * green_value;
|
|
accum_blue_intensity += remaining_opacity * blue_value;
|
|
remaining_opacity *= (1.0 - opacity);
|
|
|
|
// Increment our position and compute our voxel location
|
|
ray_position[0] += ray_increment[0];
|
|
ray_position[1] += ray_increment[1];
|
|
ray_position[2] += ray_increment[2];
|
|
voxel[0] = vtkFloorFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkFloorFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkFloorFuncMacro( ray_position[2] );
|
|
}
|
|
}
|
|
|
|
// Cap the accumulated intensity at 1.0
|
|
if ( accum_red_intensity > 1.0 )
|
|
{
|
|
accum_red_intensity = 1.0;
|
|
}
|
|
if ( accum_green_intensity > 1.0 )
|
|
{
|
|
accum_green_intensity = 1.0;
|
|
}
|
|
if ( accum_blue_intensity > 1.0 )
|
|
{
|
|
accum_blue_intensity = 1.0;
|
|
}
|
|
|
|
if( remaining_opacity < VTK_REMAINING_OPACITY )
|
|
{
|
|
remaining_opacity = 0.0;
|
|
}
|
|
|
|
// Set the return pixel value. The depth value is the distance to the
|
|
// center of the volume.
|
|
dynamicInfo->Color[0] = accum_red_intensity;
|
|
dynamicInfo->Color[1] = accum_green_intensity;
|
|
dynamicInfo->Color[2] = accum_blue_intensity;
|
|
dynamicInfo->Color[3] = 1.0 - remaining_opacity;
|
|
dynamicInfo->NumberOfStepsTaken = steps_this_ray;
|
|
|
|
|
|
}
|
|
|
|
|
|
// Description:
|
|
// This is the templated function that actually casts a ray and computes
|
|
// the composite value. This version uses trilinear interpolation, and
|
|
// does perform shading.
|
|
template <class T>
|
|
void vtkCastRay_TrilinVertices_Shaded( T *data_ptr, vtkVolumeRayCastDynamicInfo *dynamicInfo,
|
|
vtkVolumeRayCastStaticInfo *staticInfo )
|
|
{
|
|
unsigned char *grad_mag_ptr = NULL;
|
|
unsigned char *goptr;
|
|
float accum_red_intensity;
|
|
float accum_green_intensity;
|
|
float accum_blue_intensity;
|
|
float remaining_opacity;
|
|
float opacity;
|
|
int loop;
|
|
int xinc, yinc, zinc;
|
|
int voxel[3];
|
|
float ray_position[3];
|
|
int prev_voxel[3];
|
|
float A, B, C, D, E, F, G, H;
|
|
float Ago, Bgo, Cgo, Dgo, Ego, Fgo, Ggo, Hgo;
|
|
int Binc, Cinc, Dinc, Einc, Finc, Ginc, Hinc;
|
|
T *dptr;
|
|
float *SOTF;
|
|
float *CTF;
|
|
float *GTF;
|
|
float *GOTF;
|
|
float x, y, z, t1, t2, t3;
|
|
float weight;
|
|
float *red_d_shade, *green_d_shade, *blue_d_shade;
|
|
float *red_s_shade, *green_s_shade, *blue_s_shade;
|
|
unsigned short *encoded_normals, *nptr;
|
|
float red_shaded_value, green_shaded_value, blue_shaded_value;
|
|
int offset;
|
|
int steps_this_ray = 0;
|
|
int grad_op_is_constant;
|
|
float gradient_opacity_constant;
|
|
int num_steps;
|
|
float *ray_start, *ray_increment;
|
|
|
|
|
|
num_steps = dynamicInfo->NumberOfStepsToTake;
|
|
ray_start = dynamicInfo->TransformedStart;
|
|
ray_increment = dynamicInfo->TransformedIncrement;
|
|
|
|
// Get diffuse shading table pointers
|
|
red_d_shade = staticInfo->RedDiffuseShadingTable;
|
|
green_d_shade = staticInfo->GreenDiffuseShadingTable;
|
|
blue_d_shade = staticInfo->BlueDiffuseShadingTable;
|
|
|
|
|
|
// Get diffuse shading table pointers
|
|
red_s_shade = staticInfo->RedSpecularShadingTable;
|
|
green_s_shade = staticInfo->GreenSpecularShadingTable;
|
|
blue_s_shade = staticInfo->BlueSpecularShadingTable;
|
|
|
|
// Get a pointer to the encoded normals for this volume
|
|
encoded_normals = staticInfo->EncodedNormals;
|
|
|
|
// Get the scalar opacity transfer function which maps scalar input values
|
|
// to opacities
|
|
SOTF = staticInfo->Volume->GetCorrectedScalarOpacityArray();
|
|
|
|
// Get the color transfer function which maps scalar input values
|
|
// to RGB values
|
|
CTF = staticInfo->Volume->GetRGBArray();
|
|
GTF = staticInfo->Volume->GetGrayArray();
|
|
|
|
// Get the gradient opacity transfer function for this volume (which maps
|
|
// gradient magnitudes to opacities)
|
|
GOTF = staticInfo->Volume->GetGradientOpacityArray();
|
|
|
|
// Get the gradient opacity constant. If this number is greater than
|
|
// or equal to 0.0, then the gradient opacity transfer function is
|
|
// a constant at that value, otherwise it is not a constant function
|
|
gradient_opacity_constant = staticInfo->Volume->GetGradientOpacityConstant();
|
|
grad_op_is_constant = ( gradient_opacity_constant >= 0.0 );
|
|
|
|
// Get a pointer to the gradient magnitudes for this volume
|
|
if ( !grad_op_is_constant )
|
|
{
|
|
grad_mag_ptr = staticInfo->GradientMagnitudes;
|
|
}
|
|
|
|
// Move the increments into local variables
|
|
xinc = staticInfo->DataIncrement[0];
|
|
yinc = staticInfo->DataIncrement[1];
|
|
zinc = staticInfo->DataIncrement[2];
|
|
|
|
// Initialize the ray position and voxel location
|
|
ray_position[0] = ray_start[0];
|
|
ray_position[1] = ray_start[1];
|
|
ray_position[2] = ray_start[2];
|
|
voxel[0] = vtkFloorFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkFloorFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkFloorFuncMacro( ray_position[2] );
|
|
|
|
// So far we haven't accumulated anything
|
|
accum_red_intensity = 0.0;
|
|
accum_green_intensity = 0.0;
|
|
accum_blue_intensity = 0.0;
|
|
remaining_opacity = 1.0;
|
|
|
|
// Compute the increments to get to the other 7 voxel vertices from A
|
|
Binc = xinc;
|
|
Cinc = yinc;
|
|
Dinc = xinc + yinc;
|
|
Einc = zinc;
|
|
Finc = zinc + xinc;
|
|
Ginc = zinc + yinc;
|
|
Hinc = zinc + xinc + yinc;
|
|
|
|
// Compute the values for the first pass through the loop
|
|
offset = voxel[2] * zinc + voxel[1] * yinc + voxel[0];
|
|
dptr = data_ptr + offset;
|
|
nptr = encoded_normals + offset;
|
|
|
|
A = SOTF[(*(dptr))];
|
|
B = SOTF[(*(dptr + Binc))];
|
|
C = SOTF[(*(dptr + Cinc))];
|
|
D = SOTF[(*(dptr + Dinc))];
|
|
E = SOTF[(*(dptr + Einc))];
|
|
F = SOTF[(*(dptr + Finc))];
|
|
G = SOTF[(*(dptr + Ginc))];
|
|
H = SOTF[(*(dptr + Hinc))];
|
|
|
|
if ( !grad_op_is_constant )
|
|
{
|
|
goptr = grad_mag_ptr + offset;
|
|
Ago = GOTF[(*(goptr))];
|
|
Bgo = GOTF[(*(goptr + Binc))];
|
|
Cgo = GOTF[(*(goptr + Cinc))];
|
|
Dgo = GOTF[(*(goptr + Dinc))];
|
|
Ego = GOTF[(*(goptr + Einc))];
|
|
Fgo = GOTF[(*(goptr + Finc))];
|
|
Ggo = GOTF[(*(goptr + Ginc))];
|
|
Hgo = GOTF[(*(goptr + Hinc))];
|
|
}
|
|
else
|
|
{
|
|
Ago = Bgo = Cgo = Dgo = Ego = Fgo = Ggo = Hgo = 1.0;
|
|
}
|
|
|
|
|
|
// Keep track of previous voxel to know when we step into a new one
|
|
prev_voxel[0] = voxel[0];
|
|
prev_voxel[1] = voxel[1];
|
|
prev_voxel[2] = voxel[2];
|
|
|
|
// Two cases - we are working with a single color or a color transfer
|
|
// function - break them up to make it more efficient
|
|
if ( staticInfo->ColorChannels == 1 )
|
|
{
|
|
// For each step along the ray
|
|
for ( loop = 0;
|
|
loop < num_steps && remaining_opacity > VTK_REMAINING_OPACITY;
|
|
loop++ )
|
|
{
|
|
// We've taken another step
|
|
steps_this_ray++;
|
|
|
|
// Have we moved into a new voxel? If so we need to recompute A-H
|
|
if ( prev_voxel[0] != voxel[0] ||
|
|
prev_voxel[1] != voxel[1] ||
|
|
prev_voxel[2] != voxel[2] )
|
|
{
|
|
offset = voxel[2] * zinc + voxel[1] * yinc + voxel[0];
|
|
dptr = data_ptr + offset;
|
|
nptr = encoded_normals + offset;
|
|
//goptr = grad_mag_ptr + offset;
|
|
|
|
A = SOTF[(*(dptr))];
|
|
B = SOTF[(*(dptr + Binc))];
|
|
C = SOTF[(*(dptr + Cinc))];
|
|
D = SOTF[(*(dptr + Dinc))];
|
|
E = SOTF[(*(dptr + Einc))];
|
|
F = SOTF[(*(dptr + Finc))];
|
|
G = SOTF[(*(dptr + Ginc))];
|
|
H = SOTF[(*(dptr + Hinc))];
|
|
|
|
if ( !grad_op_is_constant )
|
|
{
|
|
goptr = grad_mag_ptr + offset;
|
|
Ago = GOTF[(*(goptr))];
|
|
Bgo = GOTF[(*(goptr + Binc))];
|
|
Cgo = GOTF[(*(goptr + Cinc))];
|
|
Dgo = GOTF[(*(goptr + Dinc))];
|
|
Ego = GOTF[(*(goptr + Einc))];
|
|
Fgo = GOTF[(*(goptr + Finc))];
|
|
Ggo = GOTF[(*(goptr + Ginc))];
|
|
Hgo = GOTF[(*(goptr + Hinc))];
|
|
}
|
|
else
|
|
{
|
|
Ago = Bgo = Cgo = Dgo = Ego = Fgo = Ggo = Hgo = 1.0;
|
|
}
|
|
|
|
prev_voxel[0] = voxel[0];
|
|
prev_voxel[1] = voxel[1];
|
|
prev_voxel[2] = voxel[2];
|
|
}
|
|
|
|
// Compute our offset in the voxel, and use that to trilinearly
|
|
// interpolate a value
|
|
x = ray_position[0] - (float) voxel[0];
|
|
y = ray_position[1] - (float) voxel[1];
|
|
z = ray_position[2] - (float) voxel[2];
|
|
|
|
t1 = 1.0 - x;
|
|
t2 = 1.0 - y;
|
|
t3 = 1.0 - z;
|
|
|
|
// For this sample we have do not yet have any opacity or
|
|
// shaded intensity yet
|
|
opacity = 0.0;
|
|
red_shaded_value = 0.0;
|
|
|
|
// Now add the opacity and shaded intensity value in vertex by
|
|
// vertex. If any of the A-H have a non-transparent opacity value,
|
|
// then add its contribution to the opacity
|
|
if ( A && Ago )
|
|
{
|
|
weight = t1*t2*t3 * A * Ago;
|
|
opacity += weight;
|
|
red_shaded_value += weight * ( red_d_shade[ *(nptr) ] *
|
|
GTF[*(dptr)] +
|
|
red_s_shade[ *(nptr) ] );
|
|
}
|
|
|
|
if ( B && Bgo )
|
|
{
|
|
weight = x*t2*t3 * B * Bgo;
|
|
opacity += weight;
|
|
red_shaded_value += weight * ( red_d_shade[ *(nptr + Binc) ] *
|
|
GTF[*(dptr+Binc)] +
|
|
red_s_shade[ *(nptr + Binc) ] );
|
|
}
|
|
|
|
if ( C && Cgo )
|
|
{
|
|
weight = t1*y*t3 * C * Cgo;
|
|
opacity += weight;
|
|
red_shaded_value += weight * ( red_d_shade[ *(nptr + Cinc) ] *
|
|
GTF[*(dptr+Cinc)] +
|
|
red_s_shade[ *(nptr + Cinc) ] );
|
|
}
|
|
|
|
if ( D && Dgo )
|
|
{
|
|
weight = x*y*t3 * D * Dgo;
|
|
opacity += weight;
|
|
red_shaded_value += weight * ( red_d_shade[ *(nptr + Dinc) ] *
|
|
GTF[*(dptr+Dinc)] +
|
|
red_s_shade[ *(nptr + Dinc) ] );
|
|
}
|
|
|
|
if ( E && Ego )
|
|
{
|
|
weight = t1*t2*z * E * Ego;
|
|
opacity += weight;
|
|
red_shaded_value += weight * ( red_d_shade[ *(nptr + Einc) ] *
|
|
GTF[*(dptr+Einc)] +
|
|
red_s_shade[ *(nptr + Einc) ] );
|
|
}
|
|
|
|
if ( F && Fgo )
|
|
{
|
|
weight = x*z*t2 * F * Fgo;
|
|
opacity += weight;
|
|
red_shaded_value += weight * ( red_d_shade[ *(nptr + Finc) ] *
|
|
GTF[*(dptr+Finc)] +
|
|
red_s_shade[ *(nptr + Finc) ] );
|
|
}
|
|
|
|
if ( G && Ggo )
|
|
{
|
|
weight = t1*y*z * G * Ggo;
|
|
opacity += weight;
|
|
red_shaded_value += weight * ( red_d_shade[ *(nptr + Ginc) ] *
|
|
GTF[*(dptr+Ginc)] +
|
|
red_s_shade[ *(nptr + Ginc) ] );
|
|
}
|
|
|
|
if ( H && Hgo )
|
|
{
|
|
weight = x*z*y * H * Hgo;
|
|
opacity += weight;
|
|
red_shaded_value += weight * ( red_d_shade[ *(nptr + Hinc) ] *
|
|
GTF[*(dptr+Hinc)] +
|
|
red_s_shade[ *(nptr + Hinc) ] );
|
|
}
|
|
|
|
// Accumulate intensity and opacity for this sample location
|
|
accum_red_intensity += red_shaded_value * remaining_opacity;
|
|
remaining_opacity *= (1.0 - opacity);
|
|
|
|
// Increment our position and compute our voxel location
|
|
ray_position[0] += ray_increment[0];
|
|
ray_position[1] += ray_increment[1];
|
|
ray_position[2] += ray_increment[2];
|
|
voxel[0] = vtkFloorFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkFloorFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkFloorFuncMacro( ray_position[2] );
|
|
}
|
|
accum_green_intensity = accum_red_intensity;
|
|
accum_blue_intensity = accum_red_intensity;
|
|
}
|
|
else if ( staticInfo->ColorChannels == 3 )
|
|
{
|
|
// For each step along the ray
|
|
for ( loop = 0;
|
|
loop < num_steps && remaining_opacity > VTK_REMAINING_OPACITY;
|
|
loop++ )
|
|
{
|
|
// We've taken another step
|
|
steps_this_ray++;
|
|
|
|
// Have we moved into a new voxel? If so we need to recompute A-H
|
|
if ( prev_voxel[0] != voxel[0] ||
|
|
prev_voxel[1] != voxel[1] ||
|
|
prev_voxel[2] != voxel[2] )
|
|
{
|
|
offset = voxel[2] * zinc + voxel[1] * yinc + voxel[0];
|
|
dptr = data_ptr + offset;
|
|
nptr = encoded_normals + offset;
|
|
|
|
A = SOTF[(*(dptr))];
|
|
B = SOTF[(*(dptr + Binc))];
|
|
C = SOTF[(*(dptr + Cinc))];
|
|
D = SOTF[(*(dptr + Dinc))];
|
|
E = SOTF[(*(dptr + Einc))];
|
|
F = SOTF[(*(dptr + Finc))];
|
|
G = SOTF[(*(dptr + Ginc))];
|
|
H = SOTF[(*(dptr + Hinc))];
|
|
|
|
if ( !grad_op_is_constant )
|
|
{
|
|
goptr = grad_mag_ptr + offset;
|
|
Ago = GOTF[(*(goptr))];
|
|
Bgo = GOTF[(*(goptr + Binc))];
|
|
Cgo = GOTF[(*(goptr + Cinc))];
|
|
Dgo = GOTF[(*(goptr + Dinc))];
|
|
Ego = GOTF[(*(goptr + Einc))];
|
|
Fgo = GOTF[(*(goptr + Finc))];
|
|
Ggo = GOTF[(*(goptr + Ginc))];
|
|
Hgo = GOTF[(*(goptr + Hinc))];
|
|
}
|
|
else
|
|
{
|
|
Ago = Bgo = Cgo = Dgo = Ego = Fgo = Ggo = Hgo = 1.0;
|
|
}
|
|
|
|
prev_voxel[0] = voxel[0];
|
|
prev_voxel[1] = voxel[1];
|
|
prev_voxel[2] = voxel[2];
|
|
}
|
|
|
|
// Compute our offset in the voxel, and use that to trilinearly
|
|
// interpolate a value
|
|
x = ray_position[0] - (float) voxel[0];
|
|
y = ray_position[1] - (float) voxel[1];
|
|
z = ray_position[2] - (float) voxel[2];
|
|
|
|
t1 = 1.0 - x;
|
|
t2 = 1.0 - y;
|
|
t3 = 1.0 - z;
|
|
|
|
// For this sample we have do not yet have any opacity or
|
|
// shaded intensity yet
|
|
opacity = 0.0;
|
|
red_shaded_value = 0.0;
|
|
green_shaded_value = 0.0;
|
|
blue_shaded_value = 0.0;
|
|
|
|
// Now add the opacity and shaded intensity value in vertex by
|
|
// vertex. If any of the A-H have a non-transparent opacity value,
|
|
// then add its contribution to the opacity
|
|
if ( A )
|
|
{
|
|
weight = t1*t2*t3 * A * Ago;
|
|
opacity += weight;
|
|
red_shaded_value += weight * ( red_d_shade[ *(nptr) ] *
|
|
CTF[*(dptr) * 3] +
|
|
red_s_shade[ *(nptr) ] );
|
|
green_shaded_value += weight * ( green_d_shade[ *(nptr) ] *
|
|
CTF[*(dptr) * 3 + 1] + +
|
|
green_s_shade[ *(nptr) ] );
|
|
blue_shaded_value += weight * ( blue_d_shade[ *(nptr) ] *
|
|
CTF[*(dptr) * 3 + 2] +
|
|
blue_s_shade[ *(nptr) ] );
|
|
}
|
|
|
|
if ( B )
|
|
{
|
|
weight = x*t2*t3 * B * Bgo;
|
|
opacity += weight;
|
|
red_shaded_value += weight * ( red_d_shade[ *(nptr + Binc) ] *
|
|
CTF[*(dptr+Binc) * 3] +
|
|
red_s_shade[ *(nptr + Binc) ] );
|
|
green_shaded_value += weight * ( green_d_shade[ *(nptr + Binc) ] *
|
|
CTF[*(dptr+Binc) * 3 + 1] +
|
|
green_s_shade[ *(nptr + Binc) ] );
|
|
blue_shaded_value += weight * ( blue_d_shade[ *(nptr + Binc) ] *
|
|
CTF[*(dptr+Binc) * 3 + 2] +
|
|
blue_s_shade[ *(nptr + Binc) ] );
|
|
}
|
|
|
|
if ( C )
|
|
{
|
|
weight = t1*y*t3 * C * Cgo;
|
|
opacity += weight;
|
|
red_shaded_value += weight * ( red_d_shade[ *(nptr + Cinc) ] *
|
|
CTF[*(dptr+Cinc) * 3] +
|
|
red_s_shade[ *(nptr + Cinc) ] );
|
|
green_shaded_value += weight * ( green_d_shade[ *(nptr + Cinc) ] *
|
|
CTF[*(dptr+Cinc) * 3 + 1] +
|
|
green_s_shade[ *(nptr + Cinc) ] );
|
|
blue_shaded_value += weight * ( blue_d_shade[ *(nptr + Cinc) ] *
|
|
CTF[*(dptr+Cinc) * 3 + 2] +
|
|
blue_s_shade[ *(nptr + Cinc) ] );
|
|
}
|
|
|
|
if ( D )
|
|
{
|
|
weight = x*y*t3 * D * Dgo;
|
|
opacity += weight;
|
|
red_shaded_value += weight * ( red_d_shade[ *(nptr + Dinc) ] *
|
|
CTF[*(dptr+Dinc) * 3] +
|
|
red_s_shade[ *(nptr + Dinc) ] );
|
|
green_shaded_value += weight * ( green_d_shade[ *(nptr + Dinc) ] *
|
|
CTF[*(dptr+Dinc) * 3 + 1] +
|
|
green_s_shade[ *(nptr + Dinc) ] );
|
|
blue_shaded_value += weight * ( blue_d_shade[ *(nptr + Dinc) ] *
|
|
CTF[*(dptr+Dinc) * 3 + 2] +
|
|
blue_s_shade[ *(nptr + Dinc) ] );
|
|
}
|
|
|
|
if ( E )
|
|
{
|
|
weight = t1*t2*z * E * Ego;
|
|
opacity += weight;
|
|
red_shaded_value += weight * ( red_d_shade[ *(nptr + Einc) ] *
|
|
CTF[*(dptr+Einc) * 3] +
|
|
red_s_shade[ *(nptr + Einc) ] );
|
|
green_shaded_value += weight * ( green_d_shade[ *(nptr + Einc) ] *
|
|
CTF[*(dptr+Einc) * 3 + 1] +
|
|
green_s_shade[ *(nptr + Einc) ] );
|
|
blue_shaded_value += weight * ( blue_d_shade[ *(nptr + Einc) ] *
|
|
CTF[*(dptr+Einc) * 3 + 2] +
|
|
blue_s_shade[ *(nptr + Einc) ] );
|
|
}
|
|
|
|
if ( F )
|
|
{
|
|
weight = x*z*t2 * F * Fgo;
|
|
opacity += weight;
|
|
red_shaded_value += weight * ( red_d_shade[ *(nptr + Finc) ] *
|
|
CTF[*(dptr+Finc) * 3] +
|
|
red_s_shade[ *(nptr + Finc) ] );
|
|
green_shaded_value += weight * ( green_d_shade[ *(nptr + Finc) ] *
|
|
CTF[*(dptr+Finc) * 3 + 1] +
|
|
green_s_shade[ *(nptr + Finc) ] );
|
|
blue_shaded_value += weight * ( blue_d_shade[ *(nptr + Finc) ] *
|
|
CTF[*(dptr+Finc) * 3 + 2] +
|
|
blue_s_shade[ *(nptr + Finc) ] );
|
|
}
|
|
|
|
if ( G )
|
|
{
|
|
weight = t1*y*z * G * Ggo;
|
|
opacity += weight;
|
|
red_shaded_value += weight * ( red_d_shade[ *(nptr + Ginc) ] *
|
|
CTF[*(dptr+Ginc) * 3] +
|
|
red_s_shade[ *(nptr + Ginc) ] );
|
|
green_shaded_value += weight * ( green_d_shade[ *(nptr + Ginc) ] *
|
|
CTF[*(dptr+Ginc) * 3 + 1] +
|
|
green_s_shade[ *(nptr + Ginc) ] );
|
|
blue_shaded_value += weight * ( blue_d_shade[ *(nptr + Ginc) ] *
|
|
CTF[*(dptr+Ginc) * 3 + 2] +
|
|
blue_s_shade[ *(nptr + Ginc) ] );
|
|
}
|
|
|
|
if ( H )
|
|
{
|
|
weight = x*z*y * H * Hgo;
|
|
opacity += weight;
|
|
red_shaded_value += weight * ( red_d_shade[ *(nptr + Hinc) ] *
|
|
CTF[*(dptr+Hinc) * 3] +
|
|
red_s_shade[ *(nptr + Hinc) ] );
|
|
green_shaded_value += weight * ( green_d_shade[ *(nptr + Hinc) ] *
|
|
CTF[*(dptr+Hinc) * 3 + 1] +
|
|
green_s_shade[ *(nptr + Hinc) ] );
|
|
blue_shaded_value += weight * ( blue_d_shade[ *(nptr + Hinc) ] *
|
|
CTF[*(dptr+Hinc) * 3 + 2] +
|
|
blue_s_shade[ *(nptr + Hinc) ] );
|
|
}
|
|
|
|
// Accumulate intensity and opacity for this sample location
|
|
accum_red_intensity += red_shaded_value * remaining_opacity;
|
|
accum_green_intensity += green_shaded_value * remaining_opacity;
|
|
accum_blue_intensity += blue_shaded_value * remaining_opacity;
|
|
remaining_opacity *= (1.0 - opacity);
|
|
|
|
// Increment our position and compute our voxel location
|
|
ray_position[0] += ray_increment[0];
|
|
ray_position[1] += ray_increment[1];
|
|
ray_position[2] += ray_increment[2];
|
|
voxel[0] = vtkFloorFuncMacro( ray_position[0] );
|
|
voxel[1] = vtkFloorFuncMacro( ray_position[1] );
|
|
voxel[2] = vtkFloorFuncMacro( ray_position[2] );
|
|
}
|
|
}
|
|
|
|
// Cap the accumulated intensity at 1.0
|
|
if ( accum_red_intensity > 1.0 )
|
|
{
|
|
accum_red_intensity = 1.0;
|
|
}
|
|
if ( accum_green_intensity > 1.0 )
|
|
{
|
|
accum_green_intensity = 1.0;
|
|
}
|
|
if ( accum_blue_intensity > 1.0 )
|
|
{
|
|
accum_blue_intensity = 1.0;
|
|
}
|
|
|
|
if( remaining_opacity < VTK_REMAINING_OPACITY )
|
|
{
|
|
remaining_opacity = 0.0;
|
|
}
|
|
|
|
// Set the return pixel value. The depth value is the distance to the
|
|
// center of the volume.
|
|
dynamicInfo->Color[0] = accum_red_intensity;
|
|
dynamicInfo->Color[1] = accum_green_intensity;
|
|
dynamicInfo->Color[2] = accum_blue_intensity;
|
|
dynamicInfo->Color[3] = 1.0 - remaining_opacity;
|
|
dynamicInfo->NumberOfStepsTaken = steps_this_ray;
|
|
|
|
|
|
}
|
|
|
|
// Constructor for the vtkVolumeRayCastCompositeFunction class
|
|
vtkVolumeRayCastCompositeFunction::vtkVolumeRayCastCompositeFunction()
|
|
{
|
|
this->CompositeMethod = VTK_COMPOSITE_INTERPOLATE_FIRST;
|
|
}
|
|
|
|
// Destruct the vtkVolumeRayCastCompositeFunction
|
|
vtkVolumeRayCastCompositeFunction::~vtkVolumeRayCastCompositeFunction()
|
|
{
|
|
}
|
|
|
|
// This is called from RenderAnImage (in vtkDepthPARCMapper.cxx)
|
|
// It uses the integer data type flag that is passed in to
|
|
// determine what type of ray needs to be cast (which is handled
|
|
// by a templated function. It also uses the shading and
|
|
// interpolation types to determine which templated function
|
|
// to call.
|
|
void vtkVolumeRayCastCompositeFunction::CastRay( vtkVolumeRayCastDynamicInfo *dynamicInfo,
|
|
vtkVolumeRayCastStaticInfo *staticInfo )
|
|
{
|
|
void *data_ptr;
|
|
|
|
data_ptr = staticInfo->ScalarDataPointer;
|
|
|
|
// Cast the ray for the data type and shading/interpolation type
|
|
if ( staticInfo->InterpolationType == VTK_NEAREST_INTERPOLATION )
|
|
{
|
|
if ( staticInfo->Shading == 0 )
|
|
{
|
|
// Nearest neighbor and no shading
|
|
switch ( staticInfo->ScalarDataType )
|
|
{
|
|
case VTK_UNSIGNED_CHAR:
|
|
vtkCastRay_NN_Unshaded( (unsigned char *)data_ptr, dynamicInfo,
|
|
staticInfo );
|
|
break;
|
|
case VTK_UNSIGNED_SHORT:
|
|
vtkCastRay_NN_Unshaded( (unsigned short *)data_ptr, dynamicInfo,
|
|
staticInfo );
|
|
break;
|
|
default:
|
|
vtkWarningMacro ( << "Unsigned char and unsigned short are the only supported datatypes for rendering" );
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Nearest neighbor and shading
|
|
switch ( staticInfo->ScalarDataType )
|
|
{
|
|
case VTK_UNSIGNED_CHAR:
|
|
vtkCastRay_NN_Shaded( (unsigned char *)data_ptr, dynamicInfo, staticInfo);
|
|
break;
|
|
case VTK_UNSIGNED_SHORT:
|
|
vtkCastRay_NN_Shaded( (unsigned short *)data_ptr, dynamicInfo, staticInfo);
|
|
break;
|
|
default:
|
|
vtkWarningMacro ( << "Unsigned char and unsigned short are the only supported datatypes for rendering" );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Trilinear interpolation and no shading
|
|
if ( staticInfo->Shading == 0 )
|
|
{
|
|
if ( this->CompositeMethod == VTK_COMPOSITE_INTERPOLATE_FIRST )
|
|
{
|
|
switch ( staticInfo->ScalarDataType )
|
|
{
|
|
case VTK_UNSIGNED_CHAR:
|
|
vtkCastRay_TrilinSample_Unshaded( (unsigned char *)data_ptr,
|
|
dynamicInfo, staticInfo );
|
|
break;
|
|
case VTK_UNSIGNED_SHORT:
|
|
vtkCastRay_TrilinSample_Unshaded( (unsigned short *)data_ptr,
|
|
dynamicInfo, staticInfo );
|
|
break;
|
|
default:
|
|
vtkWarningMacro ( << "Unsigned char and unsigned short are the only supported datatypes for rendering" );
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch ( staticInfo->ScalarDataType )
|
|
{
|
|
case VTK_UNSIGNED_CHAR:
|
|
vtkCastRay_TrilinVertices_Unshaded( (unsigned char *)data_ptr,
|
|
dynamicInfo, staticInfo );
|
|
break;
|
|
case VTK_UNSIGNED_SHORT:
|
|
vtkCastRay_TrilinVertices_Unshaded( (unsigned short *)data_ptr,
|
|
dynamicInfo, staticInfo );
|
|
break;
|
|
default:
|
|
vtkWarningMacro ( << "Unsigned char and unsigned short are the only supported datatypes for rendering" );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Trilinear interpolation and shading
|
|
if ( this->CompositeMethod == VTK_COMPOSITE_INTERPOLATE_FIRST )
|
|
{
|
|
switch ( staticInfo->ScalarDataType )
|
|
{
|
|
case VTK_UNSIGNED_CHAR:
|
|
vtkCastRay_TrilinSample_Shaded( (unsigned char *)data_ptr,
|
|
dynamicInfo, staticInfo );
|
|
break;
|
|
case VTK_UNSIGNED_SHORT:
|
|
vtkCastRay_TrilinSample_Shaded( (unsigned short *)data_ptr,
|
|
dynamicInfo, staticInfo );
|
|
break;
|
|
default:
|
|
vtkWarningMacro ( << "Unsigned char and unsigned short are the only supported datatypes for rendering" );
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch ( staticInfo->ScalarDataType )
|
|
{
|
|
case VTK_UNSIGNED_CHAR:
|
|
vtkCastRay_TrilinVertices_Shaded( (unsigned char *)data_ptr,
|
|
dynamicInfo, staticInfo );
|
|
break;
|
|
case VTK_UNSIGNED_SHORT:
|
|
vtkCastRay_TrilinVertices_Shaded( (unsigned short *)data_ptr,
|
|
dynamicInfo, staticInfo );
|
|
break;
|
|
default:
|
|
vtkWarningMacro ( << "Unsigned char and unsigned short are the only supported datatypes for rendering" );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
float vtkVolumeRayCastCompositeFunction::GetZeroOpacityThreshold( vtkVolume
|
|
*vol )
|
|
{
|
|
return vol->GetProperty()->GetScalarOpacity()->GetFirstNonZeroValue();
|
|
}
|
|
|
|
// We don't need to do any specific initialization here...
|
|
void vtkVolumeRayCastCompositeFunction::SpecificFunctionInitialize(
|
|
vtkRenderer *vtkNotUsed(ren),
|
|
vtkVolume *vtkNotUsed(vol),
|
|
vtkVolumeRayCastStaticInfo *vtkNotUsed(staticInfo),
|
|
vtkVolumeRayCastMapper *vtkNotUsed(mapper) )
|
|
{
|
|
}
|
|
|
|
// Description:
|
|
// Return the composite method as a descriptive character string.
|
|
const char *vtkVolumeRayCastCompositeFunction::GetCompositeMethodAsString(void)
|
|
{
|
|
if( this->CompositeMethod == VTK_COMPOSITE_INTERPOLATE_FIRST )
|
|
{
|
|
return "Interpolate First";
|
|
}
|
|
if( this->CompositeMethod == VTK_COMPOSITE_CLASSIFY_FIRST )
|
|
{
|
|
return "Classify First";
|
|
}
|
|
else
|
|
{
|
|
return "Unknown";
|
|
}
|
|
}
|
|
|
|
// Print method for vtkVolumeRayCastCompositeFunction
|
|
// Since there is nothing local to print, just print the object stuff.
|
|
void vtkVolumeRayCastCompositeFunction::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
os << indent << "Composite Method: " << this->GetCompositeMethodAsString()
|
|
<< "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|