VTK  9.7.1
vtkVolumeShaderComposer.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
2 // SPDX-License-Identifier: BSD-3-Clause
3 
4 #ifndef vtkVolumeShaderComposer_h
5 #define vtkVolumeShaderComposer_h
6 
7 #include <vtkCamera.h>
8 #include <vtkImplicitFunction.h>
10 #include <vtkRectilinearGrid.h>
11 #include <vtkRenderer.h>
12 #include <vtkStringFormatter.h>
13 #include <vtkUniformGrid.h>
14 #include <vtkVolume.h>
15 #include <vtkVolumeInputHelper.h>
16 #include <vtkVolumeMapper.h>
17 #include <vtkVolumeProperty.h>
18 #include <vtkVolumeTexture.h>
19 
20 #include <map>
21 #include <sstream>
22 #include <string>
23 
24 namespace
25 {
26 inline bool HasGradientOpacity(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs)
27 {
28  for (auto& item : inputs)
29  {
30  vtkVolumeProperty* volProp = item.second.Volume->GetProperty();
31  const bool gradOp = (volProp->HasGradientOpacity() || volProp->HasLabelGradientOpacity()) &&
32  !volProp->GetDisableGradientOpacity();
33  if (gradOp)
34  return true;
35  }
36  return false;
37 }
38 
39 inline bool HasLighting(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs)
40 {
41  for (auto& item : inputs)
42  {
43  vtkVolumeProperty* volProp = item.second.Volume->GetProperty();
44  const bool lighting = volProp->GetShade() == 1;
45  if (lighting)
46  return true;
47  }
48  return false;
49 }
50 
51 inline bool UseClippedVoxelIntensity(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs)
52 {
53  for (auto& item : inputs)
54  {
55  vtkVolumeProperty* volProp = item.second.Volume->GetProperty();
56  const bool useClippedVoxelIntensity = volProp->GetUseClippedVoxelIntensity() == 1;
57  if (useClippedVoxelIntensity)
58  {
59  return true;
60  }
61  }
62  return false;
63 }
64 
65 inline std::string ArrayBaseName(const std::string& arrayName)
66 {
67  return arrayName.substr(0, arrayName.length() - 3);
68 }
69 }
70 
71 // NOTE:
72 // In this code, we referred to various spaces described below:
73 // Object space: Raw coordinates in space defined by volume matrix
74 // Dataset space: Raw coordinates
75 // Eye space: Coordinates in eye space (as referred in computer graphics)
76 
77 namespace vtkvolume
78 {
79 VTK_ABI_NAMESPACE_BEGIN
80 //--------------------------------------------------------------------------
82  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
83 {
84  return std::string(
85  " //Transform vertex (data coordinates) to clip coordinates\n"
86  " // p_clip = T_ProjViewModel * T_dataToWorld * p_data\n"
87  " vec4 pos = in_projectionMatrix * in_modelViewMatrix * in_volumeMatrix[0] *\n"
88  " vec4(in_vertexPos.xyz, 1.0);\n"
89  " gl_Position = pos;\n");
90 }
91 
92 //--------------------------------------------------------------------------
94  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
95 {
96  return std::string(
97  " // Transform vertex (data coordinates) to texture coordinates.\n"
98  " // p_texture = T_dataToTex * p_data\n"
99  " vec3 uvx = sign(in_cellSpacing[0]) * (in_inverseTextureDatasetMatrix[0] *\n"
100  " vec4(in_vertexPos, 1.0)).xyz;\n"
101  "\n"
102  " // For point dataset, we offset the texture coordinate\n"
103  " // to account for OpenGL treating voxel at the center of the cell.\n"
104  " // Transform cell tex-coordinates to point tex-coordinates (cellToPoint\n"
105  " // is an identity matrix in the case of cell data).\n"
106  " ip_textureCoords = (in_cellToPoint[0] * vec4(uvx, 1.0)).xyz;\n"
107  " ip_inverseTextureDataAdjusted = in_cellToPoint[0] * in_inverseTextureDatasetMatrix[0];\n");
108 }
109 
110 //--------------------------------------------------------------------------
112  vtkVolume* vtkNotUsed(vol), bool multipleInputs)
113 {
114  auto gpuMapper = vtkGPUVolumeRayCastMapper::SafeDownCast(mapper);
115  const int numInputs = gpuMapper->GetInputCount();
116 
117  std::ostringstream ss;
118  ss << "uniform vec3 in_cellSpacing[" << numInputs
119  << "];\n"
120  "uniform mat4 in_modelViewMatrix;\n"
121  "uniform mat4 in_projectionMatrix;\n";
122 
123  const int numTransf = multipleInputs ? numInputs + 1 : 1;
124  ss << "uniform mat4 in_volumeMatrix[" << numTransf
125  << "];\n"
126  "uniform mat4 in_inverseTextureDatasetMatrix["
127  << numTransf
128  << "];\n"
129  "uniform mat4 in_cellToPoint["
130  << numTransf
131  << "];\n"
132  "\n"
133  "//This variable could be 'invariant varying' but it is declared\n"
134  "//as 'varying' to avoid compiler compatibility issues.\n"
135  "out mat4 ip_inverseTextureDataAdjusted;\n";
136 
137  return ss.str();
138 }
139 
140 //--------------------------------------------------------------------------
142  vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, int totalNumberOfLights,
143  int numberPositionalLights, bool defaultLighting, int noOfComponents, int independentComponents)
144 {
145  const int numInputs = static_cast<int>(inputs.size());
146 
147  std::ostringstream toShaderStr;
148  toShaderStr << "uniform sampler3D in_volume[" << numInputs << "];\n";
149 
150  toShaderStr << "uniform vec4 in_volume_scale[" << numInputs
151  << "];\n"
152  "uniform vec4 in_volume_bias["
153  << numInputs << "];\n";
154 
156  {
157  toShaderStr << "uniform sampler1D in_coordTexs;\n";
158  toShaderStr << "uniform vec3 in_coordTexSizes;\n";
159  toShaderStr << "uniform vec3 in_coordsScale;\n";
160  toShaderStr << "uniform vec3 in_coordsBias;\n";
161  }
162 
163  if (mapper->GetInput()->GetPointGhostArray() || mapper->GetInput()->GetCellGhostArray())
164  {
165  toShaderStr << "uniform sampler3D in_blanking;\n";
166  }
167 
168  toShaderStr << "uniform int in_noOfComponents;\n"
169  "\n"
170  "uniform sampler2D in_depthSampler;\n";
171 
173  if (glMapper->GetUseJittering())
174  {
175  toShaderStr << "uniform sampler2D in_noiseSampler;\n";
176  }
177 
178  // For multiple inputs (numInputs > 1), an additional transformation is
179  // needed for the bounding-box.
180  const int numTransf = (numInputs > 1) ? numInputs + 1 : 1;
181  toShaderStr << "uniform mat4 in_volumeMatrix[" << numTransf
182  << "];\n"
183  "uniform mat4 in_inverseVolumeMatrix["
184  << numTransf
185  << "];\n"
186  "uniform mat4 in_textureDatasetMatrix["
187  << numTransf
188  << "];\n"
189  "uniform mat4 in_inverseTextureDatasetMatrix["
190  << numTransf
191  << "];\n"
192  "uniform mat4 in_textureToEye["
193  << numTransf
194  << "];\n"
195  "uniform vec3 in_texMin["
196  << numTransf
197  << "];\n"
198  "uniform vec3 in_texMax["
199  << numTransf
200  << "];\n"
201  "// Eye position in dataset space\n"
202  "uniform vec3 in_eyePosObjs["
203  << numTransf
204  << "];\n"
205  "uniform mat4 in_cellToPoint["
206  << numTransf << "];\n";
207 
208  toShaderStr << "// view and model matrices\n"
209  "uniform mat4 in_projectionMatrix;\n"
210  "uniform mat4 in_inverseProjectionMatrix;\n"
211  "uniform mat4 in_modelViewMatrix;\n"
212  "uniform mat4 in_inverseModelViewMatrix;\n"
213  "in mat4 ip_inverseTextureDataAdjusted;\n"
214  "\n"
215  "// Ray step size\n"
216  "uniform vec3 in_cellStep["
217  << numInputs << "];\n";
218 
219  if (glMapper->GetVolumetricScatteringBlending() > 0.0)
220  {
221 
222  toShaderStr << "mat4 g_eyeToTexture = in_inverseTextureDatasetMatrix[0] *"
223  " in_inverseVolumeMatrix[0] * in_inverseModelViewMatrix;\n";
224  }
225 
226  toShaderStr << "mat4 g_texToView;\n";
227 
228  toShaderStr << "uniform vec2 in_scalarsRange[" << numInputs * 4
229  << "];\n"
230  "uniform vec3 in_cellSpacing["
231  << numInputs
232  << "];\n"
233  "\n"
234  "// Sample distance\n"
235  "uniform float in_sampleDistance;\n"
236  "\n"
237  "// Scales\n"
238  "uniform vec2 in_windowLowerLeftCorner;\n"
239  "uniform vec2 in_inverseOriginalWindowSize;\n"
240  "uniform vec2 in_inverseWindowSize;\n"
241  "uniform vec3 in_textureExtentsMax;\n"
242  "uniform vec3 in_textureExtentsMin;\n"
243  "\n"
244  "// Material and lighting\n"
245  "uniform vec3 in_diffuse[4];\n"
246  "uniform vec3 in_ambient[4];\n"
247  "uniform vec3 in_specular[4];\n"
248  "uniform float in_shininess[4];\n"
249  "\n"
250  "// Others\n"
251  "vec3 g_rayJitter = vec3(0.0);\n"
252  "\n"
253  "uniform vec2 in_averageIPRange;\n";
254 
255  const bool hasGradientOpacity = HasGradientOpacity(inputs);
256  if (totalNumberOfLights > 0 || hasGradientOpacity)
257  {
258  toShaderStr << "uniform bool in_twoSidedLighting;\n";
259  }
260 
261  if (glMapper->GetVolumetricScatteringBlending() > 0.0)
262  {
263  toShaderStr << R"***(
264 uniform float in_giReach;
265 uniform float in_anisotropy;
266 uniform float in_volumetricScatteringBlending;
267 
268 )***";
269  }
270 
271  if (totalNumberOfLights > 0)
272  {
273  std::string totalLights = vtk::to_string(totalNumberOfLights);
274  std::string positionalLights = vtk::to_string(numberPositionalLights);
275 
276  if (!defaultLighting)
277  {
278  toShaderStr << "#define TOTAL_NUMBER_LIGHTS " << totalLights
279  << "\n"
280  "#define NUMBER_POS_LIGHTS "
281  << positionalLights
282  << "\n"
283  "vec4 g_fragWorldPos;\n"
284  "uniform vec3 in_lightAmbientColor[TOTAL_NUMBER_LIGHTS];\n"
285  "uniform vec3 in_lightDiffuseColor[TOTAL_NUMBER_LIGHTS];\n"
286  "uniform vec3 in_lightSpecularColor[TOTAL_NUMBER_LIGHTS];\n"
287  "uniform vec3 in_lightDirection[TOTAL_NUMBER_LIGHTS];\n";
288  if (numberPositionalLights > 0)
289  {
290  toShaderStr << "uniform vec3 in_lightPosition[NUMBER_POS_LIGHTS];\n"
291  "uniform vec3 in_lightAttenuation[NUMBER_POS_LIGHTS];\n"
292  "uniform float in_lightConeAngle[NUMBER_POS_LIGHTS];\n"
293  "uniform float in_lightExponent[NUMBER_POS_LIGHTS];\n";
294  }
295 
296  if (glMapper->GetVolumetricScatteringBlending() > 0.0)
297  {
298  toShaderStr << "vec3 g_lightDirectionTex[TOTAL_NUMBER_LIGHTS];\n";
299 
300  if (numberPositionalLights > 0)
301  {
302  toShaderStr << "vec3 g_lightPositionTex[NUMBER_POS_LIGHTS];\n";
303  }
304  }
305  }
306  else
307  {
308  toShaderStr << "uniform vec3 in_lightAmbientColor[1];\n"
309  "uniform vec3 in_lightDiffuseColor[1];\n"
310  "uniform vec3 in_lightSpecularColor[1];\n"
311  "vec4 g_lightPosObj["
312  << numInputs
313  << "];\n"
314  "vec3 g_ldir["
315  << numInputs
316  << "];\n"
317  "vec3 g_vdir["
318  << numInputs
319  << "];\n"
320  "vec3 g_h["
321  << numInputs << "];\n";
322  }
323  }
324 
325  if (noOfComponents > 1 && independentComponents)
326  {
327  toShaderStr << "uniform vec4 in_componentWeight;\n";
328  }
329 
331  glMapper->GetUseDepthPass())
332  {
333  toShaderStr << "uniform sampler2D in_depthPassSampler;\n";
334  }
335 
337  {
338  toShaderStr << "#if NUMBER_OF_CONTOURS\n"
339  "uniform float in_isosurfacesValues[NUMBER_OF_CONTOURS];\n"
340  "\n"
341  "int findIsoSurfaceIndex(float scalar, float array[NUMBER_OF_CONTOURS+2])\n"
342  "{\n"
343  " int index = NUMBER_OF_CONTOURS >> 1;\n"
344  " while (scalar > array[index]) ++index;\n"
345  " while (scalar < array[index]) --index;\n"
346  " return index;\n"
347  "}\n"
348  "#endif\n";
349  }
350  else if (glMapper->GetBlendMode() == vtkVolumeMapper::SLICE_BLEND)
351  {
352  vtkVolume* vol = inputs.begin()->second.Volume;
354 
355  if (func && func->IsA("vtkPlane"))
356  {
357  toShaderStr
358  << "uniform vec3 in_slicePlaneOrigin;\n"
359  "uniform vec3 in_slicePlaneNormal;\n"
360  "vec3 g_intersection;\n"
361  "\n"
362  "float intersectRayPlane(vec3 rayOrigin, vec3 rayDir)\n"
363  "{\n"
364  " vec4 planeNormal = in_inverseVolumeMatrix[0] * vec4(in_slicePlaneNormal, 0.0);\n"
365  " float denom = dot(planeNormal.xyz, rayDir);\n"
366  " if (abs(denom) > 1e-6)\n"
367  " {\n"
368  " vec4 planeOrigin = in_inverseVolumeMatrix[0] * vec4(in_slicePlaneOrigin, 1.0);\n"
369  " return dot(planeOrigin.xyz - rayOrigin, planeNormal.xyz) / denom;\n"
370  " }\n"
371  " return -1.0;\n"
372  "}\n";
373  }
374  }
375 
376  return toShaderStr.str();
377 }
378 
379 //--------------------------------------------------------------------------
380 inline std::string BaseInit(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper,
381  vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, bool defaultLighting)
382 {
384  vtkVolume* vol = inputs.begin()->second.Volume;
385  const int numInputs = static_cast<int>(inputs.size());
386 
387  std::ostringstream shaderStr;
389  glMapper->GetUseDepthPass() && glMapper->GetBlendMode() == vtkVolumeMapper::COMPOSITE_BLEND)
390  {
391  shaderStr << "\
392  \n //\
393  \n vec2 fragTexCoord2 = (gl_FragCoord.xy - in_windowLowerLeftCorner) *\
394  \n in_inverseWindowSize;\
395  \n vec4 depthValue = texture2D(in_depthPassSampler, fragTexCoord2);\
396  \n vec4 rayOrigin = WindowToNDC(gl_FragCoord.x, gl_FragCoord.y, depthValue.x);\
397  \n\
398  \n // From normalized device coordinates to eye coordinates.\
399  \n // in_projectionMatrix is inversed because of way VT\
400  \n // From eye coordinates to texture coordinates\
401  \n rayOrigin = in_inverseTextureDatasetMatrix[0] *\
402  \n in_inverseVolumeMatrix[0] *\
403  \n in_inverseModelViewMatrix *\
404  \n in_inverseProjectionMatrix *\
405  \n rayOrigin;\
406  \n rayOrigin /= rayOrigin.w;\
407  \n g_rayOrigin = rayOrigin.xyz;";
408  }
409  else
410  {
411  shaderStr << "\
412  \n // Get the 3D texture coordinates for lookup into the in_volume dataset\
413  \n g_rayOrigin = ip_textureCoords.xyz;";
414  }
415 
416  shaderStr << "\n\
417  \n // Getting the ray marching direction (in dataset space)\
418  \n vec3 rayDir = computeRayDirection();\
419  \n\
420  \n // 2D Texture fragment coordinates [0,1] from fragment coordinates.\
421  \n // The frame buffer texture has the size of the plain buffer but \
422  \n // we use a fraction of it. The texture coordinate is less than 1 if\
423  \n // the reduction factor is less than 1.\
424  \n // Device coordinates are between -1 and 1. We need texture\
425  \n // coordinates between 0 and 1. The in_depthSampler\
426  \n // buffer has the original size buffer.\
427  \n vec2 fragTexCoord = (gl_FragCoord.xy - in_windowLowerLeftCorner) *\
428  \n in_inverseWindowSize;\
429  \n\
430  \n // Multiply the raymarching direction with the step size to get the\
431  \n // sub-step size we need to take at each raymarching step\
432  \n g_dirStep = (ip_inverseTextureDataAdjusted *\
433  \n vec4(rayDir, 0.0)).xyz * in_sampleDistance;\
434  \n g_lengthStep = length(g_dirStep);\
435  \n";
436 
437  shaderStr << "\
438  \n float jitterValue = 0.0;\
439  \n";
440 
441  if (glMapper->GetBlendMode() != vtkVolumeMapper::SLICE_BLEND)
442  {
443  // Intersection is computed with g_rayOrigin, so we should not modify it with Slice mode
444  if (glMapper->GetUseJittering())
445  {
446  shaderStr << "\
447  \n jitterValue = texture2D(in_noiseSampler, gl_FragCoord.xy /\
448  vec2(textureSize(in_noiseSampler, 0))).x;\
449  \n g_rayJitter = g_dirStep * jitterValue;\
450  \n";
451  }
452  else
453  {
454  shaderStr << "\
455  \n g_rayJitter = g_dirStep;\
456  \n";
457  }
458  shaderStr << "\
459  \n g_rayOrigin += g_rayJitter;\
460  \n";
461  }
462 
463  shaderStr << "\
464  \n // Flag to determine if voxel should be considered for the rendering\
465  \n g_skip = false;";
466 
467  if (vol->GetProperty()->GetShade() && defaultLighting)
468  {
469  shaderStr << "\
470  \n // Light position in dataset space";
471  for (int i = 0; i < numInputs; ++i)
472  {
473  // In multi-volume case the first volume matrix is of the bounding box
474  shaderStr << "\
475  \n g_lightPosObj["
476  << i << "] = vec4(in_eyePosObjs[" << (numInputs > 1 ? i + 1 : i) << "], 1.0);\
477  \n g_ldir["
478  << i << "] = normalize(g_lightPosObj[" << i << "].xyz - ip_vertexPos);\
479  \n g_vdir["
480  << i << "] = normalize(in_eyePosObjs[" << i << "].xyz - ip_vertexPos);\
481  \n g_h["
482  << i << "] = normalize(g_ldir[" << i << "] + g_vdir[" << i << "]);";
483  }
484  }
485 
486  return shaderStr.str();
487 }
488 
489 //--------------------------------------------------------------------------
491  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
492 {
494 
495  std::string str("\
496  \n g_skip = false;");
497 
498  // Blanking support
500  bool blankCells = (dataSet->GetCellGhostArray() != nullptr);
501  bool blankPoints = (dataSet->GetPointGhostArray() != nullptr);
502  if (blankPoints || blankCells)
503  {
504  str += std::string("\
505  \n // Check whether the neighboring points/cells are blank.\
506  \n // Note the half cellStep because texels are point centered.\
507  \n vec3 xvec = vec3(in_cellStep[0].x/2.0, 0.0, 0.0);\
508  \n vec3 yvec = vec3(0.0, in_cellStep[0].y/2.0, 0.0);\
509  \n vec3 zvec = vec3(0.0, 0.0, in_cellStep[0].z/2.0);\
510  \n vec3 texPosPVec[3];\
511  \n texPosPVec[0] = g_dataPos + xvec;\
512  \n texPosPVec[1] = g_dataPos + yvec;\
513  \n texPosPVec[2] = g_dataPos + zvec;\
514  \n vec3 texPosNVec[3];\
515  \n texPosNVec[0] = g_dataPos - xvec;\
516  \n texPosNVec[1] = g_dataPos - yvec;\
517  \n texPosNVec[2] = g_dataPos - zvec;\
518  \n vec4 blankValue = texture3D(in_blanking, g_dataPos);\
519  \n vec4 blankValueXP = texture3D(in_blanking, texPosPVec[0]);\
520  \n vec4 blankValueYP = texture3D(in_blanking, texPosPVec[1]);\
521  \n vec4 blankValueZP = texture3D(in_blanking, texPosPVec[2]);\
522  \n vec4 blankValueXN = texture3D(in_blanking, texPosNVec[0]);\
523  \n vec4 blankValueYN = texture3D(in_blanking, texPosNVec[1]);\
524  \n vec4 blankValueZN = texture3D(in_blanking, texPosNVec[2]);\
525  \n vec3 blankValuePx;\
526  \n blankValuePx[0] = blankValueXP.x;\
527  \n blankValuePx[1] = blankValueYP.x;\
528  \n blankValuePx[2] = blankValueZP.x;\
529  \n vec3 blankValuePy;\
530  \n blankValuePy[0] = blankValueXP.y;\
531  \n blankValuePy[1] = blankValueYP.y;\
532  \n blankValuePy[2] = blankValueZP.y;\
533  \n vec3 blankValueNx;\
534  \n blankValueNx[0] = blankValueXN.x;\
535  \n blankValueNx[1] = blankValueYN.x;\
536  \n blankValueNx[2] = blankValueZN.x;\
537  \n vec3 blankValueNy;\
538  \n blankValueNy[0] = blankValueXN.y;\
539  \n blankValueNy[1] = blankValueYN.y;\
540  \n blankValueNy[2] = blankValueZN.y;\
541  \n");
542  if (blankPoints)
543  {
544  str += std::string("\
545  \n // If the current or neighboring points\
546  \n // (that belong to cells that share this texel) are blanked,\
547  \n // skip the texel. In other words, if point 1 were blank,\
548  \n // texels 0, 1 and 2 would have to be skipped.\
549  \n if (blankValue.x > 0.0 ||\
550  \n any(greaterThan(blankValueNx, vec3(0.0))) ||\
551  \n any(greaterThan(blankValuePx, vec3(0.0))))\
552  \n {\
553  \n // skip this texel\
554  \n g_skip = true;\
555  \n }\
556  \n");
557  if (blankCells)
558  {
559  str += std::string("\
560  \n // If the current or previous cells (that share this texel)\
561  \n // are blanked, skip the texel. In other words, if cell 1\
562  \n // is blanked, texels 1 and 2 would have to be skipped.\
563  \n else if (blankValue.y > 0.0 ||\
564  \n any(greaterThan(blankValuePy, vec3(0.0))) ||\
565  \n any(greaterThan(blankValueNy, vec3(0.0))))\
566  \n {\
567  \n // skip this texel\
568  \n g_skip = true;\
569  \n }\
570  \n");
571  }
572  }
573  else if (blankCells)
574  {
575  str += std::string("\
576  \n // If the current or previous cells (that share this texel)\
577  \n // are blanked, skip the texel. In other words, if cell 1\
578  \n // is blanked, texels 1 and 2 would have to be skipped.\
579  \n if (blankValue.x > 0.0 ||\
580  \n any(greaterThan(blankValueNx, vec3(0.0))) ||\
581  \n any(greaterThan(blankValuePx, vec3(0.0))))\
582  \n {\
583  \n // skip this texel\
584  \n g_skip = true;\
585  \n }\
586  \n");
587  }
588  }
589 
590  if (glMapper->GetBlendMode() == vtkVolumeMapper::SLICE_BLEND)
591  {
592  str += std::string("\
593  \n g_dataPos = g_intersection;\
594  \n");
595  }
596 
597  return str;
598 }
599 
600 //--------------------------------------------------------------------------
602  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
603 {
604  return std::string();
605 }
606 
607 //--------------------------------------------------------------------------
608 inline std::string ComputeGradientOpacity1DDecl(vtkVolume* vol, int noOfComponents,
609  int independentComponents, std::map<int, std::string> gradientTableMap)
610 {
611  auto volProperty = vol->GetProperty();
612  std::ostringstream ss;
613  if (volProperty->HasGradientOpacity())
614  {
615  ss << "uniform sampler2D " << ArrayBaseName(gradientTableMap[0]) << "[" << noOfComponents
616  << "];\n";
617  }
618  bool useLabelGradientOpacity =
619  (volProperty->HasLabelGradientOpacity() && (noOfComponents == 1 || !independentComponents));
620  if (useLabelGradientOpacity)
621  {
622  ss << "uniform sampler2D in_labelMapGradientOpacity;\n";
623  }
624 
625  std::string shaderStr = ss.str();
626 
627  if (volProperty->HasGradientOpacity() && noOfComponents > 0)
628  {
629  if (noOfComponents == 1 || !independentComponents)
630  {
631  shaderStr += std::string("\
632  \nfloat computeGradientOpacity(vec4 grad)\
633  \n {\
634  \n return texture2D(" +
635  gradientTableMap[0] + ", vec2(grad.w, 0.0)).r;\
636  \n }");
637  }
638  else
639  {
640  shaderStr += std::string("\
641  \nfloat computeGradientOpacity(vec4 grad, int component)\
642  \n {");
643 
644  for (int i = 0; i < noOfComponents; ++i)
645  {
646  std::ostringstream toString;
647  toString << i;
648  shaderStr += std::string("\
649  \n if (component == " +
650  toString.str() + ")");
651 
652  shaderStr += std::string("\
653  \n {\
654  \n return texture2D(" +
655  gradientTableMap[i] + ", vec2(grad.w, 0.0)).r;\
656  \n }");
657  }
658 
659  shaderStr += std::string("\
660  \n }");
661  }
662  }
663 
664  if (useLabelGradientOpacity)
665  {
666  shaderStr += std::string("\
667  \nfloat computeGradientOpacityForLabel(vec4 grad, float label)\
668  \n {\
669  \n return texture2D(in_labelMapGradientOpacity, vec2(grad.w, label)).r;\
670  \n }");
671  }
672 
673  return shaderStr;
674 }
675 
676 //--------------------------------------------------------------------------
679 {
680  const bool hasLighting = HasLighting(inputs);
681  const bool hasGradientOp = HasGradientOpacity(inputs);
682 
683  std::string shaderStr;
684  if (hasLighting || hasGradientOp)
685  {
686  shaderStr += std::string(
687  "// c is short for component\n"
688  "vec4 computeGradient(in vec3 texPos, in int c, in sampler3D volume,in int index)\n"
689  "{\n"
690  " // Approximate Nabla(F) derivatives with central differences.\n"
691  " vec3 g1; // F_front\n"
692  " vec3 g2; // F_back\n"
693  " vec3 xvec = vec3(in_cellStep[index].x, 0.0, 0.0);\n"
694  " vec3 yvec = vec3(0.0, in_cellStep[index].y, 0.0);\n"
695  " vec3 zvec = vec3(0.0, 0.0, in_cellStep[index].z);\n"
696  " vec3 texPosPvec[3];\n"
697  " texPosPvec[0] = texPos + xvec;\n"
698  " texPosPvec[1] = texPos + yvec;\n"
699  " texPosPvec[2] = texPos + zvec;\n"
700  " vec3 texPosNvec[3];\n"
701  " texPosNvec[0] = texPos - xvec;\n"
702  " texPosNvec[1] = texPos - yvec;\n"
703  " texPosNvec[2] = texPos - zvec;\n"
704  " g1.x = texture3D(volume, vec3(texPosPvec[0]))[c];\n"
705  " g1.y = texture3D(volume, vec3(texPosPvec[1]))[c];\n"
706  " g1.z = texture3D(volume, vec3(texPosPvec[2]))[c];\n"
707  " g2.x = texture3D(volume, vec3(texPosNvec[0]))[c];\n"
708  " g2.y = texture3D(volume, vec3(texPosNvec[1]))[c];\n"
709  " g2.z = texture3D(volume, vec3(texPosNvec[2]))[c];\n"
710  "\n");
711  if (UseClippedVoxelIntensity(inputs) && mapper->GetClippingPlanes())
712  {
713  shaderStr +=
714  std::string(" vec4 g1ObjDataPos[3], g2ObjDataPos[3];\n"
715  " for (int i = 0; i < 3; ++i)\n"
716  " {\n"
717  " g1ObjDataPos[i] = clip_texToObjMat * vec4(texPosPvec[i], 1.0);\n"
718  " if (g1ObjDataPos[i].w != 0.0)\n"
719  " {\n"
720  " g1ObjDataPos[i] /= g1ObjDataPos[i].w;\n"
721  " }\n"
722  " g2ObjDataPos[i] = clip_texToObjMat * vec4(texPosNvec[i], 1.0);\n"
723  " if (g2ObjDataPos[i].w != 0.0)\n"
724  " {\n"
725  " g2ObjDataPos[i] /= g2ObjDataPos[i].w;\n"
726  " }\n"
727  " }\n"
728  "\n"
729  " for (int i = 0; i < clip_numPlanes && !g_skip; i = i + 6)\n"
730  " {\n"
731  " vec3 planeOrigin = vec3(in_clippingPlanes[i + 1],\n"
732  " in_clippingPlanes[i + 2],\n"
733  " in_clippingPlanes[i + 3]);\n"
734  " vec3 planeNormal = normalize(vec3(in_clippingPlanes[i + 4],\n"
735  " in_clippingPlanes[i + 5],\n"
736  " in_clippingPlanes[i + 6]));\n"
737  " for (int j = 0; j < 3; ++j)\n"
738  " {\n"
739  " if (dot(vec3(planeOrigin - g1ObjDataPos[j].xyz), planeNormal) > 0)\n"
740  " {\n"
741  " g1[j] = in_clippedVoxelIntensity;\n"
742  " }\n"
743  " if (dot(vec3(planeOrigin - g2ObjDataPos[j].xyz), planeNormal) > 0)\n"
744  " {\n"
745  " g2[j] = in_clippedVoxelIntensity;\n"
746  " }\n"
747  " }\n"
748  " }\n"
749  "\n");
750  }
751  shaderStr += std::string(" // Apply scale and bias to the fetched values.\n"
752  " g1 = g1 * in_volume_scale[index][c] + in_volume_bias[index][c];\n"
753  " g2 = g2 * in_volume_scale[index][c] + in_volume_bias[index][c];\n"
754  "\n");
755  if (!hasGradientOp)
756  {
757  shaderStr +=
758  std::string(" // Central differences: (F_front - F_back) / 2h\n"
759  " // This version of computeGradient() is only used for lighting\n"
760  " // calculations (only direction matters), hence the difference is\n"
761  " // not scaled by 2h and a dummy gradient mag is returned (-1.).\n"
762  " return vec4((g1 - g2) / in_cellSpacing[index], -1.0);\n"
763  "}\n");
764  }
765  else
766  {
767  shaderStr += std::string(
768  " // Scale values the actual scalar range.\n"
769  " float range = in_scalarsRange[4*index+c][1] - in_scalarsRange[4*index+c][0];\n"
770  " g1 = in_scalarsRange[4*index+c][0] + range * g1;\n"
771  " g2 = in_scalarsRange[4*index+c][0] + range * g2;\n"
772  "\n"
773  " // Central differences: (F_front - F_back) / 2h\n"
774  " g2 = g1 - g2;\n"
775  "\n"
776  " float avgSpacing = (in_cellSpacing[index].x +\n"
777  " in_cellSpacing[index].y + in_cellSpacing[index].z) / 3.0;\n"
778  " vec3 aspect = in_cellSpacing[index] * 2.0 / avgSpacing;\n"
779  " g2 /= aspect;\n"
780  " float grad_mag = length(g2);\n"
781  "\n"
782  " // Handle normalizing with grad_mag == 0.0\n"
783  " g2 = grad_mag > 0.0 ? normalize(g2) : vec3(0.0);\n"
784  "\n"
785  " // Since the actual range of the gradient magnitude is unknown,\n"
786  " // assume it is in the range [0, 0.25 * dataRange].\n"
787  " range = range != 0.0 ? range : 1.0;\n"
788  " grad_mag = grad_mag / (0.25 * range);\n"
789  " grad_mag = clamp(grad_mag, 0.0, 1.0);\n"
790  "\n"
791  " return vec4(g2.xyz, grad_mag);\n"
792  "}\n");
793  }
794  }
795  else
796  {
797  shaderStr += std::string(
798  "vec4 computeGradient(in vec3 texPos, in int c, in sampler3D volume, in int index)\n"
799  "{\n"
800  " return vec4(0.0);\n"
801  "}\n");
802  }
803 
804  return shaderStr;
805 }
806 
807 //---------------------------------------------------------------------------
809  vtkOpenGLGPUVolumeRayCastMapper* vtkNotUsed(mapper), int numberPositionalLights)
810 {
811  std::string resStr;
812  resStr += R"***(
813  for(int i=0; i<TOTAL_NUMBER_LIGHTS; i++)
814  {
815  g_lightDirectionTex[i] = (g_eyeToTexture * vec4(-in_lightDirection[i], 0.0)).xyz;
816  }
817  )***";
818 
819  if (numberPositionalLights > 0)
820  {
821  resStr += R"***(
822  for(int i=0; i<NUMBER_POS_LIGHTS; i++)
823  {
824  g_lightPositionTex[i] = (g_eyeToTexture * vec4(in_lightPosition[i], 1.0)).xyz;
825  }
826  )***";
827  }
828  return resStr;
829 }
830 
831 //--------------------------------------------------------------------------
833  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
834  int independentComponents, std::map<int, std::string> opacityTableMap, int useGradient)
835 {
836  std::string resStr;
837  std::string functionBody;
838  bool severalIndpt = noOfComponents > 1 && independentComponents;
839  std::string functionSignature = severalIndpt
840  ? "vec4 computeRGBAWithGrad(vec4 scalar, vec4 grad, int component)\n"
841  : "vec4 computeRGBAWithGrad(vec4 scalar, vec4 grad)\n";
842 
843  if (severalIndpt)
844  {
845  // Multiple independent components
846 
847  if (!useGradient)
848  {
849  functionBody +=
850  "vec4 yscalar = texture3D(in_transfer2DYAxis, g_dataPos);\n"
851  "for (int i = 0; i < 4; ++i)\n"
852  "{\n"
853  " yscalar[i] = yscalar[i] * in_transfer2DYAxis_scale[i] + in_transfer2DYAxis_bias[i];\n"
854  "}\n";
855  }
856 
857  for (int i = 0; i < noOfComponents; ++i)
858  {
859  std::string secondAxis(useGradient
860  // we take the same grad for all components so we have to be sure that
861  // the one given as a parameter is computed wrt the right component
862  ? "grad.w"
863  : std::string("yscalar[") + vtk::to_string(i) + "]");
864 
865  functionBody += " if(component == " + vtk::to_string(i) +
866  ")\n"
867  " {\n"
868  " return texture2D(" +
869  opacityTableMap[i] + ",\n" + " vec2(scalar[" + vtk::to_string(i) + "], " + secondAxis +
870  "))\n" + " }\n";
871  }
872  }
873 
874  else if (noOfComponents == 2 && !independentComponents)
875  {
876  std::string secondAxis(useGradient ? "grad.w" : "yscalar.y");
877 
878  functionBody += " return texture2D(" + opacityTableMap[0] +
879  ",\n"
880  " vec2(scalar.y, " +
881  secondAxis + "));\n";
882  }
883 
884  else
885  {
886  if (useGradient)
887  {
888  // Dependent components (RGBA) || Single component
889  functionBody += " return texture2D(" + opacityTableMap[0] +
890  ",\n"
891  " vec2(scalar.a, grad.w));\n";
892  }
893  else
894  {
895  // Dependent components (RGBA) || Single component
896  functionBody +=
897  " vec4 yscalar = texture3D(in_transfer2DYAxis, g_dataPos);\n"
898  " yscalar.r = yscalar.r * in_transfer2DYAxis_scale.r + in_transfer2DYAxis_bias.r;\n"
899  " yscalar = vec4(yscalar.r);\n"
900  " return texture2D(" +
901  opacityTableMap[0] +
902  ",\n"
903  " vec2(scalar.a, yscalar.w));\n";
904  }
905  }
906 
907  resStr = functionSignature + "{\n" + functionBody + "}\n";
908 
909  return resStr;
910 }
911 
912 //-----------------------------------------------------------------------
914  vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, int noOfComponents,
915  int independentComponents, int useGradYAxis, std::string position, bool requestColor = false)
916 {
917  // relies on the declaration of variables opacity, gradient, c, volume, index, scalar, gradTF,
918  // opacityTF, label in the scope
919  std::string resStr;
920 
921  if (inputs.size() > 1)
922  {
923  // Multi Volume
924  const bool hasGradOp = ::HasGradientOpacity(inputs);
925  resStr += " opacity = computeOpacity(vec4(scalar), opacityTF);\n";
926  // either all volumes have a TF either none have one, so we can have
927  // the same opacity call for all volumes
928  if (hasGradOp)
929  {
930  resStr += std::string(" gradient = computeGradient(") + position + ", c, volume, index);\n";
931  resStr += " opacity *= computeGradientOpacity(gradient, gradTF);\n";
932  }
933  // ignore request color for now, but given the actual architecture, it should be a
934  // succession of 'if' comparing the volume idx
935  if (requestColor)
936  {
937  vtkGenericWarningMacro(<< "ComputeOpacityEvaluationCall was called with requestColor, but "
938  "MultiVolume does not support this option yet.");
939  }
940  }
941  else
942  {
943  // Single Volume
944  vtkVolumeProperty* volProp = inputs[0].Volume->GetProperty();
945  const bool hasGradOp = volProp->HasGradientOpacity() && !volProp->GetDisableGradientOpacity();
946  const bool useLabelGradientOpacity = (volProp->HasLabelGradientOpacity() &&
947  (noOfComponents == 1 || !independentComponents) && !volProp->GetDisableGradientOpacity());
948 
949  const int tfMode = volProp->GetTransferFunctionMode();
950 
951  bool indpComps = (noOfComponents > 1 && independentComponents);
952  std::string compArgument = (indpComps) ? std::string(", c") : std::string();
953 
954  const bool needGrad = (tfMode == vtkVolumeProperty::TF_2D && useGradYAxis); // to be sure
955 
956  if (tfMode == vtkVolumeProperty::TF_1D)
957  {
958 
959  std::string compWeights = indpComps ? std::string(" * in_componentWeight[c]") : std::string();
960 
961  resStr += std::string(" opacity = computeOpacity(vec4(scalar)") + compArgument +
962  std::string(")") + compWeights + ";\n";
963 
964  if (hasGradOp || useLabelGradientOpacity)
965  {
966  resStr += std::string(" gradient = computeGradient(") + position +
967  std::string(", c, volume, index);\n"
968  " if(gradient.w >= 0.0) {\n") +
969  (hasGradOp ? (std::string(" opacity *= computeGradientOpacity(gradient") +
970  compArgument + ")" + compWeights + ";\n")
971  : std::string())
972 
973  + (useLabelGradientOpacity
974  ? (std::string(" opacity *= computeGradientOpacityForLabel(gradient, label);\n"))
975  : std::string())
976 
977  + std::string(" }\n");
978  }
979 
980  if (requestColor)
981  {
982  resStr +=
983  " color = texture2D(" + inputs[0].RGBTablesMap[0] + ", vec2(scalar, 0.0)).xyz;\n";
984  }
985  }
986  else
987  {
988  // 2D TF
989  if (needGrad)
990  {
991  resStr +=
992  std::string(" gradient = computeGradient(") + position + ", c, volume, index);\n";
993  }
994  resStr += std::string(" vec4 lutRes = computeRGBAWithGrad(vec4(scalar), gradient") +
995  compArgument + std::string(");\n");
996 
997  resStr += " opacity = lutRes.a;\n";
998 
999  if (requestColor)
1000  {
1001  resStr += " color = lutRes.xyz;\n";
1002  }
1003  }
1004  }
1005 
1006  return resStr;
1007 }
1008 
1009 //--------------------------------------------------------------------------
1011  vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, int noOfComponents,
1012  int independentComponents, int useGradYAxis)
1013 {
1014  const bool hasLighting = ::HasLighting(inputs);
1015  const bool hasGradientOp = ::HasGradientOpacity(inputs);
1016 
1017  std::string functionSignature;
1018 
1019  if (inputs.size() > 1)
1020  {
1021  if (hasGradientOp)
1022  {
1023  functionSignature = std::string(
1024  "vec4 computeDensityGradient(in vec3 texPos, in int c, in sampler3D volume, "
1025  "const in sampler2D opacityTF, const in sampler2D gradTF, in int index, float label)\n");
1026  }
1027  else
1028  {
1029  functionSignature =
1030  std::string("vec4 computeDensityGradient(in vec3 texPos, in int c, in sampler3D volume, "
1031  "const in sampler2D opacityTF, in int index, float label)\n");
1032  }
1033  }
1034  else
1035  {
1036  functionSignature = std::string("vec4 computeDensityGradient(in vec3 texPos, in int c, in "
1037  "sampler3D volume, in int index, float label)\n");
1038  }
1039 
1040  std::string shaderStr;
1041  if (hasLighting || hasGradientOp)
1042  {
1043 
1044  std::string opacityTFcall;
1045  // this table remembers the correspondence results <-> texture coordinates
1046  static const std::array<std::pair<const char*, const char*>, 6> results_texPos = { {
1047  { " g1.x", "texPosPvec[0]" },
1048  { " g1.y", "texPosPvec[1]" },
1049  { " g1.z", "texPosPvec[2]" },
1050  { " g2.x", "texPosNvec[0]" },
1051  { " g2.y", "texPosNvec[1]" },
1052  { " g2.z", "texPosNvec[2]" },
1053  } };
1054 
1055  shaderStr += std::string("// c is short for component\n") + functionSignature +
1056  std::string("{\n"
1057  " // Approximate Nabla(F) derivatives with central differences.\n"
1058  " vec3 g1; // F_front\n"
1059  " vec3 g2; // F_back\n"
1060  " vec3 xvec = vec3(in_cellStep[index].x, 0.0, 0.0);\n"
1061  " vec3 yvec = vec3(0.0, in_cellStep[index].y, 0.0);\n"
1062  " vec3 zvec = vec3(0.0, 0.0, in_cellStep[index].z);\n"
1063  " vec3 texPosPvec[3];\n"
1064  " texPosPvec[0] = texPos + xvec;\n"
1065  " texPosPvec[1] = texPos + yvec;\n"
1066  " texPosPvec[2] = texPos + zvec;\n"
1067  " vec3 texPosNvec[3];\n"
1068  " texPosNvec[0] = texPos - xvec;\n"
1069  " texPosNvec[1] = texPos - yvec;\n"
1070  " texPosNvec[2] = texPos - zvec;\n"
1071  " float scalar;\n"
1072  " float opacity;\n"
1073  " vec4 gradient;\n"
1074  "\n");
1075 
1076  for (auto& gradComp : results_texPos)
1077  {
1078  // opacityTFcall corresponds to code snippet used to compute the opacity
1079  opacityTFcall = ComputeOpacityEvaluationCall(
1080  mapper, inputs, noOfComponents, independentComponents, useGradYAxis, gradComp.second);
1081  shaderStr += std::string(" scalar = texture3D(volume,") + gradComp.second +
1082  std::string(")[c];\n"
1083  " scalar = scalar * in_volume_scale[index][c] + in_volume_bias[index][c];\n") +
1084  opacityTFcall + gradComp.first + " = opacity;\n";
1085  }
1086 
1087  if (::UseClippedVoxelIntensity(inputs) && mapper->GetClippingPlanes())
1088  {
1089  shaderStr +=
1090  std::string(" vec4 g1ObjDataPos[3], g2ObjDataPos[3];\n"
1091  " for (int i = 0; i < 3; ++i)\n"
1092  " {\n"
1093  " g1ObjDataPos[i] = clip_texToObjMat * vec4(texPosPvec[i], 1.0);\n"
1094  " if (g1ObjDataPos[i].w != 0.0)\n"
1095  " {\n"
1096  " g1ObjDataPos[i] /= g1ObjDataPos[i].w;\n"
1097  " }\n"
1098  " g2ObjDataPos[i] = clip_texToObjMat * vec4(texPosNvec[i], 1.0);\n"
1099  " if (g2ObjDataPos[i].w != 0.0)\n"
1100  " {\n"
1101  " g2ObjDataPos[i] /= g2ObjDataPos[i].w;\n"
1102  " }\n"
1103  " }\n"
1104  "\n"
1105  " for (int i = 0; i < clip_numPlanes && !g_skip; i = i + 6)\n"
1106  " {\n"
1107  " vec3 planeOrigin = vec3(in_clippingPlanes[i + 1],\n"
1108  " in_clippingPlanes[i + 2],\n"
1109  " in_clippingPlanes[i + 3]);\n"
1110  " vec3 planeNormal = normalize(vec3(in_clippingPlanes[i + 4],\n"
1111  " in_clippingPlanes[i + 5],\n"
1112  " in_clippingPlanes[i + 6]));\n"
1113  " for (int j = 0; j < 3; ++j)\n"
1114  " {\n"
1115  " if (dot(vec3(planeOrigin - g1ObjDataPos[j].xyz), planeNormal) > 0)\n"
1116  " {\n"
1117  " g1[j] = in_clippedVoxelIntensity;\n"
1118  " }\n"
1119  " if (dot(vec3(planeOrigin - g2ObjDataPos[j].xyz), planeNormal) > 0)\n"
1120  " {\n"
1121  " g2[j] = in_clippedVoxelIntensity;\n"
1122  " }\n"
1123  " }\n"
1124  " }\n"
1125  "\n");
1126  }
1127 
1128  if (!hasGradientOp)
1129  {
1130  shaderStr +=
1131  std::string(" // Central differences: (F_front - F_back) / 2h\n"
1132  " // This version of computeGradient() is only used for lighting\n"
1133  " // calculations (only direction matters), hence the difference is\n"
1134  " // not scaled by 2h and a dummy gradient mag is returned (-1.).\n"
1135  " return vec4((g1 - g2) / in_cellSpacing[index], -1.0);\n"
1136  "}\n");
1137  }
1138  else
1139  {
1140  shaderStr += std::string(
1141  " // Scale values the actual scalar range.\n"
1142  " float range = in_scalarsRange[4*index+c][1] - in_scalarsRange[4*index+c][0];\n"
1143  " g1 = in_scalarsRange[4*index+c][0] + range * g1;\n"
1144  " g2 = in_scalarsRange[4*index+c][0] + range * g2;\n"
1145  "\n"
1146  " // Central differences: (F_front - F_back) / 2h\n"
1147  " g2 = g1 - g2;\n"
1148  "\n"
1149  " float avgSpacing = (in_cellSpacing[index].x +\n"
1150  " in_cellSpacing[index].y + in_cellSpacing[index].z) / 3.0;\n"
1151  " vec3 aspect = in_cellSpacing[index] * 2.0 / avgSpacing;\n"
1152  " g2 /= aspect;\n"
1153  " float grad_mag = length(g2);\n"
1154  "\n"
1155  " // Handle normalizing with grad_mag == 0.0\n"
1156  " g2 = grad_mag > 0.0 ? normalize(g2) : vec3(0.0);\n"
1157  "\n"
1158  " // Since the actual range of the gradient magnitude is unknown,\n"
1159  " // assume it is in the range [0, 0.25 * dataRange].\n"
1160  " range = range != 0 ? range : 1.0;\n"
1161  " grad_mag = grad_mag / (0.25 * range);\n"
1162  " grad_mag = clamp(grad_mag, 0.0, 1.0);\n"
1163  "\n"
1164  " return vec4(g2.xyz, grad_mag);\n"
1165  "}\n");
1166  }
1167  }
1168  else
1169  {
1170  shaderStr += functionSignature +
1171  std::string("{\n"
1172  " return vec4(0.0);\n"
1173  "}\n");
1174  }
1175 
1176  return shaderStr;
1177 }
1178 
1180  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vol)
1181 {
1182  std::string resStr;
1183  // to be compatible with the surface shading model,
1184  // the phase function should be normalized to 4pi instead of 1
1185  // that's why the isotropic phase function returns 1 and not 1/4pi for example
1186  if (std::abs(vol->GetProperty()->GetScatteringAnisotropy()) < 0.01)
1187  {
1188  resStr += R"***(
1189 float phase_function(float cos_angle)
1190 {
1191  return 1.0;
1192 }
1193  )***";
1194  }
1195  else
1196  {
1197  resStr += R"***(
1198 float g_anisotropy2 = in_anisotropy * in_anisotropy;
1199 
1200 float phase_function(float cos_angle)
1201 {
1202  float d = 1.0 + g_anisotropy2 - 2.0 * in_anisotropy * cos_angle;
1203  return (1.0 - g_anisotropy2) / (d * sqrt(d));
1204 }
1205 
1206  )***";
1207  }
1208  return resStr;
1209 }
1210 
1211 //--------------------------------------------------------------------------
1213  vtkVolume* vol, int noOfComponents, int independentComponents, int totalNumberOfLights,
1214  int numberPositionalLights, bool defaultLighting)
1215 {
1216  auto glMapper = vtkOpenGLGPUVolumeRayCastMapper::SafeDownCast(mapper);
1217  vtkVolumeProperty* volProperty = vol->GetProperty();
1218  std::string shaderStr = std::string("\
1219  \nvec4 computeLighting(vec4 color, int component, float label)\
1220  \n{\
1221  \n vec4 finalColor = vec4(0.0);\n");
1222 
1223  // Shading for composite blending only
1224  int const shadeReqd = volProperty->GetShade() &&
1228 
1229  int const transferMode = volProperty->GetTransferFunctionMode();
1230 
1231  if (independentComponents)
1232  {
1233  shaderStr += "\n int lightingComponent=component;\n";
1234  }
1235  else
1236  {
1237  shaderStr += "\n int lightingComponent=0;\n";
1238  }
1239 
1240  // If shading is required, we compute a shading gradient (used for the shading model)
1241  if (shadeReqd)
1242  {
1243  if (glMapper->GetComputeNormalFromOpacity())
1244  {
1245  // we compute the gradienty according to the volume's opacity !
1246  shaderStr +=
1247  std::string(" vec4 shading_gradient = computeDensityGradient(g_dataPos, component, "
1248  "in_volume[0], 0, label);\n");
1249  }
1250  else
1251  {
1252  // otherwise we take the scalar gradient directly
1253  shaderStr += std::string(
1254  " vec4 shading_gradient = computeGradient(g_dataPos, component, in_volume[0], 0);\n");
1255  }
1256  }
1257 
1258  // If we need the scalar gradient (typically to sample a transfer function)
1259  if (volProperty->HasGradientOpacity() || volProperty->HasLabelGradientOpacity())
1260  {
1261  // If we didn't compute it before, we compute it
1262  if (!shadeReqd || glMapper->GetComputeNormalFromOpacity())
1263  {
1264  shaderStr +=
1265  std::string(" vec4 gradient = computeGradient(g_dataPos, component, in_volume[0], 0);\n");
1266  }
1267  // otherwise, we use what we already computed
1268  else
1269  {
1270  shaderStr += std::string(" vec4 gradient = shading_gradient;\n");
1271  }
1272  }
1273 
1274  if (shadeReqd)
1275  {
1276  if (defaultLighting)
1277  {
1278  shaderStr += R"***(
1279  vec3 diffuse = vec3(0.0);
1280  vec3 specular = vec3(0.0);
1281  vec3 normal = shading_gradient.xyz;
1282  float normalLength = length(normal);
1283  if (normalLength > 0.0)
1284  {
1285  normal = normalize(normal);
1286  }
1287  else
1288  {
1289  normal = vec3(0.0, 0.0, 0.0);
1290  }
1291  // XXX: normal is oriented inside the volume, so we take -g_ldir/-g_vdir
1292  float nDotL = dot(normal, -g_ldir[0]);
1293  vec3 r = normalize(2.0 * nDotL * normal + g_ldir[0]);
1294  float vDotR = dot(r, -g_vdir[0]);
1295  if (nDotL < 0.0 && in_twoSidedLighting)
1296  {
1297  nDotL = -nDotL;
1298  }
1299  if (nDotL > 0.0)
1300  {
1301  diffuse = nDotL * in_diffuse[lightingComponent] *
1302  in_lightDiffuseColor[0] * color.rgb;
1303  vDotR = max(vDotR, 0.0);
1304  specular = pow(vDotR, in_shininess[lightingComponent]) *
1305  in_specular[lightingComponent] *
1306  in_lightSpecularColor[0];
1307  }
1308  // For the headlight, ignore the light's ambient color
1309  // for now as it is causing the old mapper tests to fail
1310  finalColor.xyz = in_ambient[lightingComponent] * color.rgb +
1311  diffuse + specular;
1312 
1313  )***";
1314  }
1315  else if (totalNumberOfLights > 0)
1316  {
1317  shaderStr += R"***(
1318  g_fragWorldPos = g_texToView * vec4(g_dataPos, 1.0);
1319  if (g_fragWorldPos.w != 0.0)
1320  {
1321  g_fragWorldPos /= g_fragWorldPos.w;
1322  }
1323  vec3 viewDirection = normalize(-g_fragWorldPos.xyz);
1324  vec3 ambient = vec3(0,0,0);
1325  vec3 diffuse = vec3(0,0,0);
1326  vec3 specular = vec3(0,0,0);
1327  vec3 vertLightDirection;
1328  vec3 normal = normalize((in_textureToEye[0] * vec4(shading_gradient.xyz, 0.0)).xyz);
1329  vec3 lightDir;
1330  )***";
1331 
1332  if (numberPositionalLights > 0)
1333  {
1334  shaderStr += R"***(
1335  for (int posNum = 0; posNum < NUMBER_POS_LIGHTS; posNum++)
1336  {
1337  float attenuation = 1.0;
1338  lightDir = in_lightDirection[posNum];
1339  vertLightDirection = (g_fragWorldPos.xyz - in_lightPosition[posNum]);
1340  float distance = length(vertLightDirection);
1341  vertLightDirection = normalize(vertLightDirection);
1342  attenuation = 1.0 /
1343  (in_lightAttenuation[posNum].x
1344  + in_lightAttenuation[posNum].y * distance
1345  + in_lightAttenuation[posNum].z * distance * distance);
1346  // per OpenGL standard cone angle is 90 or less for a spot light
1347  if (in_lightConeAngle[posNum] <= 90.0)
1348  {
1349  float coneDot = dot(vertLightDirection, lightDir);
1350  // if inside the cone
1351  if (coneDot >= cos(radians(in_lightConeAngle[posNum])))
1352  {
1353  attenuation = attenuation * pow(coneDot, in_lightExponent[posNum]);
1354  }
1355  else
1356  {
1357  attenuation = 0.0;
1358  }
1359  }
1360 
1361  float nDotL = dot(normal, vertLightDirection);
1362  if (nDotL < 0.0 && in_twoSidedLighting)
1363  {
1364  nDotL = -nDotL;
1365  }
1366  if (nDotL > 0.0)
1367  {
1368  float df = max(0.0, attenuation * nDotL);
1369  diffuse += (df * in_lightDiffuseColor[posNum]);
1370  vec3 r = normalize(2.0 * nDotL * normal - vertLightDirection);
1371  float rDotV = dot(-viewDirection, r);
1372  if (rDotV < 0.0 && in_twoSidedLighting)
1373  {
1374  rDotV = -rDotV;
1375  }
1376  if (rDotV > 0.0)
1377  {
1378  float sf = attenuation * pow(rDotV, in_shininess[lightingComponent]);
1379  specular += (sf * in_lightSpecularColor[posNum]);
1380  }
1381  }
1382  ambient += in_lightAmbientColor[posNum];
1383  }
1384  )***";
1385  }
1386 
1387  shaderStr += R"***(
1388  for (int dirNum = NUMBER_POS_LIGHTS; dirNum < TOTAL_NUMBER_LIGHTS; dirNum++)
1389  {
1390  vertLightDirection = in_lightDirection[dirNum];
1391  float nDotL = dot(normal, vertLightDirection);
1392  if (nDotL < 0.0 && in_twoSidedLighting)
1393  {
1394  nDotL = -nDotL;
1395  }
1396  if (nDotL > 0.0)
1397  {
1398  float df = max(0.0, nDotL);
1399  diffuse += (df * in_lightDiffuseColor[dirNum]);
1400  vec3 r = normalize(2.0 * nDotL * normal - vertLightDirection);
1401  float rDotV = dot(-viewDirection, r);
1402  if (rDotV > 0.0)
1403  {
1404  float sf = pow(rDotV, in_shininess[lightingComponent]);
1405  specular += (sf * in_lightSpecularColor[dirNum]);
1406  }
1407  }
1408  ambient += in_lightAmbientColor[dirNum];
1409  }
1410  finalColor.xyz = in_ambient[lightingComponent] * ambient +
1411  in_diffuse[lightingComponent] * diffuse * color.rgb +
1412  in_specular[lightingComponent] * specular;
1413 
1414  )***";
1415  }
1416  }
1417  else
1418  {
1419  shaderStr += std::string("\n finalColor = vec4(color.rgb, 0.0);");
1420  }
1421 
1422  if (glMapper->GetVolumetricScatteringBlending() > 0.0 && totalNumberOfLights > 0)
1423  {
1424 
1425  float vsBlend = glMapper->GetVolumetricScatteringBlending();
1426  std::string blendingFormula = std::string(" float vol_coef = ") +
1427  (vsBlend < 1.0 ? "2.0 * in_volumetricScatteringBlending * exp( - 2.0 * "
1428  "in_volumetricScatteringBlending * shading_gradient.w * color.a)"
1429  : "2.0 * (1.0 - in_volumetricScatteringBlending) * exp( - 2.0 * "
1430  "in_volumetricScatteringBlending * shading_gradient.w * color.a) + 2.0 * "
1431  "in_volumetricScatteringBlending - 1.0") +
1432  ";\n";
1433 
1434  shaderStr +=
1435  (defaultLighting
1436  ? std::string()
1437  : std::string(
1438  "vec3 view_tdir = normalize((g_eyeToTexture * vec4(viewDirection, 0.0)).xyz);\n")) +
1439  R"***(
1440  vec3 secondary_contrib = vec3(0.0);
1441  vec3 tex_light = vec3(0.0);
1442  shading_gradient.w = length(shading_gradient.xyz);
1443  vec3 diffuse_light = vec3(0.0);
1444  float attenuation = 0.0;
1445  float vol_shadow = 0.0;
1446  float phase = 1.0;
1447  )***";
1448 
1449  if (defaultLighting)
1450  {
1451  shaderStr += R"***(
1452  tex_light = (in_inverseTextureDatasetMatrix[0] * vec4(in_eyePosObjs[0], 1.0)).xyz;
1453  phase = phase_function(-1); // always angle of pi
1454  vol_shadow = volumeShadow(g_dataPos, tex_light, 1.0, component, in_volume[0], 0, label);
1455  secondary_contrib += vol_shadow * phase * color.rgb * in_diffuse[lightingComponent] * in_lightDiffuseColor[0];
1456  secondary_contrib += in_ambient[lightingComponent] * in_lightAmbientColor[0];
1457  )***";
1458  }
1459  else
1460  {
1461  if (numberPositionalLights > 0)
1462  {
1463  shaderStr += R"***(
1464  float dist_light = 0.0;
1465  for(int posNum = 0; posNum < NUMBER_POS_LIGHTS; posNum++)
1466  {
1467  tex_light = g_lightPositionTex[posNum];
1468  vec3 light_vert = g_fragWorldPos.xyz - in_lightPosition[posNum];
1469  dist_light = length(light_vert);
1470  float light_angle = dot(normalize(light_vert), normalize(in_lightDirection[posNum]));
1471  phase = phase_function(dot(normalize(g_dataPos - tex_light), view_tdir));
1472  attenuation = 1.0 /
1473  (in_lightAttenuation[posNum].x
1474  + in_lightAttenuation[posNum].y * dist_light
1475  + in_lightAttenuation[posNum].z * dist_light * dist_light);
1476  attenuation *= max(0.0, sign(light_angle - cos(radians(in_lightConeAngle[posNum]))))
1477  * pow(light_angle, in_lightExponent[posNum]);
1478  vol_shadow = volumeShadow(g_dataPos, tex_light, 1.0, component, in_volume[0], 0, label);
1479  secondary_contrib += vol_shadow * phase * attenuation * color.rgb * in_diffuse[lightingComponent] * in_lightDiffuseColor[posNum];
1480  secondary_contrib += in_ambient[lightingComponent] * in_lightAmbientColor[posNum];
1481  }
1482  )***";
1483  }
1484 
1485  shaderStr += R"***(
1486  for(int dirNum = NUMBER_POS_LIGHTS; dirNum < TOTAL_NUMBER_LIGHTS; dirNum++)
1487  {
1488  tex_light = g_lightDirectionTex[dirNum];
1489  phase = phase_function(dot(normalize(-tex_light), view_tdir));
1490  vol_shadow = volumeShadow(g_dataPos, tex_light, 0.0, component, in_volume[0], 0, label);
1491  secondary_contrib += vol_shadow * phase * color.rgb * in_diffuse[lightingComponent] * in_lightDiffuseColor[dirNum];
1492  secondary_contrib += in_ambient[lightingComponent] * in_lightAmbientColor[dirNum];
1493  }
1494  )***";
1495  }
1496 
1497  shaderStr += blendingFormula +
1498  R"***(
1499  finalColor.xyz = (1.0 - vol_coef) * finalColor.xyz + vol_coef * secondary_contrib;
1500  )***";
1501  }
1502 
1503  // For 1D transfers only (2D transfer functions hold scalar and
1504  // gradient-magnitude opacities combined in the same table).
1505  // For multiple inputs, a different computeGradientOpacity() signature
1506  // is defined.
1507  if (transferMode == vtkVolumeProperty::TF_1D && glMapper->GetInputCount() == 1)
1508  {
1509  if (noOfComponents == 1 || !independentComponents)
1510  {
1511  if (volProperty->HasGradientOpacity())
1512  {
1513  shaderStr += std::string("\
1514  \n if (gradient.w >= 0.0 && label == 0.0)\
1515  \n {\
1516  \n color.a *= computeGradientOpacity(gradient);\
1517  \n }");
1518  }
1519  if (volProperty->HasLabelGradientOpacity())
1520  {
1521  shaderStr += std::string("\
1522  \n if (gradient.w >= 0.0 && label > 0.0)\
1523  \n {\
1524  \n color.a *= computeGradientOpacityForLabel(gradient, label);\
1525  \n }");
1526  }
1527  }
1528  else if (noOfComponents > 1 && independentComponents && volProperty->HasGradientOpacity())
1529  {
1530  shaderStr += std::string("\
1531  \n if (gradient.w >= 0.0)\
1532  \n {\
1533  \n for (int i = 0; i < in_noOfComponents; ++i)\
1534  \n {\
1535  \n color.a = color.a *\
1536  \n computeGradientOpacity(gradient, i) * in_componentWeight[i];\
1537  \n }\
1538  \n }");
1539  }
1540  }
1541 
1542  shaderStr += std::string("\
1543  \n finalColor.a = color.a;\
1544  \n //VTK::ComputeLighting::Exit\
1545  \n return finalColor;\
1546  \n }");
1547 
1548  return shaderStr;
1549 }
1550 
1551 //--------------------------------------------------------------------------
1553  vtkVolumeMapper* mapper, vtkVolume* vol, int noOfComponents, int independentComponents,
1554  int vtkNotUsed(totalNumberOfLights), bool defaultLighting)
1555 {
1556  auto glMapper = vtkOpenGLGPUVolumeRayCastMapper::SafeDownCast(mapper);
1557  vtkVolumeProperty* volProperty = vol->GetProperty();
1558  std::string shaderStr = std::string();
1559 
1560  // if no gradient TF is needed, don't add it into the function signature
1561  if (volProperty->HasGradientOpacity())
1562  {
1563  shaderStr += std::string("\
1564  \nvec4 computeLighting(vec3 texPos, vec4 color, const in sampler2D gradientTF, const in sampler3D volume, const in sampler2D opacityTF, const int volIdx, int component)\
1565  \n {\
1566  \n vec4 finalColor = vec4(0.0);\n");
1567  }
1568  else
1569  {
1570  shaderStr += std::string("\
1571  \nvec4 computeLighting(vec3 texPos, vec4 color, const in sampler3D volume, const in sampler2D opacityTF, const int volIdx, int component)\
1572  \n {\
1573  \n vec4 finalColor = vec4(0.0);\n");
1574  }
1575 
1576  if (independentComponents)
1577  {
1578  shaderStr += "\n int lightingComponent=component;\n";
1579  }
1580  else
1581  {
1582  shaderStr += "\n int lightingComponent=0;\n";
1583  }
1584 
1585  // Shading for composite blending only
1586  int const shadeReqd = volProperty->GetShade() &&
1589 
1590  int const transferMode = volProperty->GetTransferFunctionMode();
1591 
1592  // If shading is required, we compute a shading gradient (used for the shading model)
1593  if (shadeReqd)
1594  {
1595  /*
1596  We compute the gradient every time, because the alternative would be to test whether
1597  the volume has gradient cache or not. But as both branches will be evaluated anyway
1598  on GPU, we might as well compute the gradient every time.
1599  */
1600  if (glMapper->GetComputeNormalFromOpacity())
1601  {
1602  if (volProperty->HasGradientOpacity())
1603  {
1604  shaderStr += " vec4 shading_gradient = computeDensityGradient(texPos, component, volume, "
1605  "opacityTF, gradientTF, volIdx, 0.0);\n";
1606  }
1607  else
1608  {
1609  shaderStr += " vec4 shading_gradient = computeDensityGradient(texPos, component, volume, "
1610  "opacityTF, volIdx, 0.0);\n";
1611  }
1612  }
1613  else
1614  {
1615  shaderStr +=
1616  " vec4 shading_gradient = computeGradient(texPos, component, volume, volIdx);\n";
1617  }
1618  }
1619 
1620  // If we need the scalar gradient (typically to sample a transfer function)
1621  if (volProperty->HasGradientOpacity())
1622  {
1623  if (!shadeReqd || glMapper->GetComputeNormalFromOpacity())
1624  {
1625  shaderStr += " vec4 gradient = computeGradient(texPos, component, volume, volIdx);\n";
1626  }
1627  else
1628  {
1629  // if we already computed it
1630  shaderStr += " vec4 gradient = shading_gradient;\n";
1631  }
1632  }
1633 
1634  if (shadeReqd && defaultLighting)
1635  {
1636  shaderStr += std::string("\
1637  \n vec3 diffuse = vec3(0.0);\
1638  \n vec3 specular = vec3(0.0);\
1639  \n vec3 normal = shading_gradient.xyz;\
1640  \n float normalLength = length(normal);\
1641  \n if (normalLength > 0.0)\
1642  \n {\
1643  \n normal = normalize(normal);\
1644  \n }\
1645  \n else\
1646  \n {\
1647  \n normal = vec3(0.0, 0.0, 0.0);\
1648  \n }\
1649  \n // normal is oriented inside the volume (because normal = gradient, oriented inside the volume)\
1650  \n // thus we have to take minus everything\
1651  \n float nDotL = dot(normal, -g_ldir[volIdx]);\
1652  \n vec3 r = normalize(2.0 * nDotL * normal + g_ldir[volIdx]);\
1653  \n float vDotR = dot(r, -g_vdir[volIdx]);\
1654  \n if (nDotL < 0.0 && in_twoSidedLighting)\
1655  \n {\
1656  \n nDotL = -nDotL;\
1657  \n }\
1658  \n if (nDotL > 0.0)\
1659  \n {\
1660  \n diffuse = nDotL * in_diffuse[lightingComponent] *\
1661  \n in_lightDiffuseColor[0] * color.rgb;\
1662  \n vDotR = max(vDotR, 0.0);\
1663  \n specular = pow(vDotR, in_shininess[lightingComponent]) *\
1664  \n in_specular[lightingComponent] *\
1665  \n in_lightSpecularColor[0];\
1666  \n }\
1667  \n // For the headlight, ignore the light's ambient color\
1668  \n // for now as it is causing the old mapper tests to fail\
1669  \n finalColor.xyz = in_ambient[lightingComponent] * color.rgb +\
1670  \n diffuse + specular;\
1671  \n");
1672  }
1673  else
1674  {
1675  shaderStr += std::string("\n finalColor = vec4(color.rgb, 0.0);");
1676  }
1677 
1678  // For 1D transfers only (2D transfer functions hold scalar and
1679  // gradient-magnitude opacities combined in the same table).
1680  if (transferMode == vtkVolumeProperty::TF_1D)
1681  {
1682  if (volProperty->HasGradientOpacity() && (noOfComponents == 1 || !independentComponents))
1683  {
1684  shaderStr += std::string("\
1685  \n if (gradient.w >= 0.0)\
1686  \n {\
1687  \n color.a = color.a *\
1688  \n computeGradientOpacity(gradient, gradientTF);\
1689  \n }");
1690  }
1691  }
1692 
1693  shaderStr += std::string("\
1694  \n finalColor.a = color.a;\
1695  \n //VTK::ComputeLighting::Exit\
1696  \n return clamp(finalColor, 0.0, 1.0);\
1697  \n }");
1698 
1699  return shaderStr;
1700 }
1701 
1702 //--------------------------------------------------------------------------
1704  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int vtkNotUsed(noOfComponents))
1705 {
1706  if (!ren->GetActiveCamera()->GetParallelProjection())
1707  {
1708  return std::string("\
1709  \nvec3 computeRayDirection()\
1710  \n {\
1711  \n return normalize(ip_vertexPos.xyz - in_eyePosObjs[0].xyz);\
1712  \n }");
1713  }
1714  else
1715  {
1716  return std::string("\
1717  \nuniform vec3 in_projectionDirection;\
1718  \nvec3 computeRayDirection()\
1719  \n {\
1720  \n return normalize((in_inverseVolumeMatrix[0] *\
1721  \n vec4(in_projectionDirection, 0.0)).xyz);\
1722  \n }");
1723  }
1724 }
1725 
1726 //--------------------------------------------------------------------------
1728  int noOfComponents, vtkVolumeProperty* volProp)
1729 {
1730  std::string resStr;
1731  if (inputs.size() > 1)
1732  {
1733  // multi volume
1734  for (auto& item : inputs)
1735  {
1736  const auto& prop = item.second.Volume->GetProperty();
1737  if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_1D)
1738  continue;
1739 
1740  auto& map = item.second.RGBTablesMap;
1741  const auto numComp = map.size();
1742  resStr +=
1743  "uniform sampler2D " + ArrayBaseName(map[0]) + "[" + vtk::to_string(numComp) + "];\n";
1744  }
1745  }
1746  else
1747  {
1748  // single volume
1750  {
1751  resStr += "uniform sampler2D " + ArrayBaseName(inputs[0].RGBTablesMap[0]) + "[" +
1752  vtk::to_string(noOfComponents) + "];\n";
1753  }
1754  // in case of TF_2D, the texture needed is defined with computeOpacity
1755  }
1756  return resStr;
1757 }
1758 
1759 //--------------------------------------------------------------------------
1761  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
1762  int independentComponents, std::map<int, std::string> colorTableMap)
1763 {
1764  std::ostringstream ss;
1765 
1766  std::string shaderStr = ss.str();
1767  if (noOfComponents == 1)
1768  {
1769  shaderStr += std::string("\
1770  \nvec4 computeColor(vec4 scalar, float opacity)\
1771  \n {\
1772  \n return clamp(computeLighting(vec4(texture2D(" +
1773  colorTableMap[0] + ",\
1774  \n vec2(scalar.w, 0.0)).xyz, opacity), 0, 0.0), 0.0, 1.0);\
1775  \n }");
1776  return shaderStr;
1777  }
1778  else if (noOfComponents > 1 && independentComponents)
1779  {
1780  std::ostringstream toString;
1781 
1782  shaderStr += std::string("\
1783  \nvec4 computeColor(vec4 scalar, float opacity, int component)\
1784  \n {");
1785 
1786  for (int i = 0; i < noOfComponents; ++i)
1787  {
1788  toString << i;
1789  shaderStr += std::string("\
1790  \n if (component == " +
1791  toString.str() + ")");
1792 
1793  shaderStr += std::string("\
1794  \n {\
1795  \n return clamp(computeLighting(vec4(texture2D(\
1796  \n " +
1797  colorTableMap[i]);
1798  shaderStr += std::string(", vec2(\
1799  \n scalar[" +
1800  toString.str() + "],0.0)).xyz,\
1801  \n opacity)," +
1802  toString.str() + ", 0.0), 0.0, 1.0);\
1803  \n }");
1804 
1805  // Reset
1806  toString.str("");
1807  toString.clear();
1808  }
1809 
1810  shaderStr += std::string("\n }");
1811  return shaderStr;
1812  }
1813  else if (noOfComponents == 2 && !independentComponents)
1814  {
1815  shaderStr += std::string("\
1816  \nvec4 computeColor(vec4 scalar, float opacity)\
1817  \n {\
1818  \n return clamp(computeLighting(vec4(texture2D(" +
1819  colorTableMap[0] + ",\
1820  \n vec2(scalar.x, 0.0)).xyz,\
1821  \n opacity), 0, 0.0), 0.0, 1.0);\
1822  \n }");
1823  return shaderStr;
1824  }
1825  else if (noOfComponents == 4 && !independentComponents)
1826  {
1827  shaderStr += std::string("\
1828  \nvec4 computeColor(vec4 scalar, float opacity)\
1829  \n {\
1830  \n return clamp(computeLighting(vec4(scalar.xyz, opacity), 3, 0.0), 0.0, 1.0);\
1831  \n }");
1832  return shaderStr;
1833  }
1834  else
1835  {
1836  shaderStr += std::string("\
1837  \nvec4 computeColor(vec4 scalar, float opacity)\
1838  \n {\
1839  \n return clamp(computeLighting(vec4(scalar.xyz, opacity), 0, 0.0), 0.0, 1.0);\
1840  \n }");
1841  return shaderStr;
1842  }
1843 }
1844 
1845 //--------------------------------------------------------------------------
1847  vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, bool useGradientTF)
1848 {
1849  std::ostringstream ss;
1850  int lastComponentMode = vtkVolumeInputHelper::INVALID;
1851  std::map<int, std::string> lastColorTableMap;
1852  for (auto& item : inputs)
1853  {
1854  auto prop = item.second.Volume->GetProperty();
1855  if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_1D)
1856  continue;
1857  auto& map = item.second.RGBTablesMap;
1858  lastComponentMode = item.second.ComponentMode;
1859  lastColorTableMap = map;
1860  }
1861 
1862  if (lastComponentMode == vtkVolumeInputHelper::LA)
1863  {
1864  ss << "vec4 computeColor(vec4 scalar, const in sampler2D colorTF)\
1865  \n {\
1866  \n return clamp(computeLighting(vec4(texture2D(colorTF,\
1867  \n vec2(scalar.w, 0.0)).xyz, opacity), 0), 0.0, 1.0);\
1868  \n }\n";
1869  }
1870  else
1871  {
1872  std::ostringstream colorDec;
1873  colorDec << " vec3 color = ";
1874  if (lastComponentMode == vtkVolumeInputHelper::RGBA)
1875  {
1876  // Use RGB components without mapping through the color transfer function.
1877  colorDec << "scalar.xyz;\n";
1878  }
1879  else // vtkVolumeInputHelper::INDEPENDENT
1880  {
1881  // MultiVolume assumes input is 1-component, see ShadingMultipleInputs.
1882  // To support multiple independent components, each component should be mapped through the
1883  // transfer function as done in ComputeColorDeclaration for single volumes.
1884  colorDec << "texture2D(colorTF, vec2(scalar.w, 0.0)).xyz;\n";
1885  }
1886 
1887  if (useGradientTF)
1888  {
1889  ss
1890  << "vec4 computeColor(vec3 texPos, vec4 scalar, float opacity, const in sampler2D colorTF, "
1891  "const in sampler2D gradientTF, const in sampler3D volume, const in sampler2D "
1892  "opacityTF, const int volIdx)\n\n"
1893  "{\n";
1894  ss << colorDec.str()
1895  << " return clamp(computeLighting(texPos, vec4(color, opacity), gradientTF, volume, "
1896  "opacityTF,"
1897  "volIdx, 0), 0.0, 1.0);\n"
1898  "}\n";
1899  }
1900  else
1901  {
1902  ss
1903  << "vec4 computeColor(vec3 texPos, vec4 scalar, float opacity, const in sampler2D colorTF, "
1904  "const in sampler3D volume, const in sampler2D opacityTF, const int volIdx)\n\n"
1905  "{\n";
1906  ss << colorDec.str()
1907  << " return clamp(computeLighting(texPos, vec4(color, opacity), volume, opacityTF,"
1908  "volIdx, 0), 0.0, 1.0);\n"
1909  "}\n";
1910  }
1911  }
1912 
1913  return ss.str();
1914 }
1915 
1916 //--------------------------------------------------------------------------
1919 {
1920  std::ostringstream ss;
1921  for (auto& item : inputs)
1922  {
1923  auto prop = item.second.Volume->GetProperty();
1924  if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_1D)
1925  continue;
1926 
1927  auto& map = item.second.OpacityTablesMap;
1928  const auto numComp = map.size();
1929  ss << "uniform sampler2D " << ArrayBaseName(map[0]) << "[" << numComp << "];\n";
1930  }
1931 
1932  ss << "float computeOpacity(vec4 scalar, const in sampler2D opacityTF)\n"
1933  "{\n"
1934  " return texture2D(opacityTF, vec2(scalar.w, 0)).r;\n"
1935  "}\n";
1936  return ss.str();
1937 }
1938 
1939 //--------------------------------------------------------------------------
1942 {
1943  std::ostringstream ss;
1944 
1945  for (auto& item : inputs)
1946  {
1947  auto prop = item.second.Volume->GetProperty();
1948  if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_1D || !prop->HasGradientOpacity())
1949  continue;
1950 
1951  auto& map = item.second.GradientOpacityTablesMap;
1952  const auto numComp = map.size();
1953  ss << "uniform sampler2D " << ArrayBaseName(map[0]) << "[" << numComp << "];\n";
1954  }
1955 
1956  ss << "float computeGradientOpacity(vec4 grad, const in sampler2D gradientTF)\n"
1957  "{\n"
1958  " return texture2D(gradientTF, vec2(grad.w, 0.0)).r;\n"
1959  "}\n";
1960  return ss.str();
1961 }
1962 
1963 //--------------------------------------------------------------------------
1965  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
1966  int independentComponents, std::map<int, std::string> opacityTableMap)
1967 {
1968  std::ostringstream ss;
1969  ss << "uniform sampler2D " << ArrayBaseName(opacityTableMap[0]) << "[" << noOfComponents
1970  << "];\n";
1971 
1972  std::string shaderStr = ss.str();
1973  if (noOfComponents > 1 && independentComponents)
1974  {
1975  shaderStr += std::string("\
1976  \nfloat computeOpacity(vec4 scalar, int component)\
1977  \n{");
1978 
1979  for (int i = 0; i < noOfComponents; ++i)
1980  {
1981  std::ostringstream toString;
1982  toString << i;
1983  shaderStr += std::string("\
1984  \n if (component == " +
1985  toString.str() + ")");
1986 
1987  shaderStr += std::string("\
1988  \n {\
1989  \n return texture2D(" +
1990  opacityTableMap[i]);
1991 
1992  shaderStr += std::string(",vec2(scalar[" + toString.str() + "], 0)).r;\
1993  \n }");
1994  }
1995 
1996  shaderStr += std::string("\n}");
1997  return shaderStr;
1998  }
1999  else if (noOfComponents == 2 && !independentComponents)
2000  {
2001  shaderStr += std::string("\
2002  \nfloat computeOpacity(vec4 scalar)\
2003  \n{\
2004  \n return texture2D(" +
2005  opacityTableMap[0] + ", vec2(scalar.y, 0)).r;\
2006  \n}");
2007  return shaderStr;
2008  }
2009  else
2010  {
2011  shaderStr += std::string("\
2012  \nfloat computeOpacity(vec4 scalar)\
2013  \n{\
2014  \n return texture2D(" +
2015  opacityTableMap[0] + ", vec2(scalar.w, 0)).r;\
2016  \n}");
2017  return shaderStr;
2018  }
2019 }
2020 
2021 //--------------------------------------------------------------------------
2023  int vtkNotUsed(independentComponents), std::map<int, std::string> colorTableMap)
2024 {
2025  if (noOfComponents == 1)
2026  {
2027  // Single component
2028  return std::string(
2029  "vec4 computeColor(vec4 scalar, float opacity)\n"
2030  "{\n"
2031  " vec4 yscalar = texture3D(in_transfer2DYAxis, g_dataPos);\n"
2032  " yscalar.r = yscalar.r * in_transfer2DYAxis_scale.r + in_transfer2DYAxis_bias.r;\n"
2033  " yscalar = vec4(yscalar.r);\n"
2034  " vec4 color = texture2D(" +
2035  colorTableMap[0] +
2036  ",\n"
2037  " vec2(scalar.w, yscalar.w));\n"
2038  " return computeLighting(color, 0, 0);\n"
2039  "}\n");
2040  }
2041  return std::string("vec4 computeColor(vec4 scalar, float opacity)\n"
2042  "{\n"
2043  " return vec4(0, 0, 0, 0)\n"
2044  "}\n");
2045 }
2046 
2047 //--------------------------------------------------------------------------
2049  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
2050  int independentComponents, std::map<int, std::string> colorTableMap, int useGradient)
2051 {
2052  if (!useGradient)
2053  {
2054  return ComputeColor2DYAxisDeclaration(noOfComponents, independentComponents, colorTableMap);
2055  }
2056  if (noOfComponents == 1)
2057  {
2058  // Single component
2059  return std::string("vec4 computeColor(vec4 scalar, float opacity)\n"
2060  "{\n"
2061  " vec4 color = texture2D(" +
2062  colorTableMap[0] +
2063  ",\n"
2064  " vec2(scalar.w, g_gradients_0[0].w));\n"
2065  " return computeLighting(color, 0, 0);\n"
2066  "}\n");
2067  }
2068  else if (noOfComponents > 1 && independentComponents)
2069  {
2070  // Multiple independent components
2071  std::string shaderStr;
2072  shaderStr += std::string("vec4 computeColor(vec4 scalar, float opacity, int component)\n"
2073  "{\n");
2074 
2075  for (int i = 0; i < noOfComponents; ++i)
2076  {
2077  std::ostringstream toString;
2078  toString << i;
2079  std::string const num = toString.str();
2080  shaderStr += std::string(" if (component == " + num +
2081  ")\n"
2082  " {\n"
2083  " vec4 color = texture2D(" +
2084  colorTableMap[i] +
2085  ",\n"
2086  " vec2(scalar[" +
2087  num + "], g_gradients_0[" + num +
2088  "].w));\n"
2089  " return computeLighting(color, " +
2090  num +
2091  ", 0.0);\n"
2092  " }\n");
2093  }
2094  shaderStr += std::string("}\n");
2095 
2096  return shaderStr;
2097  }
2098  else if (noOfComponents == 2 && !independentComponents)
2099  {
2100  // Dependent components (Luminance/ Opacity)
2101  return std::string("vec4 computeColor(vec4 scalar, float opacity)\n"
2102  "{\n"
2103  " vec4 color = texture2D(" +
2104  colorTableMap[0] +
2105  ",\n"
2106  " vec2(scalar.x, g_gradients_0[0].w));\n"
2107  " return computeLighting(color, 0, 0.0);\n"
2108  "}\n");
2109  }
2110  else
2111  {
2112  return std::string("vec4 computeColor(vec4 scalar, float opacity)\n"
2113  "{\n"
2114  " return computeLighting(vec4(scalar.xyz, opacity), 0, 0.0);\n"
2115  "}\n");
2116  }
2117 }
2118 
2119 //--------------------------------------------------------------------------
2121 {
2122  std::ostringstream ss;
2123  for (auto& item : inputs)
2124  {
2125  auto prop = item.second.Volume->GetProperty();
2126  if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_2D)
2127  continue;
2128 
2129  auto& map = item.second.TransferFunctions2DMap;
2130  const auto numComp = map.size();
2131  ss << "uniform sampler2D " << ArrayBaseName(map[0]) << "[" << numComp << "];\n";
2132  }
2133 
2134  std::string result = ss.str() +
2135  std::string("uniform sampler3D in_transfer2DYAxis;\n"
2136  "uniform vec4 in_transfer2DYAxis_scale;\n"
2137  "uniform vec4 in_transfer2DYAxis_bias;\n");
2138 
2139  return result;
2140 }
2141 
2142 //--------------------------------------------------------------------------
2144  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
2145  int independentComponents, std::map<int, std::string> opacityTableMap, int useGradient)
2146 {
2147  std::ostringstream toString;
2148  if (noOfComponents > 1 && independentComponents)
2149  {
2150  // Multiple independent components
2151  toString << "float computeOpacity(vec4 scalar, int component)\n"
2152  "{\n";
2153  if (!useGradient)
2154  {
2155  toString
2156  << "vec4 yscalar = texture3D(in_transfer2DYAxis, g_dataPos);\n"
2157  "for (int i = 0; i < 4; ++i)\n"
2158  "{\n"
2159  " yscalar[i] = yscalar[i] * in_transfer2DYAxis_scale[i] + in_transfer2DYAxis_bias[i];\n"
2160  "}\n";
2161  if (noOfComponents == 1)
2162  {
2163  toString << "yscalar = vec4(yscalar.r);\n";
2164  }
2165  }
2166 
2167  for (int i = 0; i < noOfComponents; ++i)
2168  {
2169  if (useGradient)
2170  {
2171  toString << " if (component == " << i
2172  << ")\n"
2173  " {\n"
2174  " return texture2D("
2175  << opacityTableMap[i]
2176  << ",\n"
2177  " vec2(scalar["
2178  << i << "], g_gradients_0[" << i
2179  << "].w)).a;\n"
2180  " }\n";
2181  }
2182  else
2183  {
2184  toString << " if (component == " << i
2185  << ")\n"
2186  " {\n"
2187  " return texture2D("
2188  << opacityTableMap[i]
2189  << ",\n"
2190  " vec2(scalar["
2191  << i << "], yscalar[" << i
2192  << "])).a;\n"
2193  " }\n";
2194  }
2195  }
2196 
2197  toString << "}\n";
2198  }
2199 
2200  else if (noOfComponents == 2 && !independentComponents)
2201  {
2202  if (useGradient)
2203  {
2204  // Dependent components (Luminance/ Opacity)
2205  toString << "float computeOpacity(vec4 scalar)\n"
2206  "{\n"
2207  " return texture2D(" +
2208  opacityTableMap[0] +
2209  ",\n"
2210  " vec2(scalar.y, g_gradients_0[0].w)).a;\n"
2211  "}\n";
2212  }
2213  else
2214  {
2215  // Dependent components (Luminance/ Opacity)
2216  toString << "float computeOpacity(vec4 scalar)\n"
2217  "{\n"
2218  " return texture2D(" +
2219  opacityTableMap[0] +
2220  ",\n"
2221  " vec2(scalar.y, yscalar.y)).a;\n"
2222  "}\n";
2223  }
2224  }
2225 
2226  else
2227  {
2228  if (useGradient)
2229  {
2230  // Dependent components (RGBA) || Single component
2231  toString << "float computeOpacity(vec4 scalar)\n"
2232  "{\n"
2233  " return texture2D(" +
2234  opacityTableMap[0] +
2235  ",\n"
2236  " vec2(scalar.a, g_gradients_0[0].w)).a;\n"
2237  "}\n";
2238  }
2239  else
2240  {
2241  // Dependent components (RGBA) || Single component
2242  toString
2243  << "float computeOpacity(vec4 scalar)\n"
2244  "{\n"
2245  " vec4 yscalar = texture3D(in_transfer2DYAxis, g_dataPos);\n"
2246  " yscalar.r = yscalar.r * in_transfer2DYAxis_scale.r + in_transfer2DYAxis_bias.r;\n"
2247  " yscalar = vec4(yscalar.r);\n"
2248  " return texture2D(" +
2249  opacityTableMap[0] +
2250  ",\n"
2251  " vec2(scalar.a, yscalar.w)).a;\n"
2252  "}\n";
2253  }
2254  }
2255  return toString.str();
2256 }
2257 
2258 //--------------------------------------------------------------------------
2260  vtkVolume* vtkNotUsed(vol), int noOfComponents, int independentComponents,
2261  vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, int useGradYAxis)
2262 {
2263  std::string resStr;
2264  std::string declarations;
2265  std::string functionSignature;
2266  std::string opacityEval;
2267  std::string rayInit;
2268 
2269  const size_t numInputs = inputs.size();
2270  const bool hasGradOp = ::HasGradientOpacity(inputs);
2271 
2272  // for now, shadow is mono-chromatic (we only sample opacity)
2273  // it could be RGB
2274 
2275  functionSignature = "float volumeShadow(vec3 sample_position, vec3 light_pos_dir, float is_Pos, "
2276  " in int c, in sampler3D volume, " +
2277  (numInputs > 1 ? std::string("in sampler2D opacityTF, ") : std::string()) +
2278  (numInputs > 1 && hasGradOp ? std::string("in sampler2D gradTF, ") : std::string()) +
2279  "int index, float label)\n";
2280 
2281  declarations +=
2282  R"***(
2283  float shadow = 1.0;
2284  vec3 direction = vec3(0.0);
2285  vec3 norm_dir = vec3(0.0);
2286  float maxdist = 0.0;
2287  float scalar;
2288  vec4 gradient;
2289  float opacity = 0.0;
2290  vec3 color;
2291  Ray ray;
2292  Hit hit;
2293  float sampled_dist = 0.0;
2294  vec3 sampled_point = vec3(0.0);
2295  )***";
2296 
2297  rayInit +=
2298  R"***(
2299  // direction is light_pos_dir when light is directional
2300  // and light_pos_dir - sample_position when positional
2301  direction = light_pos_dir - is_Pos * sample_position;
2302  norm_dir = normalize(direction);
2303  // introduce little offset to avoid sampling shadows at the exact
2304  // sample position
2305  sample_position += g_lengthStep * norm_dir;
2306  direction = light_pos_dir - is_Pos * sample_position;
2307  ray.origin = sample_position;
2308  ray.dir = norm_dir;
2309  safe_0_vector(ray);
2310  ray.invDir = 1.0/ray.dir;
2311  if(!BBoxIntersect(vec3(0.0), vec3(1.0), ray, hit))
2312  {
2313  // it can happen around the bounding box
2314  return 1.0;
2315  }
2316  if(hit.tmax < g_lengthStep)
2317  {
2318  // if we're too close to the bounding box
2319  return 1.0;
2320  }
2321  // in case of directional light, we want direction not to be normalized but to go
2322  // all the way to the bbox
2323  direction *= pow(hit.tmax / length(direction), 1.0 - is_Pos);
2324  maxdist = min(hit.tmax, length(direction));
2325  maxdist = min(in_giReach, maxdist);
2326  if(maxdist < EPSILON) return 1.0;
2327 
2328  )***";
2329 
2330  // slight imprecision for the last sample : it can be something else (less) than g_lengthStep
2331  // because the last step is clamped to the end of the ray
2332  opacityEval += " scalar = texture3D(volume, sampled_point)[c];\n"
2333  " scalar = scalar * in_volume_scale[index][c] + in_volume_bias[index][c];\n";
2334  opacityEval += ComputeOpacityEvaluationCall(
2335  mapper, inputs, noOfComponents, independentComponents, useGradYAxis, "sampled_point", true);
2336 
2337  resStr += functionSignature + "{\n" + declarations + rayInit +
2338  R"***(
2339  float current_dist = 0.0;
2340  float current_step = g_lengthStep;
2341  float clamped_step = 0.0;
2342  while(current_dist < maxdist)
2343  {
2344  clamped_step = min(maxdist - current_dist, current_step);
2345  sampled_dist = current_dist + clamped_step * g_jitterValue;
2346  sampled_point = sample_position + sampled_dist * norm_dir;
2347  )***" +
2348  opacityEval +
2349  R"***(
2350  shadow *= 1.0 - opacity;
2351  current_dist += current_step;
2352  }
2353  return shadow;
2354 }
2355  )***";
2356 
2357  return resStr;
2358 }
2359 
2360 //--------------------------------------------------------------------------
2362  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2363 {
2364  return std::string();
2365 }
2366 
2367 //--------------------------------------------------------------------------
2369  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
2370 {
2372  {
2373  return std::string("\
2374  \n bool l_firstValue;\
2375  \n vec4 l_maxValue;");
2376  }
2378  {
2379  return std::string("\
2380  \n bool l_firstValue;\
2381  \n vec4 l_minValue;");
2382  }
2384  {
2385  return std::string("\
2386  \n uvec4 l_numSamples;\
2387  \n vec4 l_avgValue;");
2388  }
2389  else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
2390  {
2391  return std::string("\
2392  \n vec4 l_sumValue;");
2393  }
2394  else if (mapper->GetBlendMode() == vtkVolumeMapper::ISOSURFACE_BLEND)
2395  {
2396  return std::string("\
2397  \n int l_initialIndex = 0;\
2398  \n float l_normValues[NUMBER_OF_CONTOURS + 2];");
2399  }
2400  else
2401  {
2402  return std::string();
2403  }
2404 }
2405 
2406 //--------------------------------------------------------------------------
2408  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
2409 {
2411  {
2412  return std::string("\
2413  \n // We get data between 0.0 - 1.0 range\
2414  \n l_firstValue = true;\
2415  \n l_maxValue = vec4(0.0);");
2416  }
2418  {
2419  return std::string("\
2420  \n //We get data between 0.0 - 1.0 range\
2421  \n l_firstValue = true;\
2422  \n l_minValue = vec4(1.0);");
2423  }
2425  {
2426  return std::string("\
2427  \n //We get data between 0.0 - 1.0 range\
2428  \n l_avgValue = vec4(0.0);\
2429  \n // Keep track of number of samples\
2430  \n l_numSamples = uvec4(0);");
2431  }
2432  else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
2433  {
2434  return std::string("\
2435  \n //We get data between 0.0 - 1.0 range\
2436  \n l_sumValue = vec4(0.0);");
2437  }
2438  else if (mapper->GetBlendMode() == vtkVolumeMapper::ISOSURFACE_BLEND)
2439  {
2440  return std::string("\
2441  \n#if NUMBER_OF_CONTOURS\
2442  \n l_normValues[0] = -1e20; //-infinity\
2443  \n l_normValues[NUMBER_OF_CONTOURS+1] = +1e20; //+infinity\
2444  \n for (int i = 0; i < NUMBER_OF_CONTOURS; i++)\
2445  \n {\
2446  \n l_normValues[i+1] = (in_isosurfacesValues[i] - in_scalarsRange[0].x) / \
2447  \n (in_scalarsRange[0].y - in_scalarsRange[0].x);\
2448  \n }\
2449  \n#endif\
2450  ");
2451  }
2452  else
2453  {
2454  return std::string();
2455  }
2456 }
2457 
2458 //--------------------------------------------------------------------------
2459 inline std::string GradientCacheDec(vtkRenderer* vtkNotUsed(ren), vtkVolume* vtkNotUsed(vol),
2460  vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, int independentComponents = 0)
2461 {
2462  const int numInputs = static_cast<int>(inputs.size());
2463  const int comp = numInputs == 1 ?
2464  // Dependent components use a single opacity lut.
2465  // NOLINTNEXTLINE(readability-avoid-nested-conditional-operator)
2466  (!independentComponents ? 1 : numInputs)
2467  :
2468  // Independent components not supported with multiple-inputs
2469  1;
2470 
2471  std::ostringstream toShader;
2472  for (const auto& item : inputs)
2473  {
2474  auto& input = item.second;
2475  if (input.Volume->GetProperty()->HasGradientOpacity())
2476  {
2477  toShader << "vec4 " << input.GradientCacheName << "[" << comp << "];\n";
2478  }
2479  }
2480 
2481  return toShader.str();
2482 }
2483 
2484 //--------------------------------------------------------------------------
2485 inline std::string PreComputeGradientsImpl(vtkRenderer* vtkNotUsed(ren), vtkVolume* vtkNotUsed(vol),
2486  int noOfComponents = 1, int independentComponents = 0)
2487 {
2488  std::ostringstream shader;
2489  if (independentComponents)
2490  {
2491  if (noOfComponents == 1)
2492  {
2493  shader << "g_gradients_0[0] = computeGradient(g_dataPos, 0, in_volume[0], 0);\n";
2494  }
2495  else
2496  {
2497  // Multiple components
2498  shader << "for (int comp = 0; comp < in_noOfComponents; comp++)\n"
2499  "{\n"
2500  " g_gradients_0[comp] = computeGradient(g_dataPos, comp, in_volume[0], 0);\n"
2501  "}\n";
2502  }
2503  }
2504  else
2505  {
2506  shader << "g_gradients_0[0] = computeGradient(g_dataPos, 0, in_volume[0], 0);\n";
2507  }
2508 
2509  return shader.str();
2510 }
2511 
2512 //--------------------------------------------------------------------------
2515 {
2516  std::ostringstream toShaderStr;
2517  toShaderStr << " if (!g_skip)\n"
2518  " {\n"
2519  " vec3 texPos;\n";
2520 
2521  switch (mapper->GetBlendMode())
2522  {
2524  default:
2525  {
2526  int i = 0;
2527  for (auto& item : inputs)
2528  {
2529  auto& input = item.second;
2530  auto property = input.Volume->GetProperty();
2531  // Transformation index. Index 0 refers to the global bounding-box.
2532  const auto idx = i + 1;
2533  toShaderStr <<
2534  // From global texture coordinates (bbox) to volume_i texture coords.
2535  // texPos = T * g_dataPos
2536  // T = T_dataToTex1 * T_worldToData * T_bboxTexToWorld;
2537  " texPos = (in_cellToPoint[" << idx << "] * in_inverseTextureDatasetMatrix[" << idx
2538  << "] * in_inverseVolumeMatrix[" << idx
2539  << "] *\n"
2540  " in_volumeMatrix[0] * in_textureDatasetMatrix[0] * "
2541  "vec4(g_dataPos.xyz, 1.0)).xyz;\n"
2542  " if ((all(lessThanEqual(texPos, vec3(1.0))) &&\n"
2543  " all(greaterThanEqual(texPos, vec3(0.0)))))\n"
2544  " {\n"
2545  " vec4 scalar = texture3D(in_volume["
2546  << i
2547  << "], texPos);\n"
2548  " scalar = scalar * in_volume_scale["
2549  << i << "] + in_volume_bias[" << i << "];\n";
2550 
2551  // MultiVolume considers input has one component when independent component is on.
2552  if (property->GetIndependentComponents())
2553  {
2554  toShaderStr << " scalar = vec4(scalar.r);\n";
2555  }
2556 
2557  toShaderStr << " g_srcColor = vec4(0.0);\n";
2558 
2559  if (property->GetTransferFunctionMode() == vtkVolumeProperty::TF_1D)
2560  {
2561  std::string gradientopacity_param = (property->HasGradientOpacity())
2562  ? input.GradientOpacityTablesMap[0] + std::string(", ")
2563  : std::string();
2564 
2565  toShaderStr << " g_srcColor.a = computeOpacity(scalar,"
2566  << input.OpacityTablesMap[0]
2567  << ");\n"
2568  " if (g_srcColor.a > 0.0)\n"
2569  " {\n"
2570  " g_srcColor = computeColor(texPos, scalar, g_srcColor.a, "
2571  << input.RGBTablesMap[0] << ", " << gradientopacity_param << "in_volume[" << i
2572  << "], " << input.OpacityTablesMap[0] << ", " << i << ");\n";
2573 
2574  if (property->HasGradientOpacity())
2575  {
2576  const auto& grad = input.GradientCacheName;
2577  toShaderStr << " " << grad << "[0] = computeGradient(texPos, 0, "
2578  << "in_volume[" << i << "], " << i
2579  << ");\n"
2580  " if ("
2581  << grad
2582  << "[0].w >= 0.0)\n"
2583  " {\n"
2584  " g_srcColor.a *= computeGradientOpacity("
2585  << grad << "[0], " << input.GradientOpacityTablesMap[0]
2586  << ");\n"
2587  " }\n";
2588  }
2589  }
2590  else if (property->GetTransferFunctionMode() == vtkVolumeProperty::TF_2D)
2591  {
2592  const auto& grad = input.GradientCacheName;
2593  toShaderStr <<
2594  // Sample 2DTF directly
2595  " " << grad << "[0] = computeGradient(texPos, 0, "
2596  << "in_volume[" << i << "], " << i
2597  << ");\n"
2598  " g_srcColor = texture2D("
2599  << input.TransferFunctions2DMap[0] << ", vec2(scalar.r, "
2600  << input.GradientCacheName
2601  << "[0].w));\n"
2602  " if (g_srcColor.a > 0.0)\n"
2603  " {\n";
2604  }
2605 
2606  toShaderStr
2607  << " g_srcColor.rgb *= g_srcColor.a;\n"
2608  " g_fragColor = (1.0f - g_fragColor.a) * g_srcColor + g_fragColor;\n"
2609  " }\n"
2610  " }\n\n";
2611 
2612  i++;
2613  }
2614  }
2615  break;
2616  }
2617  toShaderStr << " }\n";
2618 
2619  return toShaderStr.str();
2620 }
2621 
2622 //--------------------------------------------------------------------------
2624  vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput, vtkVolumeTexture* mask, int maskType,
2625  int noOfComponents, int independentComponents = 0)
2626 {
2627  auto glMapper = vtkOpenGLGPUVolumeRayCastMapper::SafeDownCast(mapper);
2628 
2629  std::string shaderStr;
2630 
2631  shaderStr += std::string("\
2632  \n if (!g_skip)\
2633  \n {\
2634  \n vec4 scalar;\
2635  \n");
2637  {
2638  shaderStr += std::string("\
2639  \n // Compute IJK vertex position for current sample in the rectilinear grid\
2640  \n vec4 dataPosWorld = in_volumeMatrix[0] * in_textureDatasetMatrix[0] * vec4(g_dataPos, 1.0);\
2641  \n dataPosWorld = dataPosWorld / dataPosWorld.w;\
2642  \n dataPosWorld.w = 1.0;\
2643  \n ivec3 ijk = ivec3(0);\
2644  \n vec3 ijkTexCoord = vec3(0.0);\
2645  \n vec3 pCoords = vec3(0.0);\
2646  \n vec3 xPrev, xNext, tmp;\
2647  \n int sz = textureSize(in_coordTexs, 0);\
2648  \n vec4 dataPosWorldScaled = dataPosWorld * vec4(in_coordsScale, 1.0) +\
2649  \n vec4(in_coordsBias, 1.0);\
2650  \n for (int j = 0; j < 3; ++j)\
2651  \n {\
2652  \n xPrev = texture1D(in_coordTexs, 0.0).xyz;\
2653  \n xNext = texture1D(in_coordTexs, (in_coordTexSizes[j] - 1) / sz).xyz;\
2654  \n if (xNext[j] < xPrev[j])\
2655  \n {\
2656  \n tmp = xNext;\
2657  \n xNext = xPrev;\
2658  \n xPrev = tmp;\
2659  \n }\
2660  \n for (int i = 0; i < int(in_coordTexSizes[j]); i++)\
2661  \n {\
2662  \n xNext = texture1D(in_coordTexs, (i + 0.5) / sz).xyz;\
2663  \n if (dataPosWorldScaled[j] >= xPrev[j] && dataPosWorldScaled[j] < xNext[j])\
2664  \n {\
2665  \n ijk[j] = i - 1;\
2666  \n pCoords[j] = (dataPosWorldScaled[j] - xPrev[j]) / (xNext[j] - xPrev[j]);\
2667  \n break;\
2668  \n }\
2669  \n else if (dataPosWorldScaled[j] == xNext[j])\
2670  \n {\
2671  \n ijk[j] = i - 1;\
2672  \n pCoords[j] = 1.0;\
2673  \n break;\
2674  \n }\
2675  \n xPrev = xNext;\
2676  \n }\
2677  \n ijkTexCoord[j] = (ijk[j] + pCoords[j]) / in_coordTexSizes[j];\
2678  \n }\
2679  \n scalar = texture3D(in_volume[0], sign(in_cellSpacing[0]) * ijkTexCoord);\
2680  \n");
2681  }
2682  else
2683  {
2684  shaderStr += std::string("\
2685  \n scalar = texture3D(in_volume[0], g_dataPos);\
2686  \n");
2687  }
2688 
2689  // simulate old intensity textures
2690  if (noOfComponents == 1)
2691  {
2692  shaderStr += std::string("\
2693  \n scalar.r = scalar.r * in_volume_scale[0].r + in_volume_bias[0].r;\
2694  \n scalar = vec4(scalar.r);");
2695  }
2696  else
2697  {
2698  // handle bias and scale
2699  shaderStr += std::string("\
2700  \n scalar = scalar * in_volume_scale[0] + in_volume_bias[0];");
2701  }
2702 
2704  {
2705  if (noOfComponents > 1)
2706  {
2707  if (!independentComponents)
2708  {
2709  shaderStr += std::string("\
2710  \n if (l_maxValue.w < scalar.w || l_firstValue)\
2711  \n {\
2712  \n l_maxValue = scalar;\
2713  \n }\
2714  \n\
2715  \n if (l_firstValue)\
2716  \n {\
2717  \n l_firstValue = false;\
2718  \n }");
2719  }
2720  else
2721  {
2722  shaderStr += std::string("\
2723  \n for (int i = 0; i < in_noOfComponents; ++i)\
2724  \n {\
2725  \n if (l_maxValue[i] < scalar[i] || l_firstValue)\
2726  \n {\
2727  \n l_maxValue[i] = scalar[i];\
2728  \n }\
2729  \n }\
2730  \n if (l_firstValue)\
2731  \n {\
2732  \n l_firstValue = false;\
2733  \n }");
2734  }
2735  }
2736  else
2737  {
2738  shaderStr += std::string("\
2739  \n if (l_maxValue.w < scalar.x || l_firstValue)\
2740  \n {\
2741  \n l_maxValue.w = scalar.x;\
2742  \n }\
2743  \n\
2744  \n if (l_firstValue)\
2745  \n {\
2746  \n l_firstValue = false;\
2747  \n }");
2748  }
2749  }
2751  {
2752  if (noOfComponents > 1)
2753  {
2754  if (!independentComponents)
2755  {
2756  shaderStr += std::string("\
2757  \n if (l_minValue.w > scalar.w || l_firstValue)\
2758  \n {\
2759  \n l_minValue = scalar;\
2760  \n }\
2761  \n\
2762  \n if (l_firstValue)\
2763  \n {\
2764  \n l_firstValue = false;\
2765  \n }");
2766  }
2767  else
2768  {
2769  shaderStr += std::string("\
2770  \n for (int i = 0; i < in_noOfComponents; ++i)\
2771  \n {\
2772  \n if (l_minValue[i] < scalar[i] || l_firstValue)\
2773  \n {\
2774  \n l_minValue[i] = scalar[i];\
2775  \n }\
2776  \n }\
2777  \n if (l_firstValue)\
2778  \n {\
2779  \n l_firstValue = false;\
2780  \n }");
2781  }
2782  }
2783  else
2784  {
2785  shaderStr += std::string("\
2786  \n if (l_minValue.w > scalar.x || l_firstValue)\
2787  \n {\
2788  \n l_minValue.w = scalar.x;\
2789  \n }\
2790  \n\
2791  \n if (l_firstValue)\
2792  \n {\
2793  \n l_firstValue = false;\
2794  \n }");
2795  }
2796  }
2798  {
2799  if (noOfComponents > 1 && independentComponents)
2800  {
2801  shaderStr += std::string("\
2802  \n for (int i = 0; i < in_noOfComponents; ++i)\
2803  \n {\
2804  \n // Get the intensity in volume scalar range\
2805  \n float intensity = in_scalarsRange[i][0] +\
2806  \n (in_scalarsRange[i][1] -\
2807  \n in_scalarsRange[i][0]) * scalar[i];\
2808  \n if (in_averageIPRange.x <= intensity &&\
2809  \n intensity <= in_averageIPRange.y)\
2810  \n {\
2811  \n l_avgValue[i] += computeOpacity(scalar, i) * scalar[i];\
2812  \n ++l_numSamples[i];\
2813  \n }\
2814  \n }");
2815  }
2816  else
2817  {
2818  shaderStr += std::string("\
2819  \n // Get the intensity in volume scalar range\
2820  \n float intensity = in_scalarsRange[0][0] +\
2821  \n (in_scalarsRange[0][1] -\
2822  \n in_scalarsRange[0][0]) * scalar.x;\
2823  \n if (in_averageIPRange.x <= intensity &&\
2824  \n intensity <= in_averageIPRange.y)\
2825  \n {\
2826  \n l_avgValue.x += computeOpacity(scalar) * scalar.x;\
2827  \n ++l_numSamples.x;\
2828  \n }");
2829  }
2830  }
2831  else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
2832  {
2833  if (noOfComponents > 1 && independentComponents)
2834  {
2835  shaderStr += std::string("\
2836  \n for (int i = 0; i < in_noOfComponents; ++i)\
2837  \n {\
2838  \n float opacity = computeOpacity(scalar, i);\
2839  \n l_sumValue[i] = l_sumValue[i] + opacity * scalar[i];\
2840  \n }");
2841  }
2842  else
2843  {
2844  shaderStr += std::string("\
2845  \n float opacity = computeOpacity(scalar);\
2846  \n l_sumValue.x = l_sumValue.x + opacity * scalar.x;");
2847  }
2848  }
2849  else if (mapper->GetBlendMode() == vtkVolumeMapper::ISOSURFACE_BLEND)
2850  {
2851  shaderStr += std::string("\
2852  \n#if NUMBER_OF_CONTOURS\
2853  \n int maxComp = 0;");
2854 
2855  std::string compParamStr;
2856  if (noOfComponents > 1 && independentComponents)
2857  {
2858  shaderStr += std::string("\
2859  \n for (int i = 1; i < in_noOfComponents; ++i)\
2860  \n {\
2861  \n if (in_componentWeight[i] > in_componentWeight[maxComp])\
2862  \n maxComp = i;\
2863  \n }");
2864  compParamStr = ", maxComp";
2865  }
2866  shaderStr += std::string("\
2867  \n if (g_currentT == 0)\
2868  \n {\
2869  \n l_initialIndex = findIsoSurfaceIndex(scalar[maxComp], l_normValues);\
2870  \n }\
2871  \n else\
2872  \n {\
2873  \n float s;\
2874  \n bool shade = false;\
2875  \n l_initialIndex = clamp(l_initialIndex, 0, NUMBER_OF_CONTOURS);\
2876  \n if (scalar[maxComp] < l_normValues[l_initialIndex])\
2877  \n {\
2878  \n s = l_normValues[l_initialIndex];\
2879  \n l_initialIndex--;\
2880  \n shade = true;\
2881  \n }\
2882  \n if (scalar[maxComp] > l_normValues[l_initialIndex+1])\
2883  \n {\
2884  \n s = l_normValues[l_initialIndex+1];\
2885  \n l_initialIndex++;\
2886  \n shade = true;\
2887  \n }\
2888  \n if (shade == true)\
2889  \n {\
2890  \n vec4 vs = vec4(s);\
2891  \n g_srcColor.a = computeOpacity(vs " +
2892  compParamStr + ");\
2893  \n g_srcColor = computeColor(vs, g_srcColor.a " +
2894  compParamStr + ");\
2895  \n g_srcColor.rgb *= g_srcColor.a;\
2896  \n g_fragColor = (1.0f - g_fragColor.a) * g_srcColor + g_fragColor;\
2897  \n }\
2898  \n }\
2899  \n#endif");
2900  }
2901  else if (mapper->GetBlendMode() == vtkVolumeMapper::SLICE_BLEND)
2902  {
2903  shaderStr += std::string("\
2904  \n // test if the intersection is inside the volume bounds\
2905  \n if (any(greaterThan(g_dataPos, vec3(1.0))) || any(lessThan(g_dataPos, vec3(0.0))))\
2906  \n {\
2907  \n discard;\
2908  \n }\
2909  \n float opacity = computeOpacity(scalar);\
2910  \n g_fragColor = computeColor(scalar, opacity);\
2911  \n g_fragColor.rgb *= opacity;\
2912  \n g_exit = true;");
2913  }
2914  else if (mapper->GetBlendMode() == vtkVolumeMapper::COMPOSITE_BLEND)
2915  {
2916  if (noOfComponents > 1 && independentComponents)
2917  {
2918  shaderStr += std::string("\
2919  \n vec4 color[4]; vec4 tmp = vec4(0.0);\
2920  \n float totalAlpha = 0.0;\
2921  \n for (int i = 0; i < in_noOfComponents; ++i)\
2922  \n {\
2923  ");
2924  if (glMapper->GetUseDepthPass() &&
2925  glMapper->GetCurrentPass() == vtkOpenGLGPUVolumeRayCastMapper::DepthPass)
2926  {
2927  shaderStr += std::string("\
2928  \n // Data fetching from the red channel of volume texture\
2929  \n float opacity = computeOpacity(scalar, i);\
2930  \n if (opacity > 0.0)\
2931  \n {\
2932  \n g_srcColor.a = opacity;\
2933  \n }\
2934  \n }");
2935  }
2936  else if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2937  {
2938  shaderStr += std::string("\
2939  \n // Data fetching from the red channel of volume texture\
2940  \n color[i][3] = computeOpacity(scalar, i);\
2941  \n color[i] = computeColor(scalar, color[i][3], i);\
2942  \n totalAlpha += color[i][3] * in_componentWeight[i];\
2943  \n }\
2944  \n if (totalAlpha > 0.0)\
2945  \n {\
2946  \n for (int i = 0; i < in_noOfComponents; ++i)\
2947  \n {\
2948  \n // Only let visible components contribute to the final color\
2949  \n if (in_componentWeight[i] <= 0) continue;\
2950  \n\
2951  \n tmp.x += color[i].x * color[i].w * in_componentWeight[i];\
2952  \n tmp.y += color[i].y * color[i].w * in_componentWeight[i];\
2953  \n tmp.z += color[i].z * color[i].w * in_componentWeight[i];\
2954  \n tmp.w += ((color[i].w * color[i].w)/totalAlpha);\
2955  \n }\
2956  \n }\
2957  \n g_fragColor = (1.0f - g_fragColor.a) * tmp + g_fragColor;");
2958  }
2959  }
2960  else if (glMapper->GetUseDepthPass() &&
2961  glMapper->GetCurrentPass() == vtkOpenGLGPUVolumeRayCastMapper::DepthPass)
2962  {
2963  shaderStr += std::string("\
2964  \n g_srcColor = vec4(0.0);\
2965  \n g_srcColor.a = computeOpacity(scalar);");
2966  }
2967  else
2968  {
2969  if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2970  {
2971  shaderStr += std::string("\
2972  \n g_srcColor = vec4(0.0);\
2973  \n g_srcColor.a = computeOpacity(scalar);\
2974  \n if (g_srcColor.a > 0.0)\
2975  \n {\
2976  \n g_srcColor = computeColor(scalar, g_srcColor.a);");
2977  }
2978 
2979  shaderStr += std::string("\
2980  \n // Opacity calculation using compositing:\
2981  \n // Here we use front to back compositing scheme whereby\
2982  \n // the current sample value is multiplied to the\
2983  \n // currently accumulated alpha and then this product\
2984  \n // is subtracted from the sample value to get the\
2985  \n // alpha from the previous steps. Next, this alpha is\
2986  \n // multiplied with the current sample colour\
2987  \n // and accumulated to the composited colour. The alpha\
2988  \n // value from the previous steps is then accumulated\
2989  \n // to the composited colour alpha.\
2990  \n g_srcColor.rgb *= g_srcColor.a;\
2991  \n g_fragColor = (1.0f - g_fragColor.a) * g_srcColor + g_fragColor;");
2992 
2993  if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2994  {
2995  shaderStr += std::string("\
2996  \n }");
2997  }
2998  }
2999  }
3000  else
3001  {
3002  shaderStr += std::string();
3003  }
3004 
3005  shaderStr += std::string("\
3006  \n }");
3007  return shaderStr;
3008 }
3009 
3010 //--------------------------------------------------------------------------
3012  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3013 {
3014  return std::string("\
3015  \n // Special coloring mode which renders the Prop Id in fragments that\
3016  \n // have accumulated certain level of opacity. Used during the selection\
3017  \n // pass vtkHardwareSelection::ACTOR_PASS.\
3018  \n if (g_fragColor.a > 3.0/ 255.0)\
3019  \n {\
3020  \n gl_FragData[0] = vec4(in_propId, 1.0);\
3021  \n }\
3022  \n else\
3023  \n {\
3024  \n gl_FragData[0] = vec4(0.0);\
3025  \n }\
3026  \n return;");
3027 }
3028 
3029 //--------------------------------------------------------------------------
3031  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3032 {
3033  return std::string("\
3034  \n // Special coloring mode which renders the voxel index in fragments that\
3035  \n // have accumulated certain level of opacity. Used during the selection\
3036  \n // pass vtkHardwareSelection::ID_LOW24.\
3037  \n if (g_fragColor.a > 3.0/ 255.0)\
3038  \n {\
3039  \n uvec3 volumeDim = uvec3(in_textureExtentsMax - in_textureExtentsMin);\
3040  \n uvec3 voxelCoords = uvec3(vec3(volumeDim) * g_dataPos);\
3041  \n // vtkHardwareSelector assumes index 0 to be empty space, so add uint(1).\
3042  \n uint idx = volumeDim.x * volumeDim.y * voxelCoords.z +\
3043  \n volumeDim.x * voxelCoords.y + voxelCoords.x + uint(1);\
3044  \n gl_FragData[0] = vec4(float(idx % uint(256)) / 255.0,\
3045  \n float((idx / uint(256)) % uint(256)) / 255.0,\
3046  \n float((idx / uint(65536)) % uint(256)) / 255.0, 1.0);\
3047  \n }\
3048  \n else\
3049  \n {\
3050  \n gl_FragData[0] = vec4(0.0);\
3051  \n }\
3052  \n return;");
3053 }
3054 
3055 //--------------------------------------------------------------------------
3057  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3058 {
3059  return std::string("\
3060  \n // Special coloring mode which renders the voxel index in fragments that\
3061  \n // have accumulated certain level of opacity. Used during the selection\
3062  \n // pass vtkHardwareSelection::ID_MID24.\
3063  \n if (g_fragColor.a > 3.0/ 255.0)\
3064  \n {\
3065  \n uvec3 volumeDim = uvec3(in_textureExtentsMax - in_textureExtentsMin);\
3066  \n uvec3 voxelCoords = uvec3(vec3(volumeDim) * g_dataPos);\
3067  \n // vtkHardwareSelector assumes index 0 to be empty space, so add uint(1).\
3068  \n uint idx = volumeDim.x * volumeDim.y * voxelCoords.z +\
3069  \n volumeDim.x * voxelCoords.y + voxelCoords.x + uint(1);\
3070  \n idx = ((idx & 0xff000000u) >> 24u);\
3071  \n gl_FragData[0] = vec4(float(idx % uint(256)) / 255.0,\
3072  \n float((idx / uint(256)) % uint(256)) / 255.0,\
3073  \n float(idx / uint(65536)) / 255.0, 1.0);\
3074  \n }\
3075  \n else\
3076  \n {\
3077  \n gl_FragData[0] = vec4(0.0);\
3078  \n }\
3079  \n return;");
3080 }
3081 
3082 //--------------------------------------------------------------------------
3083 inline std::string ShadingExit(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper,
3084  vtkVolume* vtkNotUsed(vol), int noOfComponents, int independentComponents = 0)
3085 {
3087 
3088  if (glMapper->GetUseDepthPass() &&
3091  {
3092  return std::string();
3093  }
3095  {
3096  if (noOfComponents > 1 && independentComponents)
3097  {
3098  return std::string("\
3099  \n g_srcColor = vec4(0);\
3100  \n for (int i = 0; i < in_noOfComponents; ++i)\
3101  \n {\
3102  \n vec4 tmp = computeColor(l_maxValue, computeOpacity(l_maxValue, i), i);\
3103  \n g_srcColor[0] += tmp[0] * tmp[3] * in_componentWeight[i];\
3104  \n g_srcColor[1] += tmp[1] * tmp[3] * in_componentWeight[i];\
3105  \n g_srcColor[2] += tmp[2] * tmp[3] * in_componentWeight[i];\
3106  \n g_srcColor[3] += tmp[3] * in_componentWeight[i];\
3107  \n }\
3108  \n g_fragColor = g_srcColor;");
3109  }
3110  else
3111  {
3112  return std::string("\
3113  \n g_srcColor = computeColor(l_maxValue,\
3114  \n computeOpacity(l_maxValue));\
3115  \n g_fragColor.rgb = g_srcColor.rgb * g_srcColor.a;\
3116  \n g_fragColor.a = g_srcColor.a;");
3117  }
3118  }
3120  {
3121  if (noOfComponents > 1 && independentComponents)
3122  {
3123  return std::string("\
3124  \n g_srcColor = vec4(0);\
3125  \n for (int i = 0; i < in_noOfComponents; ++i)\
3126  \n {\
3127  \n vec4 tmp = computeColor(l_minValue, computeOpacity(l_minValue, i), i);\
3128  \n g_srcColor[0] += tmp[0] * tmp[3] * in_componentWeight[i];\
3129  \n g_srcColor[1] += tmp[1] * tmp[3] * in_componentWeight[i];\
3130  \n g_srcColor[2] += tmp[2] * tmp[3] * in_componentWeight[i];\
3131  \n g_srcColor[2] += tmp[3] * tmp[3] * in_componentWeight[i];\
3132  \n }\
3133  \n g_fragColor = g_srcColor;");
3134  }
3135  else
3136  {
3137  return std::string("\
3138  \n g_srcColor = computeColor(l_minValue,\
3139  \n computeOpacity(l_minValue));\
3140  \n g_fragColor.rgb = g_srcColor.rgb * g_srcColor.a;\
3141  \n g_fragColor.a = g_srcColor.a;");
3142  }
3143  }
3145  {
3146  if (noOfComponents > 1 && independentComponents)
3147  {
3148  return std::string("\
3149  \n for (int i = 0; i < in_noOfComponents; ++i)\
3150  \n {\
3151  \n if (l_numSamples[i] == uint(0))\
3152  \n {\
3153  \n continue;\
3154  \n }\
3155  \n l_avgValue[i] = l_avgValue[i] * in_componentWeight[i] /\
3156  \n l_numSamples[i];\
3157  \n if (i > 0)\
3158  \n {\
3159  \n l_avgValue[0] += l_avgValue[i];\
3160  \n }\
3161  \n }\
3162  \n l_avgValue[0] = clamp(l_avgValue[0], 0.0, 1.0);\
3163  \n g_fragColor = vec4(vec3(l_avgValue[0]), 1.0);");
3164  }
3165  else
3166  {
3167  return std::string("\
3168  \n if (l_numSamples.x == uint(0))\
3169  \n {\
3170  \n discard;\
3171  \n }\
3172  \n else\
3173  \n {\
3174  \n l_avgValue.x /= l_numSamples.x;\
3175  \n l_avgValue.x = clamp(l_avgValue.x, 0.0, 1.0);\
3176  \n g_fragColor = vec4(vec3(l_avgValue.x), 1.0);\
3177  \n }");
3178  }
3179  }
3180  else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
3181  {
3182  if (noOfComponents > 1 && independentComponents)
3183  {
3184  // Add all the components to get final color
3185  return std::string("\
3186  \n l_sumValue.x *= in_componentWeight.x;\
3187  \n for (int i = 1; i < in_noOfComponents; ++i)\
3188  \n {\
3189  \n l_sumValue.x += l_sumValue[i] * in_componentWeight[i];\
3190  \n }\
3191  \n l_sumValue.x = clamp(l_sumValue.x, 0.0, 1.0);\
3192  \n g_fragColor = vec4(vec3(l_sumValue.x), 1.0);");
3193  }
3194  else
3195  {
3196  return std::string("\
3197  \n l_sumValue.x = clamp(l_sumValue.x, 0.0, 1.0);\
3198  \n g_fragColor = vec4(vec3(l_sumValue.x), 1.0);");
3199  }
3200  }
3201  else
3202  {
3203  return std::string();
3204  }
3205 }
3206 
3207 //--------------------------------------------------------------------------
3209  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3210 {
3211  return std::string();
3212 }
3213 
3214 //--------------------------------------------------------------------------
3216  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3217 {
3218  return std::string("\
3219  \n const float g_opacityThreshold = 1.0 - 1.0 / 255.0;");
3220 }
3221 
3222 //--------------------------------------------------------------------------
3224  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3225 {
3226  return std::string("\
3227  \n uniform vec3 in_propId;");
3228 }
3229 
3230 //--------------------------------------------------------------------------
3232  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vol)
3233 {
3234  std::string shaderStr;
3235  shaderStr += std::string("\
3236  \n // Flag to indicate if the raymarch loop should terminate \
3237  \n bool stop = false;\
3238  \n\
3239  \n g_terminatePointMax = 0.0;\
3240  \n\
3241  \n vec4 l_depthValue = texture2D(in_depthSampler, fragTexCoord);\
3242  \n // Depth test\
3243  \n if(gl_FragCoord.z >= l_depthValue.x)\
3244  \n {\
3245  \n discard;\
3246  \n }\
3247  \n\
3248  \n // color buffer or max scalar buffer have a reduced size.\
3249  \n fragTexCoord = (gl_FragCoord.xy - in_windowLowerLeftCorner) *\
3250  \n in_inverseOriginalWindowSize;\
3251  \n");
3252 
3253  if (mapper->GetBlendMode() == vtkVolumeMapper::SLICE_BLEND)
3254  {
3255  vtkImplicitFunction* sliceFunc = vol->GetProperty()->GetSliceFunction();
3256  if (sliceFunc)
3257  {
3258  if (sliceFunc->IsA("vtkPlane"))
3259  {
3260  shaderStr += std::string("\
3261  \n\
3262  \n // Intersection with plane\
3263  \n float t = intersectRayPlane(ip_vertexPos, rayDir);\
3264  \n vec4 intersection = vec4(ip_vertexPos + t * rayDir, 1.0);\
3265  \n g_intersection = (in_inverseTextureDatasetMatrix[0] * intersection).xyz;\
3266  \n vec4 intersDC = in_projectionMatrix * in_modelViewMatrix * in_volumeMatrix[0] * intersection;\
3267  \n intersDC.xyz /= intersDC.w;\
3268  \n vec4 intersWin = NDCToWindow(intersDC.x, intersDC.y, intersDC.z);\
3269  \n if(intersWin.z >= l_depthValue.x)\
3270  \n {\
3271  \n discard;\
3272  \n }\
3273  \n");
3274  }
3275  else
3276  {
3277  vtkErrorWithObjectMacro(
3278  sliceFunc, "Implicit function type is not supported by this mapper.");
3279  }
3280  }
3281  }
3282 
3283  shaderStr += std::string("\
3284  \n // Compute max number of iterations it will take before we hit\
3285  \n // the termination point\
3286  \n\
3287  \n // Abscissa of the point on the depth buffer along the ray.\
3288  \n // point in texture coordinates\
3289  \n vec4 rayTermination = WindowToNDC(gl_FragCoord.x, gl_FragCoord.y, l_depthValue.x);\
3290  \n\
3291  \n // From normalized device coordinates to eye coordinates.\
3292  \n // in_projectionMatrix is inversed because of way VT\
3293  \n // From eye coordinates to texture coordinates\
3294  \n rayTermination = ip_inverseTextureDataAdjusted *\
3295  \n in_inverseVolumeMatrix[0] *\
3296  \n in_inverseModelViewMatrix *\
3297  \n in_inverseProjectionMatrix *\
3298  \n rayTermination;\
3299  \n g_rayTermination = rayTermination.xyz / rayTermination.w;\
3300  \n\
3301  \n // Setup the current segment:\
3302  \n g_dataPos = g_rayOrigin;\
3303  \n g_terminatePos = g_rayTermination;\
3304  \n\
3305  \n g_terminatePointMax = length(g_terminatePos.xyz - g_dataPos.xyz) /\
3306  \n length(g_dirStep);\
3307  \n g_currentT = 0.0;");
3308 
3309  return shaderStr;
3310 }
3311 
3312 //--------------------------------------------------------------------------
3314  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3315 {
3316  return std::string("\
3317  \n if(any(greaterThan(max(g_dirStep, vec3(0.0))*(g_dataPos - in_texMax[0]),vec3(0.0))) ||\
3318  \n any(greaterThan(min(g_dirStep, vec3(0.0))*(g_dataPos - in_texMin[0]),vec3(0.0))))\
3319  \n {\
3320  \n break;\
3321  \n }\
3322  \n\
3323  \n // Early ray termination\
3324  \n // if the currently composited colour alpha is already fully saturated\
3325  \n // we terminated the loop or if we have hit an obstacle in the\
3326  \n // direction of they ray (using depth buffer) we terminate as well.\
3327  \n if((g_fragColor.a > g_opacityThreshold) || \
3328  \n g_currentT >= g_terminatePointMax)\
3329  \n {\
3330  \n break;\
3331  \n }\
3332  \n ++g_currentT;");
3333 }
3334 
3335 //--------------------------------------------------------------------------
3337  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3338 {
3339  return std::string();
3340 }
3341 
3342 //--------------------------------------------------------------------------
3344  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3345 {
3346  return std::string();
3347 }
3348 
3349 //--------------------------------------------------------------------------
3351  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
3352 {
3353  if (!mapper->GetCropping())
3354  {
3355  return std::string();
3356  }
3357 
3358  return std::string("\
3359  \nuniform float in_croppingPlanes[6];\
3360  \nuniform int in_croppingFlags [32];\
3361  \nfloat croppingPlanesTexture[6];\
3362  \n\
3363  \n// X: axis = 0, Y: axis = 1, Z: axis = 2\
3364  \n// cp Cropping plane bounds (minX, maxX, minY, maxY, minZ, maxZ)\
3365  \nint computeRegionCoord(float cp[6], vec3 pos, int axis)\
3366  \n {\
3367  \n int cpmin = axis * 2;\
3368  \n int cpmax = cpmin + 1;\
3369  \n\
3370  \n if (pos[axis] < cp[cpmin])\
3371  \n {\
3372  \n return 1;\
3373  \n }\
3374  \n else if (pos[axis] >= cp[cpmin] &&\
3375  \n pos[axis] < cp[cpmax])\
3376  \n {\
3377  \n return 2;\
3378  \n }\
3379  \n else if (pos[axis] >= cp[cpmax])\
3380  \n {\
3381  \n return 3;\
3382  \n }\
3383  \n return 0;\
3384  \n }\
3385  \n\
3386  \nint computeRegion(float cp[6], vec3 pos)\
3387  \n {\
3388  \n return (computeRegionCoord(cp, pos, 0) +\
3389  \n (computeRegionCoord(cp, pos, 1) - 1) * 3 +\
3390  \n (computeRegionCoord(cp, pos, 2) - 1) * 9);\
3391  \n }");
3392 }
3393 
3394 //--------------------------------------------------------------------------
3396  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
3397 {
3398  if (!mapper->GetCropping())
3399  {
3400  return std::string();
3401  }
3402 
3403  return std::string("\
3404  \n // Convert cropping region to texture space\
3405  \n mat4 datasetToTextureMat = in_inverseTextureDatasetMatrix[0];\
3406  \n\
3407  \n vec4 tempCrop = vec4(in_croppingPlanes[0], 0.0, 0.0, 1.0);\
3408  \n tempCrop = datasetToTextureMat * tempCrop;\
3409  \n if (tempCrop[3] != 0.0)\
3410  \n {\
3411  \n tempCrop[0] /= tempCrop[3];\
3412  \n }\
3413  \n croppingPlanesTexture[0] = tempCrop[0];\
3414  \n\
3415  \n tempCrop = vec4(in_croppingPlanes[1], 0.0, 0.0, 1.0);\
3416  \n tempCrop = datasetToTextureMat * tempCrop;\
3417  \n if (tempCrop[3] != 0.0)\
3418  \n {\
3419  \n tempCrop[0] /= tempCrop[3];\
3420  \n }\
3421  \n croppingPlanesTexture[1] = tempCrop[0];\
3422  \n\
3423  \n tempCrop = vec4(0.0, in_croppingPlanes[2], 0.0, 1.0);\
3424  \n tempCrop = datasetToTextureMat * tempCrop;\
3425  \n if (tempCrop[3] != 0.0)\
3426  \n {\
3427  \n tempCrop[1] /= tempCrop[3];\
3428  \n }\
3429  \n croppingPlanesTexture[2] = tempCrop[1];\
3430  \n\
3431  \n tempCrop = vec4(0.0, in_croppingPlanes[3], 0.0, 1.0);\
3432  \n tempCrop = datasetToTextureMat * tempCrop;\
3433  \n if (tempCrop[3] != 0.0)\
3434  \n {\
3435  \n tempCrop[1] /= tempCrop[3];\
3436  \n }\
3437  \n croppingPlanesTexture[3] = tempCrop[1];\
3438  \n\
3439  \n tempCrop = vec4(0.0, 0.0, in_croppingPlanes[4], 1.0);\
3440  \n tempCrop = datasetToTextureMat * tempCrop;\
3441  \n if (tempCrop[3] != 0.0)\
3442  \n {\
3443  \n tempCrop[2] /= tempCrop[3];\
3444  \n }\
3445  \n croppingPlanesTexture[4] = tempCrop[2];\
3446  \n\
3447  \n tempCrop = vec4(0.0, 0.0, in_croppingPlanes[5], 1.0);\
3448  \n tempCrop = datasetToTextureMat * tempCrop;\
3449  \n if (tempCrop[3] != 0.0)\
3450  \n {\
3451  \n tempCrop[2] /= tempCrop[3];\
3452  \n }\
3453  \n croppingPlanesTexture[5] = tempCrop[2];");
3454 }
3455 
3456 //--------------------------------------------------------------------------
3458  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
3459 {
3460  if (!mapper->GetCropping())
3461  {
3462  return std::string();
3463  }
3464 
3465  return std::string("\
3466  \n // Determine region\
3467  \n int regionNo = computeRegion(croppingPlanesTexture, g_dataPos);\
3468  \n\
3469  \n // Do & operation with cropping flags\
3470  \n // Pass the flag that its Ok to sample or not to sample\
3471  \n if (in_croppingFlags[regionNo] == 0)\
3472  \n {\
3473  \n // Skip this voxel\
3474  \n g_skip = true;\
3475  \n }");
3476 }
3477 
3478 //--------------------------------------------------------------------------
3480  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3481 {
3482  return std::string();
3483 }
3484 
3485 //--------------------------------------------------------------------------
3487  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3488 {
3489  return std::string();
3490 }
3491 
3492 //--------------------------------------------------------------------------
3494  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
3495 {
3496  if (!mapper->GetClippingPlanes())
3497  {
3498  return std::string();
3499  }
3500 
3501  return std::string("\
3502  \n /// We support only 8 clipping planes for now\
3503  \n /// The first value is the size of the data array for clipping\
3504  \n /// planes (origin, normal)\
3505  \n uniform float in_clippingPlanes[49];\
3506  \n uniform float in_clippedVoxelIntensity;\
3507  \n\
3508  \n int clip_numPlanes;\
3509  \n vec3 clip_rayDirObj;\
3510  \n mat4 clip_texToObjMat;\
3511  \n mat4 clip_objToTexMat;\
3512  \n\
3513  \n// Tighten the sample range as needed to account for clip planes. \
3514  \n// Arguments are in texture coordinates. \
3515  \n// Returns true if the range is at all valid after clipping. If not, \
3516  \n// the fragment should be discarded. \
3517  \nbool AdjustSampleRangeForClipping(inout vec3 startPosTex, inout vec3 stopPosTex) \
3518  \n{ \
3519  \n vec4 startPosObj = vec4(0.0);\
3520  \n {\
3521  \n startPosObj = clip_texToObjMat * vec4(startPosTex - g_rayJitter, 1.0);\
3522  \n startPosObj = startPosObj / startPosObj.w;\
3523  \n startPosObj.w = 1.0;\
3524  \n }\
3525  \n\
3526  \n vec4 stopPosObj = vec4(0.0);\
3527  \n {\
3528  \n stopPosObj = clip_texToObjMat * vec4(stopPosTex, 1.0);\
3529  \n stopPosObj = stopPosObj / stopPosObj.w;\
3530  \n stopPosObj.w = 1.0;\
3531  \n }\
3532  \n\
3533  \n for (int i = 0; i < clip_numPlanes; i = i + 6)\
3534  \n {\
3535  \n vec3 planeOrigin = vec3(in_clippingPlanes[i + 1],\
3536  \n in_clippingPlanes[i + 2],\
3537  \n in_clippingPlanes[i + 3]);\
3538  \n vec3 planeNormal = normalize(vec3(in_clippingPlanes[i + 4],\
3539  \n in_clippingPlanes[i + 5],\
3540  \n in_clippingPlanes[i + 6]));\
3541  \n\
3542  \n // Abort if the entire segment is clipped:\
3543  \n // (We can do this before adjusting the term point, since it'll \
3544  \n // only move further into the clipped area)\
3545  \n float startDistance = dot(planeNormal, planeOrigin - startPosObj.xyz);\
3546  \n float stopDistance = dot(planeNormal, planeOrigin - stopPosObj.xyz);\
3547  \n bool startClipped = startDistance > 0.0;\
3548  \n bool stopClipped = stopDistance > 0.0;\
3549  \n if (startClipped && stopClipped)\
3550  \n {\
3551  \n return false;\
3552  \n }\
3553  \n\
3554  \n float rayDotNormal = dot(clip_rayDirObj, planeNormal);\
3555  \n bool frontFace = rayDotNormal > 0.0;\
3556  \n\
3557  \n // Move the start position further from the eye if needed:\
3558  \n if (frontFace && // Observing from the clipped side (plane's front face)\
3559  \n startDistance > 0.0) // Ray-entry lies on the clipped side.\
3560  \n {\
3561  \n // Scale the point-plane distance to the ray direction and update the\
3562  \n // entry point.\
3563  \n float rayScaledDist = startDistance / rayDotNormal;\
3564  \n startPosObj = vec4(startPosObj.xyz + rayScaledDist * clip_rayDirObj, 1.0);\
3565  \n vec4 newStartPosTex = clip_objToTexMat * vec4(startPosObj.xyz, 1.0);\
3566  \n newStartPosTex /= newStartPosTex.w;\
3567  \n startPosTex = newStartPosTex.xyz;\
3568  \n startPosTex += g_rayJitter;\
3569  \n }\
3570  \n\
3571  \n // Move the end position closer to the eye if needed:\
3572  \n if (!frontFace && // Observing from the unclipped side (plane's back face)\
3573  \n stopDistance > 0.0) // Ray-entry lies on the unclipped side.\
3574  \n {\
3575  \n // Scale the point-plane distance to the ray direction and update the\
3576  \n // termination point.\
3577  \n float rayScaledDist = stopDistance / rayDotNormal;\
3578  \n stopPosObj = vec4(stopPosObj.xyz + rayScaledDist * clip_rayDirObj, 1.0);\
3579  \n vec4 newStopPosTex = clip_objToTexMat * vec4(stopPosObj.xyz, 1.0);\
3580  \n newStopPosTex /= newStopPosTex.w;\
3581  \n stopPosTex = newStopPosTex.xyz;\
3582  \n }\
3583  \n }\
3584  \n\
3585  \n if (any(greaterThan(startPosTex, in_texMax[0])) ||\
3586  \n any(lessThan(startPosTex, in_texMin[0])))\
3587  \n {\
3588  \n return false;\
3589  \n }\
3590  \n\
3591  \n return true;\
3592  \n}\
3593  \n");
3594 }
3595 
3596 //--------------------------------------------------------------------------
3598  vtkRenderer* ren, vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
3599 {
3600  if (!mapper->GetClippingPlanes())
3601  {
3602  return std::string();
3603  }
3604 
3605  std::string shaderStr;
3606  if (!ren->GetActiveCamera()->GetParallelProjection())
3607  {
3608  shaderStr = std::string("\
3609  \n vec4 tempClip = in_volumeMatrix[0] * vec4(rayDir, 0.0);\
3610  \n if (tempClip.w != 0.0)\
3611  \n {\
3612  \n tempClip = tempClip/tempClip.w;\
3613  \n tempClip.w = 1.0;\
3614  \n }\
3615  \n clip_rayDirObj = normalize(tempClip.xyz);");
3616  }
3617  else
3618  {
3619  shaderStr = std::string("\
3620  clip_rayDirObj = normalize(in_projectionDirection);");
3621  }
3622 
3623  shaderStr += std::string("\
3624  \n clip_numPlanes = int(in_clippingPlanes[0]);\
3625  \n clip_texToObjMat = in_volumeMatrix[0] * inverse(ip_inverseTextureDataAdjusted);\
3626  \n clip_objToTexMat = ip_inverseTextureDataAdjusted * in_inverseVolumeMatrix[0];\
3627  \n\
3628  \n // Adjust for clipping.\
3629  \n if (!AdjustSampleRangeForClipping(g_rayOrigin, g_rayTermination))\
3630  \n { // entire ray is clipped.\
3631  \n discard;\
3632  \n }\
3633  \n\
3634  \n // Update the segment post-clip:\
3635  \n g_dataPos = g_rayOrigin;\
3636  \n g_terminatePos = g_rayTermination;\
3637  \n g_terminatePointMax = length(g_terminatePos.xyz - g_dataPos.xyz) /\
3638  \n length(g_dirStep);\
3639  \n");
3640 
3641  return shaderStr;
3642 }
3643 
3644 //--------------------------------------------------------------------------
3646  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3647 {
3648  return std::string();
3649 }
3650 
3651 //--------------------------------------------------------------------------
3653  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3654 {
3655  return std::string();
3656 }
3657 
3658 //--------------------------------------------------------------------------
3660  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput,
3661  vtkVolumeTexture* mask, int vtkNotUsed(maskType))
3662 {
3663  if (!mask || !maskInput)
3664  {
3665  return std::string();
3666  }
3667  else
3668  {
3669  return std::string("uniform sampler3D in_mask;");
3670  }
3671 }
3672 
3673 //--------------------------------------------------------------------------
3675  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput,
3676  vtkVolumeTexture* mask, int maskType)
3677 {
3678  if (!mask || !maskInput || maskType == vtkGPUVolumeRayCastMapper::LabelMapMaskType)
3679  {
3680  return std::string();
3681  }
3682  else
3683  {
3684  return std::string("\
3685  \nvec4 maskValue = texture3D(in_mask, g_dataPos);\
3686  \nif(maskValue.r <= 0.0)\
3687  \n {\
3688  \n g_skip = true;\
3689  \n }");
3690  }
3691 }
3692 
3693 //--------------------------------------------------------------------------
3695  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput,
3696  vtkVolumeTexture* mask, int maskType)
3697 {
3698  if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
3699  {
3700  return std::string();
3701  }
3702  else
3703  {
3704  return std::string("\
3705  \nuniform float in_maskBlendFactor;\
3706  \nuniform sampler2D in_labelMapTransfer;\
3707  \nuniform float in_mask_scale;\
3708  \nuniform float in_mask_bias;\
3709  \nuniform int in_labelMapNumLabels;\
3710  \n");
3711  }
3712 }
3713 
3714 //--------------------------------------------------------------------------
3716  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput,
3717  vtkVolumeTexture* mask, int maskType, int noOfComponents)
3718 {
3719  if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
3720  {
3721  return std::string();
3722  }
3723  else
3724  {
3725  std::string shaderStr = std::string("\
3726  \nvec4 scalar = texture3D(in_volume[0], g_dataPos);");
3727 
3728  // simulate old intensity textures
3729  if (noOfComponents == 1)
3730  {
3731  shaderStr += std::string("\
3732  \n scalar.r = scalar.r * in_volume_scale[0].r + in_volume_bias[0].r;\
3733  \n scalar = vec4(scalar.r);");
3734  }
3735  else
3736  {
3737  // handle bias and scale
3738  shaderStr += std::string("\
3739  \n scalar = scalar * in_volume_scale[0] + in_volume_bias[0];");
3740  }
3741 
3742  // Assumeing single component scalar for label texture lookup.
3743  // This can be extended to composite color obtained from all components
3744  // in the scalar array.
3745  return shaderStr + std::string("\
3746  \nif (in_maskBlendFactor == 0.0)\
3747  \n {\
3748  \n g_srcColor.a = computeOpacity(scalar);\
3749  \n if (g_srcColor.a > 0)\
3750  \n {\
3751  \n g_srcColor = computeColor(scalar, g_srcColor.a);\
3752  \n }\
3753  \n }\
3754  \nelse\
3755  \n {\
3756  \n float opacity = computeOpacity(scalar);\
3757  \n // Get the mask value at this same location\
3758  \n vec4 maskValue = texture3D(in_mask, g_dataPos);\
3759  \n maskValue.r = maskValue.r * in_mask_scale + in_mask_bias;\
3760  \n // Quantize the height of the labelmap texture over number of labels\
3761  \n if (in_labelMapNumLabels > 0)\
3762  \n {\
3763  \n maskValue.r =\
3764  \n floor(maskValue.r * in_labelMapNumLabels) /\
3765  \n in_labelMapNumLabels;\
3766  \n }\
3767  \n else\
3768  \n {\
3769  \n maskValue.r = 0.0;\
3770  \n }\
3771  \n if(maskValue.r == 0.0)\
3772  \n {\
3773  \n g_srcColor.a = opacity;\
3774  \n if (g_srcColor.a > 0)\
3775  \n {\
3776  \n g_srcColor = computeColor(scalar, g_srcColor.a);\
3777  \n }\
3778  \n }\
3779  \n else\
3780  \n {\
3781  \n g_srcColor = texture2D(in_labelMapTransfer,\
3782  \n vec2(scalar.r, maskValue.r));\
3783  \n if (g_srcColor.a > 0)\
3784  \n {\
3785  \n g_srcColor = computeLighting(g_srcColor, 0, maskValue.r);\
3786  \n }\
3787  \n if (in_maskBlendFactor < 1.0)\
3788  \n {\
3789  \n vec4 color = opacity > 0 ? computeColor(scalar, opacity) : vec4(0);\
3790  \n g_srcColor = (1.0 - in_maskBlendFactor) * color +\
3791  \n in_maskBlendFactor * g_srcColor;\
3792  \n }\
3793  \n }\
3794  \n }");
3795  }
3796 }
3797 
3798 //--------------------------------------------------------------------------
3800  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3801 {
3802  return std::string("uniform bool in_clampDepthToBackface;\n"
3803  "vec3 l_opaqueFragPos;\n"
3804  "bool l_updateDepth;\n");
3805 }
3806 
3807 //--------------------------------------------------------------------------
3809  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3810 {
3811  return std::string("\
3812  \n l_opaqueFragPos = vec3(-1.0);\
3813  \n if(in_clampDepthToBackface)\
3814  \n {\
3815  \n l_opaqueFragPos = g_dataPos;\
3816  \n }\
3817  \n l_updateDepth = true;");
3818 }
3819 
3820 //--------------------------------------------------------------------------
3822  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3823 {
3824  return std::string("\
3825  \n if(!g_skip && g_srcColor.a > 0.0 && l_updateDepth)\
3826  \n {\
3827  \n l_opaqueFragPos = g_dataPos;\
3828  \n l_updateDepth = false;\
3829  \n }");
3830 }
3831 
3832 //--------------------------------------------------------------------------
3834  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3835 {
3836  return std::string("\
3837  \n if (l_opaqueFragPos == vec3(-1.0))\
3838  \n {\
3839  \n gl_FragData[1] = vec4(1.0);\
3840  \n }\
3841  \n else\
3842  \n {\
3843  \n vec4 depthValue = in_projectionMatrix * in_modelViewMatrix *\
3844  \n in_volumeMatrix[0] * in_textureDatasetMatrix[0] *\
3845  \n vec4(l_opaqueFragPos, 1.0);\
3846  \n depthValue /= depthValue.w;\
3847  \n gl_FragData[1] = vec4(vec3(0.5 * (gl_DepthRange.far -\
3848  \n gl_DepthRange.near) * depthValue.z + 0.5 *\
3849  \n (gl_DepthRange.far + gl_DepthRange.near)), 1.0);\
3850  \n }");
3851 }
3852 
3853 //--------------------------------------------------------------------------
3855  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3856 {
3857  return std::string("\
3858  \n vec3 l_isoPos = g_dataPos;");
3859 }
3860 
3861 //--------------------------------------------------------------------------
3863  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3864 {
3865  return std::string("\
3866  \n if(!g_skip && g_srcColor.a > 0.0)\
3867  \n {\
3868  \n l_isoPos = g_dataPos;\
3869  \n g_exit = true; g_skip = true;\
3870  \n }");
3871 }
3872 
3873 //--------------------------------------------------------------------------
3875  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3876 {
3877  return std::string("\
3878  \n vec4 depthValue = in_projectionMatrix * in_modelViewMatrix *\
3879  \n in_volumeMatrix[0] * in_textureDatasetMatrix[0] *\
3880  \n vec4(l_isoPos, 1.0);\
3881  \n gl_FragData[0] = vec4(l_isoPos, 1.0);\
3882  \n gl_FragData[1] = vec4(vec3((depthValue.z/depthValue.w) * 0.5 + 0.5),\
3883  \n 1.0);");
3884 }
3885 
3886 //---------------------------------------------------------------------------
3888  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3889 {
3890  return std::string("\
3891  \n g_texToView = in_modelViewMatrix * in_volumeMatrix[0] * in_textureDatasetMatrix[0];\
3892  \n initializeRayCast();\
3893  \n castRay(-1.0, -1.0);\
3894  \n finalizeRayCast();");
3895 }
3896 
3897 //---------------------------------------------------------------------------
3899  const std::vector<std::string>& varNames, size_t usedNames)
3900 {
3901  std::string shader = "\n";
3902  for (size_t i = 0; i < usedNames; i++)
3903  {
3904  shader += "uniform sampler2D " + varNames[i] + ";\n";
3905  }
3906  return shader;
3907 }
3908 
3909 //---------------------------------------------------------------------------
3911  const std::vector<std::string>& varNames, size_t usedNames)
3912 {
3913  std::string shader = "\n";
3914  for (size_t i = 0; i < usedNames; i++)
3915  {
3916  std::stringstream ss;
3917  ss << i;
3918  shader += " gl_FragData[" + ss.str() + "] = texture2D(" + varNames[i] + ", texCoord);\n";
3919  }
3920  shader += " return;\n";
3921  return shader;
3922 }
3923 VTK_ABI_NAMESPACE_END
3924 }
3925 
3926 #endif // vtkVolumeShaderComposer_h
3927 // VTK-HeaderTest-Exclude: vtkVolumeShaderComposer.h
abstract interface for implicit functions
std::string RenderToImageDeclarationFragment(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
virtual float GetScatteringAnisotropy()
Get/Set the volume's scattering anisotropy.
std::string PreComputeGradientsImpl(vtkRenderer *ren, vtkVolume *vol, int noOfComponents=1, int independentComponents=0)
represents a volume (data & properties) in a rendered scene
Definition: vtkVolume.h:40
std::string BinaryMaskDeclaration(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol, vtkImageData *maskInput, vtkVolumeTexture *mask, int maskType)
std::string BaseDeclarationFragment(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs, int totalNumberOfLights, int numberPositionalLights, bool defaultLighting, int noOfComponents, int independentComponents)
virtual int GetUseClippedVoxelIntensity()
Set/Get whether to use a fixed intensity value for voxels in the clipped space for gradient calculati...
std::string ClippingDeclarationVertex(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string RenderToImageInit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
Abstract class for a volume mapper.
std::string DepthPassImplementation(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string BinaryMaskImplementation(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol, vtkImageData *maskInput, vtkVolumeTexture *mask, int maskType)
std::string ComputeGradientOpacityMulti1DDecl(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs)
std::string PickingActorPassDeclaration(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string CompositeMaskImplementation(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol, vtkImageData *maskInput, vtkVolumeTexture *mask, int maskType, int noOfComponents)
std::string BaseExit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string TerminationExit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
virtual int GetBlendMode()
Set/Get the blend mode.
vtkUnsignedCharArray * GetCellGhostArray()
Get the array that defines the ghost type of each cell.
Creates and manages the volume texture rendered by vtkOpenGLGPUVolumeRayCastMapper.
std::map< int, vtkVolumeInputHelper > VolumeInputMap
std::string PickingIdHigh24PassExit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string CroppingInit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string ClippingInit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string PickingActorPassExit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string ClippingImplementation(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string BaseImplementation(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
virtual vtkVolumeProperty * GetProperty()
Set/Get the volume property.
std::string PickingIdLow24PassExit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string ComputeGradientOpacity1DDecl(vtkVolume *vol, int noOfComponents, int independentComponents, std::map< int, std::string > gradientTableMap)
std::string ShadingExit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol, int noOfComponents, int independentComponents=0)
std::string ComputeClipPositionImplementation(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string ComputeVolumetricShadowDec(vtkOpenGLGPUVolumeRayCastMapper *mapper, vtkVolume *vol, int noOfComponents, int independentComponents, vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs, int useGradYAxis)
abstract specification for renderers
Definition: vtkRenderer.h:63
virtual vtkImplicitFunction * GetSliceFunction()
Get/Set the function used for slicing.
vtkUnsignedCharArray * GetPointGhostArray()
Gets the array that defines the ghost type of each point.
std::string ComputeOpacityEvaluationCall(vtkOpenGLGPUVolumeRayCastMapper *mapper, vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs, int noOfComponents, int independentComponents, int useGradYAxis, std::string position, bool requestColor=false)
std::string TerminationImplementation(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string VTKCOMMONCORE_EXPORT to_string(vtkArrayComponents enumerant)
Given an enumerant, return a human-presentable string with its value.
std::string ComputeLightingMultiDeclaration(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol, int noOfComponents, int independentComponents, int totalNumberOfLights, bool defaultLighting)
std::string ComputeColorUniforms(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs, int noOfComponents, vtkVolumeProperty *volProp)
virtual vtkPlaneCollection * GetClippingPlanes()
Get/Set the vtkPlaneCollection which specifies the clipping planes.
virtual int GetTransferFunctionMode()
Color-opacity transfer function mode.
vtkCamera * GetActiveCamera()
Get the current camera.
std::string TerminationInit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string TerminationDeclarationVertex(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string ComputeRayDirectionDeclaration(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol, int noOfComponents)
std::string PhaseFunctionDeclaration(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
int GetShade(int index)
Set/Get the shading of a volume.
std::string ComputeColorDeclaration(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol, int noOfComponents, int independentComponents, std::map< int, std::string > colorTableMap)
std::string CroppingImplementation(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
virtual vtkDataSet * GetInput()
Set/Get the input data.
OpenGL implementation of volume rendering through ray-casting.
static vtkOpenGLGPUVolumeRayCastMapper * SafeDownCast(vtkObjectBase *o)
std::string CroppingExit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
virtual int GetDisableGradientOpacity(int index)
Enable/Disable the gradient opacity function for the given component.
std::string ComputeRGBA2DWithGradientDeclaration(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol, int noOfComponents, int independentComponents, std::map< int, std::string > opacityTableMap, int useGradient)
std::string TerminationDeclarationFragment(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string GradientCacheDec(vtkRenderer *ren, vtkVolume *vol, vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs, int independentComponents=0)
std::string ComputeLightingDeclaration(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol, int noOfComponents, int independentComponents, int totalNumberOfLights, int numberPositionalLights, bool defaultLighting)
static vtkRectilinearGrid * SafeDownCast(vtkObjectBase *o)
topologically and geometrically regular array of data
Definition: vtkImageData.h:45
std::string ImageSampleImplementationFrag(const std::vector< std::string > &varNames, size_t usedNames)
bool HasGradientOpacity(int index=0)
Check whether or not we have the gradient opacity.
std::string ComputeColor2DYAxisDeclaration(int noOfComponents, int independentComponents, std::map< int, std::string > colorTableMap)
std::string ShadingSingleInput(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol, vtkImageData *maskInput, vtkVolumeTexture *mask, int maskType, int noOfComponents, int independentComponents=0)
std::string ImageSampleDeclarationFrag(const std::vector< std::string > &varNames, size_t usedNames)
static vtkGPUVolumeRayCastMapper * SafeDownCast(vtkObjectBase *o)
std::string RenderToImageExit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
static vtkDataSet * SafeDownCast(vtkObjectBase *o)
std::string WorkerImplementation(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string ComputeOpacityDeclaration(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol, int noOfComponents, int independentComponents, std::map< int, std::string > opacityTableMap)
std::string ComputeColor2DDeclaration(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol, int noOfComponents, int independentComponents, std::map< int, std::string > colorTableMap, int useGradient)
virtual vtkTypeBool GetUseJittering()
If UseJittering is on, each ray traversal direction will be perturbed slightly using a noise-texture ...
represents the common properties for rendering a volume.
virtual vtkTypeBool GetCropping()
Turn On/Off orthogonal cropping.
std::string Transfer2DDeclaration(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs)
std::string ComputeColorMultiDeclaration(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs, bool useGradientTF)
std::string ComputeOpacityMultiDeclaration(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs)
std::string ClippingDeclarationFragment(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string ShadingDeclarationFragment(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
virtual float GetVolumetricScatteringBlending()
This parameter controls the blending between surfacic approximation and volumetric multi-scattering...
std::string CroppingDeclarationFragment(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string DepthPassInit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string ComputeMatricesInit(vtkOpenGLGPUVolumeRayCastMapper *mapper, int numberPositionalLights)
virtual vtkTypeBool GetParallelProjection()
Set/Get the value of the ParallelProjection instance variable.
std::string ComputeOpacity2DDeclaration(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol, int noOfComponents, int independentComponents, std::map< int, std::string > opacityTableMap, int useGradient)
virtual vtkTypeBool GetUseDepthPass()
If UseDepthPass is on, the mapper will use two passes.
std::string CroppingDeclarationVertex(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string ShadingMultipleInputs(vtkVolumeMapper *mapper, vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs)
std::string ComputeTextureCoordinates(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string BaseInit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs, bool defaultLighting)
virtual vtkTypeBool IsA(const char *type)
Return 1 if this class is the same type of (or a subclass of) the named class.
std::string DepthPassExit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string RenderToImageImplementation(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string ComputeGradientDeclaration(vtkOpenGLGPUVolumeRayCastMapper *mapper, vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs)
Optimized C++ utilities for formatting values to strings and files.
std::string ShadingInit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string ComputeDensityGradientDeclaration(vtkOpenGLGPUVolumeRayCastMapper *mapper, vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs, int noOfComponents, int independentComponents, int useGradYAxis)
std::string BaseDeclarationVertex(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol, bool multipleInputs)
std::string CompositeMaskDeclarationFragment(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol, vtkImageData *maskInput, vtkVolumeTexture *mask, int maskType)
std::string ShadingDeclarationVertex(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)
std::string ClippingExit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vol)