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