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