Commit f4ef870a authored by David E. DeMarle's avatar David E. DeMarle

Merge commit '4ada4f52' into release

parents e95e780f 4ada4f52
......@@ -262,6 +262,15 @@ public:
* of mapper, turning shading off is generally the same as setting
* ambient=1, diffuse=0, specular=0. Shading can be independently
* turned on/off per component.
*
* \note Shading is \b only supported for vtkVolumeMapper::COMPOSITE_BLEND.
* For minimum and maximum intensity blend modes, there is not necessarily one
* unique location along the ray through the volume where that minimum or
* maximum occurs. For average and additive blend modes, the value being
* visualized does not represent a location in the volume but rather a
* statistical measurement along the ray traversing through the volume, and
* hence shading is not applicable.
* \sa vtkVolumeMapper::BlendModes
*/
void SetShade(int index, int value);
void SetShade(int value)
......
......@@ -53,6 +53,7 @@ endif()
# These tests are only built for the OpenGL2 backend
set (VolumeOpenGL2CxxTests
TestGPURayCastBlendModes.cxx
TestGPURayCastAverageIP.cxx
TestGPURayCastCameraInside.cxx
TestGPURayCastCameraInsideSmallSpacing.cxx
......@@ -62,6 +63,8 @@ set (VolumeOpenGL2CxxTests
TestGPURayCastClippingPolyData.cxx
TestGPURayCastClippingUserTransform.cxx
TestGPURayCastDependentComponentsLightParameters.cxx
TestGPURayCastFourComponentsAdditive.cxx
TestGPURayCastFourComponentsAverage.cxx
TestGPURayCastFourComponentsDependentGradient.cxx
TestGPURayCastGradientOpacity.cxx
TestGPURayCastGradientOpacityLight.cxx
......
/*=========================================================================
Program: Visualization Toolkit
Module: TestGPURayCastBlendModes.cxx
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.
=========================================================================*/
// Description
// This test renders a simple cube volume using different blend modes
#include "vtkCamera.h"
#include "vtkColorTransferFunction.h"
#include "vtkGPUVolumeRayCastMapper.h"
#include "vtkImageData.h"
#include "vtkNew.h"
#include "vtkPiecewiseFunction.h"
#include "vtkRegressionTestImage.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkVolume.h"
#include "vtkVolumeProperty.h"
int TestGPURayCastBlendModes(int argc, char *argv[])
{
cout << "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)" << endl;
int dims[3] = {100, 100, 100};
int boundary[3] = {10, 10, 10};
// Create a vtkImageData with two components
vtkNew<vtkImageData> image;
image->SetDimensions(dims[0], dims[1], dims[2]);
image->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
// Fill the first half rectangular parallelopiped along X with the
// first component values and the second half with second component values
unsigned char * ptr =
static_cast<unsigned char *> (image->GetScalarPointer(0, 0, 0));
for (int z = 0; z < dims[2]; ++z)
{
for (int y = 0; y < dims[1]; ++y)
{
for (int x = 0; x < dims[0]; ++x)
{
if ((z < boundary[2] || z > (dims[2] - boundary[2] - 1)) ||
(y < boundary[1] || y > (dims[1] - boundary[1] - 1)) ||
(x < boundary[0] || x > (dims[0] - boundary[0] - 1)))
{
*ptr++ = 255;
}
else
{
*ptr++ = 0;
}
}
}
}
vtkNew<vtkColorTransferFunction> color;
color->AddRGBPoint(0.0, 0.2, 0.3, 0.6);
color->AddRGBPoint(255.0, 0.2, 0.6, 0.3);
vtkNew<vtkPiecewiseFunction> opacity;
opacity->AddPoint(0.0, 0.0);
opacity->AddPoint(255.0, 0.8);
vtkNew<vtkVolumeProperty> property;
property->SetScalarOpacity(opacity.GetPointer());
property->SetColor(color.GetPointer());
vtkNew<vtkVolume> volume[4];
vtkNew<vtkGPUVolumeRayCastMapper> mapper[4];
mapper[0]->SetBlendModeToMaximumIntensity();
mapper[1]->SetBlendModeToMinimumIntensity();
mapper[2]->SetBlendModeToAdditive();
mapper[3]->SetBlendModeToAverageIntensity();
vtkNew<vtkRenderWindow> renWin;
renWin->SetMultiSamples(0);
renWin->SetSize(301, 300); // Intentional NPOT size
vtkNew<vtkRenderer> renderer[4];
renderer[0]->SetViewport(0.0, 0.0, 0.5, 0.5);
renderer[1]->SetViewport(0.5, 0.0, 1.0, 0.5);
renderer[2]->SetViewport(0.0, 0.5, 0.5, 1.0);
renderer[3]->SetViewport(0.5, 0.5, 1.0, 1.0);
for (int i = 0; i < 4; ++i)
{
mapper[i]->SetInputData(image.GetPointer());
volume[i]->SetMapper(mapper[i].GetPointer());
volume[i]->SetProperty(property.GetPointer());
renderer[i]->AddVolume(volume[i].GetPointer());
renderer[i]->SetBackground(0.3, 0.3, 0.3);
renderer[i]->GetActiveCamera()->Yaw(20.0);
renderer[i]->ResetCamera();
renWin->AddRenderer(renderer[i].GetPointer());
}
vtkNew<vtkRenderWindowInteractor> iren;
iren->SetRenderWindow(renWin.GetPointer());
renWin->Render();
int retVal = vtkTesting::Test(argc, argv, renWin.GetPointer(), 15);
if (retVal == vtkRegressionTester::DO_INTERACTOR)
{
iren->Start();
}
if ((retVal == vtkTesting::PASSED) || (retVal == vtkTesting::DO_INTERACTOR))
{
return EXIT_SUCCESS;
}
else
{
return EXIT_FAILURE;
}
}
/*=========================================================================
Program: Visualization Toolkit
Module: TestGPURayCastFourComponentsAdditive.cxx
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.
=========================================================================*/
// This test volume renders the vase dataset with 4 dependent components
// using the additive projection method.
#include "vtkGPUVolumeRayCastMapper.h"
#include "vtkTestUtilities.h"
#include "vtkXMLImageDataReader.h"
#include "vtkImageShiftScale.h"
#include "vtkColorTransferFunction.h"
#include "vtkPiecewiseFunction.h"
#include "vtkTransform.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkVolumeProperty.h"
#include "vtkCamera.h"
#include "vtkRegressionTestImage.h"
int TestGPURayCastFourComponentsAdditive(int argc,
char *argv[])
{
cout << "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)" << endl;
char *cfname=
vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/vase_4comp.vti");
vtkXMLImageDataReader *reader=vtkXMLImageDataReader::New();
reader->SetFileName(cfname);
delete [] cfname;
vtkRenderer *ren1=vtkRenderer::New();
vtkRenderWindow *renWin=vtkRenderWindow::New();
renWin->AddRenderer(ren1);
renWin->SetSize(301,300);
vtkRenderWindowInteractor *iren=vtkRenderWindowInteractor::New();
iren->SetRenderWindow(renWin);
renWin->Render();
vtkGPUVolumeRayCastMapper *volumeMapper;
vtkVolumeProperty *volumeProperty;
vtkVolume *volume;
volumeMapper=vtkGPUVolumeRayCastMapper::New();
volumeMapper->SetBlendModeToAdditive();
volumeMapper->SetInputConnection(
reader->GetOutputPort());
volumeProperty=vtkVolumeProperty::New();
volumeProperty->IndependentComponentsOff();
volumeProperty->SetInterpolationType(VTK_LINEAR_INTERPOLATION);
volumeProperty->SetShade(1);
vtkPiecewiseFunction *f = vtkPiecewiseFunction::New();
f->AddPoint( 0, 0.0);
f->AddPoint(255, 0.1);
volumeProperty->SetScalarOpacity(f);
f->Delete();
volume=vtkVolume::New();
volume->SetMapper(volumeMapper);
volume->SetProperty(volumeProperty);
ren1->AddViewProp(volume);
int valid=volumeMapper->IsRenderSupported(renWin,volumeProperty);
int retVal;
if(valid)
{
iren->Initialize();
ren1->SetBackground(0.1, 0.4, 0.2);
ren1->ResetCamera();
renWin->Render();
retVal = vtkTesting::Test(argc, argv, renWin, 75);
if (retVal == vtkRegressionTester::DO_INTERACTOR)
{
iren->Start();
}
}
else
{
retVal=vtkTesting::PASSED;
cout << "Required extensions not supported." << endl;
}
iren->Delete();
renWin->Delete();
ren1->Delete();
volumeMapper->Delete();
volumeProperty->Delete();
volume->Delete();
reader->Delete();
if ((retVal == vtkTesting::PASSED) || (retVal == vtkTesting::DO_INTERACTOR))
{
return 0;
}
else
{
return 1;
}
}
/*=========================================================================
Program: Visualization Toolkit
Module: TestGPURayCastFourComponentsAverage.cxx
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.
=========================================================================*/
// This test volume renders the vase dataset with 4 dependent components
// using the average intensity projection method.
#include "vtkGPUVolumeRayCastMapper.h"
#include "vtkTestUtilities.h"
#include "vtkXMLImageDataReader.h"
#include "vtkImageShiftScale.h"
#include "vtkColorTransferFunction.h"
#include "vtkPiecewiseFunction.h"
#include "vtkTransform.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkVolumeProperty.h"
#include "vtkCamera.h"
#include "vtkRegressionTestImage.h"
int TestGPURayCastFourComponentsAverage(int argc,
char *argv[])
{
cout << "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)" << endl;
char *cfname=
vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/vase_4comp.vti");
vtkXMLImageDataReader *reader=vtkXMLImageDataReader::New();
reader->SetFileName(cfname);
delete [] cfname;
vtkRenderer *ren1=vtkRenderer::New();
vtkRenderWindow *renWin=vtkRenderWindow::New();
renWin->AddRenderer(ren1);
renWin->SetSize(301,300);
vtkRenderWindowInteractor *iren=vtkRenderWindowInteractor::New();
iren->SetRenderWindow(renWin);
renWin->Render();
vtkGPUVolumeRayCastMapper *volumeMapper;
vtkVolumeProperty *volumeProperty;
vtkVolume *volume;
volumeMapper=vtkGPUVolumeRayCastMapper::New();
volumeMapper->SetBlendModeToAverageIntensity();
volumeMapper->SetAverageIPScalarRange(20, 300);
volumeMapper->SetInputConnection(
reader->GetOutputPort());
volumeProperty=vtkVolumeProperty::New();
volumeProperty->IndependentComponentsOff();
volumeProperty->SetInterpolationType(VTK_LINEAR_INTERPOLATION);
volumeProperty->SetShade(1);
vtkPiecewiseFunction *f = vtkPiecewiseFunction::New();
f->AddPoint( 0, 0.0);
f->AddPoint(255, 1.0);
volumeProperty->SetScalarOpacity(f);
f->Delete();
volume=vtkVolume::New();
volume->SetMapper(volumeMapper);
volume->SetProperty(volumeProperty);
ren1->AddViewProp(volume);
int valid=volumeMapper->IsRenderSupported(renWin,volumeProperty);
int retVal;
if(valid)
{
iren->Initialize();
ren1->SetBackground(0.1, 0.4, 0.2);
ren1->ResetCamera();
renWin->Render();
retVal = vtkTesting::Test(argc, argv, renWin, 10);
if (retVal == vtkRegressionTester::DO_INTERACTOR)
{
iren->Start();
}
}
else
{
retVal=vtkTesting::PASSED;
cout << "Required extensions not supported." << endl;
}
iren->Delete();
renWin->Delete();
ren1->Delete();
volumeMapper->Delete();
volumeProperty->Delete();
volume->Delete();
reader->Delete();
if ((retVal == vtkTesting::PASSED) || (retVal == vtkTesting::DO_INTERACTOR))
{
return 0;
}
else
{
return 1;
}
}
......@@ -1480,11 +1480,10 @@ void vtkFixedPointVolumeRayCastMapper::Render( vtkRenderer *ren, vtkVolume *vol
if(this->GetBlendMode()!=vtkVolumeMapper::COMPOSITE_BLEND &&
this->GetBlendMode()!=vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND &&
this->GetBlendMode()!=vtkVolumeMapper::MINIMUM_INTENSITY_BLEND &&
this->GetBlendMode()!=vtkVolumeMapper::AVERAGE_INTENSITY_BLEND &&
this->GetBlendMode()!=vtkVolumeMapper::ADDITIVE_BLEND)
{
vtkErrorMacro(<< "Selected blend mode not supported. "
<< "Only Composite, MIP, MinIP, averageIP and additive modes "
<< "Only Composite, MIP, MinIP and additive modes "
<< "are supported by the fixed point implementation.");
return;
}
......
......@@ -61,10 +61,40 @@ public:
//@{
/**
* Set/Get the blend mode.
* Additive blend mode adds scalars along the ray and multiply them by
* their opacity mapping value.
* Average blend mode averages scalars and determines the final color by
* passing the average through the color and opacity transfer functions.
* The default mode is Composite where the scalar values are sampled through
* the volume and composited in a front-to-back scheme through alpha blending.
* The final color and opacity is determined using the color and opacity
* transfer functions.
*
* Maximum and minimum intensity blend modes use the maximum and minimum
* scalar values, respectively, along the sampling ray. The final color and
* opacity is determined by passing the resultant value through the color and
* opacity transfer functions.
*
* Additive blend mode accumulates scalar values by passing each value through
* the opacity transfer function and then adding up the product of the value
* and its opacity. In other words, the scalar values are scaled using the
* opacity transfer function and summed to derive the final color. Note that
* the resulting image is always grayscale i.e. aggregated values are not
* passed through the color transfer function. This is because the final
* value is a derived value and not a real data value along the sampling ray.
*
* Average intensity blend mode works similar to the additive blend mode where
* the scalar values are multiplied by opacity calculated from the opacity
* transfer function and then added. The additional step here is to
* divide the sum by the number of samples taken through the volume.
* One can control the scalar range by setting the AverageIPScalarRange ivar
* to disregard scalar values, not in the range of interest, from the average
* computation.
* As is the case with the additive intensity projection, the final
* image will always be grayscale i.e. the aggregated values are not
* passed through the color transfer function. This is because the
* resultant value is a derived value and not a real data value along
* the sampling ray.
*
* \note vtkVolumeMapper::AVERAGE_INTENSITY_BLEND is only supported by the
* vtkGPUVolumeRayCastMapper with the OpenGL2 backend.
* \sa SetAverageIPScalarRange()
*/
vtkSetMacro( BlendMode, int );
void SetBlendModeToComposite()
......@@ -162,7 +192,40 @@ public:
*/
virtual void ReleaseGraphicsResources(vtkWindow *) {}
enum
/**
* Blend modes.
* The default mode is Composite where the scalar values are sampled through
* the volume and composited in a front-to-back scheme through alpha blending.
* The final color and opacity is determined using the color and opacity
* transfer functions.
*
* Maximum and minimum intensity blend modes use the maximum and minimum
* scalar values, respectively, along the sampling ray. The final color and
* opacity is determined by passing the resultant value through the color and
* opacity transfer functions.
*
* Additive blend mode accumulates scalar values by passing each value through
* the opacity transfer function and then adding up the product of the value
* and its opacity. In other words, the scalar values are scaled using the
* opacity transfer function and summed to derive the final color. Note that
* the resulting image is always grayscale i.e. aggregated values are not
* passed through the color transfer function. This is because the final
* value is a derived value and not a real data value along the sampling ray.
*
* Average intensity blend mode works similar to the additive blend mode where
* the scalar values are multiplied by opacity calculated from the opacity
* transfer function and then added. The additional step here is to
* divide the sum by the number of samples taken through the volume.
* As is the case with the additive intensity projection, the final
* image will always be grayscale i.e. the aggregated values are not
* passed through the color transfer function. This is because the
* resultant value is a derived value and not a real data value along
* the sampling ray.
*
* \note vtkVolumeMapper::AVERAGE_INTENSITY_BLEND is only supported by the
* vtkGPUVolumeRayCastMapper with the OpenGL2 backend.
*/
enum BlendModes
{
COMPOSITE_BLEND,
MAXIMUM_INTENSITY_BLEND,
......@@ -175,24 +238,32 @@ protected:
vtkVolumeMapper();
~vtkVolumeMapper();
// Compute a sample distance from the data spacing. When the number of
// voxels is 8, the sample distance will be roughly 1/200 the average voxel
// size. The distance will grow proportionally to numVoxels^(1/3).
/**
* Compute a sample distance from the data spacing. When the number of
* voxels is 8, the sample distance will be roughly 1/200 the average voxel
* size. The distance will grow proportionally to numVoxels^(1/3).
*/
double SpacingAdjustedSampleDistance(double inputSpacing[3],
int inputExtent[6]);
int inputExtent[6]);
int BlendMode;
// Threshold range for average intensity projection
/**
* Threshold range for average intensity projection
*/
double AverageIPScalarRange[2];
// Cropping variables, and a method for converting the world
// coordinate cropping region planes to voxel coordinates
//@{
/**
* Cropping variables, and a method for converting the world
* coordinate cropping region planes to voxel coordinates
*/
int Cropping;
double CroppingRegionPlanes[6];
double VoxelCroppingRegionPlanes[6];
int CroppingRegionFlags;
void ConvertCroppingRegionPlanesToVoxels();
//@}
virtual int FillInputPortInformation(int, vtkInformation*);
......
......@@ -4209,6 +4209,17 @@ void vtkOpenGLGPUVolumeRayCastMapper::PreRender(vtkRenderer *ren,
int shadeMethod=vtkOpenGLGPUVolumeRayCastMapperShadeNotUsed;
int componentMethod=vtkOpenGLGPUVolumeRayCastMapperComponentNotUsed;
if(this->GetBlendMode()!=vtkVolumeMapper::COMPOSITE_BLEND &&
this->GetBlendMode()!=vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND &&
this->GetBlendMode()!=vtkVolumeMapper::MINIMUM_INTENSITY_BLEND &&
this->GetBlendMode()!=vtkVolumeMapper::ADDITIVE_BLEND)
{
vtkErrorMacro(<< "Selected blend mode not supported. "
<< "Only Composite, MIP, MinIP and additive modes "
<< "are supported by this implementation.");
return;
}
switch(this->BlendMode)
{
case vtkVolumeMapper::COMPOSITE_BLEND:
......
......@@ -1177,8 +1177,7 @@ namespace vtkvolume
\n if (in_averageIPRange.x <= intensity &&\
\n intensity <= in_averageIPRange.y)\
\n {\
\n float opacity = computeOpacity(scalar, i);\
\n l_avgValue[i] += scalar[i];\
\n l_avgValue[i] += computeOpacity(scalar, i) * scalar[i];\
\n ++l_numSamples[i];\
\n }\
\n }"
......@@ -1194,33 +1193,23 @@ namespace vtkvolume
\n if (in_averageIPRange.x <= intensity &&\
\n intensity <= in_averageIPRange.y)\
\n {\
\n l_avgValue.w += scalar.x;\
\n ++l_numSamples.w;\
\n l_avgValue.x += computeOpacity(scalar) * scalar.x;\
\n ++l_numSamples.x;\
\n }"
);
}
}
else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
{
if (noOfComponents > 1)
if (noOfComponents > 1 && independentComponents)
{
if (!independentComponents)
{
shaderStr += std::string("\
\n float opacity = computeOpacity(scalar);\
\n l_sumValue.x = l_sumValue.x + opacity * scalar.x;"
);
}
else
{
shaderStr += std::string("\
\n for (int i = 0; i < in_noOfComponents; ++i)\
\n {\
\n float opacity = computeOpacity(scalar, i);\
\n l_sumValue[i] = l_sumValue[i] + opacity * scalar[i];\
\n }"
);
}
shaderStr += std::string("\
\n for (int i = 0; i < in_noOfComponents; ++i)\
\n {\
\n float opacity = computeOpacity(scalar, i);\
\n l_sumValue[i] = l_sumValue[i] + opacity * scalar[i];\
\n }"
);
}
else
{
......@@ -1483,38 +1472,35 @@ namespace vtkvolume
if (noOfComponents > 1 && independentComponents)
{
return std::string("\
\n g_srcColor = vec4(0);\
\n for (int i = 0; i < in_noOfComponents; ++i)\
\n {\
\n if (l_numSamples[i] == uint(0))\
\n {\
\n continue;\
\n }\
\n l_avgValue[i] /= l_numSamples[i];\
\n vec4 tmp = computeColor(l_avgValue,\
\n computeOpacity(l_avgValue, i), i);\
\n g_srcColor[0] += tmp[0] * tmp[3] * in_componentWeight[i];\
\n g_srcColor[1] += tmp[1] * tmp[3] * in_componentWeight[i];\
\n g_srcColor[2] += tmp[2] * tmp[3] * in_componentWeight[i];\
\n g_srcColor[3] += tmp[3] * in_componentWeight[i];\
\n l_avgValue[i] = l_avgValue[i] * in_componentWeight[i] /\
\n l_numSamples[i];\
\n if (i > 0)\
\n {\
\n l_avgValue[0] += l_avgValue[i];\
\n }\
\n }\
\n g_fragColor = g_srcColor;"
\n l_avgValue[0] = clamp(l_avgValue[0], 0.0, 1.0);\
\n g_fragColor = vec4(vec3(l_avgValue[0]), 1.0);"
);
}
else
{
return std::string("\
\n if (l_numSamples.w == uint(0))\
\n if (l_numSamples.x == uint(0))\
\n {\
\n g_fragColor = vec4(0);\
\n discard;\
\n }\
\n else\
\n {\
\n l_avgValue.w /= l_numSamples.w;\
\n g_srcColor = computeColor(l_avgValue,\
\n computeOpacity(l_avgValue));\
\n g_fragColor.rgb = g_srcColor.rgb * g_srcColor.a;\
\n g_fragColor.a = g_srcColor.a;\
\n l_avgValue.x /= l_numSamples.x;\
\n l_avgValue.x = clamp(l_avgValue.x, 0.0, 1.0);\
\n g_fragColor = vec4(vec3(l_avgValue.x), 1.0);\
\n }"
);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment