1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: TestGPURayCastDepthPeelingClip.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 * Tests depth peeling pass with volume rendering + clipping.
17 */
18
19 #include <vtkCallbackCommand.h>
20 #include <vtkCamera.h>
21 #include <vtkColorTransferFunction.h>
22 #include <vtkDataArray.h>
23 #include <vtkGPUVolumeRayCastMapper.h>
24 #include <vtkImageData.h>
25 #include <vtkImageReader.h>
26 #include <vtkImageShiftScale.h>
27 #include <vtkInteractorStyleTrackballCamera.h>
28 #include <vtkNew.h>
29 #include <vtkOpenGLRenderer.h>
30 #include <vtkOutlineFilter.h>
31 #include <vtkPiecewiseFunction.h>
32 #include <vtkPlane.h>
33 #include <vtkPlaneCollection.h>
34 #include <vtkPointData.h>
35 #include <vtkPolyDataMapper.h>
36 #include <vtkProperty.h>
37 #include <vtkRegressionTestImage.h>
38 #include <vtkRenderTimerLog.h>
39 #include <vtkRenderWindow.h>
40 #include <vtkRenderWindowInteractor.h>
41 #include <vtkRenderer.h>
42 #include <vtkSmartPointer.h>
43 #include <vtkSphereSource.h>
44 #include <vtkTestUtilities.h>
45 #include <vtkTestingObjectFactory.h>
46 #include <vtkTimerLog.h>
47 #include <vtkVolumeProperty.h>
48 #include <vtkXMLImageDataReader.h>
49
50 #include <cassert>
51
52 namespace
53 {
54
RenderComplete(vtkObject * obj,unsigned long,void *,void *)55 void RenderComplete(vtkObject* obj, unsigned long, void*, void*)
56 {
57 vtkRenderWindow* renWin = vtkRenderWindow::SafeDownCast(obj);
58 assert(renWin);
59
60 vtkRenderTimerLog* timer = renWin->GetRenderTimer();
61 while (timer->FrameReady())
62 {
63 std::cout << "-- Frame Timing:------------------------------------------\n";
64 timer->PopFirstReadyFrame().Print(std::cout);
65 std::cout << "\n";
66 }
67 }
68
69 } // end anon namespace
70
71 class SamplingDistanceCallback : public vtkCommand
72 {
73 public:
New()74 static SamplingDistanceCallback* New() { return new SamplingDistanceCallback; }
75
Execute(vtkObject * vtkNotUsed (caller),unsigned long event,void * vtkNotUsed (data))76 void Execute(vtkObject* vtkNotUsed(caller), unsigned long event, void* vtkNotUsed(data)) override
77 {
78 switch (event)
79 {
80 case vtkCommand::StartInteractionEvent:
81 {
82 // Higher ImageSampleDistance to make the volume-rendered image's
83 // resolution visibly lower during interaction.
84 this->Mapper->SetImageSampleDistance(6.5);
85 }
86 break;
87
88 case vtkCommand::EndInteractionEvent:
89 {
90 // Default ImageSampleDistance
91 this->Mapper->SetImageSampleDistance(1.0);
92 }
93 }
94 }
95
96 vtkGPUVolumeRayCastMapper* Mapper = nullptr;
97 };
98
TestGPURayCastDepthPeelingClip(int argc,char * argv[])99 int TestGPURayCastDepthPeelingClip(int argc, char* argv[])
100 {
101 // Volume peeling is only supported through the dual depth peeling algorithm.
102 // If the current system only supports the legacy peeler, skip this test:
103 vtkNew<vtkRenderWindow> renWin;
104 vtkNew<vtkRenderWindowInteractor> iren;
105 iren->SetRenderWindow(renWin);
106
107 vtkNew<vtkRenderer> ren;
108 renWin->Render(); // Create the context
109 renWin->AddRenderer(ren);
110 vtkOpenGLRenderer* oglRen = vtkOpenGLRenderer::SafeDownCast(ren);
111 assert(oglRen); // This test should only be enabled for OGL2 backend.
112 // This will print details about why depth peeling is unsupported:
113 oglRen->SetDebug(true);
114 bool supported = oglRen->IsDualDepthPeelingSupported();
115 oglRen->SetDebug(false);
116 if (!supported)
117 {
118 std::cerr << "Skipping test; volume peeling not supported.\n";
119 return VTK_SKIP_RETURN_CODE;
120 }
121
122 // Setup the rendertimer observer:
123 vtkNew<vtkCallbackCommand> renderCompleteCB;
124 renderCompleteCB->SetCallback(RenderComplete);
125 renWin->GetRenderTimer()->LoggingEnabledOn();
126 renWin->AddObserver(vtkCommand::EndEvent, renderCompleteCB);
127
128 double scalarRange[2];
129
130 vtkNew<vtkActor> outlineActor;
131 vtkNew<vtkPolyDataMapper> outlineMapper;
132 vtkNew<vtkGPUVolumeRayCastMapper> volumeMapper;
133
134 vtkNew<vtkXMLImageDataReader> reader;
135 const char* volumeFile = vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/vase_1comp.vti");
136 reader->SetFileName(volumeFile);
137 delete[] volumeFile;
138 volumeMapper->SetInputConnection(reader->GetOutputPort());
139
140 // Add outline filter
141 vtkNew<vtkOutlineFilter> outlineFilter;
142 outlineFilter->SetInputConnection(reader->GetOutputPort());
143 outlineMapper->SetInputConnection(outlineFilter->GetOutputPort());
144 outlineActor->SetMapper(outlineMapper);
145
146 volumeMapper->GetInput()->GetScalarRange(scalarRange);
147 volumeMapper->SetSampleDistance(0.1);
148 volumeMapper->SetAutoAdjustSampleDistances(0);
149 volumeMapper->SetBlendModeToComposite();
150
151 // Test clipping now
152 const double* bounds = reader->GetOutput()->GetBounds();
153 vtkNew<vtkPlane> clipPlane1;
154 clipPlane1->SetOrigin(0.45 * (bounds[0] + bounds[1]), 0.0, 0.0);
155 clipPlane1->SetNormal(0.8, 0.0, 0.0);
156
157 vtkNew<vtkPlane> clipPlane2;
158 clipPlane2->SetOrigin(0.45 * (bounds[0] + bounds[1]), 0.35 * (bounds[2] + bounds[3]), 0.0);
159 clipPlane2->SetNormal(0.2, -0.2, 0.0);
160
161 vtkNew<vtkPlaneCollection> clipPlaneCollection;
162 clipPlaneCollection->AddItem(clipPlane1);
163 clipPlaneCollection->AddItem(clipPlane2);
164 volumeMapper->SetClippingPlanes(clipPlaneCollection);
165
166 renWin->SetMultiSamples(0);
167 renWin->SetSize(400, 400);
168 ren->SetBackground(0.0, 0.0, 0.0);
169
170 vtkNew<vtkPiecewiseFunction> scalarOpacity;
171 scalarOpacity->AddPoint(50, 0.0);
172 scalarOpacity->AddPoint(75, 1.0);
173
174 vtkNew<vtkVolumeProperty> volumeProperty;
175 volumeProperty->ShadeOn();
176 volumeProperty->SetInterpolationType(VTK_LINEAR_INTERPOLATION);
177 volumeProperty->SetScalarOpacity(scalarOpacity);
178
179 vtkSmartPointer<vtkColorTransferFunction> colorTransferFunction =
180 volumeProperty->GetRGBTransferFunction(0);
181 colorTransferFunction->RemoveAllPoints();
182 colorTransferFunction->AddRGBPoint(scalarRange[0], 0.6, 0.6, 0.6);
183
184 vtkSmartPointer<vtkVolume> volume = vtkSmartPointer<vtkVolume>::New();
185 volume->SetMapper(volumeMapper);
186 volume->SetProperty(volumeProperty);
187
188 int dims[3];
189 double spacing[3], center[3], origin[3];
190 reader->Update();
191 vtkSmartPointer<vtkImageData> im = reader->GetOutput();
192 im->GetDimensions(dims);
193 im->GetOrigin(origin);
194 im->GetSpacing(spacing);
195
196 // Add sphere 1
197 center[0] = origin[0] + spacing[0] * dims[0] / 2.0;
198 center[1] = origin[1] + spacing[1] * dims[1] / 2.0;
199 center[2] = origin[2] + spacing[2] * dims[2] / 2.0;
200
201 vtkNew<vtkSphereSource> sphereSource;
202 sphereSource->SetCenter(center);
203 sphereSource->SetRadius(dims[1] / 3.0);
204 vtkNew<vtkActor> sphereActor;
205 vtkProperty* sphereProperty = sphereActor->GetProperty();
206 sphereProperty->SetColor(0.5, 0.9, 0.7);
207 sphereProperty->SetOpacity(0.3);
208 vtkNew<vtkPolyDataMapper> sphereMapper;
209 sphereMapper->SetInputConnection(sphereSource->GetOutputPort());
210 sphereActor->SetMapper(sphereMapper);
211
212 // Add sphere 2
213 center[0] += 15.0;
214 center[1] += 15.0;
215 center[2] += 15.0;
216
217 vtkNew<vtkSphereSource> sphereSource2;
218 sphereSource2->SetCenter(center);
219 sphereSource2->SetRadius(dims[1] / 3.0);
220 vtkNew<vtkActor> sphereActor2;
221 sphereProperty = sphereActor2->GetProperty();
222 sphereProperty->SetColor(0.9, 0.4, 0.1);
223 sphereProperty->SetOpacity(0.3);
224 vtkNew<vtkPolyDataMapper> sphereMapper2;
225 sphereMapper2->SetInputConnection(sphereSource2->GetOutputPort());
226 sphereActor2->SetMapper(sphereMapper2);
227
228 // Add actors
229 ren->AddVolume(volume);
230 ren->AddActor(outlineActor);
231 ren->AddActor(sphereActor);
232 ren->AddActor(sphereActor2);
233
234 // Configure depth peeling
235 ren->SetUseDepthPeeling(1);
236 ren->SetOcclusionRatio(0.0);
237 ren->SetMaximumNumberOfPeels(17);
238 ren->SetUseDepthPeelingForVolumes(true);
239
240 vtkNew<vtkInteractorStyleTrackballCamera> style;
241 renWin->GetInteractor()->SetInteractorStyle(style);
242
243 vtkNew<SamplingDistanceCallback> callback;
244 callback->Mapper = volumeMapper;
245 style->AddObserver(vtkCommand::StartInteractionEvent, callback);
246 style->AddObserver(vtkCommand::EndInteractionEvent, callback);
247
248 ren->ResetCamera();
249 renWin->Render();
250
251 iren->Initialize();
252
253 int retVal = vtkRegressionTestImage(renWin);
254 if (retVal == vtkRegressionTester::DO_INTERACTOR)
255 {
256 iren->Start();
257 }
258
259 return !retVal;
260 }
261