Commit f48e3e5b authored by Aashish Chaudhary's avatar Aashish Chaudhary Committed by Kitware Robot

Merge topic 'volume_fix_gradient_opacity'

f2a95cf2 Fixed style issues
80e6e809 Updated test and baselines to avoid aliasing artifacts
c7cc87fc Fixed undefined variable
0917b2c3 Added missing baseline
73c5aa6d Fixed various issues with gradient opacity
147f22e2 Added test for independent two component gradient computation
5754a747 Fixed gradient computation and shading for multiple components
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Acked-by: Aashish Chaudhary's avatarAashish Chaudhary <aashish.chaudhary@kitware.com>
Merge-request: !1007
parents 959ed938 f2a95cf2
Pipeline #2516 failed with stage
......@@ -63,6 +63,7 @@ set (VolumeOpenGL2CxxTests
TestGPURayCastRenderToTexture.cxx
TestGPURayCastThreeComponentsIndependent.cxx
TestGPURayCastTwoComponentsDependent.cxx
TestGPURayCastTwoComponentsGradient.cxx
TestGPURayCastTwoComponentsIndependent.cxx
TestGPURayCastVolumeLightKit.cxx
TestGPURayCastVolumePolyData.cxx
......
#include <vtkSmartPointer.h>
#include <vtkPlanes.h>
#include <vtkCamera.h>
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkPolyData.h>
#include <vtkPointData.h>
/*=========================================================================
Program: Visualization Toolkit
Module: TestGPURayCastTwoComponentsIndependent.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 creates a vtkImageData with two components.
// The data is volume rendered considering the two components as independent.
#include "vtkCamera.h"
#include "vtkColorTransferFunction.h"
#include "vtkGPUVolumeRayCastMapper.h"
#include "vtkImageData.h"
#include "vtkNew.h"
#include "vtkPiecewiseFunction.h"
#include "vtkRegressionTestImage.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkTesting.h"
#include "vtkTestUtilities.h"
#include "vtkVolume.h"
#include "vtkVolumeProperty.h"
#include "vtkUnsignedShortArray.h"
int TestGPURayCastTwoComponentsGradient(int argc, char *argv[])
{
cout << "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)" << endl;
int dims[3] = { 35, 35, 35 };
// Create a vtkImageData with two components
vtkNew<vtkImageData> image;
image->SetDimensions(dims[0], dims[1], dims[2]);
image->AllocateScalars(VTK_DOUBLE, 2);
// Fill the first half rectangular parallelopiped along X with the
// first component values and the second half with second component values
double * ptr = static_cast<double *> (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 (x < dims[0] / 2)
{
*ptr++ = 0.0;
*ptr++ = 0.0;
}
else
{
*ptr++ = 1.0;
*ptr++ = 1.0;
}
}
}
}
vtkNew<vtkRenderWindow> renWin;
renWin->SetSize(301, 300); // Intentional NPOT size
renWin->SetMultiSamples(0);
vtkNew<vtkRenderer> ren;
renWin->AddRenderer(ren.GetPointer());
vtkNew<vtkRenderWindowInteractor> iren;
iren->SetRenderWindow(renWin.GetPointer());
renWin->Render();
// Volume render the dataset
vtkNew<vtkGPUVolumeRayCastMapper> mapper;
mapper->AutoAdjustSampleDistancesOff();
mapper->SetSampleDistance(0.9);
mapper->SetInputData(image.GetPointer());
// Color transfer function
vtkNew<vtkColorTransferFunction> ctf1;
ctf1->AddRGBPoint(0.0, 0.0, 0.0, 0.0);
ctf1->AddRGBPoint(1.0, 1.0, 0.0, 0.0);
vtkNew<vtkColorTransferFunction> ctf2;
ctf2->AddRGBPoint(0.0, 0.0, 0.0, 0.0);
ctf2->AddRGBPoint(1.0, 0.0, 0.0, 1.0);
// Opacity functions
vtkNew<vtkPiecewiseFunction> pf1;
pf1->AddPoint(0.0, 0.0);
pf1->AddPoint(1.0, 1.0);
vtkNew<vtkPiecewiseFunction> pf2;
pf2->AddPoint(0.0, 0.0);
pf2->AddPoint(1.0, 1.0);
// Gradient Opacity function
vtkNew<vtkPiecewiseFunction> pf3;
pf3->AddPoint(0.0, 0.0);
pf3->AddPoint(1.0, 1.0);
vtkNew<vtkPiecewiseFunction> pf4;
pf4->AddPoint(0.0, 0.0);
pf4->AddPoint(1.0, 1.0);
// Volume property with independent components ON
vtkNew<vtkVolumeProperty> property;
property->IndependentComponentsOn();
// Set color and opacity functions
property->SetColor(0, ctf1.GetPointer());
property->SetColor(1, ctf2.GetPointer());
property->SetScalarOpacity(0, pf1.GetPointer());
property->SetScalarOpacity(1, pf2.GetPointer());
property->SetGradientOpacity(0, pf3.GetPointer());
property->SetGradientOpacity(1, pf4.GetPointer());
vtkNew<vtkVolume> volume;
volume->SetMapper(mapper.GetPointer());
volume->SetProperty(property.GetPointer());
ren->AddVolume(volume.GetPointer());
ren->ResetCamera();
renWin->Render();
iren->Initialize();
int retVal = vtkRegressionTestImage( renWin.GetPointer() );
if( retVal == vtkRegressionTester::DO_INTERACTOR)
{
iren->Start();
}
return !retVal;
}
......@@ -112,6 +112,11 @@ public:
this->TextureSize[0] = this->TextureSize[1] = this->TextureSize[2] = -1;
this->WindowLowerLeft[0] = this->WindowLowerLeft[1] = 0;
this->WindowSize[0] = this->WindowSize[1] = 0;
this->ScalarsRange[0][0] = this->ScalarsRange[0][1] = 0.0;
this->ScalarsRange[1][0] = this->ScalarsRange[1][1] = 0.0;
this->ScalarsRange[2][0] = this->ScalarsRange[2][1] = 0.0;
this->ScalarsRange[3][0] = this->ScalarsRange[3][1] = 0.0;
this->CellScale[0] = this->CellScale[1] = this->CellScale[2] = 0.0;
this->NoiseTextureData = 0;
......@@ -128,7 +133,6 @@ public:
this->MaskTextures = new vtkMapMaskTextureId;
this->ScalarsRange.clear();
this->Scale.clear();
this->Bias.clear();
......@@ -181,7 +185,6 @@ public:
delete this->MaskTextures;
this->ScalarsRange.clear();
this->Scale.clear();
this->Bias.clear();
}
......@@ -201,6 +204,8 @@ public:
static void ToFloat(T (&in)[2], float (&out)[2]);
template<typename T>
static void ToFloat(T& in, float& out);
template<typename T>
static void ToFloat(T (&in)[4][2], float (&out)[4][2]);
void Initialize(vtkRenderer* ren, vtkVolume* vol,
int noOfComponents, int independentComponents);
......@@ -316,9 +321,8 @@ public:
int TextureSize[3];
int WindowLowerLeft[2];
int WindowSize[2];
int LastWindowSize[2];
std::vector< std::vector<double> > ScalarsRange;
double ScalarsRange[4][2];
double LoadedBounds[6];
int Extents[6];
double DatasetStepSize[3];
......@@ -432,6 +436,21 @@ void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::ToFloat(
out = static_cast<float>(in);
}
//----------------------------------------------------------------------------
template<typename T>
void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::ToFloat(
T (&in)[4][2], float (&out)[4][2])
{
out[0][0] = static_cast<float>(in[0][0]);
out[0][1] = static_cast<float>(in[0][1]);
out[1][0] = static_cast<float>(in[1][0]);
out[1][1] = static_cast<float>(in[1][1]);
out[2][0] = static_cast<float>(in[2][0]);
out[2][1] = static_cast<float>(in[2][1]);
out[3][0] = static_cast<float>(in[3][0]);
out[3][1] = static_cast<float>(in[3][1]);
}
//----------------------------------------------------------------------------
void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::Initialize(
vtkRenderer* vtkNotUsed(ren), vtkVolume* vol, int
......@@ -699,8 +718,8 @@ bool vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::LoadVolume(
for (int n = 0; n < noOfComponents; ++n)
{
double oglA = this->ScalarsRange[n][0]*oglScale + oglBias;
double oglB = this->ScalarsRange[n][1]*oglScale + oglBias;
double oglA = this->ScalarsRange[n][0] * oglScale + oglBias;
double oglB = this->ScalarsRange[n][1] * oglScale + oglBias;
scale[n] = 1.0/ (oglB - oglA);
bias[n] = 0.0 - oglA*scale[n];
}
......@@ -2252,8 +2271,9 @@ void vtkOpenGLGPUVolumeRayCastMapper::BuildShader(vtkRenderer* ren,
fragmentShader,
"//VTK::Base::Dec",
vtkvolume::BaseDeclarationFragment(ren, this, vol, this->Impl->NumberOfLights,
this->Impl->LightComplexity, noOfComponents,
independentComponents),
this->Impl->LightComplexity,
vol->GetProperty()->HasGradientOpacity(),
noOfComponents, independentComponents),
true);
fragmentShader = vtkvolume::replace(
......@@ -2390,7 +2410,6 @@ void vtkOpenGLGPUVolumeRayCastMapper::BuildShader(vtkRenderer* ren,
"//VTK::Cropping::Dec",
vtkvolume::CroppingDeclarationVertex(ren, this, vol),
true);
fragmentShader = vtkvolume::replace(
fragmentShader,
"//VTK::Cropping::Dec",
......@@ -2752,11 +2771,6 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren,
// Allocate important variables
this->Impl->Bias.resize(noOfComponents, 0.0);
this->Impl->ScalarsRange.resize(noOfComponents);
for (int n = 0; n < noOfComponents; ++n)
{
this->Impl->ScalarsRange[n].resize(2, 0.0);
}
// Set OpenGL states
vtkVolumeStateRAII glState;
......@@ -2970,13 +2984,10 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren,
this->Impl->ShaderProgram->SetUniformf("in_sampleDistance",
this->Impl->ActualSampleDistance);
double scalarRange[2];
for (int i = 0; i < 2; ++i)
{
scalarRange[i] = this->Impl->ScalarsRange[noOfComponents - 1][i];
}
vtkInternal::ToFloat(scalarRange, fvalue2);
this->Impl->ShaderProgram->SetUniform2fv("in_scalarsRange", 1, &fvalue2);
float scalarsRange[4][2];
vtkInternal::ToFloat(this->Impl->ScalarsRange, scalarsRange);
this->Impl->ShaderProgram->SetUniform2fv("in_scalarsRange", 4,
scalarsRange);
// Bind textures
this->Impl->VolumeTextureObject->Activate();
......
......@@ -106,12 +106,12 @@ public:
}
gradientOpacity->GetTable(0,
(this->LastRange[1] - this->LastRange[0]) * 0.25,
this->TextureWidth, this->Table);
(this->LastRange[1] - this->LastRange[0]) * 0.25,
this->TextureWidth, this->Table);
this->TextureObject->Create2DFromRaw(this->TextureWidth,1,1,
VTK_FLOAT,
this->Table);
this->TextureObject->Create2DFromRaw(this->TextureWidth, 1, 1,
VTK_FLOAT,
this->Table);
this->TextureObject->SetWrapS(vtkTextureObject::ClampToEdge);
this->TextureObject->SetMagnificationFilter(filterValue);
......
......@@ -130,6 +130,7 @@ namespace vtkvolume
vtkVolume* vtkNotUsed(vol),
int vtkNotUsed(numberOfLights),
int lightingComplexity,
bool hasGradientOpacity,
int noOfComponents,
int independentComponents)
{
......@@ -160,7 +161,7 @@ namespace vtkvolume
\n\
\n// Ray step size\
\nuniform vec3 in_cellStep;\
\nuniform vec2 in_scalarsRange;\
\nuniform vec2 in_scalarsRange[4];\
\nuniform vec3 in_cellSpacing;\
\n\
\n// Sample distance\
......@@ -182,13 +183,19 @@ namespace vtkvolume
\nuniform bool in_cellFlag;\
");
if (lightingComplexity > 0)
if (hasGradientOpacity || lightingComplexity > 0)
{
shaderStr += std::string("\
\nuniform bool in_twoSidedLighting;\
\nvec3 g_xvec;\
\nvec3 g_yvec;\
\nvec3 g_zvec;\
\nvec3 g_zvec;"
);
}
if (lightingComplexity > 0 || hasGradientOpacity)
{
shaderStr += std::string("\
\nuniform bool in_twoSidedLighting;\
\nvec3 g_cellSpacing;\
\nfloat g_avgSpacing;"
);
......@@ -292,27 +299,35 @@ namespace vtkvolume
\n }\
\n g_ldir = normalize(g_lightPosObj.xyz - ip_vertexPos);\
\n g_vdir = normalize(g_eyePosObj.xyz - ip_vertexPos);\
\n g_h = normalize(g_ldir + g_vdir);\
\n g_cellSpacing = vec3(in_cellSpacing[0],\
\n in_cellSpacing[1],\
\n in_cellSpacing[2]);\
\n g_avgSpacing = (g_cellSpacing[0] +\
\n g_cellSpacing[1] +\
\n g_cellSpacing[2])/3.0;\
\n // Adjust the aspect\
\n g_aspect.x = g_cellSpacing[0] * 2.0 / g_avgSpacing;\
\n g_aspect.y = g_cellSpacing[1] * 2.0 / g_avgSpacing;\
\n g_aspect.z = g_cellSpacing[2] * 2.0 / g_avgSpacing;"
\n g_h = normalize(g_ldir + g_vdir);"
);
}
if (vol->GetProperty()->GetShade())
if (vol->GetProperty()->GetShade() ||
vol->GetProperty()->HasGradientOpacity())
{
shaderStr += std::string("\
\n g_cellSpacing = vec3(in_cellSpacing[0],\
\n in_cellSpacing[1],\
\n in_cellSpacing[2]);\
\n g_avgSpacing = (g_cellSpacing[0] +\
\n g_cellSpacing[1] +\
\n g_cellSpacing[2])/3.0;\
\n g_xvec = vec3(in_cellStep[0], 0.0, 0.0);\
\n g_yvec = vec3(0.0, in_cellStep[1], 0.0);\
\n g_zvec = vec3(0.0, 0.0, in_cellStep[2]);"
);
}
if (vol->GetProperty()->HasGradientOpacity())
{
shaderStr += std::string("\
\n // Adjust the aspect\
\n g_aspect.x = g_cellSpacing[0] * 2.0 / g_avgSpacing;\
\n g_aspect.y = g_cellSpacing[1] * 2.0 / g_avgSpacing;\
\n g_aspect.z = g_cellSpacing[2] * 2.0 / g_avgSpacing;"
);
}
return shaderStr;
}
......@@ -340,7 +355,8 @@ namespace vtkvolume
vtkVolume* vol,
int noOfComponents,
int independentComponents,
std::map<int, std::string> gradientTableMap)
std::map<int, std::string>
gradientTableMap)
{
std::string shaderStr;
if (noOfComponents == 1 && vol->GetProperty()->HasGradientOpacity())
......@@ -349,13 +365,14 @@ namespace vtkvolume
\nuniform sampler2D in_gradientTransferFunc;\
\nfloat computeGradientOpacity(vec4 grad)\
\n {\
\n return texture2D(in_gradientTransferFunc, vec2(grad.w,0.0)).r;\
\n return texture2D("+gradientTableMap[0]+", vec2(grad.w, 0.0)).r;\
\n }"
);
}
else if (noOfComponents > 1 && independentComponents &&
vol->GetProperty()->HasGradientOpacity())
{
std::ostringstream toString;
for (int i = 0; i < noOfComponents; ++i)
{
shaderStr += std::string("\n uniform sampler2D ") +
......@@ -364,32 +381,35 @@ namespace vtkvolume
shaderStr += std::string("\
\nfloat computeGradientOpacity(vec4 grad, int component)\
\n {\
\n if (component == 0)\
\n {\
\n return texture2D(in_gradientTransferFunc, vec2(grad.w,0.0)).r;\
\n }\
\n if (component == 1)\
\n {\
\n return texture2D(in_gradientTransferFunc1, vec2(grad.w,0.0)).r;\
\n }\
\n if (component == 2)\
\n {\
\n return texture2D(in_gradientTransferFunc2, vec2(grad.w,0.0)).r;\
\n }\
\n if (component == 3)\
\n {\
\n return texture2D(in_gradientTransferFunc3, vec2(grad.w,0.0)).r;\
\n }\
\n }"
);
\n {");
for (int i = 0; i < noOfComponents; ++i)
{
toString << i;
shaderStr += std::string("\
\n if (component == " + toString.str() + ")");
shaderStr += std::string("\
\n {\
\n return texture2D("+ gradientTableMap[i] + ", vec2(grad.w, 0.0)).r;\
\n }"
);
// Reset
toString.str("");
toString.clear();
}
shaderStr += std::string("\
\n }");
}
if (vol->GetProperty()->GetShade() &&
!vol->GetProperty()->HasGradientOpacity())
{
shaderStr += std::string("\
\nvec4 computeGradient()\
\n// c is short for component\
\nvec4 computeGradient(int c)\
\n {\
\n vec3 g1;\
\n vec3 g2;\
......@@ -405,11 +425,11 @@ namespace vtkvolume
\n }"
);
}
else if (vol->GetProperty()->GetShade() &&
vol->GetProperty()->HasGradientOpacity())
else if (vol->GetProperty()->HasGradientOpacity())
{
shaderStr += std::string("\
\nvec4 computeGradient()\
\n// c is short for component\
\nvec4 computeGradient(int c)\
\n {\
\n vec3 g1;\
\n vec4 g2;\
......@@ -419,27 +439,26 @@ namespace vtkvolume
\n g2.x = texture3D(in_volume, vec3(g_dataPos - g_xvec)).x;\
\n g2.y = texture3D(in_volume, vec3(g_dataPos - g_yvec)).x;\
\n g2.z = texture3D(in_volume, vec3(g_dataPos - g_zvec)).x;\
\n g1 = g1*in_volume_scale.r + in_volume_bias.r;\
\n g2 = g2*in_volume_scale.r + in_volume_bias.r;\
\n g1.x = in_scalarsRange[0] + (\
\n in_scalarsRange[1] - in_scalarsRange[0]) * g1.x;\
\n g1.y = in_scalarsRange[0] + (\
\n in_scalarsRange[1] - in_scalarsRange[0]) * g1.y;\
\n g1.z = in_scalarsRange[0] + (\
\n in_scalarsRange[1] - in_scalarsRange[0]) * g1.z;\
\n g2.x = in_scalarsRange[0] + (\
\n in_scalarsRange[1] - in_scalarsRange[0]) * g2.x;\
\n g2.y = in_scalarsRange[0] + (\
\n in_scalarsRange[1] - in_scalarsRange[0]) * g2.y;\
\n g2.z = in_scalarsRange[0] + (\
\n in_scalarsRange[1] - in_scalarsRange[0]) * g2.z;\
\n g1 = g1 * in_volume_scale.r + in_volume_bias.r;\
\n g2 = g2 * in_volume_scale.r + in_volume_bias.r;\
\n g1.x = in_scalarsRange[c][0] + (\
\n in_scalarsRange[c][1] - in_scalarsRange[c][0]) * g1.x;\
\n g1.y = in_scalarsRange[c][0] + (\
\n in_scalarsRange[c][1] - in_scalarsRange[c][0]) * g1.y;\
\n g1.z = in_scalarsRange[c][0] + (\
\n in_scalarsRange[c][1] - in_scalarsRange[c][0]) * g1.z;\
\n g2.x = in_scalarsRange[c][0] + (\
\n in_scalarsRange[c][1] - in_scalarsRange[c][0]) * g2.x;\
\n g2.y = in_scalarsRange[c][0] + (\
\n in_scalarsRange[c][1] - in_scalarsRange[c][0]) * g2.y;\
\n g2.z = in_scalarsRange[c][0] + (\
\n in_scalarsRange[c][1] - in_scalarsRange[c][0]) * g2.z;\
\n g2.xyz = g1 - g2.xyz;\
\n g2.x /= g_aspect.x;\
\n g2.y /= g_aspect.y;\
\n g2.z /= g_aspect.z;\
\n float grad_mag = sqrt(g2.x * g2.x +\
\n g2.y * g2.y +\
\n g2.z * g2.z);\
\n g2.w = 0.0;\
\n float grad_mag = length(g2);\
\n if (grad_mag > 0.0)\
\n {\
\n g2.x /= grad_mag;\
......@@ -450,8 +469,8 @@ namespace vtkvolume
\n {\
\n g2.xyz = vec3(0.0, 0.0, 0.0);\
\n }\
\n grad_mag = grad_mag * 1.0 / (0.25 * (in_scalarsRange[1] -\
\n (in_scalarsRange[0])));\
\n grad_mag = grad_mag * 1.0 / (0.25 * (in_scalarsRange[c][1] -\
\n (in_scalarsRange[c][0])));\
\n grad_mag = clamp(grad_mag, 0.0, 1.0);\
\n g2.w = grad_mag;\
\n return g2;\
......@@ -461,7 +480,7 @@ namespace vtkvolume
else
{
shaderStr += std::string("\
\nvec4 computeGradient()\
\nvec4 computeGradient(int component)\
\n {\
\n return vec4(0.0);\
\n }");
......@@ -481,7 +500,7 @@ namespace vtkvolume
{
vtkVolumeProperty* volProperty = vol->GetProperty();
std::string shaderStr = std::string("\
\nvec4 computeLighting(vec4 color)\
\nvec4 computeLighting(vec4 color, int component)\
\n {\
\n vec4 finalColor = vec4(0.0);"
);
......@@ -490,7 +509,7 @@ namespace vtkvolume
{
shaderStr += std::string("\
\n // Compute gradient function only once\
\n vec4 gradient = computeGradient();"
\n vec4 gradient = computeGradient(component);"
);
}
......@@ -676,7 +695,7 @@ namespace vtkvolume
\n if (gradient.w >= 0.0)\
\n {\
\n color.a = color.a *\
\n computeGradientOpacity(gradient);\
\n computeGradientOpacity(gradient);\
\n }"
);
}
......@@ -690,7 +709,8 @@ namespace vtkvolume
\n {\
\n color.a = color.a *\
\n computeGradientOpacity(gradient, i) * in_componentWeight[i];\
\n }"
\n }\
\n }"
);
}
......@@ -744,7 +764,7 @@ namespace vtkvolume
\nvec4 computeColor(vec4 scalar, float opacity)\