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