1 #include <sstream>
2
3 #include "vtkOpenGLGPUVolumeRayCastMapper.h"
4 #include "vtkVolumeInputHelper.h"
5 #include "vtkOpenGLRenderWindow.h"
6 #include "vtkOpenGLTransferFunction2D.h"
7 #include "vtkOpenGLVolumeGradientOpacityTable.h"
8 #include "vtkOpenGLVolumeOpacityTable.h"
9 #include "vtkOpenGLVolumeRGBTable.h"
10 #include "vtkRenderer.h"
11 #include "vtkShaderProgram.h"
12 #include "vtkVolume.h"
13 #include "vtkVolumeProperty.h"
14 #include "vtkVolumeTexture.h"
15
16
17
vtkVolumeInputHelper(vtkSmartPointer<vtkVolumeTexture> tex,vtkVolume * vol)18 vtkVolumeInputHelper::vtkVolumeInputHelper(vtkSmartPointer<vtkVolumeTexture> tex,
19 vtkVolume* vol)
20 : Texture(tex)
21 , Volume(vol)
22 {
23 };
24
RefreshTransferFunction(vtkRenderer * ren,const int uniformIndex,const int blendMode,const float samplingDist)25 void vtkVolumeInputHelper::RefreshTransferFunction(vtkRenderer* ren, const int uniformIndex,
26 const int blendMode, const float samplingDist)
27 {
28 if (this->InitializeTransfer ||
29 this->Volume->GetProperty()->GetMTime() > this->LutInit.GetMTime())
30 {
31 this->InitializeTransferFunction(ren, uniformIndex);
32 }
33 this->UpdateTransferFunctions(ren, blendMode, samplingDist);
34 }
35
InitializeTransferFunction(vtkRenderer * ren,const int index)36 void vtkVolumeInputHelper::InitializeTransferFunction(vtkRenderer* ren, const int index)
37 {
38 const int transferMode =
39 this->Volume->GetProperty()->GetTransferFunctionMode();
40 switch(transferMode)
41 {
42 case vtkVolumeProperty::TF_2D:
43 this->CreateTransferFunction2D(ren, index);
44 break;
45
46 case vtkVolumeProperty::TF_1D:
47 default:
48 this->CreateTransferFunction1D(ren, index);
49 }
50 this->InitializeTransfer = false;
51 }
52
UpdateTransferFunctions(vtkRenderer * ren,const int blendMode,const float samplingDist)53 void vtkVolumeInputHelper::UpdateTransferFunctions(vtkRenderer* ren, const int blendMode,
54 const float samplingDist)
55 {
56 auto vol = this->Volume;
57 const int transferMode = vol->GetProperty()->GetTransferFunctionMode();
58 const int numComp =
59 this->Texture->GetLoadedScalars()->GetNumberOfComponents();
60 switch(transferMode)
61 {
62 case vtkVolumeProperty::TF_1D:
63 switch(this->ComponentMode)
64 {
65 case vtkVolumeInputHelper::INDEPENDENT:
66 for (int i = 0; i < numComp; ++i)
67 {
68 this->UpdateOpacityTransferFunction(ren, vol, i,
69 blendMode, samplingDist);
70 this->UpdateGradientOpacityTransferFunction(ren, vol, i,
71 samplingDist);
72 this->UpdateColorTransferFunction(ren, vol, i);
73 }
74 break;
75 default: // RGBA or LA
76 this->UpdateOpacityTransferFunction(ren, vol, numComp - 1,
77 blendMode, samplingDist);
78 this->UpdateGradientOpacityTransferFunction(ren, vol, numComp - 1,
79 samplingDist);
80 this->UpdateColorTransferFunction(ren, vol, 0);
81 }
82 break;
83
84 case vtkVolumeProperty::TF_2D:
85 switch(this->ComponentMode)
86 {
87 case vtkVolumeInputHelper::INDEPENDENT:
88 for (int i = 0; i < numComp; ++i)
89 {
90 this->UpdateTransferFunction2D(ren, i);
91 }
92 break;
93 default: // RGBA or LA
94 this->UpdateTransferFunction2D(ren, 0);
95 }
96 break;
97 }
98 }
99
UpdateOpacityTransferFunction(vtkRenderer * ren,vtkVolume * vol,unsigned int component,const int blendMode,const float samplingDist)100 int vtkVolumeInputHelper::UpdateOpacityTransferFunction(vtkRenderer* ren, vtkVolume* vol,
101 unsigned int component, const int blendMode, const float samplingDist)
102 {
103 vtkVolumeProperty* volumeProperty = vol->GetProperty();
104
105 // Use the first LUT when using dependent components
106 unsigned int lookupTableIndex = volumeProperty->GetIndependentComponents() ?
107 component : 0;
108 vtkPiecewiseFunction* scalarOpacity =
109 volumeProperty->GetScalarOpacity(lookupTableIndex);
110
111 auto volumeTex = this->Texture.GetPointer();
112 double componentRange[2];
113 if (scalarOpacity->GetSize() < 1 ||
114 this->ScalarOpacityRangeType == vtkGPUVolumeRayCastMapper::SCALAR)
115 {
116 for (int i = 0; i < 2; ++i)
117 {
118 componentRange[i] = volumeTex->ScalarRange[component][i];
119 }
120 }
121 else
122 {
123 scalarOpacity->GetRange(componentRange);
124 }
125
126
127 if (scalarOpacity->GetSize() < 1)
128 {
129 scalarOpacity->AddPoint(componentRange[0], 0.0);
130 scalarOpacity->AddPoint(componentRange[1], 0.5);
131 }
132
133 int filterVal =
134 volumeProperty->GetInterpolationType() == VTK_LINEAR_INTERPOLATION ?
135 vtkTextureObject::Linear : vtkTextureObject::Nearest;
136
137 this->OpacityTables->GetTable(lookupTableIndex)->Update(
138 scalarOpacity, blendMode,
139 samplingDist,
140 componentRange,
141 volumeProperty->GetScalarOpacityUnitDistance(component),
142 #if GL_ES_VERSION_3_0 != 1
143 filterVal,
144 #else
145 vtkTextureObject::Nearest,
146 #endif
147 vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow()));
148
149 return 0;
150 }
151
UpdateColorTransferFunction(vtkRenderer * ren,vtkVolume * vol,unsigned int component)152 int vtkVolumeInputHelper::UpdateColorTransferFunction(vtkRenderer* ren, vtkVolume* vol,
153 unsigned int component)
154 {
155 vtkVolumeProperty* volumeProperty = vol->GetProperty();
156
157 // Build the colormap in a 1D texture. 1D RGB-texture-mapping from scalar
158 // values to color values build the table.
159 vtkColorTransferFunction* colorTransferFunction =
160 volumeProperty->GetRGBTransferFunction(component);
161
162 auto volumeTex = this->Texture.GetPointer();
163 double componentRange[2];
164 if (colorTransferFunction->GetSize() < 1 ||
165 this->ColorRangeType == vtkGPUVolumeRayCastMapper::SCALAR)
166 {
167 for (int i = 0; i < 2; ++i)
168 {
169 componentRange[i] = volumeTex->ScalarRange[component][i];
170 }
171 }
172 else
173 {
174 colorTransferFunction->GetRange(componentRange);
175 }
176
177 // Add points only if its not being added before
178 if (colorTransferFunction->GetSize() < 1)
179 {
180 colorTransferFunction->AddRGBPoint(componentRange[0], 0.0, 0.0, 0.0);
181 colorTransferFunction->AddRGBPoint(componentRange[1], 1.0, 1.0, 1.0);
182 }
183
184 int filterVal =
185 volumeProperty->GetInterpolationType() == VTK_LINEAR_INTERPOLATION ?
186 vtkTextureObject::Linear : vtkTextureObject::Nearest;
187
188 this->RGBTables->GetTable(component)->Update(
189 volumeProperty->GetRGBTransferFunction(component),
190 componentRange,
191 #if GL_ES_VERSION_3_0 != 1
192 filterVal,
193 #else
194 vtkTextureObject::Nearest,
195 #endif
196 vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow()));
197
198 return 0;
199 }
200
UpdateGradientOpacityTransferFunction(vtkRenderer * ren,vtkVolume * vol,unsigned int component,const float samplingDist)201 int vtkVolumeInputHelper::UpdateGradientOpacityTransferFunction(vtkRenderer* ren, vtkVolume* vol,
202 unsigned int component, const float samplingDist)
203 {
204 vtkVolumeProperty* volumeProperty = vol->GetProperty();
205
206 // Use the first LUT when using dependent components
207 unsigned int lookupTableIndex = volumeProperty->GetIndependentComponents() ?
208 component : 0;
209
210 if (!volumeProperty->HasGradientOpacity(lookupTableIndex) ||
211 !this->GradientOpacityTables)
212 {
213 return 1;
214 }
215
216 vtkPiecewiseFunction* gradientOpacity =
217 volumeProperty->GetGradientOpacity(lookupTableIndex);
218
219 auto volumeTex = this->Texture.GetPointer();
220 double componentRange[2];
221 if (gradientOpacity->GetSize() < 1 ||
222 this->GradientOpacityRangeType == vtkGPUVolumeRayCastMapper::SCALAR)
223 {
224 for (int i = 0; i < 2; ++i)
225 {
226 componentRange[i] = volumeTex->ScalarRange[component][i];
227 }
228 }
229 else
230 {
231 gradientOpacity->GetRange(componentRange);
232 }
233
234 if (gradientOpacity->GetSize() < 1)
235 {
236 gradientOpacity->AddPoint(componentRange[0], 0.0);
237 gradientOpacity->AddPoint(componentRange[1], 0.5);
238 }
239
240 int filterVal =
241 volumeProperty->GetInterpolationType() == VTK_LINEAR_INTERPOLATION ?
242 vtkTextureObject::Linear : vtkTextureObject::Nearest;
243
244 this->GradientOpacityTables->GetTable(lookupTableIndex)->Update(
245 gradientOpacity,
246 samplingDist,
247 componentRange,
248 volumeProperty->GetScalarOpacityUnitDistance(component),
249 #if GL_ES_VERSION_3_0 != 1
250 filterVal,
251 #else
252 vtkTextureObject::Nearest,
253 #endif
254 vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow()));
255
256 return 0;
257 }
258
UpdateTransferFunction2D(vtkRenderer * ren,unsigned int component)259 void vtkVolumeInputHelper::UpdateTransferFunction2D(vtkRenderer* ren,
260 unsigned int component)
261 {
262 // Use the first LUT when using dependent components
263 vtkVolumeProperty* prop = this->Volume->GetProperty();
264 unsigned int const lutIndex = prop->GetIndependentComponents() ?
265 component : 0;
266
267 vtkImageData* transfer2D = prop->GetTransferFunction2D(lutIndex);
268 #if GL_ES_VERSION_3_0 != 1
269 int const interp = prop->GetInterpolationType() == VTK_LINEAR_INTERPOLATION ?
270 vtkTextureObject::Linear : vtkTextureObject::Nearest;
271 #else
272 int const interp = vtkTextureObject::Nearest;
273 #endif
274
275 this->TransferFunctions2D->GetTable(lutIndex)->Update(transfer2D, interp,
276 vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow()));
277 }
278
ActivateTransferFunction(vtkShaderProgram * prog,const int blendMode)279 void vtkVolumeInputHelper::ActivateTransferFunction(vtkShaderProgram* prog, const int blendMode)
280 {
281 int const transferMode =
282 this->Volume->GetProperty()->GetTransferFunctionMode();
283 int const numActiveLuts = this->ComponentMode == INDEPENDENT ?
284 Texture->GetLoadedScalars()->GetNumberOfComponents() : 1;
285 switch (transferMode)
286 {
287 case vtkVolumeProperty::TF_1D:
288 for (int i = 0; i < numActiveLuts; ++i)
289 {
290 this->OpacityTables->GetTable(i)->Activate();
291 prog->SetUniformi(
292 this->OpacityTablesMap[i].c_str(),
293 this->OpacityTables->GetTable(i)->GetTextureUnit());
294
295 if (blendMode != vtkGPUVolumeRayCastMapper::ADDITIVE_BLEND)
296 {
297 this->RGBTables->GetTable(i)->Activate();
298 prog->SetUniformi(
299 this->RGBTablesMap[i].c_str(),
300 this->RGBTables->GetTable(i)->GetTextureUnit());
301 }
302
303 if (this->GradientOpacityTables)
304 {
305 this->GradientOpacityTables->GetTable(i)->Activate();
306 prog->SetUniformi(
307 this->GradientOpacityTablesMap[i].c_str(),
308 this->GradientOpacityTables->GetTable(i)->GetTextureUnit());
309 }
310 }
311 break;
312 case vtkVolumeProperty::TF_2D:
313 for (int i = 0; i < numActiveLuts; ++i)
314 {
315 vtkOpenGLTransferFunction2D* table =
316 this->TransferFunctions2D->GetTable(i);
317 table->Activate();
318 prog->SetUniformi(this->TransferFunctions2DMap[i].c_str(),
319 table->GetTextureUnit());
320 }
321 break;
322 }
323 }
324
DeactivateTransferFunction(const int blendMode)325 void vtkVolumeInputHelper::DeactivateTransferFunction(const int blendMode)
326 {
327 int const transferMode =
328 this->Volume->GetProperty()->GetTransferFunctionMode();
329 int const numActiveLuts = this->ComponentMode == INDEPENDENT ?
330 Texture->GetLoadedScalars()->GetNumberOfComponents() : 1;
331 switch(transferMode)
332 {
333 case vtkVolumeProperty::TF_1D:
334 for (int i = 0; i < numActiveLuts; ++i)
335 {
336 this->OpacityTables->GetTable(i)->Deactivate();
337 if (blendMode != vtkGPUVolumeRayCastMapper::ADDITIVE_BLEND)
338 {
339 this->RGBTables->GetTable(i)->Deactivate();
340 }
341 if (this->GradientOpacityTables)
342 {
343 this->GradientOpacityTables->GetTable(i)->Deactivate();
344 }
345 }
346 break;
347 case vtkVolumeProperty::TF_2D:
348 for (int i = 0; i < numActiveLuts; ++i)
349 {
350 this->TransferFunctions2D->GetTable(i)->Deactivate();
351 }
352 break;
353 }
354 }
355
CreateTransferFunction1D(vtkRenderer * ren,const int index)356 void vtkVolumeInputHelper::CreateTransferFunction1D(vtkRenderer* ren, const int index)
357 {
358 this->ReleaseGraphicsTransfer1D(ren->GetRenderWindow());
359
360 int const numActiveLuts = this->ComponentMode == INDEPENDENT ?
361 Texture->GetLoadedScalars()->GetNumberOfComponents() : 1;
362
363 // Create RGB and opacity (scalar and gradient) lookup tables. Up to four
364 // components are supported in single-input independentComponents mode.
365 this->RGBTables = vtkSmartPointer<vtkOpenGLVolumeRGBTables>::New();
366 this->RGBTables->Create(numActiveLuts);
367 this->OpacityTables = vtkSmartPointer<vtkOpenGLVolumeOpacityTables>::New();
368 this->OpacityTables->Create(numActiveLuts);
369 this->GradientOpacityTables =
370 vtkSmartPointer<vtkOpenGLVolumeGradientOpacityTables>::New();
371 this->GradientOpacityTables->Create(numActiveLuts);
372
373 this->OpacityTablesMap.clear();
374 this->RGBTablesMap.clear();
375 this->GradientOpacityTablesMap.clear();
376
377 std::ostringstream idx;
378 idx << index;
379
380 this->GradientCacheName = "g_gradients_" + idx.str();
381
382 for (int i = 0; i < numActiveLuts; ++i)
383 {
384 std::ostringstream comp;
385 comp << "[" << i << "]";
386
387 this->OpacityTablesMap[i] =
388 "in_opacityTransferFunc_" + idx.str() + comp.str();
389 this->RGBTablesMap[i] = "in_colorTransferFunc_" + idx.str() + comp.str();
390
391 // Unlike color and scalar-op, graident-op is optional (some inputs may
392 // or may not have gradient-op active).
393 if (this->Volume->GetProperty()->HasGradientOpacity())
394 {
395 this->GradientOpacityTablesMap[i] =
396 "in_gradientTransferFunc_" + idx.str() + comp.str();
397 }
398 }
399
400 this->LutInit.Modified();
401 }
402
CreateTransferFunction2D(vtkRenderer * ren,const int index)403 void vtkVolumeInputHelper::CreateTransferFunction2D(vtkRenderer* ren,
404 const int index)
405 {
406 this->ReleaseGraphicsTransfer2D(ren->GetRenderWindow());
407
408 unsigned int const num = this->ComponentMode == INDEPENDENT ?
409 Texture->GetLoadedScalars()->GetNumberOfComponents() : 1;
410
411 this->TransferFunctions2D =
412 vtkSmartPointer<vtkOpenGLTransferFunctions2D>::New();
413 this->TransferFunctions2D->Create(num);
414
415 std::ostringstream idx;
416 idx << index;
417
418 this->GradientCacheName = "g_gradients_" + idx.str();
419
420 for (unsigned int i = 0; i < num; i++)
421 {
422 std::ostringstream comp;
423 comp << "[" << i << "]";
424
425 this->TransferFunctions2DMap[i] = "in_transfer2D_" + idx.str() + comp.str();
426 }
427
428 this->LutInit.Modified();
429 }
430
ReleaseGraphicsResources(vtkWindow * window)431 void vtkVolumeInputHelper::ReleaseGraphicsResources(vtkWindow* window)
432 {
433 this->ReleaseGraphicsTransfer1D(window);
434 this->ReleaseGraphicsTransfer2D(window);
435 this->Texture->ReleaseGraphicsResources(window);
436 this->InitializeTransfer = true;
437 }
438
ReleaseGraphicsTransfer1D(vtkWindow * window)439 void vtkVolumeInputHelper::ReleaseGraphicsTransfer1D(vtkWindow* window)
440 {
441 if (this->RGBTables)
442 {
443 this->RGBTables->ReleaseGraphicsResources(window);
444 }
445 this->RGBTables = nullptr;
446
447 if (this->OpacityTables)
448 {
449 this->OpacityTables->ReleaseGraphicsResources(window);
450 }
451 this->OpacityTables = nullptr;
452
453 if (this->GradientOpacityTables)
454 {
455 this->GradientOpacityTables->ReleaseGraphicsResources(window);
456 }
457 this->GradientOpacityTables = nullptr;
458 }
459
ReleaseGraphicsTransfer2D(vtkWindow * window)460 void vtkVolumeInputHelper::ReleaseGraphicsTransfer2D(vtkWindow* window)
461 {
462 if (this->TransferFunctions2D)
463 {
464 this->TransferFunctions2D->ReleaseGraphicsResources(window);
465 }
466 this->TransferFunctions2D = nullptr;
467 }
468
ForceTransferInit()469 void vtkVolumeInputHelper::ForceTransferInit()
470 {
471 this->InitializeTransfer = true;
472 }
473