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