VTK  9.1.0
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 vtkNotUsed(numberOfLights),
153  int lightingComplexity, 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  toShaderStr << "uniform vec2 in_scalarsRange[" << numInputs * 4
229  << "];\n"
230  "uniform vec3 in_cellSpacing["
231  << numInputs
232  << "];\n"
233  "\n"
234  "// Sample distance\n"
235  "uniform float in_sampleDistance;\n"
236  "\n"
237  "// Scales\n"
238  "uniform vec2 in_windowLowerLeftCorner;\n"
239  "uniform vec2 in_inverseOriginalWindowSize;\n"
240  "uniform vec2 in_inverseWindowSize;\n"
241  "uniform vec3 in_textureExtentsMax;\n"
242  "uniform vec3 in_textureExtentsMin;\n"
243  "\n"
244  "// Material and lighting\n"
245  "uniform vec3 in_diffuse[4];\n"
246  "uniform vec3 in_ambient[4];\n"
247  "uniform vec3 in_specular[4];\n"
248  "uniform float in_shininess[4];\n"
249  "\n"
250  "// Others\n"
251  "vec3 g_rayJitter = vec3(0.0);\n"
252  "\n"
253  "uniform vec2 in_averageIPRange;\n";
254 
255  toShaderStr << "vec4 g_eyePosObjs[" << numInputs << "];\n";
256 
257  const bool hasGradientOpacity = HasGradientOpacity(inputs);
258  if (lightingComplexity > 0 || hasGradientOpacity)
259  {
260  toShaderStr << "uniform bool in_twoSidedLighting;\n";
261  }
262 
263  if (lightingComplexity == 3)
264  {
265  toShaderStr << "vec4 g_fragWorldPos;\n"
266  "uniform int in_numberOfLights;\n"
267  "uniform vec3 in_lightAmbientColor[6];\n"
268  "uniform vec3 in_lightDiffuseColor[6];\n"
269  "uniform vec3 in_lightSpecularColor[6];\n"
270  "uniform vec3 in_lightDirection[6];\n"
271  "uniform vec3 in_lightPosition[6];\n"
272  "uniform vec3 in_lightAttenuation[6];\n"
273  "uniform float in_lightConeAngle[6];\n"
274  "uniform float in_lightExponent[6];\n"
275  "uniform int in_lightPositional[6];\n";
276  }
277  else if (lightingComplexity == 2)
278  {
279  toShaderStr << "vec4 g_fragWorldPos;\n"
280  "uniform int in_numberOfLights;\n"
281  "uniform vec3 in_lightAmbientColor[6];\n"
282  "uniform vec3 in_lightDiffuseColor[6];\n"
283  "uniform vec3 in_lightSpecularColor[6];\n"
284  "uniform vec3 in_lightDirection[6];\n";
285  }
286  else
287  {
288  toShaderStr << "uniform vec3 in_lightAmbientColor[1];\n"
289  "uniform vec3 in_lightDiffuseColor[1];\n"
290  "uniform vec3 in_lightSpecularColor[1];\n"
291  "vec4 g_lightPosObj["
292  << numInputs
293  << "];\n"
294  "vec3 g_ldir["
295  << numInputs
296  << "];\n"
297  "vec3 g_vdir["
298  << numInputs
299  << "];\n"
300  "vec3 g_h["
301  << numInputs << "];\n";
302  }
303 
304  if (noOfComponents > 1 && independentComponents)
305  {
306  toShaderStr << "uniform vec4 in_componentWeight;\n";
307  }
308 
310  glMapper->GetUseDepthPass())
311  {
312  toShaderStr << "uniform sampler2D in_depthPassSampler;\n";
313  }
314 
316  {
317  toShaderStr << "#if NUMBER_OF_CONTOURS\n"
318  "uniform float in_isosurfacesValues[NUMBER_OF_CONTOURS];\n"
319  "\n"
320  "int findIsoSurfaceIndex(float scalar, float array[NUMBER_OF_CONTOURS+2])\n"
321  "{\n"
322  " int index = NUMBER_OF_CONTOURS >> 1;\n"
323  " while (scalar > array[index]) ++index;\n"
324  " while (scalar < array[index]) --index;\n"
325  " return index;\n"
326  "}\n"
327  "#endif\n";
328  }
329  else if (glMapper->GetBlendMode() == vtkVolumeMapper::SLICE_BLEND)
330  {
331  vtkVolume* vol = inputs.begin()->second.Volume;
332  vtkImplicitFunction* func = vol->GetProperty()->GetSliceFunction();
333 
334  if (func && func->IsA("vtkPlane"))
335  {
336  toShaderStr
337  << "uniform vec3 in_slicePlaneOrigin;\n"
338  "uniform vec3 in_slicePlaneNormal;\n"
339  "vec3 g_intersection;\n"
340  "\n"
341  "float intersectRayPlane(vec3 rayOrigin, vec3 rayDir)\n"
342  "{\n"
343  " vec4 planeNormal = in_inverseVolumeMatrix[0] * vec4(in_slicePlaneNormal, 0.0);\n"
344  " float denom = dot(planeNormal.xyz, rayDir);\n"
345  " if (abs(denom) > 1e-6)\n"
346  " {\n"
347  " vec4 planeOrigin = in_inverseVolumeMatrix[0] * vec4(in_slicePlaneOrigin, 1.0);\n"
348  " return dot(planeOrigin.xyz - rayOrigin, planeNormal.xyz) / denom;\n"
349  " }\n"
350  " return -1.0;\n"
351  "}\n";
352  }
353  }
354 
355  return toShaderStr.str();
356 }
357 
358 //--------------------------------------------------------------------------
360  vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, int lightingComplexity)
361 {
363  vtkVolume* vol = inputs.begin()->second.Volume;
364  const int numInputs = static_cast<int>(inputs.size());
365 
366  std::ostringstream shaderStr;
368  glMapper->GetUseDepthPass() && glMapper->GetBlendMode() == vtkVolumeMapper::COMPOSITE_BLEND)
369  {
370  shaderStr << "\
371  \n //\
372  \n vec2 fragTexCoord2 = (gl_FragCoord.xy - in_windowLowerLeftCorner) *\
373  \n in_inverseWindowSize;\
374  \n vec4 depthValue = texture2D(in_depthPassSampler, fragTexCoord2);\
375  \n vec4 rayOrigin = WindowToNDC(gl_FragCoord.x, gl_FragCoord.y, depthValue.x);\
376  \n\
377  \n // From normalized device coordinates to eye coordinates.\
378  \n // in_projectionMatrix is inversed because of way VT\
379  \n // From eye coordinates to texture coordinates\
380  \n rayOrigin = in_inverseTextureDatasetMatrix[0] *\
381  \n in_inverseVolumeMatrix[0] *\
382  \n in_inverseModelViewMatrix *\
383  \n in_inverseProjectionMatrix *\
384  \n rayOrigin;\
385  \n rayOrigin /= rayOrigin.w;\
386  \n g_rayOrigin = rayOrigin.xyz;";
387  }
388  else
389  {
390  shaderStr << "\
391  \n // Get the 3D texture coordinates for lookup into the in_volume dataset\
392  \n g_rayOrigin = ip_textureCoords.xyz;";
393  }
394 
395  shaderStr << "\
396  \n\
397  \n // Eye position in dataset space\
398  \n g_eyePosObj = in_inverseVolumeMatrix[0] * vec4(in_cameraPos, 1.0);";
399  for (int i = 0; i < numInputs; ++i)
400  {
401  // In multi-volume case the first volume matrix is of the bounding box
402  shaderStr << "\
403  \n g_eyePosObjs["
404  << i << "] = in_inverseVolumeMatrix[" << (numInputs > 1 ? i + 1 : i)
405  << "] * vec4(in_cameraPos, 1.0);";
406  }
407  shaderStr << "\n\
408  \n // Getting the ray marching direction (in dataset space)\
409  \n vec3 rayDir = computeRayDirection();\
410  \n\
411  \n // 2D Texture fragment coordinates [0,1] from fragment coordinates.\
412  \n // The frame buffer texture has the size of the plain buffer but \
413  \n // we use a fraction of it. The texture coordinate is less than 1 if\
414  \n // the reduction factor is less than 1.\
415  \n // Device coordinates are between -1 and 1. We need texture\
416  \n // coordinates between 0 and 1. The in_depthSampler\
417  \n // buffer has the original size buffer.\
418  \n vec2 fragTexCoord = (gl_FragCoord.xy - in_windowLowerLeftCorner) *\
419  \n in_inverseWindowSize;\
420  \n\
421  \n // Multiply the raymarching direction with the step size to get the\
422  \n // sub-step size we need to take at each raymarching step\
423  \n g_dirStep = (ip_inverseTextureDataAdjusted *\
424  \n vec4(rayDir, 0.0)).xyz * in_sampleDistance;\
425  \n";
426 
427  if (glMapper->GetBlendMode() != vtkVolumeMapper::SLICE_BLEND)
428  {
429  // Intersection is computed with g_rayOrigin, so we should not modify it with Slice mode
430  if (glMapper->GetUseJittering())
431  {
432  shaderStr << "\
433  \n float jitterValue = texture2D(in_noiseSampler, gl_FragCoord.xy /\
434  vec2(textureSize(in_noiseSampler, 0))).x;\
435  \n g_rayJitter = g_dirStep * jitterValue;\
436  \n";
437  }
438  else
439  {
440  shaderStr << "\
441  \n g_rayJitter = g_dirStep;\
442  \n";
443  }
444  shaderStr << "\
445  \n g_rayOrigin += g_rayJitter;\
446  \n";
447  }
448 
449  shaderStr << "\
450  \n // Flag to determine if voxel should be considered for the rendering\
451  \n g_skip = false;";
452 
453  if (vol->GetProperty()->GetShade() && lightingComplexity == 1)
454  {
455  shaderStr << "\
456  \n // Light position in dataset space";
457  for (int i = 0; i < numInputs; ++i)
458  {
459  // In multi-volume case the first volume matrix is of the bounding box
460  shaderStr << "\
461  \n g_lightPosObj["
462  << i << "] = (in_inverseVolumeMatrix[" << (numInputs > 1 ? i + 1 : i) << "] *\
463  \n vec4(in_cameraPos, 1.0));\
464  \n g_ldir["
465  << i << "] = normalize(g_lightPosObj[" << i << "].xyz - ip_vertexPos);\
466  \n g_vdir["
467  << i << "] = normalize(g_eyePosObjs[" << i << "].xyz - ip_vertexPos);\
468  \n g_h["
469  << i << "] = normalize(g_ldir[" << i << "] + g_vdir[" << i << "]);";
470  }
471  }
472 
473  return shaderStr.str();
474 }
475 
476 //--------------------------------------------------------------------------
478  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
479 {
481 
482  std::string str("\
483  \n g_skip = false;");
484 
485  // Blanking support
487  bool blankCells = (dataSet->GetCellGhostArray() != nullptr);
488  bool blankPoints = (dataSet->GetPointGhostArray() != nullptr);
489  if (blankPoints || blankCells)
490  {
491  str += std::string("\
492  \n // Check whether the neighboring points/cells are blank.\
493  \n // Note the half cellStep because texels are point centered.\
494  \n vec3 xvec = vec3(in_cellStep[0].x/2.0, 0.0, 0.0);\
495  \n vec3 yvec = vec3(0.0, in_cellStep[0].y/2.0, 0.0);\
496  \n vec3 zvec = vec3(0.0, 0.0, in_cellStep[0].z/2.0);\
497  \n vec3 texPosPVec[3];\
498  \n texPosPVec[0] = g_dataPos + xvec;\
499  \n texPosPVec[1] = g_dataPos + yvec;\
500  \n texPosPVec[2] = g_dataPos + zvec;\
501  \n vec3 texPosNVec[3];\
502  \n texPosNVec[0] = g_dataPos - xvec;\
503  \n texPosNVec[1] = g_dataPos - yvec;\
504  \n texPosNVec[2] = g_dataPos - zvec;\
505  \n vec4 blankValue = texture3D(in_blanking, g_dataPos);\
506  \n vec4 blankValueXP = texture3D(in_blanking, texPosPVec[0]);\
507  \n vec4 blankValueYP = texture3D(in_blanking, texPosPVec[1]);\
508  \n vec4 blankValueZP = texture3D(in_blanking, texPosPVec[2]);\
509  \n vec4 blankValueXN = texture3D(in_blanking, texPosNVec[0]);\
510  \n vec4 blankValueYN = texture3D(in_blanking, texPosNVec[1]);\
511  \n vec4 blankValueZN = texture3D(in_blanking, texPosNVec[2]);\
512  \n vec3 blankValuePx;\
513  \n blankValuePx[0] = blankValueXP.x;\
514  \n blankValuePx[1] = blankValueYP.x;\
515  \n blankValuePx[2] = blankValueZP.x;\
516  \n vec3 blankValuePy;\
517  \n blankValuePy[0] = blankValueXP.y;\
518  \n blankValuePy[1] = blankValueYP.y;\
519  \n blankValuePy[2] = blankValueZP.y;\
520  \n vec3 blankValueNx;\
521  \n blankValueNx[0] = blankValueXN.x;\
522  \n blankValueNx[1] = blankValueYN.x;\
523  \n blankValueNx[2] = blankValueZN.x;\
524  \n vec3 blankValueNy;\
525  \n blankValueNy[0] = blankValueXN.y;\
526  \n blankValueNy[1] = blankValueYN.y;\
527  \n blankValueNy[2] = blankValueZN.y;\
528  \n");
529  if (blankPoints)
530  {
531  str += std::string("\
532  \n // If the current or neighboring points\
533  \n // (that belong to cells that share this texel) are blanked,\
534  \n // skip the texel. In other words, if point 1 were blank,\
535  \n // texels 0, 1 and 2 would have to be skipped.\
536  \n if (blankValue.x > 0.0 ||\
537  \n any(greaterThan(blankValueNx, vec3(0.0))) ||\
538  \n any(greaterThan(blankValuePx, vec3(0.0))))\
539  \n {\
540  \n // skip this texel\
541  \n g_skip = true;\
542  \n }\
543  \n");
544  if (blankCells)
545  {
546  str += std::string("\
547  \n // If the current or previous cells (that share this texel)\
548  \n // are blanked, skip the texel. In other words, if cell 1\
549  \n // is blanked, texels 1 and 2 would have to be skipped.\
550  \n else if (blankValue.y > 0.0 ||\
551  \n any(greaterThan(blankValuePy, vec3(0.0))) ||\
552  \n any(greaterThan(blankValueNy, vec3(0.0))))\
553  \n {\
554  \n // skip this texel\
555  \n g_skip = true;\
556  \n }\
557  \n");
558  }
559  }
560  else if (blankCells)
561  {
562  str += std::string("\
563  \n // If the current or previous cells (that share this texel)\
564  \n // are blanked, skip the texel. In other words, if cell 1\
565  \n // is blanked, texels 1 and 2 would have to be skipped.\
566  \n if (blankValue.x > 0.0 ||\
567  \n any(greaterThan(blankValueNx, vec3(0.0))) ||\
568  \n any(greaterThan(blankValuePx, vec3(0.0))))\
569  \n {\
570  \n // skip this texel\
571  \n g_skip = true;\
572  \n }\
573  \n");
574  }
575  }
576 
577  if (glMapper->GetBlendMode() == vtkVolumeMapper::SLICE_BLEND)
578  {
579  str += std::string("\
580  \n g_dataPos = g_intersection;\
581  \n");
582  }
583 
584  return str;
585 }
586 
587 //--------------------------------------------------------------------------
589  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
590 {
591  return std::string();
592 }
593 
594 //--------------------------------------------------------------------------
596  int independentComponents, std::map<int, std::string> gradientTableMap)
597 {
598  auto volProperty = vol->GetProperty();
599  std::ostringstream ss;
600  if (volProperty->HasGradientOpacity())
601  {
602  ss << "uniform sampler2D " << ArrayBaseName(gradientTableMap[0]) << "[" << noOfComponents
603  << "];\n";
604  }
605  bool useLabelGradientOpacity =
606  (volProperty->HasLabelGradientOpacity() && (noOfComponents == 1 || !independentComponents));
607  if (useLabelGradientOpacity)
608  {
609  ss << "uniform sampler2D in_labelMapGradientOpacity;\n";
610  }
611 
612  std::string shaderStr = ss.str();
613  if (volProperty->HasGradientOpacity() && (noOfComponents == 1 || !independentComponents))
614  {
615  shaderStr += std::string("\
616  \nfloat computeGradientOpacity(vec4 grad)\
617  \n {\
618  \n return texture2D(" +
619  gradientTableMap[0] + ", vec2(grad.w, 0.0)).r;\
620  \n }");
621  }
622  else if (noOfComponents > 1 && independentComponents && volProperty->HasGradientOpacity())
623  {
624  shaderStr += std::string("\
625  \nfloat computeGradientOpacity(vec4 grad, int component)\
626  \n {");
627 
628  for (int i = 0; i < noOfComponents; ++i)
629  {
630  std::ostringstream toString;
631  toString << i;
632  shaderStr += std::string("\
633  \n if (component == " +
634  toString.str() + ")");
635 
636  shaderStr += std::string("\
637  \n {\
638  \n return texture2D(" +
639  gradientTableMap[i] + ", vec2(grad.w, 0.0)).r;\
640  \n }");
641  }
642 
643  shaderStr += std::string("\
644  \n }");
645  }
646 
647  if (useLabelGradientOpacity)
648  {
649  shaderStr += std::string("\
650  \nfloat computeGradientOpacityForLabel(vec4 grad, float label)\
651  \n {\
652  \n return texture2D(in_labelMapGradientOpacity, vec2(grad.w, label)).r;\
653  \n }");
654  }
655 
656  return shaderStr;
657 }
658 
659 //--------------------------------------------------------------------------
662 {
663  const bool hasLighting = HasLighting(inputs);
664  const bool hasGradientOp = HasGradientOpacity(inputs);
665 
666  std::string shaderStr;
667  if (hasLighting || hasGradientOp)
668  {
669  shaderStr += std::string(
670  "// c is short for component\n"
671  "vec4 computeGradient(in vec3 texPos, in int c, in sampler3D volume,in int index)\n"
672  "{\n"
673  " // Approximate Nabla(F) derivatives with central differences.\n"
674  " vec3 g1; // F_front\n"
675  " vec3 g2; // F_back\n"
676  " vec3 xvec = vec3(in_cellStep[index].x, 0.0, 0.0);\n"
677  " vec3 yvec = vec3(0.0, in_cellStep[index].y, 0.0);\n"
678  " vec3 zvec = vec3(0.0, 0.0, in_cellStep[index].z);\n"
679  " vec3 texPosPvec[3];\n"
680  " texPosPvec[0] = texPos + xvec;\n"
681  " texPosPvec[1] = texPos + yvec;\n"
682  " texPosPvec[2] = texPos + zvec;\n"
683  " vec3 texPosNvec[3];\n"
684  " texPosNvec[0] = texPos - xvec;\n"
685  " texPosNvec[1] = texPos - yvec;\n"
686  " texPosNvec[2] = texPos - zvec;\n"
687  " g1.x = texture3D(volume, vec3(texPosPvec[0]))[c];\n"
688  " g1.y = texture3D(volume, vec3(texPosPvec[1]))[c];\n"
689  " g1.z = texture3D(volume, vec3(texPosPvec[2]))[c];\n"
690  " g2.x = texture3D(volume, vec3(texPosNvec[0]))[c];\n"
691  " g2.y = texture3D(volume, vec3(texPosNvec[1]))[c];\n"
692  " g2.z = texture3D(volume, vec3(texPosNvec[2]))[c];\n"
693  "\n");
694  if (UseClippedVoxelIntensity(inputs) && mapper->GetClippingPlanes())
695  {
696  shaderStr +=
697  std::string(" vec4 g1ObjDataPos[3], g2ObjDataPos[3];\n"
698  " for (int i = 0; i < 3; ++i)\n"
699  " {\n"
700  " g1ObjDataPos[i] = clip_texToObjMat * vec4(texPosPvec[i], 1.0);\n"
701  " if (g1ObjDataPos[i].w != 0.0)\n"
702  " {\n"
703  " g1ObjDataPos[i] /= g1ObjDataPos[i].w;\n"
704  " }\n"
705  " g2ObjDataPos[i] = clip_texToObjMat * vec4(texPosNvec[i], 1.0);\n"
706  " if (g2ObjDataPos[i].w != 0.0)\n"
707  " {\n"
708  " g2ObjDataPos[i] /= g2ObjDataPos[i].w;\n"
709  " }\n"
710  " }\n"
711  "\n"
712  " for (int i = 0; i < clip_numPlanes && !g_skip; i = i + 6)\n"
713  " {\n"
714  " vec3 planeOrigin = vec3(in_clippingPlanes[i + 1],\n"
715  " in_clippingPlanes[i + 2],\n"
716  " in_clippingPlanes[i + 3]);\n"
717  " vec3 planeNormal = normalize(vec3(in_clippingPlanes[i + 4],\n"
718  " in_clippingPlanes[i + 5],\n"
719  " in_clippingPlanes[i + 6]));\n"
720  " for (int j = 0; j < 3; ++j)\n"
721  " {\n"
722  " if (dot(vec3(planeOrigin - g1ObjDataPos[j].xyz), planeNormal) > 0)\n"
723  " {\n"
724  " g1[j] = in_clippedVoxelIntensity;\n"
725  " }\n"
726  " if (dot(vec3(planeOrigin - g2ObjDataPos[j].xyz), planeNormal) > 0)\n"
727  " {\n"
728  " g2[j] = in_clippedVoxelIntensity;\n"
729  " }\n"
730  " }\n"
731  " }\n"
732  "\n");
733  }
734  shaderStr += std::string(" // Apply scale and bias to the fetched values.\n"
735  " g1 = g1 * in_volume_scale[index][c] + in_volume_bias[index][c];\n"
736  " g2 = g2 * in_volume_scale[index][c] + in_volume_bias[index][c];\n"
737  "\n");
738  if (!hasGradientOp)
739  {
740  shaderStr +=
741  std::string(" // Central differences: (F_front - F_back) / 2h\n"
742  " // This version of computeGradient() is only used for lighting\n"
743  " // calculations (only direction matters), hence the difference is\n"
744  " // not scaled by 2h and a dummy gradient mag is returned (-1.).\n"
745  " return vec4((g1 - g2) / in_cellSpacing[index], -1.0);\n"
746  "}\n");
747  }
748  else
749  {
750  shaderStr += std::string(
751  " // Scale values the actual scalar range.\n"
752  " float range = in_scalarsRange[4*index+c][1] - in_scalarsRange[4*index+c][0];\n"
753  " g1 = in_scalarsRange[4*index+c][0] + range * g1;\n"
754  " g2 = in_scalarsRange[4*index+c][0] + range * g2;\n"
755  "\n"
756  " // Central differences: (F_front - F_back) / 2h\n"
757  " g2 = g1 - g2;\n"
758  "\n"
759  " float avgSpacing = (in_cellSpacing[index].x +\n"
760  " in_cellSpacing[index].y + in_cellSpacing[index].z) / 3.0;\n"
761  " vec3 aspect = in_cellSpacing[index] * 2.0 / avgSpacing;\n"
762  " g2 /= aspect;\n"
763  " float grad_mag = length(g2);\n"
764  "\n"
765  " // Handle normalizing with grad_mag == 0.0\n"
766  " g2 = grad_mag > 0.0 ? normalize(g2) : vec3(0.0);\n"
767  "\n"
768  " // Since the actual range of the gradient magnitude is unknown,\n"
769  " // assume it is in the range [0, 0.25 * dataRange].\n"
770  " range = range != 0 ? range : 1.0;\n"
771  " grad_mag = grad_mag / (0.25 * range);\n"
772  " grad_mag = clamp(grad_mag, 0.0, 1.0);\n"
773  "\n"
774  " return vec4(g2.xyz, grad_mag);\n"
775  "}\n");
776  }
777  }
778  else
779  {
780  shaderStr += std::string(
781  "vec4 computeGradient(in vec3 texPos, in int c, in sampler3D volume, in int index)\n"
782  "{\n"
783  " return vec4(0.0);\n"
784  "}\n");
785  }
786 
787  return shaderStr;
788 }
789 
790 //--------------------------------------------------------------------------
792  vtkVolume* vol, int noOfComponents, int independentComponents, int vtkNotUsed(numberOfLights),
793  int lightingComplexity)
794 {
795  vtkVolumeProperty* volProperty = vol->GetProperty();
796  std::string shaderStr = std::string("\
797  \nvec4 computeLighting(vec4 color, int component, float label)\
798  \n {\
799  \n vec4 finalColor = vec4(0.0);");
800 
801  // Shading for composite blending only
802  int const shadeReqd = volProperty->GetShade() &&
806 
807  int const transferMode = volProperty->GetTransferFunctionMode();
808 
809  if (shadeReqd || volProperty->HasGradientOpacity() || volProperty->HasLabelGradientOpacity())
810  {
811  switch (transferMode)
812  {
814  shaderStr += std::string(
815  " // Compute gradient function only once\n"
816  " vec4 gradient = computeGradient(g_dataPos, component, in_volume[0], 0);\n");
817  break;
819  shaderStr += std::string(" // TransferFunction2D is enabled so the gradient for\n"
820  " // each component has already been cached\n"
821  " vec4 gradient = g_gradients_0[component];\n");
822  break;
823  }
824  }
825 
826  if (shadeReqd)
827  {
828  if (lightingComplexity == 1)
829  {
830  shaderStr += std::string("\
831  \n vec3 diffuse = vec3(0.0);\
832  \n vec3 specular = vec3(0.0);\
833  \n vec3 normal = gradient.xyz;\
834  \n float normalLength = length(normal);\
835  \n if (normalLength > 0.0)\
836  \n {\
837  \n normal = normalize(normal);\
838  \n }\
839  \n else\
840  \n {\
841  \n normal = vec3(0.0, 0.0, 0.0);\
842  \n }\
843  \n float nDotL = dot(normal, g_ldir[0]);\
844  \n float nDotH = dot(normal, g_h[0]);\
845  \n if (nDotL < 0.0 && in_twoSidedLighting)\
846  \n {\
847  \n nDotL = -nDotL;\
848  \n }\
849  \n if (nDotH < 0.0 && in_twoSidedLighting)\
850  \n {\
851  \n nDotH = -nDotH;\
852  \n }\
853  \n if (nDotL > 0.0)\
854  \n {\
855  \n diffuse = nDotL * in_diffuse[component] *\
856  \n in_lightDiffuseColor[0] * color.rgb;\
857  \n }\
858  \n specular = pow(nDotH, in_shininess[component]) *\
859  \n in_specular[component] *\
860  \n in_lightSpecularColor[0];\
861  \n // For the headlight, ignore the light's ambient color\
862  \n // for now as it is causing the old mapper tests to fail\
863  \n finalColor.xyz = in_ambient[component] * color.rgb +\
864  \n diffuse + specular;\
865  \n");
866  }
867  else if (lightingComplexity == 2)
868  {
869  shaderStr += std::string("\
870  \n g_fragWorldPos = in_modelViewMatrix * in_volumeMatrix[0] *\
871  \n in_textureDatasetMatrix[0] * vec4(-g_dataPos, 1.0);\
872  \n if (g_fragWorldPos.w != 0.0)\
873  \n {\
874  \n g_fragWorldPos /= g_fragWorldPos.w;\
875  \n }\
876  \n vec3 vdir = normalize(g_fragWorldPos.xyz);\
877  \n vec3 normal = gradient.xyz;\
878  \n vec3 ambient = vec3(0.0);\
879  \n vec3 diffuse = vec3(0.0);\
880  \n vec3 specular = vec3(0.0);\
881  \n float normalLength = length(normal);\
882  \n if (normalLength > 0.0)\
883  \n {\
884  \n normal = normalize((in_textureToEye[0] * vec4(normal, 0.0)).xyz);\
885  \n }\
886  \n else\
887  \n {\
888  \n normal = vec3(0.0, 0.0, 0.0);\
889  \n }\
890  \n for (int lightNum = 0; lightNum < in_numberOfLights; lightNum++)\
891  \n {\
892  \n vec3 ldir = in_lightDirection[lightNum].xyz;\
893  \n vec3 h = normalize(ldir + vdir);\
894  \n float nDotH = dot(normal, h);\
895  \n if (nDotH < 0.0 && in_twoSidedLighting)\
896  \n {\
897  \n nDotH = -nDotH;\
898  \n }\
899  \n float nDotL = dot(normal, ldir);\
900  \n if (nDotL < 0.0 && in_twoSidedLighting)\
901  \n {\
902  \n nDotL = -nDotL;\
903  \n }\
904  \n if (nDotL > 0.0)\
905  \n {\
906  \n diffuse += in_lightDiffuseColor[lightNum] * nDotL;\
907  \n }\
908  \n if (nDotH > 0.0)\
909  \n {\
910  \n specular = in_lightSpecularColor[lightNum] *\
911  \n pow(nDotH, in_shininess[component]);\
912  \n }\
913  \n ambient += in_lightAmbientColor[lightNum];\
914  \n }\
915  \n finalColor.xyz = in_ambient[component] * ambient +\
916  \n in_diffuse[component] * diffuse * color.rgb +\
917  \n in_specular[component] * specular;");
918  }
919  else if (lightingComplexity == 3)
920  {
921  shaderStr += std::string("\
922  \n g_fragWorldPos = in_modelViewMatrix * in_volumeMatrix[0] *\
923  \n in_textureDatasetMatrix[0] * vec4(g_dataPos, 1.0);\
924  \n if (g_fragWorldPos.w != 0.0)\
925  \n {\
926  \n g_fragWorldPos /= g_fragWorldPos.w;\
927  \n }\
928  \n vec3 viewDirection = normalize(-g_fragWorldPos.xyz);\
929  \n vec3 ambient = vec3(0,0,0);\
930  \n vec3 diffuse = vec3(0,0,0);\
931  \n vec3 specular = vec3(0,0,0);\
932  \n vec3 vertLightDirection;\
933  \n vec3 normal = normalize((in_textureToEye[0] * vec4(gradient.xyz, 0.0)).xyz);\
934  \n vec3 lightDir;\
935  \n for (int lightNum = 0; lightNum < in_numberOfLights; lightNum++)\
936  \n {\
937  \n float attenuation = 1.0;\
938  \n // directional\
939  \n lightDir = in_lightDirection[lightNum];\
940  \n if (in_lightPositional[lightNum] == 0)\
941  \n {\
942  \n vertLightDirection = lightDir;\
943  \n }\
944  \n else\
945  \n {\
946  \n vertLightDirection = (g_fragWorldPos.xyz - in_lightPosition[lightNum]);\
947  \n float distance = length(vertLightDirection);\
948  \n vertLightDirection = normalize(vertLightDirection);\
949  \n attenuation = 1.0 /\
950  \n (in_lightAttenuation[lightNum].x\
951  \n + in_lightAttenuation[lightNum].y * distance\
952  \n + in_lightAttenuation[lightNum].z * distance * distance);\
953  \n // per OpenGL standard cone angle is 90 or less for a spot light\
954  \n if (in_lightConeAngle[lightNum] <= 90.0)\
955  \n {\
956  \n float coneDot = dot(vertLightDirection, lightDir);\
957  \n // if inside the cone\
958  \n if (coneDot >= cos(radians(in_lightConeAngle[lightNum])))\
959  \n {\
960  \n attenuation = attenuation * pow(coneDot, in_lightExponent[lightNum]);\
961  \n }\
962  \n else\
963  \n {\
964  \n attenuation = 0.0;\
965  \n }\
966  \n }\
967  \n }\
968  \n // diffuse and specular lighting\
969  \n float nDotL = dot(normal, vertLightDirection);\
970  \n if (nDotL < 0.0 && in_twoSidedLighting)\
971  \n {\
972  \n nDotL = -nDotL;\
973  \n }\
974  \n if (nDotL > 0.0)\
975  \n {\
976  \n float df = max(0.0, attenuation * nDotL);\
977  \n diffuse += (df * in_lightDiffuseColor[lightNum]);\
978  \n }\
979  \n vec3 h = normalize(vertLightDirection + viewDirection);\
980  \n float nDotH = dot(normal, h);\
981  \n if (nDotH < 0.0 && in_twoSidedLighting)\
982  \n {\
983  \n nDotH = -nDotH;\
984  \n }\
985  \n if (nDotH > 0.0)\
986  \n {\
987  \n float sf = attenuation * pow(nDotH, in_shininess[component]);\
988  \n specular += (sf * in_lightSpecularColor[lightNum]);\
989  \n }\
990  \n ambient += in_lightAmbientColor[lightNum];\
991  \n }\
992  \n finalColor.xyz = in_ambient[component] * ambient +\
993  \n in_diffuse[component] * diffuse * color.rgb +\
994  \n in_specular[component] * specular;\
995  ");
996  }
997  }
998  else
999  {
1000  shaderStr += std::string("\n finalColor = vec4(color.rgb, 0.0);");
1001  }
1002 
1003  auto glMapper = vtkOpenGLGPUVolumeRayCastMapper::SafeDownCast(mapper);
1004  // For 1D transfers only (2D transfer functions hold scalar and
1005  // gradient-magnitude opacities combined in the same table).
1006  // For multiple inputs, a different computeGradientOpacity() signature
1007  // is defined.
1008  if (transferMode == vtkVolumeProperty::TF_1D && glMapper->GetInputCount() == 1)
1009  {
1010  if (noOfComponents == 1 || !independentComponents)
1011  {
1012  if (volProperty->HasGradientOpacity())
1013  {
1014  shaderStr += std::string("\
1015  \n if (gradient.w >= 0.0 && label == 0.0)\
1016  \n {\
1017  \n color.a *= computeGradientOpacity(gradient);\
1018  \n }");
1019  }
1020  if (volProperty->HasLabelGradientOpacity())
1021  {
1022  shaderStr += std::string("\
1023  \n if (gradient.w >= 0.0 && label > 0.0)\
1024  \n {\
1025  \n color.a *= computeGradientOpacityForLabel(gradient, label);\
1026  \n }");
1027  }
1028  }
1029  else if (noOfComponents > 1 && independentComponents && volProperty->HasGradientOpacity())
1030  {
1031  shaderStr += std::string("\
1032  \n if (gradient.w >= 0.0)\
1033  \n {\
1034  \n for (int i = 0; i < in_noOfComponents; ++i)\
1035  \n {\
1036  \n color.a = color.a *\
1037  \n computeGradientOpacity(gradient, i) * in_componentWeight[i];\
1038  \n }\
1039  \n }");
1040  }
1041  }
1042 
1043  shaderStr += std::string("\
1044  \n finalColor.a = color.a;\
1045  \n return finalColor;\
1046  \n }");
1047 
1048  return shaderStr;
1049 }
1050 
1051 //--------------------------------------------------------------------------
1053  vtkVolume* vol, int noOfComponents, int independentComponents, int vtkNotUsed(numberOfLights),
1054  int lightingComplexity)
1055 {
1056  vtkVolumeProperty* volProperty = vol->GetProperty();
1057  std::string shaderStr = std::string("\
1058  \nvec4 computeLighting(vec3 texPos, vec4 color, const in sampler2D gradientTF, const in sampler3D volume, const int volIdx, int component)\
1059  \n {\
1060  \n vec4 finalColor = vec4(0.0);");
1061 
1062  // Shading for composite blending only
1063  int const shadeReqd = volProperty->GetShade() &&
1066 
1067  int const transferMode = volProperty->GetTransferFunctionMode();
1068 
1069  if ((shadeReqd || volProperty->HasGradientOpacity()) && transferMode == vtkVolumeProperty::TF_1D)
1070  {
1071  shaderStr +=
1072  std::string(" // Compute gradient function only once\n"
1073  " vec4 gradient = computeGradient(texPos, component, volume, volIdx);\n");
1074  }
1075 
1076  if (shadeReqd && lightingComplexity == 1)
1077  {
1078  shaderStr += std::string("\
1079  \n vec3 diffuse = vec3(0.0);\
1080  \n vec3 specular = vec3(0.0);\
1081  \n vec3 normal = gradient.xyz;\
1082  \n float normalLength = length(normal);\
1083  \n if (normalLength > 0.0)\
1084  \n {\
1085  \n normal = normalize(normal);\
1086  \n }\
1087  \n else\
1088  \n {\
1089  \n normal = vec3(0.0, 0.0, 0.0);\
1090  \n }\
1091  \n float nDotL = dot(normal, g_ldir[volIdx]);\
1092  \n float nDotH = dot(normal, g_h[volIdx]);\
1093  \n if (nDotL < 0.0 && in_twoSidedLighting)\
1094  \n {\
1095  \n nDotL = -nDotL;\
1096  \n }\
1097  \n if (nDotH < 0.0 && in_twoSidedLighting)\
1098  \n {\
1099  \n nDotH = -nDotH;\
1100  \n }\
1101  \n if (nDotL > 0.0)\
1102  \n {\
1103  \n diffuse = nDotL * in_diffuse[component] *\
1104  \n in_lightDiffuseColor[0] * color.rgb;\
1105  \n }\
1106  \n specular = pow(nDotH, in_shininess[component]) *\
1107  \n in_specular[component] *\
1108  \n in_lightSpecularColor[0];\
1109  \n // For the headlight, ignore the light's ambient color\
1110  \n // for now as it is causing the old mapper tests to fail\
1111  \n finalColor.xyz = in_ambient[component] * color.rgb +\
1112  \n diffuse + specular;\
1113  \n");
1114  }
1115  else
1116  {
1117  shaderStr += std::string("\n finalColor = vec4(color.rgb, 0.0);");
1118  }
1119 
1120  // For 1D transfers only (2D transfer functions hold scalar and
1121  // gradient-magnitude opacities combined in the same table).
1122  if (transferMode == vtkVolumeProperty::TF_1D)
1123  {
1124  if (volProperty->HasGradientOpacity() && (noOfComponents == 1 || !independentComponents))
1125  {
1126  shaderStr += std::string("\
1127  \n if (gradient.w >= 0.0)\
1128  \n {\
1129  \n color.a = color.a *\
1130  \n computeGradientOpacity(gradient, gradientTF);\
1131  \n }");
1132  }
1133  }
1134 
1135  shaderStr += std::string("\
1136  \n finalColor.a = color.a;\
1137  \n return clamp(finalColor, 0.0, 1.0);\
1138  \n }");
1139 
1140  return shaderStr;
1141 }
1142 
1143 //--------------------------------------------------------------------------
1145  vtkVolume* vtkNotUsed(vol), int vtkNotUsed(noOfComponents))
1146 {
1147  if (!ren->GetActiveCamera()->GetParallelProjection())
1148  {
1149  return std::string("\
1150  \nvec3 computeRayDirection()\
1151  \n {\
1152  \n return normalize(ip_vertexPos.xyz - g_eyePosObj.xyz);\
1153  \n }");
1154  }
1155  else
1156  {
1157  return std::string("\
1158  \nuniform vec3 in_projectionDirection;\
1159  \nvec3 computeRayDirection()\
1160  \n {\
1161  \n return normalize((in_inverseVolumeMatrix[0] *\
1162  \n vec4(in_projectionDirection, 0.0)).xyz);\
1163  \n }");
1164  }
1165 }
1166 
1167 //--------------------------------------------------------------------------
1169  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
1170  int independentComponents, std::map<int, std::string> colorTableMap)
1171 {
1172  std::ostringstream ss;
1173  ss << "uniform sampler2D " << ArrayBaseName(colorTableMap[0]) << "[" << noOfComponents << "];\n";
1174 
1175  std::string shaderStr = ss.str();
1176  if (noOfComponents == 1)
1177  {
1178  shaderStr += std::string("\
1179  \nvec4 computeColor(vec4 scalar, float opacity)\
1180  \n {\
1181  \n return clamp(computeLighting(vec4(texture2D(" +
1182  colorTableMap[0] + ",\
1183  \n vec2(scalar.w, 0.0)).xyz, opacity), 0, 0.0), 0.0, 1.0);\
1184  \n }");
1185  return shaderStr;
1186  }
1187  else if (noOfComponents > 1 && independentComponents)
1188  {
1189  std::ostringstream toString;
1190 
1191  shaderStr += std::string("\
1192  \nvec4 computeColor(vec4 scalar, float opacity, int component)\
1193  \n {");
1194 
1195  for (int i = 0; i < noOfComponents; ++i)
1196  {
1197  toString << i;
1198  shaderStr += std::string("\
1199  \n if (component == " +
1200  toString.str() + ")");
1201 
1202  shaderStr += std::string("\
1203  \n {\
1204  \n return clamp(computeLighting(vec4(texture2D(\
1205  \n " +
1206  colorTableMap[i]);
1207  shaderStr += std::string(", vec2(\
1208  \n scalar[" +
1209  toString.str() + "],0.0)).xyz,\
1210  \n opacity)," +
1211  toString.str() + ", 0.0), 0.0, 1.0);\
1212  \n }");
1213 
1214  // Reset
1215  toString.str("");
1216  toString.clear();
1217  }
1218 
1219  shaderStr += std::string("\n }");
1220  return shaderStr;
1221  }
1222  else if (noOfComponents == 2 && !independentComponents)
1223  {
1224  shaderStr += std::string("\
1225  \nvec4 computeColor(vec4 scalar, float opacity)\
1226  \n {\
1227  \n return clamp(computeLighting(vec4(texture2D(" +
1228  colorTableMap[0] + ",\
1229  \n vec2(scalar.x, 0.0)).xyz,\
1230  \n opacity), 0, 0.0), 0.0, 1.0);\
1231  \n }");
1232  return shaderStr;
1233  }
1234  else
1235  {
1236  shaderStr += std::string("\
1237  \nvec4 computeColor(vec4 scalar, float opacity)\
1238  \n {\
1239  \n return clamp(computeLighting(vec4(scalar.xyz, opacity), 0, 0.0), 0.0, 1.0);\
1240  \n }");
1241  return shaderStr;
1242  }
1243 }
1244 
1245 //--------------------------------------------------------------------------
1247 {
1248  std::ostringstream ss;
1249  int i = 0;
1250  int lastComponentMode = vtkVolumeInputHelper::INVALID;
1251  std::map<int, std::string> lastColorTableMap;
1252  for (auto& item : inputs)
1253  {
1254  auto prop = item.second.Volume->GetProperty();
1255  if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_1D)
1256  continue;
1257 
1258  auto& map = item.second.RGBTablesMap;
1259  const auto numComp = map.size();
1260  ss << "uniform sampler2D " << ArrayBaseName(map[0]) << "[" << numComp << "];\n";
1261 
1262  lastComponentMode = item.second.ComponentMode;
1263  lastColorTableMap = map;
1264  i++;
1265  }
1266 
1267  if (lastComponentMode == vtkVolumeInputHelper::LA)
1268  {
1269  ss << "vec4 computeColor(vec4 scalar, const in sampler2D colorTF)\
1270  \n {\
1271  \n return clamp(computeLighting(vec4(texture2D(colorTF,\
1272  \n vec2(scalar.w, 0.0)).xyz, opacity), 0), 0.0, 1.0);\
1273  \n }\n";
1274  }
1275  else
1276  {
1277  ss << "vec4 computeColor(vec3 texPos, vec4 scalar, float opacity, const in sampler2D colorTF, "
1278  "const in sampler2D gradientTF, const in sampler3D volume, const int volIdx)\n"
1279  "{\n"
1280  " return clamp(computeLighting(texPos, vec4(texture2D(colorTF,\n"
1281  " vec2(scalar.w, 0.0)).xyz, opacity), gradientTF, volume, "
1282  "volIdx, 0), 0.0, 1.0);\n"
1283  "}\n";
1284  }
1285 
1286  return ss.str();
1287 }
1288 
1289 //--------------------------------------------------------------------------
1291 {
1292  std::ostringstream ss;
1293  int i = 0;
1294  for (auto& item : inputs)
1295  {
1296  auto prop = item.second.Volume->GetProperty();
1297  if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_1D)
1298  continue;
1299 
1300  auto& map = item.second.OpacityTablesMap;
1301  const auto numComp = map.size();
1302  ss << "uniform sampler2D " << ArrayBaseName(map[0]) << "[" << numComp << "];\n";
1303  i++;
1304  }
1305 
1306  ss << "float computeOpacity(vec4 scalar, const in sampler2D opacityTF)\n"
1307  "{\n"
1308  " return texture2D(opacityTF, vec2(scalar.w, 0)).r;\n"
1309  "}\n";
1310  return ss.str();
1311 }
1312 
1313 //--------------------------------------------------------------------------
1316 {
1317  std::ostringstream ss;
1318 
1319  int i = 0;
1320  for (auto& item : inputs)
1321  {
1322  auto prop = item.second.Volume->GetProperty();
1323  if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_1D || !prop->HasGradientOpacity())
1324  continue;
1325 
1326  auto& map = item.second.GradientOpacityTablesMap;
1327  const auto numComp = map.size();
1328  ss << "uniform sampler2D " << ArrayBaseName(map[0]) << "[" << numComp << "];\n";
1329  i++;
1330  }
1331 
1332  ss << "float computeGradientOpacity(vec4 grad, const in sampler2D gradientTF)\n"
1333  "{\n"
1334  " return texture2D(gradientTF, vec2(grad.w, 0.0)).r;\n"
1335  "}\n";
1336  return ss.str();
1337 }
1338 
1339 //--------------------------------------------------------------------------
1341  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
1342  int independentComponents, std::map<int, std::string> opacityTableMap)
1343 {
1344  std::ostringstream ss;
1345  ss << "uniform sampler2D " << ArrayBaseName(opacityTableMap[0]) << "[" << noOfComponents
1346  << "];\n";
1347 
1348  std::string shaderStr = ss.str();
1349  if (noOfComponents > 1 && independentComponents)
1350  {
1351  shaderStr += std::string("\
1352  \nfloat computeOpacity(vec4 scalar, int component)\
1353  \n{");
1354 
1355  for (int i = 0; i < noOfComponents; ++i)
1356  {
1357  std::ostringstream toString;
1358  toString << i;
1359  shaderStr += std::string("\
1360  \n if (component == " +
1361  toString.str() + ")");
1362 
1363  shaderStr += std::string("\
1364  \n {\
1365  \n return texture2D(" +
1366  opacityTableMap[i]);
1367 
1368  shaderStr += std::string(",vec2(scalar[" + toString.str() + "], 0)).r;\
1369  \n }");
1370  }
1371 
1372  shaderStr += std::string("\n}");
1373  return shaderStr;
1374  }
1375  else if (noOfComponents == 2 && !independentComponents)
1376  {
1377  shaderStr += std::string("\
1378  \nfloat computeOpacity(vec4 scalar)\
1379  \n{\
1380  \n return texture2D(" +
1381  opacityTableMap[0] + ", vec2(scalar.y, 0)).r;\
1382  \n}");
1383  return shaderStr;
1384  }
1385  else
1386  {
1387  shaderStr += std::string("\
1388  \nfloat computeOpacity(vec4 scalar)\
1389  \n{\
1390  \n return texture2D(" +
1391  opacityTableMap[0] + ", vec2(scalar.w, 0)).r;\
1392  \n}");
1393  return shaderStr;
1394  }
1395 }
1396 
1397 //--------------------------------------------------------------------------
1399  int vtkNotUsed(independentComponents), std::map<int, std::string> colorTableMap)
1400 {
1401  if (noOfComponents == 1)
1402  {
1403  // Single component
1404  return std::string(
1405  "vec4 computeColor(vec4 scalar, float opacity)\n"
1406  "{\n"
1407  " vec4 yscalar = texture3D(in_transfer2DYAxis, g_dataPos);\n"
1408  " yscalar.r = yscalar.r * in_transfer2DYAxis_scale.r + in_transfer2DYAxis_bias.r;\n"
1409  " yscalar = vec4(yscalar.r);\n"
1410  " vec4 color = texture2D(" +
1411  colorTableMap[0] +
1412  ",\n"
1413  " vec2(scalar.w, yscalar.w));\n"
1414  " return computeLighting(color, 0, 0);\n"
1415  "}\n");
1416  }
1417  return std::string("vec4 computeColor(vec4 scalar, float opacity)\n"
1418  "{\n"
1419  " return vec4(0, 0, 0, 0)\n"
1420  "}\n");
1421 }
1422 
1423 //--------------------------------------------------------------------------
1425  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
1426  int independentComponents, std::map<int, std::string> colorTableMap, int useGradient)
1427 {
1428  if (!useGradient)
1429  {
1430  return ComputeColor2DYAxisDeclaration(noOfComponents, independentComponents, colorTableMap);
1431  }
1432  if (noOfComponents == 1)
1433  {
1434  // Single component
1435  return std::string("vec4 computeColor(vec4 scalar, float opacity)\n"
1436  "{\n"
1437  " vec4 color = texture2D(" +
1438  colorTableMap[0] +
1439  ",\n"
1440  " vec2(scalar.w, g_gradients_0[0].w));\n"
1441  " return computeLighting(color, 0, 0);\n"
1442  "}\n");
1443  }
1444  else if (noOfComponents > 1 && independentComponents)
1445  {
1446  // Multiple independent components
1447  std::string shaderStr;
1448  shaderStr += std::string("vec4 computeColor(vec4 scalar, float opacity, int component)\n"
1449  "{\n");
1450 
1451  for (int i = 0; i < noOfComponents; ++i)
1452  {
1453  std::ostringstream toString;
1454  toString << i;
1455  std::string const num = toString.str();
1456  shaderStr += std::string(" if (component == " + num +
1457  ")\n"
1458  " {\n"
1459  " vec4 color = texture2D(" +
1460  colorTableMap[i] +
1461  ",\n"
1462  " vec2(scalar[" +
1463  num + "], g_gradients_0[" + num +
1464  "].w));\n"
1465  " return computeLighting(color, " +
1466  num +
1467  ", 0.0);\n"
1468  " }\n");
1469  }
1470  shaderStr += std::string("}\n");
1471 
1472  return shaderStr;
1473  }
1474  else if (noOfComponents == 2 && !independentComponents)
1475  {
1476  // Dependent components (Luminance/ Opacity)
1477  return std::string("vec4 computeColor(vec4 scalar, float opacity)\n"
1478  "{\n"
1479  " vec4 color = texture2D(" +
1480  colorTableMap[0] +
1481  ",\n"
1482  " vec2(scalar.x, g_gradients_0[0].w));\n"
1483  " return computeLighting(color, 0, 0.0);\n"
1484  "}\n");
1485  }
1486  else
1487  {
1488  return std::string("vec4 computeColor(vec4 scalar, float opacity)\n"
1489  "{\n"
1490  " return computeLighting(vec4(scalar.xyz, opacity), 0, 0.0);\n"
1491  "}\n");
1492  }
1493 }
1494 
1495 //--------------------------------------------------------------------------
1497 {
1498  std::ostringstream ss;
1499  int i = 0;
1500  for (auto& item : inputs)
1501  {
1502  auto prop = item.second.Volume->GetProperty();
1503  if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_2D)
1504  continue;
1505 
1506  auto& map = item.second.TransferFunctions2DMap;
1507  const auto numComp = map.size();
1508  ss << "uniform sampler2D " << ArrayBaseName(map[0]) << "[" << numComp << "];\n";
1509  i++;
1510  }
1511 
1512  std::string result = ss.str() +
1513  std::string("uniform sampler3D in_transfer2DYAxis;\n"
1514  "uniform vec4 in_transfer2DYAxis_scale;\n"
1515  "uniform vec4 in_transfer2DYAxis_bias;\n");
1516 
1517  return result;
1518 }
1519 
1520 //--------------------------------------------------------------------------
1522  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
1523  int independentComponents, std::map<int, std::string> opacityTableMap, int useGradient)
1524 {
1525  std::ostringstream toString;
1526  if (noOfComponents > 1 && independentComponents)
1527  {
1528  // Multiple independent components
1529  toString << "float computeOpacity(vec4 scalar, int component)\n"
1530  "{\n";
1531  if (!useGradient)
1532  {
1533  toString
1534  << "vec4 yscalar = texture3D(in_transfer2DYAxis, g_dataPos);\n"
1535  "for (int i = 0; i < 4; ++i)\n"
1536  "{\n"
1537  " yscalar[i] = yscalar[i] * in_transfer2DYAxis_scale[i] + in_transfer2DYAxis_bias[i];\n"
1538  "}\n";
1539  if (noOfComponents == 1)
1540  {
1541  toString << "yscalar = vec4(yscalar.r);\n";
1542  }
1543  }
1544 
1545  for (int i = 0; i < noOfComponents; ++i)
1546  {
1547  if (useGradient)
1548  {
1549  toString << " if (component == " << i
1550  << ")\n"
1551  " {\n"
1552  " return texture2D("
1553  << opacityTableMap[i]
1554  << ",\n"
1555  " vec2(scalar["
1556  << i << "], g_gradients_0[" << i
1557  << "].w)).a;\n"
1558  " }\n";
1559  }
1560  else
1561  {
1562  toString << " if (component == " << i
1563  << ")\n"
1564  " {\n"
1565  " return texture2D("
1566  << opacityTableMap[i]
1567  << ",\n"
1568  " vec2(scalar["
1569  << i << "], yscalar[" << i
1570  << "])).a;\n"
1571  " }\n";
1572  }
1573  }
1574 
1575  toString << "}\n";
1576  }
1577 
1578  else if (noOfComponents == 2 && !independentComponents)
1579  {
1580  if (useGradient)
1581  {
1582  // Dependent components (Luminance/ Opacity)
1583  toString << "float computeOpacity(vec4 scalar)\n"
1584  "{\n"
1585  " return texture2D(" +
1586  opacityTableMap[0] +
1587  ",\n"
1588  " vec2(scalar.y, g_gradients_0[0].w)).a;\n"
1589  "}\n";
1590  }
1591  else
1592  {
1593  // Dependent components (Luminance/ Opacity)
1594  toString << "float computeOpacity(vec4 scalar)\n"
1595  "{\n"
1596  " return texture2D(" +
1597  opacityTableMap[0] +
1598  ",\n"
1599  " vec2(scalar.y, yscalar.y)).a;\n"
1600  "}\n";
1601  }
1602  }
1603 
1604  else
1605  {
1606  if (useGradient)
1607  {
1608  // Dependent compoennts (RGBA) || Single component
1609  toString << "float computeOpacity(vec4 scalar)\n"
1610  "{\n"
1611  " return texture2D(" +
1612  opacityTableMap[0] +
1613  ",\n"
1614  " vec2(scalar.a, g_gradients_0[0].w)).a;\n"
1615  "}\n";
1616  }
1617  else
1618  {
1619  // Dependent compoennts (RGBA) || Single component
1620  toString
1621  << "float computeOpacity(vec4 scalar)\n"
1622  "{\n"
1623  " vec4 yscalar = texture3D(in_transfer2DYAxis, g_dataPos);\n"
1624  " yscalar.r = yscalar.r * in_transfer2DYAxis_scale.r + in_transfer2DYAxis_bias.r;\n"
1625  " yscalar = vec4(yscalar.r);\n"
1626  " return texture2D(" +
1627  opacityTableMap[0] +
1628  ",\n"
1629  " vec2(scalar.a, yscalar.w)).a;\n"
1630  "}\n";
1631  }
1632  }
1633  return toString.str();
1634 }
1635 
1636 //--------------------------------------------------------------------------
1638  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
1639 {
1640  return std::string();
1641 }
1642 
1643 //--------------------------------------------------------------------------
1645  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
1646 {
1648  {
1649  return std::string("\
1650  \n bool l_firstValue;\
1651  \n vec4 l_maxValue;");
1652  }
1654  {
1655  return std::string("\
1656  \n bool l_firstValue;\
1657  \n vec4 l_minValue;");
1658  }
1660  {
1661  return std::string("\
1662  \n uvec4 l_numSamples;\
1663  \n vec4 l_avgValue;");
1664  }
1665  else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
1666  {
1667  return std::string("\
1668  \n vec4 l_sumValue;");
1669  }
1670  else if (mapper->GetBlendMode() == vtkVolumeMapper::ISOSURFACE_BLEND)
1671  {
1672  return std::string("\
1673  \n int l_initialIndex = 0;\
1674  \n float l_normValues[NUMBER_OF_CONTOURS + 2];");
1675  }
1676  else
1677  {
1678  return std::string();
1679  }
1680 }
1681 
1682 //--------------------------------------------------------------------------
1684  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
1685 {
1687  {
1688  return std::string("\
1689  \n // We get data between 0.0 - 1.0 range\
1690  \n l_firstValue = true;\
1691  \n l_maxValue = vec4(0.0);");
1692  }
1694  {
1695  return std::string("\
1696  \n //We get data between 0.0 - 1.0 range\
1697  \n l_firstValue = true;\
1698  \n l_minValue = vec4(1.0);");
1699  }
1701  {
1702  return std::string("\
1703  \n //We get data between 0.0 - 1.0 range\
1704  \n l_avgValue = vec4(0.0);\
1705  \n // Keep track of number of samples\
1706  \n l_numSamples = uvec4(0);");
1707  }
1708  else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
1709  {
1710  return std::string("\
1711  \n //We get data between 0.0 - 1.0 range\
1712  \n l_sumValue = vec4(0.0);");
1713  }
1714  else if (mapper->GetBlendMode() == vtkVolumeMapper::ISOSURFACE_BLEND)
1715  {
1716  return std::string("\
1717  \n#if NUMBER_OF_CONTOURS\
1718  \n l_normValues[0] = -1e20; //-infinity\
1719  \n l_normValues[NUMBER_OF_CONTOURS+1] = +1e20; //+infinity\
1720  \n for (int i = 0; i < NUMBER_OF_CONTOURS; i++)\
1721  \n {\
1722  \n l_normValues[i+1] = (in_isosurfacesValues[i] - in_scalarsRange[0].x) / \
1723  \n (in_scalarsRange[0].y - in_scalarsRange[0].x);\
1724  \n }\
1725  \n#endif\
1726  ");
1727  }
1728  else
1729  {
1730  return std::string();
1731  }
1732 }
1733 
1734 //--------------------------------------------------------------------------
1735 std::string GradientCacheDec(vtkRenderer* vtkNotUsed(ren), vtkVolume* vtkNotUsed(vol),
1736  vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, int independentComponents = 0)
1737 {
1738  const int numInputs = static_cast<int>(inputs.size());
1739  const int comp = numInputs == 1 ?
1740  // Dependent components use a single opacity lut.
1741  (!independentComponents ? 1 : numInputs)
1742  :
1743  // Independent components not supported with multiple-inputs
1744  1;
1745 
1746  std::ostringstream toShader;
1747  for (const auto& item : inputs)
1748  {
1749  auto& input = item.second;
1750  if (input.Volume->GetProperty()->HasGradientOpacity())
1751  {
1752  toShader << "vec4 " << input.GradientCacheName << "[" << comp << "];\n";
1753  }
1754  }
1755 
1756  return toShader.str();
1757 }
1758 
1759 //--------------------------------------------------------------------------
1760 std::string PreComputeGradientsImpl(vtkRenderer* vtkNotUsed(ren), vtkVolume* vtkNotUsed(vol),
1761  int noOfComponents = 1, int independentComponents = 0)
1762 {
1763  std::ostringstream shader;
1764  if (independentComponents)
1765  {
1766  if (noOfComponents == 1)
1767  {
1768  shader << "g_gradients_0[0] = computeGradient(g_dataPos, 0, in_volume[0], 0);\n";
1769  }
1770  else
1771  {
1772  // Multiple components
1773  shader << "for (int comp = 0; comp < in_noOfComponents; comp++)\n"
1774  "{\n"
1775  " g_gradients_0[comp] = computeGradient(g_dataPos, comp, in_volume[0], 0);\n"
1776  "}\n";
1777  }
1778  }
1779  else
1780  {
1781  shader << "g_gradients_0[0] = computeGradient(g_dataPos, 0, in_volume[0], 0);\n";
1782  }
1783 
1784  return shader.str();
1785 }
1786 
1787 //--------------------------------------------------------------------------
1790 {
1791  std::ostringstream toShaderStr;
1792  toShaderStr << " if (!g_skip)\n"
1793  " {\n"
1794  " vec3 texPos;\n";
1795 
1796  switch (mapper->GetBlendMode())
1797  {
1799  default:
1800  {
1801  int i = 0;
1802  for (auto& item : inputs)
1803  {
1804  auto& input = item.second;
1805  auto property = input.Volume->GetProperty();
1806  // Transformation index. Index 0 refers to the global bounding-box.
1807  const auto idx = i + 1;
1808  toShaderStr <<
1809  // From global texture coordinates (bbox) to volume_i texture coords.
1810  // texPos = T * g_dataPos
1811  // T = T_dataToTex1 * T_worldToData * T_bboxTexToWorld;
1812  " texPos = (in_cellToPoint[" << idx << "] * in_inverseTextureDatasetMatrix[" << idx
1813  << "] * in_inverseVolumeMatrix[" << idx
1814  << "] *\n"
1815  " in_volumeMatrix[0] * in_textureDatasetMatrix[0] * "
1816  "vec4(g_dataPos.xyz, 1.0)).xyz;\n"
1817  " if ((all(lessThanEqual(texPos, vec3(1.0))) &&\n"
1818  " all(greaterThanEqual(texPos, vec3(0.0)))))\n"
1819  " {\n"
1820  " vec4 scalar = texture3D(in_volume["
1821  << i
1822  << "], texPos);\n"
1823  " scalar = scalar * in_volume_scale["
1824  << i << "] + in_volume_bias[" << i
1825  << "];\n"
1826  " scalar = vec4(scalar.r);\n"
1827  " g_srcColor = vec4(0.0);\n";
1828 
1829  if (property->GetTransferFunctionMode() == vtkVolumeProperty::TF_1D)
1830  {
1831  toShaderStr << " g_srcColor.a = computeOpacity(scalar,"
1832  << input.OpacityTablesMap[0]
1833  << ");\n"
1834  " if (g_srcColor.a > 0.0)\n"
1835  " {\n"
1836  " g_srcColor = computeColor(texPos, scalar, g_srcColor.a, "
1837  << input.RGBTablesMap[0] << ", " << input.GradientOpacityTablesMap[0] << ", "
1838  << "in_volume[" << i << "], " << i << ");\n";
1839 
1840  if (property->HasGradientOpacity())
1841  {
1842  const auto& grad = input.GradientCacheName;
1843  toShaderStr << " " << grad << "[0] = computeGradient(texPos, 0, "
1844  << "in_volume[" << i << "], " << i
1845  << ");\n"
1846  " if ("
1847  << grad
1848  << "[0].w >= 0.0)\n"
1849  " {\n"
1850  " g_srcColor.a *= computeGradientOpacity("
1851  << grad << "[0], " << input.GradientOpacityTablesMap[0]
1852  << ");\n"
1853  " }\n";
1854  }
1855  }
1856  else if (property->GetTransferFunctionMode() == vtkVolumeProperty::TF_2D)
1857  {
1858  const auto& grad = input.GradientCacheName;
1859  toShaderStr <<
1860  // Sample 2DTF directly
1861  " " << grad << "[0] = computeGradient(texPos, 0, "
1862  << "in_volume[" << i << "], " << i
1863  << ");\n"
1864  " g_srcColor = texture2D("
1865  << input.TransferFunctions2DMap[0] << ", vec2(scalar.r, "
1866  << input.GradientCacheName
1867  << "[0].w));\n"
1868  " if (g_srcColor.a > 0.0)\n"
1869  " {\n";
1870  }
1871 
1872  toShaderStr
1873  << " g_srcColor.rgb *= g_srcColor.a;\n"
1874  " g_fragColor = (1.0f - g_fragColor.a) * g_srcColor + g_fragColor;\n"
1875  " }\n"
1876  " }\n\n";
1877 
1878  i++;
1879  }
1880  }
1881  break;
1882  }
1883  toShaderStr << " }\n";
1884 
1885  return toShaderStr.str();
1886 }
1887 
1888 //--------------------------------------------------------------------------
1890  vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput, vtkVolumeTexture* mask, int maskType,
1891  int noOfComponents, int independentComponents = 0)
1892 {
1893  auto glMapper = vtkOpenGLGPUVolumeRayCastMapper::SafeDownCast(mapper);
1894 
1895  std::string shaderStr;
1896 
1897  shaderStr += std::string("\
1898  \n if (!g_skip)\
1899  \n {\
1900  \n vec4 scalar;\
1901  \n");
1903  {
1904  shaderStr += std::string("\
1905  \n // Compute IJK vertex position for current sample in the rectilinear grid\
1906  \n vec4 dataPosWorld = in_volumeMatrix[0] * in_textureDatasetMatrix[0] * vec4(g_dataPos, 1.0);\
1907  \n dataPosWorld = dataPosWorld / dataPosWorld.w;\
1908  \n dataPosWorld.w = 1.0;\
1909  \n ivec3 ijk = ivec3(0);\
1910  \n vec3 ijkTexCoord = vec3(0.0);\
1911  \n vec3 pCoords = vec3(0.0);\
1912  \n vec3 xPrev, xNext, tmp;\
1913  \n int sz = textureSize(in_coordTexs, 0);\
1914  \n vec4 dataPosWorldScaled = dataPosWorld * vec4(in_coordsScale, 1.0) +\
1915  \n vec4(in_coordsBias, 1.0);\
1916  \n for (int j = 0; j < 3; ++j)\
1917  \n {\
1918  \n xPrev = texture1D(in_coordTexs, 0.0).xyz;\
1919  \n xNext = texture1D(in_coordTexs, (in_coordTexSizes[j] - 1) / sz).xyz;\
1920  \n if (xNext[j] < xPrev[j])\
1921  \n {\
1922  \n tmp = xNext;\
1923  \n xNext = xPrev;\
1924  \n xPrev = tmp;\
1925  \n }\
1926  \n for (int i = 0; i < int(in_coordTexSizes[j]); i++)\
1927  \n {\
1928  \n xNext = texture1D(in_coordTexs, (i + 0.5) / sz).xyz;\
1929  \n if (dataPosWorldScaled[j] >= xPrev[j] && dataPosWorldScaled[j] < xNext[j])\
1930  \n {\
1931  \n ijk[j] = i - 1;\
1932  \n pCoords[j] = (dataPosWorldScaled[j] - xPrev[j]) / (xNext[j] - xPrev[j]);\
1933  \n break;\
1934  \n }\
1935  \n else if (dataPosWorldScaled[j] == xNext[j])\
1936  \n {\
1937  \n ijk[j] = i - 1;\
1938  \n pCoords[j] = 1.0;\
1939  \n break;\
1940  \n }\
1941  \n xPrev = xNext;\
1942  \n }\
1943  \n ijkTexCoord[j] = (ijk[j] + pCoords[j]) / in_coordTexSizes[j];\
1944  \n }\
1945  \n scalar = texture3D(in_volume[0], sign(in_cellSpacing[0]) * ijkTexCoord);\
1946  \n");
1947  }
1948  else
1949  {
1950  shaderStr += std::string("\
1951  \n scalar = texture3D(in_volume[0], g_dataPos);\
1952  \n");
1953  }
1954 
1955  // simulate old intensity textures
1956  if (noOfComponents == 1)
1957  {
1958  shaderStr += std::string("\
1959  \n scalar.r = scalar.r * in_volume_scale[0].r + in_volume_bias[0].r;\
1960  \n scalar = vec4(scalar.r);");
1961  }
1962  else
1963  {
1964  // handle bias and scale
1965  shaderStr += std::string("\
1966  \n scalar = scalar * in_volume_scale[0] + in_volume_bias[0];");
1967  }
1968 
1970  {
1971  if (noOfComponents > 1)
1972  {
1973  if (!independentComponents)
1974  {
1975  shaderStr += std::string("\
1976  \n if (l_maxValue.w < scalar.w || l_firstValue)\
1977  \n {\
1978  \n l_maxValue = scalar;\
1979  \n }\
1980  \n\
1981  \n if (l_firstValue)\
1982  \n {\
1983  \n l_firstValue = false;\
1984  \n }");
1985  }
1986  else
1987  {
1988  shaderStr += std::string("\
1989  \n for (int i = 0; i < in_noOfComponents; ++i)\
1990  \n {\
1991  \n if (l_maxValue[i] < scalar[i] || l_firstValue)\
1992  \n {\
1993  \n l_maxValue[i] = scalar[i];\
1994  \n }\
1995  \n }\
1996  \n if (l_firstValue)\
1997  \n {\
1998  \n l_firstValue = false;\
1999  \n }");
2000  }
2001  }
2002  else
2003  {
2004  shaderStr += std::string("\
2005  \n if (l_maxValue.w < scalar.x || l_firstValue)\
2006  \n {\
2007  \n l_maxValue.w = scalar.x;\
2008  \n }\
2009  \n\
2010  \n if (l_firstValue)\
2011  \n {\
2012  \n l_firstValue = false;\
2013  \n }");
2014  }
2015  }
2017  {
2018  if (noOfComponents > 1)
2019  {
2020  if (!independentComponents)
2021  {
2022  shaderStr += std::string("\
2023  \n if (l_minValue.w > scalar.w || l_firstValue)\
2024  \n {\
2025  \n l_minValue = scalar;\
2026  \n }\
2027  \n\
2028  \n if (l_firstValue)\
2029  \n {\
2030  \n l_firstValue = false;\
2031  \n }");
2032  }
2033  else
2034  {
2035  shaderStr += std::string("\
2036  \n for (int i = 0; i < in_noOfComponents; ++i)\
2037  \n {\
2038  \n if (l_minValue[i] < scalar[i] || l_firstValue)\
2039  \n {\
2040  \n l_minValue[i] = scalar[i];\
2041  \n }\
2042  \n }\
2043  \n if (l_firstValue)\
2044  \n {\
2045  \n l_firstValue = false;\
2046  \n }");
2047  }
2048  }
2049  else
2050  {
2051  shaderStr += std::string("\
2052  \n if (l_minValue.w > scalar.x || l_firstValue)\
2053  \n {\
2054  \n l_minValue.w = scalar.x;\
2055  \n }\
2056  \n\
2057  \n if (l_firstValue)\
2058  \n {\
2059  \n l_firstValue = false;\
2060  \n }");
2061  }
2062  }
2064  {
2065  if (noOfComponents > 1 && independentComponents)
2066  {
2067  shaderStr += std::string("\
2068  \n for (int i = 0; i < in_noOfComponents; ++i)\
2069  \n {\
2070  \n // Get the intensity in volume scalar range\
2071  \n float intensity = in_scalarsRange[i][0] +\
2072  \n (in_scalarsRange[i][1] -\
2073  \n in_scalarsRange[i][0]) * scalar[i];\
2074  \n if (in_averageIPRange.x <= intensity &&\
2075  \n intensity <= in_averageIPRange.y)\
2076  \n {\
2077  \n l_avgValue[i] += computeOpacity(scalar, i) * scalar[i];\
2078  \n ++l_numSamples[i];\
2079  \n }\
2080  \n }");
2081  }
2082  else
2083  {
2084  shaderStr += std::string("\
2085  \n // Get the intensity in volume scalar range\
2086  \n float intensity = in_scalarsRange[0][0] +\
2087  \n (in_scalarsRange[0][1] -\
2088  \n in_scalarsRange[0][0]) * scalar.x;\
2089  \n if (in_averageIPRange.x <= intensity &&\
2090  \n intensity <= in_averageIPRange.y)\
2091  \n {\
2092  \n l_avgValue.x += computeOpacity(scalar) * scalar.x;\
2093  \n ++l_numSamples.x;\
2094  \n }");
2095  }
2096  }
2097  else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
2098  {
2099  if (noOfComponents > 1 && independentComponents)
2100  {
2101  shaderStr += std::string("\
2102  \n for (int i = 0; i < in_noOfComponents; ++i)\
2103  \n {\
2104  \n float opacity = computeOpacity(scalar, i);\
2105  \n l_sumValue[i] = l_sumValue[i] + opacity * scalar[i];\
2106  \n }");
2107  }
2108  else
2109  {
2110  shaderStr += std::string("\
2111  \n float opacity = computeOpacity(scalar);\
2112  \n l_sumValue.x = l_sumValue.x + opacity * scalar.x;");
2113  }
2114  }
2115  else if (mapper->GetBlendMode() == vtkVolumeMapper::ISOSURFACE_BLEND)
2116  {
2117  shaderStr += std::string("\
2118  \n#if NUMBER_OF_CONTOURS\
2119  \n int maxComp = 0;");
2120 
2121  std::string compParamStr = "";
2122  if (noOfComponents > 1 && independentComponents)
2123  {
2124  shaderStr += std::string("\
2125  \n for (int i = 1; i < in_noOfComponents; ++i)\
2126  \n {\
2127  \n if (in_componentWeight[i] > in_componentWeight[maxComp])\
2128  \n maxComp = i;\
2129  \n }");
2130  compParamStr = ", maxComp";
2131  }
2132  shaderStr += std::string("\
2133  \n if (g_currentT == 0)\
2134  \n {\
2135  \n l_initialIndex = findIsoSurfaceIndex(scalar[maxComp], l_normValues);\
2136  \n }\
2137  \n else\
2138  \n {\
2139  \n float s;\
2140  \n bool shade = false;\
2141  \n l_initialIndex = clamp(l_initialIndex, 0, NUMBER_OF_CONTOURS);\
2142  \n if (scalar[maxComp] < l_normValues[l_initialIndex])\
2143  \n {\
2144  \n s = l_normValues[l_initialIndex];\
2145  \n l_initialIndex--;\
2146  \n shade = true;\
2147  \n }\
2148  \n if (scalar[maxComp] > l_normValues[l_initialIndex+1])\
2149  \n {\
2150  \n s = l_normValues[l_initialIndex+1];\
2151  \n l_initialIndex++;\
2152  \n shade = true;\
2153  \n }\
2154  \n if (shade == true)\
2155  \n {\
2156  \n vec4 vs = vec4(s);\
2157  \n g_srcColor.a = computeOpacity(vs " +
2158  compParamStr + ");\
2159  \n g_srcColor = computeColor(vs, g_srcColor.a " +
2160  compParamStr + ");\
2161  \n g_srcColor.rgb *= g_srcColor.a;\
2162  \n g_fragColor = (1.0f - g_fragColor.a) * g_srcColor + g_fragColor;\
2163  \n }\
2164  \n }\
2165  \n#endif");
2166  }
2167  else if (mapper->GetBlendMode() == vtkVolumeMapper::SLICE_BLEND)
2168  {
2169  shaderStr += std::string("\
2170  \n // test if the intersection is inside the volume bounds\
2171  \n if (any(greaterThan(g_dataPos, vec3(1.0))) || any(lessThan(g_dataPos, vec3(0.0))))\
2172  \n {\
2173  \n discard;\
2174  \n }\
2175  \n float opacity = computeOpacity(scalar);\
2176  \n g_fragColor = computeColor(scalar, opacity);\
2177  \n g_fragColor.rgb *= opacity;\
2178  \n g_exit = true;");
2179  }
2180  else if (mapper->GetBlendMode() == vtkVolumeMapper::COMPOSITE_BLEND)
2181  {
2182  if (noOfComponents > 1 && independentComponents)
2183  {
2184  shaderStr += std::string("\
2185  \n vec4 color[4]; vec4 tmp = vec4(0.0);\
2186  \n float totalAlpha = 0.0;\
2187  \n for (int i = 0; i < in_noOfComponents; ++i)\
2188  \n {\
2189  ");
2190  if (glMapper->GetUseDepthPass() &&
2191  glMapper->GetCurrentPass() == vtkOpenGLGPUVolumeRayCastMapper::DepthPass)
2192  {
2193  shaderStr += std::string("\
2194  \n // Data fetching from the red channel of volume texture\
2195  \n float opacity = computeOpacity(scalar, i);\
2196  \n if (opacity > 0.0)\
2197  \n {\
2198  \n g_srcColor.a = opacity;\
2199  \n }\
2200  \n }");
2201  }
2202  else if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2203  {
2204  shaderStr += std::string("\
2205  \n // Data fetching from the red channel of volume texture\
2206  \n color[i][3] = computeOpacity(scalar, i);\
2207  \n color[i] = computeColor(scalar, color[i][3], i);\
2208  \n totalAlpha += color[i][3] * in_componentWeight[i];\
2209  \n }\
2210  \n if (totalAlpha > 0.0)\
2211  \n {\
2212  \n for (int i = 0; i < in_noOfComponents; ++i)\
2213  \n {\
2214  \n // Only let visible components contribute to the final color\
2215  \n if (in_componentWeight[i] <= 0) continue;\
2216  \n\
2217  \n tmp.x += color[i].x * color[i].w * in_componentWeight[i];\
2218  \n tmp.y += color[i].y * color[i].w * in_componentWeight[i];\
2219  \n tmp.z += color[i].z * color[i].w * in_componentWeight[i];\
2220  \n tmp.w += ((color[i].w * color[i].w)/totalAlpha);\
2221  \n }\
2222  \n }\
2223  \n g_fragColor = (1.0f - g_fragColor.a) * tmp + g_fragColor;");
2224  }
2225  }
2226  else if (glMapper->GetUseDepthPass() &&
2227  glMapper->GetCurrentPass() == vtkOpenGLGPUVolumeRayCastMapper::DepthPass)
2228  {
2229  shaderStr += std::string("\
2230  \n g_srcColor = vec4(0.0);\
2231  \n g_srcColor.a = computeOpacity(scalar);");
2232  }
2233  else
2234  {
2235  if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2236  {
2237  shaderStr += std::string("\
2238  \n g_srcColor = vec4(0.0);\
2239  \n g_srcColor.a = computeOpacity(scalar);\
2240  \n if (g_srcColor.a > 0.0)\
2241  \n {\
2242  \n g_srcColor = computeColor(scalar, g_srcColor.a);");
2243  }
2244 
2245  shaderStr += std::string("\
2246  \n // Opacity calculation using compositing:\
2247  \n // Here we use front to back compositing scheme whereby\
2248  \n // the current sample value is multiplied to the\
2249  \n // currently accumulated alpha and then this product\
2250  \n // is subtracted from the sample value to get the\
2251  \n // alpha from the previous steps. Next, this alpha is\
2252  \n // multiplied with the current sample colour\
2253  \n // and accumulated to the composited colour. The alpha\
2254  \n // value from the previous steps is then accumulated\
2255  \n // to the composited colour alpha.\
2256  \n g_srcColor.rgb *= g_srcColor.a;\
2257  \n g_fragColor = (1.0f - g_fragColor.a) * g_srcColor + g_fragColor;");
2258 
2259  if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2260  {
2261  shaderStr += std::string("\
2262  \n }");
2263  }
2264  }
2265  }
2266  else
2267  {
2268  shaderStr += std::string();
2269  }
2270 
2271  shaderStr += std::string("\
2272  \n }");
2273  return shaderStr;
2274 }
2275 
2276 //--------------------------------------------------------------------------
2278  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2279 {
2280  return std::string("\
2281  \n // Special coloring mode which renders the Prop Id in fragments that\
2282  \n // have accumulated certain level of opacity. Used during the selection\
2283  \n // pass vtkHardwareSelection::ACTOR_PASS.\
2284  \n if (g_fragColor.a > 3.0/ 255.0)\
2285  \n {\
2286  \n gl_FragData[0] = vec4(in_propId, 1.0);\
2287  \n }\
2288  \n else\
2289  \n {\
2290  \n gl_FragData[0] = vec4(0.0);\
2291  \n }\
2292  \n return;");
2293 };
2294 
2295 //--------------------------------------------------------------------------
2297  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2298 {
2299  return std::string("\
2300  \n // Special coloring mode which renders the voxel index in fragments that\
2301  \n // have accumulated certain level of opacity. Used during the selection\
2302  \n // pass vtkHardwareSelection::ID_LOW24.\
2303  \n if (g_fragColor.a > 3.0/ 255.0)\
2304  \n {\
2305  \n uvec3 volumeDim = uvec3(in_textureExtentsMax - in_textureExtentsMin);\
2306  \n uvec3 voxelCoords = uvec3(volumeDim * g_dataPos);\
2307  \n // vtkHardwareSelector assumes index 0 to be empty space, so add uint(1).\
2308  \n uint idx = volumeDim.x * volumeDim.y * voxelCoords.z +\
2309  \n volumeDim.x * voxelCoords.y + voxelCoords.x + uint(1);\
2310  \n gl_FragData[0] = vec4(float(idx % uint(256)) / 255.0,\
2311  \n float((idx / uint(256)) % uint(256)) / 255.0,\
2312  \n float((idx / uint(65536)) % uint(256)) / 255.0, 1.0);\
2313  \n }\
2314  \n else\
2315  \n {\
2316  \n gl_FragData[0] = vec4(0.0);\
2317  \n }\
2318  \n return;");
2319 };
2320 
2321 //--------------------------------------------------------------------------
2323  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2324 {
2325  return std::string("\
2326  \n // Special coloring mode which renders the voxel index in fragments that\
2327  \n // have accumulated certain level of opacity. Used during the selection\
2328  \n // pass vtkHardwareSelection::ID_MID24.\
2329  \n if (g_fragColor.a > 3.0/ 255.0)\
2330  \n {\
2331  \n uvec3 volumeDim = uvec3(in_textureExtentsMax - in_textureExtentsMin);\
2332  \n uvec3 voxelCoords = uvec3(volumeDim * g_dataPos);\
2333  \n // vtkHardwareSelector assumes index 0 to be empty space, so add uint(1).\
2334  \n uint idx = volumeDim.x * volumeDim.y * voxelCoords.z +\
2335  \n volumeDim.x * voxelCoords.y + voxelCoords.x + uint(1);\
2336  \n idx = ((idx & 0xff000000) >> 24);\
2337  \n gl_FragData[0] = vec4(float(idx % uint(256)) / 255.0,\
2338  \n float((idx / uint(256)) % uint(256)) / 255.0,\
2339  \n float(idx / uint(65536)) / 255.0, 1.0);\
2340  \n }\
2341  \n else\
2342  \n {\
2343  \n gl_FragData[0] = vec4(0.0);\
2344  \n }\
2345  \n return;");
2346 };
2347 
2348 //--------------------------------------------------------------------------
2350  vtkVolume* vtkNotUsed(vol), int noOfComponents, int independentComponents = 0)
2351 {
2353 
2354  if (glMapper->GetUseDepthPass() &&
2357  {
2358  return std::string();
2359  }
2361  {
2362  if (noOfComponents > 1 && independentComponents)
2363  {
2364  return std::string("\
2365  \n g_srcColor = vec4(0);\
2366  \n for (int i = 0; i < in_noOfComponents; ++i)\
2367  \n {\
2368  \n vec4 tmp = computeColor(l_maxValue, computeOpacity(l_maxValue, i), i);\
2369  \n g_srcColor[0] += tmp[0] * tmp[3] * in_componentWeight[i];\
2370  \n g_srcColor[1] += tmp[1] * tmp[3] * in_componentWeight[i];\
2371  \n g_srcColor[2] += tmp[2] * tmp[3] * in_componentWeight[i];\
2372  \n g_srcColor[3] += tmp[3] * in_componentWeight[i];\
2373  \n }\
2374  \n g_fragColor = g_srcColor;");
2375  }
2376  else
2377  {
2378  return std::string("\
2379  \n g_srcColor = computeColor(l_maxValue,\
2380  \n computeOpacity(l_maxValue));\
2381  \n g_fragColor.rgb = g_srcColor.rgb * g_srcColor.a;\
2382  \n g_fragColor.a = g_srcColor.a;");
2383  }
2384  }
2386  {
2387  if (noOfComponents > 1 && independentComponents)
2388  {
2389  return std::string("\
2390  \n g_srcColor = vec4(0);\
2391  \n for (int i = 0; i < in_noOfComponents; ++i)\
2392  \n {\
2393  \n vec4 tmp = computeColor(l_minValue, computeOpacity(l_minValue, i), i);\
2394  \n g_srcColor[0] += tmp[0] * tmp[3] * in_componentWeight[i];\
2395  \n g_srcColor[1] += tmp[1] * tmp[3] * in_componentWeight[i];\
2396  \n g_srcColor[2] += tmp[2] * tmp[3] * in_componentWeight[i];\
2397  \n g_srcColor[2] += tmp[3] * tmp[3] * in_componentWeight[i];\
2398  \n }\
2399  \n g_fragColor = g_srcColor;");
2400  }
2401  else
2402  {
2403  return std::string("\
2404  \n g_srcColor = computeColor(l_minValue,\
2405  \n computeOpacity(l_minValue));\
2406  \n g_fragColor.rgb = g_srcColor.rgb * g_srcColor.a;\
2407  \n g_fragColor.a = g_srcColor.a;");
2408  }
2409  }
2411  {
2412  if (noOfComponents > 1 && independentComponents)
2413  {
2414  return std::string("\
2415  \n for (int i = 0; i < in_noOfComponents; ++i)\
2416  \n {\
2417  \n if (l_numSamples[i] == uint(0))\
2418  \n {\
2419  \n continue;\
2420  \n }\
2421  \n l_avgValue[i] = l_avgValue[i] * in_componentWeight[i] /\
2422  \n l_numSamples[i];\
2423  \n if (i > 0)\
2424  \n {\
2425  \n l_avgValue[0] += l_avgValue[i];\
2426  \n }\
2427  \n }\
2428  \n l_avgValue[0] = clamp(l_avgValue[0], 0.0, 1.0);\
2429  \n g_fragColor = vec4(vec3(l_avgValue[0]), 1.0);");
2430  }
2431  else
2432  {
2433  return std::string("\
2434  \n if (l_numSamples.x == uint(0))\
2435  \n {\
2436  \n discard;\
2437  \n }\
2438  \n else\
2439  \n {\
2440  \n l_avgValue.x /= l_numSamples.x;\
2441  \n l_avgValue.x = clamp(l_avgValue.x, 0.0, 1.0);\
2442  \n g_fragColor = vec4(vec3(l_avgValue.x), 1.0);\
2443  \n }");
2444  }
2445  }
2446  else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
2447  {
2448  if (noOfComponents > 1 && independentComponents)
2449  {
2450  // Add all the components to get final color
2451  return std::string("\
2452  \n l_sumValue.x *= in_componentWeight.x;\
2453  \n for (int i = 1; i < in_noOfComponents; ++i)\
2454  \n {\
2455  \n l_sumValue.x += l_sumValue[i] * in_componentWeight[i];\
2456  \n }\
2457  \n l_sumValue.x = clamp(l_sumValue.x, 0.0, 1.0);\
2458  \n g_fragColor = vec4(vec3(l_sumValue.x), 1.0);");
2459  }
2460  else
2461  {
2462  return std::string("\
2463  \n l_sumValue.x = clamp(l_sumValue.x, 0.0, 1.0);\
2464  \n g_fragColor = vec4(vec3(l_sumValue.x), 1.0);");
2465  }
2466  }
2467  else
2468  {
2469  return std::string();
2470  }
2471 }
2472 
2473 //--------------------------------------------------------------------------
2475  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2476 {
2477  return std::string();
2478 }
2479 
2480 //--------------------------------------------------------------------------
2482  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2483 {
2484  return std::string("\
2485  \n const float g_opacityThreshold = 1.0 - 1.0 / 255.0;");
2486 }
2487 
2488 //--------------------------------------------------------------------------
2490  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2491 {
2492  return std::string("\
2493  \n uniform vec3 in_propId;");
2494 };
2495 
2496 //--------------------------------------------------------------------------
2498 {
2499  std::string shaderStr;
2500  shaderStr += std::string("\
2501  \n // Flag to indicate if the raymarch loop should terminate \
2502  \n bool stop = false;\
2503  \n\
2504  \n g_terminatePointMax = 0.0;\
2505  \n\
2506  \n vec4 l_depthValue = texture2D(in_depthSampler, fragTexCoord);\
2507  \n // Depth test\
2508  \n if(gl_FragCoord.z >= l_depthValue.x)\
2509  \n {\
2510  \n discard;\
2511  \n }\
2512  \n\
2513  \n // color buffer or max scalar buffer have a reduced size.\
2514  \n fragTexCoord = (gl_FragCoord.xy - in_windowLowerLeftCorner) *\
2515  \n in_inverseOriginalWindowSize;\
2516  \n");
2517 
2518  if (mapper->GetBlendMode() == vtkVolumeMapper::SLICE_BLEND)
2519  {
2520  vtkImplicitFunction* sliceFunc = vol->GetProperty()->GetSliceFunction();
2521  if (sliceFunc)
2522  {
2523  if (sliceFunc->IsA("vtkPlane"))
2524  {
2525  shaderStr += std::string("\
2526  \n\
2527  \n // Intersection with plane\
2528  \n float t = intersectRayPlane(ip_vertexPos, rayDir);\
2529  \n vec4 intersection = vec4(ip_vertexPos + t * rayDir, 1.0);\
2530  \n g_intersection = (in_inverseTextureDatasetMatrix[0] * intersection).xyz;\
2531  \n vec4 intersDC = in_projectionMatrix * in_modelViewMatrix * in_volumeMatrix[0] * intersection;\
2532  \n intersDC.xyz /= intersDC.w;\
2533  \n vec4 intersWin = NDCToWindow(intersDC.x, intersDC.y, intersDC.z);\
2534  \n if(intersWin.z >= l_depthValue.x)\
2535  \n {\
2536  \n discard;\
2537  \n }\
2538  \n");
2539  }
2540  else
2541  {
2542  vtkErrorWithObjectMacro(
2543  sliceFunc, "Implicit function type is not supported by this mapper.");
2544  }
2545  }
2546  }
2547 
2548  shaderStr += std::string("\
2549  \n // Compute max number of iterations it will take before we hit\
2550  \n // the termination point\
2551  \n\
2552  \n // Abscissa of the point on the depth buffer along the ray.\
2553  \n // point in texture coordinates\
2554  \n vec4 rayTermination = WindowToNDC(gl_FragCoord.x, gl_FragCoord.y, l_depthValue.x);\
2555  \n\
2556  \n // From normalized device coordinates to eye coordinates.\
2557  \n // in_projectionMatrix is inversed because of way VT\
2558  \n // From eye coordinates to texture coordinates\
2559  \n rayTermination = ip_inverseTextureDataAdjusted *\
2560  \n in_inverseVolumeMatrix[0] *\
2561  \n in_inverseModelViewMatrix *\
2562  \n in_inverseProjectionMatrix *\
2563  \n rayTermination;\
2564  \n g_rayTermination = rayTermination.xyz / rayTermination.w;\
2565  \n\
2566  \n // Setup the current segment:\
2567  \n g_dataPos = g_rayOrigin;\
2568  \n g_terminatePos = g_rayTermination;\
2569  \n\
2570  \n g_terminatePointMax = length(g_terminatePos.xyz - g_dataPos.xyz) /\
2571  \n length(g_dirStep);\
2572  \n g_currentT = 0.0;");
2573 
2574  return shaderStr;
2575 }
2576 
2577 //--------------------------------------------------------------------------
2579  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2580 {
2581  return std::string("\
2582  \n if(any(greaterThan(max(g_dirStep, vec3(0.0))*(g_dataPos - in_texMax[0]),vec3(0.0))) ||\
2583  \n any(greaterThan(min(g_dirStep, vec3(0.0))*(g_dataPos - in_texMin[0]),vec3(0.0))))\
2584  \n {\
2585  \n break;\
2586  \n }\
2587  \n\
2588  \n // Early ray termination\
2589  \n // if the currently composited colour alpha is already fully saturated\
2590  \n // we terminated the loop or if we have hit an obstacle in the\
2591  \n // direction of they ray (using depth buffer) we terminate as well.\
2592  \n if((g_fragColor.a > g_opacityThreshold) || \
2593  \n g_currentT >= g_terminatePointMax)\
2594  \n {\
2595  \n break;\
2596  \n }\
2597  \n ++g_currentT;");
2598 }
2599 
2600 //--------------------------------------------------------------------------
2602  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2603 {
2604  return std::string();
2605 }
2606 
2607 //--------------------------------------------------------------------------
2609  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2610 {
2611  return std::string();
2612 }
2613 
2614 //--------------------------------------------------------------------------
2616  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
2617 {
2618  if (!mapper->GetCropping())
2619  {
2620  return std::string();
2621  }
2622 
2623  return std::string("\
2624  \nuniform float in_croppingPlanes[6];\
2625  \nuniform int in_croppingFlags [32];\
2626  \nfloat croppingPlanesTexture[6];\
2627  \n\
2628  \n// X: axis = 0, Y: axis = 1, Z: axis = 2\
2629  \n// cp Cropping plane bounds (minX, maxX, minY, maxY, minZ, maxZ)\
2630  \nint computeRegionCoord(float cp[6], vec3 pos, int axis)\
2631  \n {\
2632  \n int cpmin = axis * 2;\
2633  \n int cpmax = cpmin + 1;\
2634  \n\
2635  \n if (pos[axis] < cp[cpmin])\
2636  \n {\
2637  \n return 1;\
2638  \n }\
2639  \n else if (pos[axis] >= cp[cpmin] &&\
2640  \n pos[axis] < cp[cpmax])\
2641  \n {\
2642  \n return 2;\
2643  \n }\
2644  \n else if (pos[axis] >= cp[cpmax])\
2645  \n {\
2646  \n return 3;\
2647  \n }\
2648  \n return 0;\
2649  \n }\
2650  \n\
2651  \nint computeRegion(float cp[6], vec3 pos)\
2652  \n {\
2653  \n return (computeRegionCoord(cp, pos, 0) +\
2654  \n (computeRegionCoord(cp, pos, 1) - 1) * 3 +\
2655  \n (computeRegionCoord(cp, pos, 2) - 1) * 9);\
2656  \n }");
2657 }
2658 
2659 //--------------------------------------------------------------------------
2661  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
2662 {
2663  if (!mapper->GetCropping())
2664  {
2665  return std::string();
2666  }
2667 
2668  return std::string("\
2669  \n // Convert cropping region to texture space\
2670  \n mat4 datasetToTextureMat = in_inverseTextureDatasetMatrix[0];\
2671  \n\
2672  \n vec4 tempCrop = vec4(in_croppingPlanes[0], 0.0, 0.0, 1.0);\
2673  \n tempCrop = datasetToTextureMat * tempCrop;\
2674  \n if (tempCrop[3] != 0.0)\
2675  \n {\
2676  \n tempCrop[0] /= tempCrop[3];\
2677  \n }\
2678  \n croppingPlanesTexture[0] = tempCrop[0];\
2679  \n\
2680  \n tempCrop = vec4(in_croppingPlanes[1], 0.0, 0.0, 1.0);\
2681  \n tempCrop = datasetToTextureMat * tempCrop;\
2682  \n if (tempCrop[3] != 0.0)\
2683  \n {\
2684  \n tempCrop[0] /= tempCrop[3];\
2685  \n }\
2686  \n croppingPlanesTexture[1] = tempCrop[0];\
2687  \n\
2688  \n tempCrop = vec4(0.0, in_croppingPlanes[2], 0.0, 1.0);\
2689  \n tempCrop = datasetToTextureMat * tempCrop;\
2690  \n if (tempCrop[3] != 0.0)\
2691  \n {\
2692  \n tempCrop[1] /= tempCrop[3];\
2693  \n }\
2694  \n croppingPlanesTexture[2] = tempCrop[1];\
2695  \n\
2696  \n tempCrop = vec4(0.0, in_croppingPlanes[3], 0.0, 1.0);\
2697  \n tempCrop = datasetToTextureMat * tempCrop;\
2698  \n if (tempCrop[3] != 0.0)\
2699  \n {\
2700  \n tempCrop[1] /= tempCrop[3];\
2701  \n }\
2702  \n croppingPlanesTexture[3] = tempCrop[1];\
2703  \n\
2704  \n tempCrop = vec4(0.0, 0.0, in_croppingPlanes[4], 1.0);\
2705  \n tempCrop = datasetToTextureMat * tempCrop;\
2706  \n if (tempCrop[3] != 0.0)\
2707  \n {\
2708  \n tempCrop[2] /= tempCrop[3];\
2709  \n }\
2710  \n croppingPlanesTexture[4] = tempCrop[2];\
2711  \n\
2712  \n tempCrop = vec4(0.0, 0.0, in_croppingPlanes[5], 1.0);\
2713  \n tempCrop = datasetToTextureMat * tempCrop;\
2714  \n if (tempCrop[3] != 0.0)\
2715  \n {\
2716  \n tempCrop[2] /= tempCrop[3];\
2717  \n }\
2718  \n croppingPlanesTexture[5] = tempCrop[2];");
2719 }
2720 
2721 //--------------------------------------------------------------------------
2723  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
2724 {
2725  if (!mapper->GetCropping())
2726  {
2727  return std::string();
2728  }
2729 
2730  return std::string("\
2731  \n // Determine region\
2732  \n int regionNo = computeRegion(croppingPlanesTexture, g_dataPos);\
2733  \n\
2734  \n // Do & operation with cropping flags\
2735  \n // Pass the flag that its Ok to sample or not to sample\
2736  \n if (in_croppingFlags[regionNo] == 0)\
2737  \n {\
2738  \n // Skip this voxel\
2739  \n g_skip = true;\
2740  \n }");
2741 }
2742 
2743 //--------------------------------------------------------------------------
2745  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2746 {
2747  return std::string();
2748 }
2749 
2750 //--------------------------------------------------------------------------
2752  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2753 {
2754  return std::string();
2755 }
2756 
2757 //--------------------------------------------------------------------------
2759  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
2760 {
2761  if (!mapper->GetClippingPlanes())
2762  {
2763  return std::string();
2764  }
2765 
2766  return std::string("\
2767  \n /// We support only 8 clipping planes for now\
2768  \n /// The first value is the size of the data array for clipping\
2769  \n /// planes (origin, normal)\
2770  \n uniform float in_clippingPlanes[49];\
2771  \n uniform float in_clippedVoxelIntensity;\
2772  \n\
2773  \n int clip_numPlanes;\
2774  \n vec3 clip_rayDirObj;\
2775  \n mat4 clip_texToObjMat;\
2776  \n mat4 clip_objToTexMat;\
2777  \n\
2778  \n// Tighten the sample range as needed to account for clip planes. \
2779  \n// Arguments are in texture coordinates. \
2780  \n// Returns true if the range is at all valid after clipping. If not, \
2781  \n// the fragment should be discarded. \
2782  \nbool AdjustSampleRangeForClipping(inout vec3 startPosTex, inout vec3 stopPosTex) \
2783  \n{ \
2784  \n vec4 startPosObj = vec4(0.0);\
2785  \n {\
2786  \n startPosObj = clip_texToObjMat * vec4(startPosTex - g_rayJitter, 1.0);\
2787  \n startPosObj = startPosObj / startPosObj.w;\
2788  \n startPosObj.w = 1.0;\
2789  \n }\
2790  \n\
2791  \n vec4 stopPosObj = vec4(0.0);\
2792  \n {\
2793  \n stopPosObj = clip_texToObjMat * vec4(stopPosTex, 1.0);\
2794  \n stopPosObj = stopPosObj / stopPosObj.w;\
2795  \n stopPosObj.w = 1.0;\
2796  \n }\
2797  \n\
2798  \n for (int i = 0; i < clip_numPlanes; i = i + 6)\
2799  \n {\
2800  \n vec3 planeOrigin = vec3(in_clippingPlanes[i + 1],\
2801  \n in_clippingPlanes[i + 2],\
2802  \n in_clippingPlanes[i + 3]);\
2803  \n vec3 planeNormal = normalize(vec3(in_clippingPlanes[i + 4],\
2804  \n in_clippingPlanes[i + 5],\
2805  \n in_clippingPlanes[i + 6]));\
2806  \n\
2807  \n // Abort if the entire segment is clipped:\
2808  \n // (We can do this before adjusting the term point, since it'll \
2809  \n // only move further into the clipped area)\
2810  \n float startDistance = dot(planeNormal, planeOrigin - startPosObj.xyz);\
2811  \n float stopDistance = dot(planeNormal, planeOrigin - stopPosObj.xyz);\
2812  \n bool startClipped = startDistance > 0.0;\
2813  \n bool stopClipped = stopDistance > 0.0;\
2814  \n if (startClipped && stopClipped)\
2815  \n {\
2816  \n return false;\
2817  \n }\
2818  \n\
2819  \n float rayDotNormal = dot(clip_rayDirObj, planeNormal);\
2820  \n bool frontFace = rayDotNormal > 0.0;\
2821  \n\
2822  \n // Move the start position further from the eye if needed:\
2823  \n if (frontFace && // Observing from the clipped side (plane's front face)\
2824  \n startDistance > 0.0) // Ray-entry lies on the clipped side.\
2825  \n {\
2826  \n // Scale the point-plane distance to the ray direction and update the\
2827  \n // entry point.\
2828  \n float rayScaledDist = startDistance / rayDotNormal;\
2829  \n startPosObj = vec4(startPosObj.xyz + rayScaledDist * clip_rayDirObj, 1.0);\
2830  \n vec4 newStartPosTex = clip_objToTexMat * vec4(startPosObj.xyz, 1.0);\
2831  \n newStartPosTex /= newStartPosTex.w;\
2832  \n startPosTex = newStartPosTex.xyz;\
2833  \n startPosTex += g_rayJitter;\
2834  \n }\
2835  \n\
2836  \n // Move the end position closer to the eye if needed:\
2837  \n if (!frontFace && // Observing from the unclipped side (plane's back face)\
2838  \n stopDistance > 0.0) // Ray-entry lies on the unclipped side.\
2839  \n {\
2840  \n // Scale the point-plane distance to the ray direction and update the\
2841  \n // termination point.\
2842  \n float rayScaledDist = stopDistance / rayDotNormal;\
2843  \n stopPosObj = vec4(stopPosObj.xyz + rayScaledDist * clip_rayDirObj, 1.0);\
2844  \n vec4 newStopPosTex = clip_objToTexMat * vec4(stopPosObj.xyz, 1.0);\
2845  \n newStopPosTex /= newStopPosTex.w;\
2846  \n stopPosTex = newStopPosTex.xyz;\
2847  \n }\
2848  \n }\
2849  \n\
2850  \n if (any(greaterThan(startPosTex, in_texMax[0])) ||\
2851  \n any(lessThan(startPosTex, in_texMin[0])))\
2852  \n {\
2853  \n return false;\
2854  \n }\
2855  \n\
2856  \n return true;\
2857  \n}\
2858  \n");
2859 }
2860 
2861 //--------------------------------------------------------------------------
2863 {
2864  if (!mapper->GetClippingPlanes())
2865  {
2866  return std::string();
2867  }
2868 
2869  std::string shaderStr;
2870  if (!ren->GetActiveCamera()->GetParallelProjection())
2871  {
2872  shaderStr = std::string("\
2873  \n vec4 tempClip = in_volumeMatrix[0] * vec4(rayDir, 0.0);\
2874  \n if (tempClip.w != 0.0)\
2875  \n {\
2876  \n tempClip = tempClip/tempClip.w;\
2877  \n tempClip.w = 1.0;\
2878  \n }\
2879  \n clip_rayDirObj = normalize(tempClip.xyz);");
2880  }
2881  else
2882  {
2883  shaderStr = std::string("\
2884  clip_rayDirObj = normalize(in_projectionDirection);");
2885  }
2886 
2887  shaderStr += std::string("\
2888  \n clip_numPlanes = int(in_clippingPlanes[0]);\
2889  \n clip_texToObjMat = in_volumeMatrix[0] * in_textureDatasetMatrix[0];\
2890  \n clip_objToTexMat = in_inverseTextureDatasetMatrix[0] * in_inverseVolumeMatrix[0];\
2891  \n\
2892  \n // Adjust for clipping.\
2893  \n if (!AdjustSampleRangeForClipping(g_rayOrigin, g_rayTermination))\
2894  \n { // entire ray is clipped.\
2895  \n discard;\
2896  \n }\
2897  \n\
2898  \n // Update the segment post-clip:\
2899  \n g_dataPos = g_rayOrigin;\
2900  \n g_terminatePos = g_rayTermination;\
2901  \n g_terminatePointMax = length(g_terminatePos.xyz - g_dataPos.xyz) /\
2902  \n length(g_dirStep);\
2903  \n");
2904 
2905  return shaderStr;
2906 }
2907 
2908 //--------------------------------------------------------------------------
2910  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2911 {
2912  return std::string();
2913 }
2914 
2915 //--------------------------------------------------------------------------
2917  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2918 {
2919  return std::string();
2920 }
2921 
2922 //--------------------------------------------------------------------------
2923 std::string BinaryMaskDeclaration(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper),
2924  vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput, vtkVolumeTexture* mask,
2925  int vtkNotUsed(maskType))
2926 {
2927  if (!mask || !maskInput)
2928  {
2929  return std::string();
2930  }
2931  else
2932  {
2933  return std::string("uniform sampler3D in_mask;");
2934  }
2935 }
2936 
2937 //--------------------------------------------------------------------------
2939  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput,
2940  vtkVolumeTexture* mask, int maskType)
2941 {
2942  if (!mask || !maskInput || maskType == vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2943  {
2944  return std::string();
2945  }
2946  else
2947  {
2948  return std::string("\
2949  \nvec4 maskValue = texture3D(in_mask, g_dataPos);\
2950  \nif(maskValue.r <= 0.0)\
2951  \n {\
2952  \n g_skip = true;\
2953  \n }");
2954  }
2955 }
2956 
2957 //--------------------------------------------------------------------------
2959  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput,
2960  vtkVolumeTexture* mask, int maskType)
2961 {
2962  if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2963  {
2964  return std::string();
2965  }
2966  else
2967  {
2968  return std::string("\
2969  \nuniform float in_maskBlendFactor;\
2970  \nuniform sampler2D in_labelMapTransfer;\
2971  \nuniform float in_mask_scale;\
2972  \nuniform float in_mask_bias;\
2973  \nuniform int in_labelMapNumLabels;\
2974  \n");
2975  }
2976 }
2977 
2978 //--------------------------------------------------------------------------
2980  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput,
2981  vtkVolumeTexture* mask, int maskType, int noOfComponents)
2982 {
2983  if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2984  {
2985  return std::string();
2986  }
2987  else
2988  {
2989  std::string shaderStr = std::string("\
2990  \nvec4 scalar = texture3D(in_volume[0], g_dataPos);");
2991 
2992  // simulate old intensity textures
2993  if (noOfComponents == 1)
2994  {
2995  shaderStr += std::string("\
2996  \n scalar.r = scalar.r * in_volume_scale[0].r + in_volume_bias[0].r;\
2997  \n scalar = vec4(scalar.r);");
2998  }
2999  else
3000  {
3001  // handle bias and scale
3002  shaderStr += std::string("\
3003  \n scalar = scalar * in_volume_scale[0] + in_volume_bias[0];");
3004  }
3005 
3006  // Assumeing single component scalar for label texture lookup.
3007  // This can be extended to composite color obtained from all components
3008  // in the scalar array.
3009  return shaderStr + std::string("\
3010  \nif (in_maskBlendFactor == 0.0)\
3011  \n {\
3012  \n g_srcColor.a = computeOpacity(scalar);\
3013  \n if (g_srcColor.a > 0)\
3014  \n {\
3015  \n g_srcColor = computeColor(scalar, g_srcColor.a);\
3016  \n }\
3017  \n }\
3018  \nelse\
3019  \n {\
3020  \n float opacity = computeOpacity(scalar);\
3021  \n // Get the mask value at this same location\
3022  \n vec4 maskValue = texture3D(in_mask, g_dataPos);\
3023  \n maskValue.r = maskValue.r * in_mask_scale + in_mask_bias;\
3024  \n // Quantize the height of the labelmap texture over number of labels\
3025  \n if (in_labelMapNumLabels > 0)\
3026  \n {\
3027  \n maskValue.r =\
3028  \n floor(maskValue.r * in_labelMapNumLabels) /\
3029  \n in_labelMapNumLabels;\
3030  \n }\
3031  \n else\
3032  \n {\
3033  \n maskValue.r = 0.0;\
3034  \n }\
3035  \n if(maskValue.r == 0.0)\
3036  \n {\
3037  \n g_srcColor.a = opacity;\
3038  \n if (g_srcColor.a > 0)\
3039  \n {\
3040  \n g_srcColor = computeColor(scalar, g_srcColor.a);\
3041  \n }\
3042  \n }\
3043  \n else\
3044  \n {\
3045  \n g_srcColor = texture2D(in_labelMapTransfer,\
3046  \n vec2(scalar.r, maskValue.r));\
3047  \n if (g_srcColor.a > 0)\
3048  \n {\
3049  \n g_srcColor = computeLighting(g_srcColor, 0, maskValue.r);\
3050  \n }\
3051  \n if (in_maskBlendFactor < 1.0)\
3052  \n {\
3053  \n vec4 color = opacity > 0 ? computeColor(scalar, opacity) : vec4(0);\
3054  \n g_srcColor = (1.0 - in_maskBlendFactor) * color +\
3055  \n in_maskBlendFactor * g_srcColor;\
3056  \n }\
3057  \n }\
3058  \n }");
3059  }
3060 }
3061 
3062 //--------------------------------------------------------------------------
3064  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3065 {
3066  return std::string("uniform bool in_clampDepthToBackface;\n"
3067  "vec3 l_opaqueFragPos;\n"
3068  "bool l_updateDepth;\n");
3069 }
3070 
3071 //--------------------------------------------------------------------------
3073  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3074 {
3075  return std::string("\
3076  \n l_opaqueFragPos = vec3(-1.0);\
3077  \n if(in_clampDepthToBackface)\
3078  \n {\
3079  \n l_opaqueFragPos = g_dataPos;\
3080  \n }\
3081  \n l_updateDepth = true;");
3082 }
3083 
3084 //--------------------------------------------------------------------------
3086  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3087 {
3088  return std::string("\
3089  \n if(!g_skip && g_srcColor.a > 0.0 && l_updateDepth)\
3090  \n {\
3091  \n l_opaqueFragPos = g_dataPos;\
3092  \n l_updateDepth = false;\
3093  \n }");
3094 }
3095 
3096 //--------------------------------------------------------------------------
3098  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3099 {
3100  return std::string("\
3101  \n if (l_opaqueFragPos == vec3(-1.0))\
3102  \n {\
3103  \n gl_FragData[1] = vec4(1.0);\
3104  \n }\
3105  \n else\
3106  \n {\
3107  \n vec4 depthValue = in_projectionMatrix * in_modelViewMatrix *\
3108  \n in_volumeMatrix[0] * in_textureDatasetMatrix[0] *\
3109  \n vec4(l_opaqueFragPos, 1.0);\
3110  \n depthValue /= depthValue.w;\
3111  \n gl_FragData[1] = vec4(vec3(0.5 * (gl_DepthRange.far -\
3112  \n gl_DepthRange.near) * depthValue.z + 0.5 *\
3113  \n (gl_DepthRange.far + gl_DepthRange.near)), 1.0);\
3114  \n }");
3115 }
3116 
3117 //--------------------------------------------------------------------------
3119  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3120 {
3121  return std::string("\
3122  \n vec3 l_isoPos = g_dataPos;");
3123 }
3124 
3125 //--------------------------------------------------------------------------
3127  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3128 {
3129  return std::string("\
3130  \n if(!g_skip && g_srcColor.a > 0.0)\
3131  \n {\
3132  \n l_isoPos = g_dataPos;\
3133  \n g_exit = true; g_skip = true;\
3134  \n }");
3135 }
3136 
3137 //--------------------------------------------------------------------------
3139  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3140 {
3141  return std::string("\
3142  \n vec4 depthValue = in_projectionMatrix * in_modelViewMatrix *\
3143  \n in_volumeMatrix[0] * in_textureDatasetMatrix[0] *\
3144  \n vec4(l_isoPos, 1.0);\
3145  \n gl_FragData[0] = vec4(l_isoPos, 1.0);\
3146  \n gl_FragData[1] = vec4(vec3((depthValue.z/depthValue.w) * 0.5 + 0.5),\
3147  \n 1.0);");
3148 }
3149 
3150 //---------------------------------------------------------------------------
3152  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3153 {
3154  return std::string("\
3155  \n initializeRayCast();\
3156  \n castRay(-1.0, -1.0);\
3157  \n finalizeRayCast();");
3158 }
3159 
3160 //---------------------------------------------------------------------------
3162  const std::vector<std::string>& varNames, const size_t usedNames)
3163 {
3164  std::string shader = "\n";
3165  for (size_t i = 0; i < usedNames; i++)
3166  {
3167  shader += "uniform sampler2D " + varNames[i] + ";\n";
3168  }
3169  return shader;
3170 }
3171 
3172 //---------------------------------------------------------------------------
3174  const std::vector<std::string>& varNames, const size_t usedNames)
3175 {
3176  std::string shader = "\n";
3177  for (size_t i = 0; i < usedNames; i++)
3178  {
3179  std::stringstream ss;
3180  ss << i;
3181  shader += " gl_FragData[" + ss.str() + "] = texture2D(" + varNames[i] + ", texCoord);\n";
3182  }
3183  shader += " return;\n";
3184  return shader;
3185 }
3186 }
3187 
3188 #endif // vtkVolumeShaderComposer_h
3189 // VTK-HeaderTest-Exclude: vtkVolumeShaderComposer.h
virtual vtkPlaneCollection * GetClippingPlanes()
Get/Set the vtkPlaneCollection which specifies the clipping planes.
virtual vtkTypeBool GetParallelProjection()
Set/Get the value of the ParallelProjection instance variable.
vtkUnsignedCharArray * GetPointGhostArray()
Gets the array that defines the ghost type of each point.
vtkUnsignedCharArray * GetCellGhostArray()
Get the array that defines the ghost type of each cell.
static vtkDataSet * SafeDownCast(vtkObjectBase *o)
static vtkGPUVolumeRayCastMapper * SafeDownCast(vtkObjectBase *o)
virtual vtkTypeBool GetUseDepthPass()
If UseDepthPass is on, the mapper will use two passes.
virtual vtkTypeBool GetUseJittering()
If UseJittering is on, each ray traversal direction will be perturbed slightly using a noise-texture ...
topologically and geometrically regular array of data
Definition: vtkImageData.h:48
abstract interface for implicit functions
virtual vtkTypeBool IsA(const char *type)
Return 1 if this class is the same type of (or a subclass of) the named class.
OpenGL implementation of volume rendering through ray-casting.
std::map< int, vtkVolumeInputHelper > VolumeInputMap
static vtkOpenGLGPUVolumeRayCastMapper * SafeDownCast(vtkObjectBase *o)
static vtkRectilinearGrid * SafeDownCast(vtkObjectBase *o)
abstract specification for renderers
Definition: vtkRenderer.h:73
vtkCamera * GetActiveCamera()
Get the current camera.
Abstract class for a volume mapper.
virtual vtkTypeBool GetCropping()
Turn On/Off orthogonal cropping.
virtual int GetBlendMode()
Set/Get the blend mode.
virtual vtkDataSet * GetInput()
Set/Get the input data.
represents the common properties for rendering a volume.
virtual int GetDisableGradientOpacity(int index)
Enable/Disable the gradient opacity function for the given component.
virtual int GetUseClippedVoxelIntensity()
Set/Get whether to use a fixed intensity value for voxels in the clipped space for gradient calculati...
bool HasGradientOpacity(int index=0)
Check whether or not we have the gradient opacity.
int GetShade(int index)
Set/Get the shading of a volume.
virtual int GetTransferFunctionMode()
Color-opacity transfer function mode.
Creates and manages the volume texture rendered by vtkOpenGLGPUVolumeRayCastMapper.
represents a volume (data & properties) in a rendered scene
Definition: vtkVolume.h:45
virtual vtkVolumeProperty * GetProperty()
Set/Get the volume property.
@ string
Definition: vtkX3D.h:496
std::string ClippingDeclarationFragment(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkVolume *vtkNotUsed(vol))
std::string ComputeGradientOpacity1DDecl(vtkVolume *vol, int noOfComponents, int independentComponents, std::map< int, std::string > gradientTableMap)
std::string WorkerImplementation(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string TerminationExit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string ClippingDeclarationVertex(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string TerminationImplementation(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string ComputeLightingMultiDeclaration(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkVolume *vol, int noOfComponents, int independentComponents, int vtkNotUsed(numberOfLights), int lightingComplexity)
std::string BinaryMaskDeclaration(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol), vtkImageData *maskInput, vtkVolumeTexture *mask, int vtkNotUsed(maskType))
std::string PickingIdLow24PassExit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string ComputeLightingDeclaration(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkVolume *vol, int noOfComponents, int independentComponents, int vtkNotUsed(numberOfLights), int lightingComplexity)
std::string CroppingDeclarationFragment(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 CroppingImplementation(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkVolume *vtkNotUsed(vol))
std::string ShadingExit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkVolume *vtkNotUsed(vol), int noOfComponents, int independentComponents=0)
std::string BaseExit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string ImageSampleDeclarationFrag(const std::vector< std::string > &varNames, const size_t usedNames)
std::string ComputeOpacityMultiDeclaration(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs)
std::string BaseDeclarationVertex(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkVolume *vtkNotUsed(vol), bool multipleInputs)
std::string ComputeTextureCoordinates(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string DepthPassInit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string TerminationInit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkVolume *vol)
std::string RenderToImageInit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string ComputeClipPositionImplementation(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string RenderToImageImplementation(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string ComputeOpacityDeclaration(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol), int noOfComponents, int independentComponents, std::map< int, std::string > opacityTableMap)
std::string PreComputeGradientsImpl(vtkRenderer *vtkNotUsed(ren), vtkVolume *vtkNotUsed(vol), int noOfComponents=1, int independentComponents=0)
std::string ComputeColorMultiDeclaration(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs)
std::string ClippingExit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string ComputeGradientDeclaration(vtkOpenGLGPUVolumeRayCastMapper *mapper, vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs)
std::string BaseInit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs, int lightingComplexity)
std::string PickingIdHigh24PassExit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string TerminationDeclarationVertex(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string PickingActorPassExit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string RenderToImageDeclarationFragment(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string BaseImplementation(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkVolume *vtkNotUsed(vol))
std::string RenderToImageExit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string ShadingDeclarationVertex(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string ShadingSingleInput(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkVolume *vtkNotUsed(vol), vtkImageData *maskInput, vtkVolumeTexture *mask, int maskType, int noOfComponents, int independentComponents=0)
std::string ShadingMultipleInputs(vtkVolumeMapper *mapper, vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs)
std::string CompositeMaskDeclarationFragment(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol), vtkImageData *maskInput, vtkVolumeTexture *mask, int maskType)
std::string ComputeRayDirectionDeclaration(vtkRenderer *ren, vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol), int vtkNotUsed(noOfComponents))
std::string DepthPassImplementation(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string GradientCacheDec(vtkRenderer *vtkNotUsed(ren), vtkVolume *vtkNotUsed(vol), vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs, int independentComponents=0)
std::string Transfer2DDeclaration(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs)
std::string ClippingImplementation(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string CroppingDeclarationVertex(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string CroppingInit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkVolume *vtkNotUsed(vol))
std::string CompositeMaskImplementation(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol), vtkImageData *maskInput, vtkVolumeTexture *mask, int maskType, int noOfComponents)
std::string ComputeColor2DYAxisDeclaration(int noOfComponents, int vtkNotUsed(independentComponents), std::map< int, std::string > colorTableMap)
std::string ImageSampleImplementationFrag(const std::vector< std::string > &varNames, const size_t usedNames)
std::string CroppingExit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string ClippingInit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vtkNotUsed(vol))
std::string TerminationDeclarationFragment(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string ShadingDeclarationFragment(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkVolume *vtkNotUsed(vol))
std::string PickingActorPassDeclaration(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string ShadingInit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkVolume *vtkNotUsed(vol))
std::string BinaryMaskImplementation(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol), vtkImageData *maskInput, vtkVolumeTexture *mask, int maskType)
std::string DepthPassExit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string ComputeOpacity2DDeclaration(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol), int noOfComponents, int independentComponents, std::map< int, std::string > opacityTableMap, int useGradient)
std::string ComputeColor2DDeclaration(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol), int noOfComponents, int independentComponents, std::map< int, std::string > colorTableMap, int useGradient)
std::string ComputeGradientOpacityMulti1DDecl(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs)
std::string BaseDeclarationFragment(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs, int vtkNotUsed(numberOfLights), int lightingComplexity, int noOfComponents, int independentComponents)