1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    TestGPURayCastBlendModes.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 /**
17  * Tests support for blend modes with translucent geometry (similar to
18  * TestGPURayCastBlendModes).
19  *
20  * Maximum, Minimum, Additive and Average blend modes are only partially
21  * correct when using translucent geometry given that vtkDualDepthPeelingPass
22  * renders volumes through various intermediate passes and composites the
23  * intermediate results using under and over blending.  Hence, Max, Min,
24  * Additive and Average values are only locally correct in areas overlapping
25  * with translucent geometry.
26  */
27 
28 #include "vtkCamera.h"
29 #include "vtkColorTransferFunction.h"
30 #include "vtkGPUVolumeRayCastMapper.h"
31 #include "vtkImageData.h"
32 #include "vtkNew.h"
33 #include "vtkOpenGLRenderer.h"
34 #include "vtkPiecewiseFunction.h"
35 #include "vtkPolyDataMapper.h"
36 #include "vtkProperty.h"
37 #include "vtkRegressionTestImage.h"
38 #include "vtkRenderWindow.h"
39 #include "vtkRenderWindowInteractor.h"
40 #include "vtkRenderer.h"
41 #include "vtkSphereSource.h"
42 #include "vtkTestingObjectFactory.h"
43 #include "vtkVolume.h"
44 #include "vtkVolumeProperty.h"
45 
TestGPURayCastDepthPeelingBlendModes(int argc,char * argv[])46 int TestGPURayCastDepthPeelingBlendModes(int argc, char* argv[])
47 {
48   // Volume peeling is only supported through the dual depth peeling algorithm.
49   // If the current system only supports the legacy peeler, skip this test:
50   vtkNew<vtkRenderWindow> renWin;
51   vtkNew<vtkRenderWindowInteractor> iren;
52   iren->SetRenderWindow(renWin);
53 
54   vtkNew<vtkRenderer> ren;
55   renWin->Render(); // Create the context
56   renWin->AddRenderer(ren);
57   vtkOpenGLRenderer* oglRen = vtkOpenGLRenderer::SafeDownCast(ren);
58   assert(oglRen); // This test should only be enabled for OGL2 backend.
59   // This will print details about why depth peeling is unsupported:
60   oglRen->SetDebug(true);
61   bool supported = oglRen->IsDualDepthPeelingSupported();
62   oglRen->SetDebug(false);
63   if (!supported)
64   {
65     std::cerr << "Skipping test; volume peeling not supported.\n";
66     return VTK_SKIP_RETURN_CODE;
67   }
68   renWin->RemoveRenderer(ren);
69 
70   cout << "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)" << endl;
71 
72   int dims[3] = { 100, 100, 100 };
73   int boundary[3] = { 10, 10, 10 };
74 
75   // Create a vtkImageData with two components
76   vtkNew<vtkImageData> image;
77   image->SetDimensions(dims[0], dims[1], dims[2]);
78   image->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
79 
80   // Fill the first half rectangular parallelopiped along X with the
81   // first component values and the second half with second component values
82   unsigned char* ptr = static_cast<unsigned char*>(image->GetScalarPointer(0, 0, 0));
83 
84   for (int z = 0; z < dims[2]; ++z)
85   {
86     for (int y = 0; y < dims[1]; ++y)
87     {
88       for (int x = 0; x < dims[0]; ++x)
89       {
90         if ((z < boundary[2] || z > (dims[2] - boundary[2] - 1)) ||
91           (y < boundary[1] || y > (dims[1] - boundary[1] - 1)) ||
92           (x < boundary[0] || x > (dims[0] - boundary[0] - 1)))
93         {
94           *ptr++ = 255;
95         }
96         else
97         {
98           *ptr++ = 0;
99         }
100       }
101     }
102   }
103 
104   vtkNew<vtkColorTransferFunction> color;
105   color->AddRGBPoint(0.0, 0.2, 0.3, 0.6);
106   color->AddRGBPoint(255.0, 0.2, 0.6, 0.3);
107 
108   vtkNew<vtkPiecewiseFunction> opacity;
109   opacity->AddPoint(0.0, 0.0);
110   opacity->AddPoint(255.0, 0.8);
111 
112   vtkNew<vtkVolumeProperty> property;
113   property->SetScalarOpacity(opacity);
114   property->SetColor(color);
115 
116   vtkNew<vtkVolume> volume[4];
117 
118   vtkNew<vtkGPUVolumeRayCastMapper> mapper[4];
119   mapper[0]->SetBlendModeToMaximumIntensity();
120   mapper[1]->SetBlendModeToMinimumIntensity();
121   mapper[2]->SetBlendModeToAdditive();
122   mapper[3]->SetBlendModeToAverageIntensity();
123 
124   renWin->SetMultiSamples(0);
125   renWin->SetSize(301, 300); // Intentional NPOT size
126 
127   vtkNew<vtkRenderer> renderer[4];
128   renderer[0]->SetViewport(0.0, 0.0, 0.5, 0.5);
129   renderer[1]->SetViewport(0.5, 0.0, 1.0, 0.5);
130   renderer[2]->SetViewport(0.0, 0.5, 0.5, 1.0);
131   renderer[3]->SetViewport(0.5, 0.5, 1.0, 1.0);
132 
133   // Translucent geometry
134   vtkNew<vtkSphereSource> sphereSource;
135   sphereSource->SetCenter(90.0, 90.0, 15.0);
136   sphereSource->SetRadius(30.0);
137 
138   vtkNew<vtkActor> sphereActor;
139   vtkProperty* sphereProperty = sphereActor->GetProperty();
140   sphereProperty->SetColor(1., 0.9, 1);
141   sphereProperty->SetOpacity(0.4);
142 
143   vtkNew<vtkPolyDataMapper> sphereMapper;
144   sphereMapper->SetInputConnection(sphereSource->GetOutputPort());
145   sphereActor->SetMapper(sphereMapper);
146 
147   for (int i = 0; i < 4; ++i)
148   {
149     mapper[i]->SetInputData(image);
150     volume[i]->SetMapper(mapper[i]);
151     volume[i]->SetProperty(property);
152 
153     renderer[i]->AddVolume(volume[i]);
154     renderer[i]->AddActor(sphereActor);
155 
156     renderer[i]->SetUseDepthPeeling(1);
157     renderer[i]->SetOcclusionRatio(0.0);
158     renderer[i]->SetMaximumNumberOfPeels(5);
159     renderer[i]->SetUseDepthPeelingForVolumes(true);
160     renderer[i]->SetBackground(0.3, 0.3, 0.3);
161     renderer[i]->GetActiveCamera()->Yaw(20.0);
162     renderer[i]->ResetCamera();
163 
164     renWin->AddRenderer(renderer[i]);
165   }
166 
167   renWin->Render();
168 
169   int retVal = vtkTesting::Test(argc, argv, renWin, 15);
170   if (retVal == vtkRegressionTester::DO_INTERACTOR)
171   {
172     iren->Start();
173   }
174 
175   if ((retVal == vtkTesting::PASSED) || (retVal == vtkTesting::DO_INTERACTOR))
176   {
177     return EXIT_SUCCESS;
178   }
179   else
180   {
181     return EXIT_FAILURE;
182   }
183 }
184