1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: TestGPURayCastUserShader.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15
16 // Description
17 // Test the volume mapper's ability to perform shader substitutions based on
18 // user specified strings.
19
20 #include "vtkActor.h"
21 #include "vtkCamera.h"
22 #include "vtkColorTransferFunction.h"
23 #include "vtkDataArray.h"
24 #include "vtkImageData.h"
25 #include "vtkNew.h"
26 #include "vtkNrrdReader.h"
27 #include "vtkOpenGLGPUVolumeRayCastMapper.h"
28 #include "vtkPiecewiseFunction.h"
29 #include "vtkPointData.h"
30 #include "vtkRegressionTestImage.h"
31 #include "vtkRenderWindow.h"
32 #include "vtkRenderWindowInteractor.h"
33 #include "vtkRenderer.h"
34 #include "vtkShaderProperty.h"
35 #include "vtkTestUtilities.h"
36 #include "vtkVolume.h"
37 #include "vtkVolumeProperty.h"
38
TestGPURayCastUserShader(int argc,char * argv[])39 int TestGPURayCastUserShader(int argc, char* argv[])
40 {
41 cout << "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)" << endl;
42
43 // Load data
44 char* fname = vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/tooth.nhdr");
45 vtkNew<vtkNrrdReader> reader;
46 reader->SetFileName(fname);
47 reader->Update();
48 delete[] fname;
49
50 vtkNew<vtkVolumeProperty> volumeProperty;
51 volumeProperty->ShadeOn();
52 volumeProperty->SetInterpolationType(VTK_LINEAR_INTERPOLATION);
53
54 vtkDataArray* arr = reader->GetOutput()->GetPointData()->GetScalars();
55 double range[2];
56 arr->GetRange(range);
57
58 // Prepare 1D Transfer Functions
59 vtkNew<vtkColorTransferFunction> ctf;
60 ctf->AddRGBPoint(0, 0.0, 0.0, 0.0);
61 ctf->AddRGBPoint(510, 0.4, 0.4, 1.0);
62 ctf->AddRGBPoint(640, 1.0, 1.0, 1.0);
63 ctf->AddRGBPoint(range[1], 0.9, 0.1, 0.1);
64
65 vtkNew<vtkPiecewiseFunction> pf;
66 pf->AddPoint(0, 0.00);
67 pf->AddPoint(510, 0.00);
68 pf->AddPoint(640, 0.5);
69 pf->AddPoint(range[1], 0.4);
70
71 volumeProperty->SetScalarOpacity(pf.GetPointer());
72 volumeProperty->SetColor(ctf.GetPointer());
73 volumeProperty->SetShade(1);
74
75 vtkNew<vtkOpenGLGPUVolumeRayCastMapper> mapper;
76 mapper->SetInputConnection(reader->GetOutputPort());
77 mapper->SetUseJittering(1);
78
79 vtkNew<vtkShaderProperty> shaderProperty;
80
81 // Modify the shader to color based on the depth of the translucent voxel
82 shaderProperty->AddFragmentShaderReplacement("//VTK::Base::Dec", // Source string to replace
83 true, // before the standard replacements
84 "//VTK::Base::Dec" // We still want the default
85 "\n bool l_updateDepth;"
86 "\n vec3 l_opaqueFragPos;",
87 false // only do it once i.e. only replace the first match
88 );
89 shaderProperty->AddFragmentShaderReplacement("//VTK::Base::Init", true,
90 "//VTK::Base::Init\n"
91 "\n l_updateDepth = true;"
92 "\n l_opaqueFragPos = vec3(0.0);",
93 false);
94 shaderProperty->AddFragmentShaderReplacement("//VTK::Base::Impl", true,
95 "//VTK::Base::Impl"
96 "\n if(!g_skip && g_srcColor.a > 0.0 && l_updateDepth)"
97 "\n {"
98 "\n l_opaqueFragPos = g_dataPos;"
99 "\n l_updateDepth = false;"
100 "\n }",
101 false);
102 shaderProperty->AddFragmentShaderReplacement("//VTK::RenderToImage::Exit", true,
103 "//VTK::RenderToImage::Exit"
104 "\n if (l_opaqueFragPos == vec3(0.0))"
105 "\n {"
106 "\n fragOutput0 = vec4(0.0);"
107 "\n }"
108 "\n else"
109 "\n {"
110 "\n vec4 depthValue = in_projectionMatrix * in_modelViewMatrix *"
111 "\n in_volumeMatrix[0] * in_textureDatasetMatrix[0] *"
112 "\n vec4(l_opaqueFragPos, 1.0);"
113 "\n depthValue /= depthValue.w;"
114 "\n fragOutput0 = vec4(vec3(0.5 * (gl_DepthRange.far -"
115 "\n gl_DepthRange.near) * depthValue.z + 0.5 *"
116 "\n (gl_DepthRange.far + gl_DepthRange.near)), 1.0);"
117 "\n }",
118 false);
119 shaderProperty->AddFragmentShaderReplacement( // add dummy replacement
120 "//VTK::ComputeGradient::Dec", true, "VTK::ComputeGradient::Dec", false);
121 shaderProperty->ClearFragmentShaderReplacement( // clear dummy replacement
122 "//VTK::ComputeGradient::Dec", true);
123
124 vtkNew<vtkVolume> volume;
125 volume->SetMapper(mapper.GetPointer());
126 volume->SetProperty(volumeProperty.GetPointer());
127 volume->SetShaderProperty(shaderProperty.GetPointer());
128
129 vtkNew<vtkRenderWindow> renWin;
130 renWin->SetMultiSamples(0);
131 renWin->SetSize(300, 300); // Intentional NPOT size
132
133 vtkNew<vtkRenderer> ren;
134 renWin->AddRenderer(ren.GetPointer());
135
136 vtkNew<vtkRenderWindowInteractor> iren;
137 iren->SetRenderWindow(renWin.GetPointer());
138
139 ren->AddVolume(volume.GetPointer());
140 ren->GetActiveCamera()->Elevation(-60.0);
141 ren->ResetCamera();
142 ren->GetActiveCamera()->Zoom(1.3);
143
144 renWin->Render();
145
146 int retVal = vtkRegressionTestImage(renWin);
147 if (retVal == vtkRegressionTester::DO_INTERACTOR)
148 {
149 iren->Start();
150 }
151 return !retVal;
152 }
153