VTK  9.0.3
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 <vtkRenderer.h>
22 #include <vtkVolume.h>
23 #include <vtkVolumeInputHelper.h>
24 #include <vtkVolumeMapper.h>
25 #include <vtkVolumeProperty.h>
26 #include <vtkVolumeTexture.h>
27 
28 #include <map>
29 #include <sstream>
30 #include <string>
31 
32 namespace
33 {
34 bool HasGradientOpacity(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs)
35 {
36  for (auto& item : inputs)
37  {
38  vtkVolumeProperty* volProp = item.second.Volume->GetProperty();
39  const bool gradOp = (volProp->HasGradientOpacity() || volProp->HasLabelGradientOpacity()) &&
40  !volProp->GetDisableGradientOpacity();
41  if (gradOp)
42  return true;
43  }
44  return false;
45 }
46 
48 {
49  for (auto& item : inputs)
50  {
51  vtkVolumeProperty* volProp = item.second.Volume->GetProperty();
52  const bool lighting = volProp->GetShade() == 1;
53  if (lighting)
54  return true;
55  }
56  return false;
57 }
58 
59 bool UseClippedVoxelIntensity(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs)
60 {
61  for (auto& item : inputs)
62  {
63  vtkVolumeProperty* volProp = item.second.Volume->GetProperty();
64  const bool useClippedVoxelIntensity = volProp->GetUseClippedVoxelIntensity() == 1;
65  if (useClippedVoxelIntensity)
66  {
67  return true;
68  }
69  }
70  return false;
71 }
72 
73 const std::string ArrayBaseName(const std::string& arrayName)
74 {
75  const std::string base = arrayName.substr(0, arrayName.length() - 3);
76  return base;
77 }
78 }
79 
80 // NOTE:
81 // In this code, we referred to various spaces described below:
82 // Object space: Raw coordinates in space defined by volume matrix
83 // Dataset space: Raw coordinates
84 // Eye space: Coordinates in eye space (as referred in computer graphics)
85 
86 namespace vtkvolume
87 {
88 //--------------------------------------------------------------------------
90  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
91 {
92  return std::string(
93  " //Transform vertex (data coordinates) to clip coordinates\n"
94  " // p_clip = T_ProjViewModel * T_dataToWorld * p_data\n"
95  " vec4 pos = in_projectionMatrix * in_modelViewMatrix * in_volumeMatrix[0] *\n"
96  " vec4(in_vertexPos.xyz, 1.0);\n"
97  " gl_Position = pos;\n");
98 }
99 
100 //--------------------------------------------------------------------------
102  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
103 {
104  return std::string(
105  " // Transform vertex (data coordinates) to texture coordinates.\n"
106  " // p_texture = T_dataToTex * p_data\n"
107  " vec3 uvx = sign(in_cellSpacing[0]) * (in_inverseTextureDatasetMatrix[0] *\n"
108  " vec4(in_vertexPos, 1.0)).xyz;\n"
109  "\n"
110  " // For point dataset, we offset the texture coordinate\n"
111  " // to account for OpenGL treating voxel at the center of the cell.\n"
112  " // Transform cell tex-coordinates to point tex-coordinates (cellToPoint\n"
113  " // is an identity matrix in the case of cell data).\n"
114  " ip_textureCoords = (in_cellToPoint[0] * vec4(uvx, 1.0)).xyz;\n"
115  " ip_inverseTextureDataAdjusted = in_cellToPoint[0] * in_inverseTextureDatasetMatrix[0];\n");
116 }
117 
118 //--------------------------------------------------------------------------
120  vtkVolume* vtkNotUsed(vol), bool multipleInputs)
121 {
122  auto gpuMapper = vtkGPUVolumeRayCastMapper::SafeDownCast(mapper);
123  const int numInputs = gpuMapper->GetInputCount();
124 
125  std::ostringstream ss;
126  ss << "uniform vec3 in_cellSpacing[" << numInputs
127  << "];\n"
128  "uniform mat4 in_modelViewMatrix;\n"
129  "uniform mat4 in_projectionMatrix;\n";
130 
131  const int numTransf = multipleInputs ? numInputs + 1 : 1;
132  ss << "uniform mat4 in_volumeMatrix[" << numTransf
133  << "];\n"
134  "uniform mat4 in_inverseTextureDatasetMatrix["
135  << numTransf
136  << "];\n"
137  "uniform mat4 in_cellToPoint["
138  << numTransf
139  << "];\n"
140  "\n"
141  "//This variable could be 'invariant varying' but it is declared\n"
142  "//as 'varying' to avoid compiler compatibility issues.\n"
143  "out mat4 ip_inverseTextureDataAdjusted;\n";
144 
145  return ss.str();
146 }
147 
148 //--------------------------------------------------------------------------
150  vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, int vtkNotUsed(numberOfLights),
151  int lightingComplexity, int noOfComponents, int independentComponents)
152 {
153  const int numInputs = static_cast<int>(inputs.size());
154 
155  std::ostringstream toShaderStr;
156  toShaderStr << "uniform sampler3D in_volume[" << numInputs << "];\n";
157 
158  toShaderStr << "uniform vec4 in_volume_scale[" << numInputs
159  << "];\n"
160  "uniform vec4 in_volume_bias["
161  << numInputs << "];\n";
162 
163  toShaderStr << "uniform int in_noOfComponents;\n"
164  "uniform int in_independentComponents;\n"
165  "\n"
166  "uniform sampler2D in_noiseSampler;\n"
167  "#ifndef GL_ES\n"
168  "uniform sampler2D in_depthSampler;\n"
169  "#endif\n"
170  "\n"
171  "// Camera position\n"
172  "uniform vec3 in_cameraPos;\n";
173 
174  // For multiple inputs (numInputs > 1), an additional transformation is
175  // needed for the bounding-box.
176  const int numTransf = (numInputs > 1) ? numInputs + 1 : 1;
177  toShaderStr << "uniform mat4 in_volumeMatrix[" << numTransf
178  << "];\n"
179  "uniform mat4 in_inverseVolumeMatrix["
180  << numTransf
181  << "];\n"
182  "uniform mat4 in_textureDatasetMatrix["
183  << numTransf
184  << "];\n"
185  "uniform mat4 in_inverseTextureDatasetMatrix["
186  << numTransf
187  << "];\n"
188  "uniform mat4 in_textureToEye["
189  << numTransf
190  << "];\n"
191  "uniform vec3 in_texMin["
192  << numTransf
193  << "];\n"
194  "uniform vec3 in_texMax["
195  << numTransf
196  << "];\n"
197  "uniform mat4 in_cellToPoint["
198  << numTransf << "];\n";
199 
200  toShaderStr << "// view and model matrices\n"
201  "uniform mat4 in_projectionMatrix;\n"
202  "uniform mat4 in_inverseProjectionMatrix;\n"
203  "uniform mat4 in_modelViewMatrix;\n"
204  "uniform mat4 in_inverseModelViewMatrix;\n"
205  "in mat4 ip_inverseTextureDataAdjusted;\n"
206  "\n"
207  "// Ray step size\n"
208  "uniform vec3 in_cellStep["
209  << numInputs << "];\n";
210 
211  toShaderStr << "uniform vec2 in_scalarsRange[" << numInputs * 4
212  << "];\n"
213  "uniform vec3 in_cellSpacing["
214  << numInputs
215  << "];\n"
216  "\n"
217  "// Sample distance\n"
218  "uniform float in_sampleDistance;\n"
219  "\n"
220  "// Scales\n"
221  "uniform vec2 in_windowLowerLeftCorner;\n"
222  "uniform vec2 in_inverseOriginalWindowSize;\n"
223  "uniform vec2 in_inverseWindowSize;\n"
224  "uniform vec3 in_textureExtentsMax;\n"
225  "uniform vec3 in_textureExtentsMin;\n"
226  "\n"
227  "// Material and lighting\n"
228  "uniform vec3 in_diffuse[4];\n"
229  "uniform vec3 in_ambient[4];\n"
230  "uniform vec3 in_specular[4];\n"
231  "uniform float in_shininess[4];\n"
232  "\n"
233  "// Others\n"
234  "uniform bool in_useJittering;\n"
235  "vec3 g_rayJitter = vec3(0.0);\n"
236  "\n"
237  "uniform vec2 in_averageIPRange;\n";
238 
239  const bool hasGradientOpacity = HasGradientOpacity(inputs);
240  if (lightingComplexity > 0 || hasGradientOpacity)
241  {
242  toShaderStr << "uniform bool in_twoSidedLighting;\n";
243  }
244 
245  if (lightingComplexity == 3)
246  {
247  toShaderStr << "vec4 g_fragWorldPos;\n"
248  "uniform int in_numberOfLights;\n"
249  "uniform vec3 in_lightAmbientColor[6];\n"
250  "uniform vec3 in_lightDiffuseColor[6];\n"
251  "uniform vec3 in_lightSpecularColor[6];\n"
252  "uniform vec3 in_lightDirection[6];\n"
253  "uniform vec3 in_lightPosition[6];\n"
254  "uniform vec3 in_lightAttenuation[6];\n"
255  "uniform float in_lightConeAngle[6];\n"
256  "uniform float in_lightExponent[6];\n"
257  "uniform int in_lightPositional[6];\n";
258  }
259  else if (lightingComplexity == 2)
260  {
261  toShaderStr << "vec4 g_fragWorldPos;\n"
262  "uniform int in_numberOfLights;\n"
263  "uniform vec3 in_lightAmbientColor[6];\n"
264  "uniform vec3 in_lightDiffuseColor[6];\n"
265  "uniform vec3 in_lightSpecularColor[6];\n"
266  "uniform vec3 in_lightDirection[6];\n";
267  }
268  else
269  {
270  toShaderStr << "uniform vec3 in_lightAmbientColor[1];\n"
271  "uniform vec3 in_lightDiffuseColor[1];\n"
272  "uniform vec3 in_lightSpecularColor[1];\n"
273  "vec4 g_lightPosObj;\n"
274  "vec3 g_ldir;\n"
275  "vec3 g_vdir;\n"
276  "vec3 g_h;\n";
277  }
278 
279  if (noOfComponents > 1 && independentComponents)
280  {
281  toShaderStr << "uniform vec4 in_componentWeight;\n";
282  }
283 
286  glMapper->GetUseDepthPass())
287  {
288  toShaderStr << "uniform sampler2D in_depthPassSampler;\n";
289  }
290 
292  {
293  toShaderStr << "#if NUMBER_OF_CONTOURS\n"
294  "uniform float in_isosurfacesValues[NUMBER_OF_CONTOURS];\n"
295  "\n"
296  "int findIsoSurfaceIndex(float scalar, float array[NUMBER_OF_CONTOURS+2])\n"
297  "{\n"
298  " int index = NUMBER_OF_CONTOURS >> 1;\n"
299  " while (scalar > array[index]) ++index;\n"
300  " while (scalar < array[index]) --index;\n"
301  " return index;\n"
302  "}\n"
303  "#endif\n";
304  }
305  else if (glMapper->GetBlendMode() == vtkVolumeMapper::SLICE_BLEND)
306  {
307  vtkVolume* vol = inputs.begin()->second.Volume;
308  vtkImplicitFunction* func = vol->GetProperty()->GetSliceFunction();
309 
310  if (func && func->IsA("vtkPlane"))
311  {
312  toShaderStr
313  << "uniform vec3 in_slicePlaneOrigin;\n"
314  "uniform vec3 in_slicePlaneNormal;\n"
315  "vec3 g_intersection;\n"
316  "\n"
317  "float intersectRayPlane(vec3 rayOrigin, vec3 rayDir)\n"
318  "{\n"
319  " vec4 planeNormal = in_inverseVolumeMatrix[0] * vec4(in_slicePlaneNormal, 0.0);\n"
320  " float denom = dot(planeNormal.xyz, rayDir);\n"
321  " if (abs(denom) > 1e-6)\n"
322  " {\n"
323  " vec4 planeOrigin = in_inverseVolumeMatrix[0] * vec4(in_slicePlaneOrigin, 1.0);\n"
324  " return dot(planeOrigin.xyz - rayOrigin, planeNormal.xyz) / denom;\n"
325  " }\n"
326  " return -1.0;\n"
327  "}\n";
328  }
329  }
330 
331  return toShaderStr.str();
332 }
333 
334 //--------------------------------------------------------------------------
336  vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, int lightingComplexity)
337 {
339  vtkVolume* vol = inputs.begin()->second.Volume;
340 
341  std::string shaderStr;
343  glMapper->GetUseDepthPass() && glMapper->GetBlendMode() == vtkVolumeMapper::COMPOSITE_BLEND)
344  {
345  shaderStr += std::string("\
346  \n //\
347  \n vec2 fragTexCoord2 = (gl_FragCoord.xy - in_windowLowerLeftCorner) *\
348  \n in_inverseWindowSize;\
349  \n vec4 depthValue = texture2D(in_depthPassSampler, fragTexCoord2);\
350  \n vec4 rayOrigin = WindowToNDC(gl_FragCoord.x, gl_FragCoord.y, depthValue.x);\
351  \n\
352  \n // From normalized device coordinates to eye coordinates.\
353  \n // in_projectionMatrix is inversed because of way VT\
354  \n // From eye coordinates to texture coordinates\
355  \n rayOrigin = in_inverseTextureDatasetMatrix[0] *\
356  \n in_inverseVolumeMatrix[0] *\
357  \n in_inverseModelViewMatrix *\
358  \n in_inverseProjectionMatrix *\
359  \n rayOrigin;\
360  \n rayOrigin /= rayOrigin.w;\
361  \n g_rayOrigin = rayOrigin.xyz;");
362  }
363  else
364  {
365  shaderStr += std::string("\
366  \n // Get the 3D texture coordinates for lookup into the in_volume dataset\
367  \n g_rayOrigin = ip_textureCoords.xyz;");
368  }
369 
370  shaderStr += std::string("\
371  \n\
372  \n // Eye position in dataset space\
373  \n g_eyePosObj = in_inverseVolumeMatrix[0] * vec4(in_cameraPos, 1.0);\
374  \n\
375  \n // Getting the ray marching direction (in dataset space)\
376  \n vec3 rayDir = computeRayDirection();\
377  \n\
378  \n // 2D Texture fragment coordinates [0,1] from fragment coordinates.\
379  \n // The frame buffer texture has the size of the plain buffer but \
380  \n // we use a fraction of it. The texture coordinate is less than 1 if\
381  \n // the reduction factor is less than 1.\
382  \n // Device coordinates are between -1 and 1. We need texture\
383  \n // coordinates between 0 and 1. The in_depthSampler\
384  \n // buffer has the original size buffer.\
385  \n vec2 fragTexCoord = (gl_FragCoord.xy - in_windowLowerLeftCorner) *\
386  \n in_inverseWindowSize;\
387  \n\
388  \n // Multiply the raymarching direction with the step size to get the\
389  \n // sub-step size we need to take at each raymarching step\
390  \n g_dirStep = (ip_inverseTextureDataAdjusted *\
391  \n vec4(rayDir, 0.0)).xyz * in_sampleDistance;\
392  \n");
393 
394  if (glMapper->GetBlendMode() != vtkVolumeMapper::SLICE_BLEND)
395  {
396  // Intersection is computed with g_rayOrigin, so we should not modify it with Slice mode
397  shaderStr += std::string("\
398  \n if (in_useJittering)\
399  \n {\
400  \n float jitterValue = texture2D(in_noiseSampler, gl_FragCoord.xy / textureSize(in_noiseSampler, 0)).x;\
401  \n g_rayJitter = g_dirStep * jitterValue;\
402  \n }\
403  \n else\
404  \n {\
405  \n g_rayJitter = g_dirStep;\
406  \n }\
407  \n g_rayOrigin += g_rayJitter;\
408  \n");
409  }
410 
411  shaderStr += std::string("\
412  \n // Flag to determine if voxel should be considered for the rendering\
413  \n g_skip = false;");
414 
415  if (vol->GetProperty()->GetShade() && lightingComplexity == 1)
416  {
417  shaderStr += std::string("\
418  \n // Light position in dataset space\
419  \n g_lightPosObj = (in_inverseVolumeMatrix[0] *\
420  \n vec4(in_cameraPos, 1.0));\
421  \n g_ldir = normalize(g_lightPosObj.xyz - ip_vertexPos);\
422  \n g_vdir = normalize(g_eyePosObj.xyz - ip_vertexPos);\
423  \n g_h = normalize(g_ldir + g_vdir);");
424  }
425 
426  return shaderStr;
427 }
428 
429 //--------------------------------------------------------------------------
431  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
432 {
434 
435  std::string str("\
436  \n g_skip = false;");
437 
438  if (glMapper->GetBlendMode() == vtkVolumeMapper::SLICE_BLEND)
439  {
440  str += std::string("\
441  \n g_dataPos = g_intersection;\
442  \n");
443  }
444 
445  return str;
446 }
447 
448 //--------------------------------------------------------------------------
450  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
451 {
452  return std::string();
453 }
454 
455 //--------------------------------------------------------------------------
457  int independentComponents, std::map<int, std::string> gradientTableMap)
458 {
459  std::ostringstream ss;
460  ss << "uniform sampler2D " << ArrayBaseName(gradientTableMap[0]) << "[" << noOfComponents
461  << "];\n";
462  ss << "uniform sampler2D in_labelMapGradientOpacity;\n";
463 
464  std::string shaderStr = ss.str();
465  if (vol->GetProperty()->HasGradientOpacity() && (noOfComponents == 1 || !independentComponents))
466  {
467  shaderStr += std::string("\
468  \nfloat computeGradientOpacity(vec4 grad)\
469  \n {\
470  \n return texture2D(" +
471  gradientTableMap[0] + ", vec2(grad.w, 0.0)).r;\
472  \n }");
473  }
474  else if (noOfComponents > 1 && independentComponents && vol->GetProperty()->HasGradientOpacity())
475  {
476  shaderStr += std::string("\
477  \nfloat computeGradientOpacity(vec4 grad, int component)\
478  \n {");
479 
480  for (int i = 0; i < noOfComponents; ++i)
481  {
482  std::ostringstream toString;
483  toString << i;
484  shaderStr += std::string("\
485  \n if (component == " +
486  toString.str() + ")");
487 
488  shaderStr += std::string("\
489  \n {\
490  \n return texture2D(" +
491  gradientTableMap[i] + ", vec2(grad.w, 0.0)).r;\
492  \n }");
493  }
494 
495  shaderStr += std::string("\
496  \n }");
497  }
498 
499  if (vol->GetProperty()->HasLabelGradientOpacity() &&
500  (noOfComponents == 1 || !independentComponents))
501  {
502  shaderStr += std::string("\
503  \nfloat computeGradientOpacityForLabel(vec4 grad, float label)\
504  \n {\
505  \n return texture2D(in_labelMapGradientOpacity, vec2(grad.w, label)).r;\
506  \n }");
507  }
508 
509  return shaderStr;
510 }
511 
512 //--------------------------------------------------------------------------
515 {
516  const bool hasLighting = HasLighting(inputs);
517  const bool hasGradientOp = HasGradientOpacity(inputs);
518 
519  std::string shaderStr;
520  if (hasLighting || hasGradientOp)
521  {
522  shaderStr += std::string(
523  "// c is short for component\n"
524  "vec4 computeGradient(in vec3 texPos, in int c, in sampler3D volume,in int index)\n"
525  "{\n"
526  " // Approximate Nabla(F) derivatives with central differences.\n"
527  " vec3 g1; // F_front\n"
528  " vec3 g2; // F_back\n"
529  " vec3 xvec = vec3(in_cellStep[index].x, 0.0, 0.0);\n"
530  " vec3 yvec = vec3(0.0, in_cellStep[index].y, 0.0);\n"
531  " vec3 zvec = vec3(0.0, 0.0, in_cellStep[index].z);\n"
532  " vec3 texPosPvec[3];\n"
533  " texPosPvec[0] = texPos + xvec;\n"
534  " texPosPvec[1] = texPos + yvec;\n"
535  " texPosPvec[2] = texPos + zvec;\n"
536  " vec3 texPosNvec[3];\n"
537  " texPosNvec[0] = texPos - xvec;\n"
538  " texPosNvec[1] = texPos - yvec;\n"
539  " texPosNvec[2] = texPos - zvec;\n"
540  " g1.x = texture3D(volume, vec3(texPosPvec[0]))[c];\n"
541  " g1.y = texture3D(volume, vec3(texPosPvec[1]))[c];\n"
542  " g1.z = texture3D(volume, vec3(texPosPvec[2]))[c];\n"
543  " g2.x = texture3D(volume, vec3(texPosNvec[0]))[c];\n"
544  " g2.y = texture3D(volume, vec3(texPosNvec[1]))[c];\n"
545  " g2.z = texture3D(volume, vec3(texPosNvec[2]))[c];\n"
546  "\n");
547  if (UseClippedVoxelIntensity(inputs) && mapper->GetClippingPlanes())
548  {
549  shaderStr +=
550  std::string(" vec4 g1ObjDataPos[3], g2ObjDataPos[3];\n"
551  " for (int i = 0; i < 3; ++i)\n"
552  " {\n"
553  " g1ObjDataPos[i] = clip_texToObjMat * vec4(texPosPvec[i], 1.0);\n"
554  " if (g1ObjDataPos[i].w != 0.0)\n"
555  " {\n"
556  " g1ObjDataPos[i] /= g1ObjDataPos[i].w;\n"
557  " }\n"
558  " g2ObjDataPos[i] = clip_texToObjMat * vec4(texPosNvec[i], 1.0);\n"
559  " if (g2ObjDataPos[i].w != 0.0)\n"
560  " {\n"
561  " g2ObjDataPos[i] /= g2ObjDataPos[i].w;\n"
562  " }\n"
563  " }\n"
564  "\n"
565  " for (int i = 0; i < clip_numPlanes && !g_skip; i = i + 6)\n"
566  " {\n"
567  " vec3 planeOrigin = vec3(in_clippingPlanes[i + 1],\n"
568  " in_clippingPlanes[i + 2],\n"
569  " in_clippingPlanes[i + 3]);\n"
570  " vec3 planeNormal = normalize(vec3(in_clippingPlanes[i + 4],\n"
571  " in_clippingPlanes[i + 5],\n"
572  " in_clippingPlanes[i + 6]));\n"
573  " for (int j = 0; j < 3; ++j)\n"
574  " {\n"
575  " if (dot(vec3(planeOrigin - g1ObjDataPos[j].xyz), planeNormal) > 0)\n"
576  " {\n"
577  " g1[j] = in_clippedVoxelIntensity;\n"
578  " }\n"
579  " if (dot(vec3(planeOrigin - g2ObjDataPos[j].xyz), planeNormal) > 0)\n"
580  " {\n"
581  " g2[j] = in_clippedVoxelIntensity;\n"
582  " }\n"
583  " }\n"
584  " }\n"
585  "\n");
586  }
587  shaderStr += std::string(" // Apply scale and bias to the fetched values.\n"
588  " g1 = g1 * in_volume_scale[index][c] + in_volume_bias[index][c];\n"
589  " g2 = g2 * in_volume_scale[index][c] + in_volume_bias[index][c];\n"
590  "\n");
591  if (!hasGradientOp)
592  {
593  shaderStr +=
594  std::string(" // Central differences: (F_front - F_back) / 2h\n"
595  " // This version of computeGradient() is only used for lighting\n"
596  " // calculations (only direction matters), hence the difference is\n"
597  " // not scaled by 2h and a dummy gradient mag is returned (-1.).\n"
598  " return vec4((g1 - g2) / in_cellSpacing[index], -1.0);\n"
599  "}\n");
600  }
601  else
602  {
603  shaderStr += std::string(" // Scale values the actual scalar range.\n"
604  " float range = in_scalarsRange[c][1] - in_scalarsRange[c][0];\n"
605  " g1 = in_scalarsRange[c][0] + range * g1;\n"
606  " g2 = in_scalarsRange[c][0] + range * g2;\n"
607  "\n"
608  " // Central differences: (F_front - F_back) / 2h\n"
609  " g2 = g1 - g2;\n"
610  "\n"
611  " float avgSpacing = (in_cellSpacing[index].x +\n"
612  " in_cellSpacing[index].y + in_cellSpacing[index].z) / 3.0;\n"
613  " vec3 aspect = in_cellSpacing[index] * 2.0 / avgSpacing;\n"
614  " g2 /= aspect;\n"
615  " float grad_mag = length(g2);\n"
616  "\n"
617  " // Handle normalizing with grad_mag == 0.0\n"
618  " g2 = grad_mag > 0.0 ? normalize(g2) : vec3(0.0);\n"
619  "\n"
620  " // Since the actual range of the gradient magnitude is unknown,\n"
621  " // assume it is in the range [0, 0.25 * dataRange].\n"
622  " range = range != 0 ? range : 1.0;\n"
623  " grad_mag = grad_mag / (0.25 * range);\n"
624  " grad_mag = clamp(grad_mag, 0.0, 1.0);\n"
625  "\n"
626  " return vec4(g2.xyz, grad_mag);\n"
627  "}\n");
628  }
629  }
630  else
631  {
632  shaderStr += std::string(
633  "vec4 computeGradient(in vec3 texPos, in int c, in sampler3D volume, in int index)\n"
634  "{\n"
635  " return vec4(0.0);\n"
636  "}\n");
637  }
638 
639  return shaderStr;
640 }
641 
642 //--------------------------------------------------------------------------
644  vtkVolume* vol, int noOfComponents, int independentComponents, int vtkNotUsed(numberOfLights),
645  int lightingComplexity)
646 {
647  vtkVolumeProperty* volProperty = vol->GetProperty();
648  std::string shaderStr = std::string("\
649  \nvec4 computeLighting(vec4 color, int component, float label)\
650  \n {\
651  \n vec4 finalColor = vec4(0.0);");
652 
653  // Shading for composite blending only
654  int const shadeReqd = volProperty->GetShade() &&
658 
659  int const transferMode = volProperty->GetTransferFunctionMode();
660 
661  if (shadeReqd || volProperty->HasGradientOpacity() || volProperty->HasLabelGradientOpacity())
662  {
663  switch (transferMode)
664  {
666  shaderStr += std::string(
667  " // Compute gradient function only once\n"
668  " vec4 gradient = computeGradient(g_dataPos, component, in_volume[0], 0);\n");
669  break;
671  shaderStr += std::string(" // TransferFunction2D is enabled so the gradient for\n"
672  " // each component has already been cached\n"
673  " vec4 gradient = g_gradients_0[component];\n");
674  break;
675  }
676  }
677 
678  if (shadeReqd)
679  {
680  if (lightingComplexity == 1)
681  {
682  shaderStr += std::string("\
683  \n vec3 diffuse = vec3(0.0);\
684  \n vec3 specular = vec3(0.0);\
685  \n vec3 normal = gradient.xyz;\
686  \n float normalLength = length(normal);\
687  \n if (normalLength > 0.0)\
688  \n {\
689  \n normal = normalize(normal);\
690  \n }\
691  \n else\
692  \n {\
693  \n normal = vec3(0.0, 0.0, 0.0);\
694  \n }\
695  \n float nDotL = dot(normal, g_ldir);\
696  \n float nDotH = dot(normal, g_h);\
697  \n if (nDotL < 0.0 && in_twoSidedLighting)\
698  \n {\
699  \n nDotL = -nDotL;\
700  \n }\
701  \n if (nDotH < 0.0 && in_twoSidedLighting)\
702  \n {\
703  \n nDotH = -nDotH;\
704  \n }\
705  \n if (nDotL > 0.0)\
706  \n {\
707  \n diffuse = nDotL * in_diffuse[component] *\
708  \n in_lightDiffuseColor[0] * color.rgb;\
709  \n }\
710  \n specular = pow(nDotH, in_shininess[component]) *\
711  \n in_specular[component] *\
712  \n in_lightSpecularColor[0];\
713  \n // For the headlight, ignore the light's ambient color\
714  \n // for now as it is causing the old mapper tests to fail\
715  \n finalColor.xyz = in_ambient[component] * color.rgb +\
716  \n diffuse + specular;\
717  \n");
718  }
719  else if (lightingComplexity == 2)
720  {
721  shaderStr += std::string("\
722  \n g_fragWorldPos = in_modelViewMatrix * in_volumeMatrix[0] *\
723  \n in_textureDatasetMatrix[0] * vec4(-g_dataPos, 1.0);\
724  \n if (g_fragWorldPos.w != 0.0)\
725  \n {\
726  \n g_fragWorldPos /= g_fragWorldPos.w;\
727  \n }\
728  \n vec3 vdir = normalize(g_fragWorldPos.xyz);\
729  \n vec3 normal = gradient.xyz;\
730  \n vec3 ambient = vec3(0.0);\
731  \n vec3 diffuse = vec3(0.0);\
732  \n vec3 specular = vec3(0.0);\
733  \n float normalLength = length(normal);\
734  \n if (normalLength > 0.0)\
735  \n {\
736  \n normal = normalize((in_textureToEye[0] * vec4(normal, 0.0)).xyz);\
737  \n }\
738  \n else\
739  \n {\
740  \n normal = vec3(0.0, 0.0, 0.0);\
741  \n }\
742  \n for (int lightNum = 0; lightNum < in_numberOfLights; lightNum++)\
743  \n {\
744  \n vec3 ldir = in_lightDirection[lightNum].xyz;\
745  \n vec3 h = normalize(ldir + vdir);\
746  \n float nDotH = dot(normal, h);\
747  \n if (nDotH < 0.0 && in_twoSidedLighting)\
748  \n {\
749  \n nDotH = -nDotH;\
750  \n }\
751  \n float nDotL = dot(normal, ldir);\
752  \n if (nDotL < 0.0 && in_twoSidedLighting)\
753  \n {\
754  \n nDotL = -nDotL;\
755  \n }\
756  \n if (nDotL > 0.0)\
757  \n {\
758  \n diffuse += in_lightDiffuseColor[lightNum] * nDotL;\
759  \n }\
760  \n if (nDotH > 0.0)\
761  \n {\
762  \n specular = in_lightSpecularColor[lightNum] *\
763  \n pow(nDotH, in_shininess[component]);\
764  \n }\
765  \n ambient += in_lightAmbientColor[lightNum];\
766  \n }\
767  \n finalColor.xyz = in_ambient[component] * ambient +\
768  \n in_diffuse[component] * diffuse * color.rgb +\
769  \n in_specular[component] * specular;");
770  }
771  else if (lightingComplexity == 3)
772  {
773  shaderStr += std::string("\
774  \n g_fragWorldPos = in_modelViewMatrix * in_volumeMatrix[0] *\
775  \n in_textureDatasetMatrix[0] * vec4(g_dataPos, 1.0);\
776  \n if (g_fragWorldPos.w != 0.0)\
777  \n {\
778  \n g_fragWorldPos /= g_fragWorldPos.w;\
779  \n }\
780  \n vec3 viewDirection = normalize(-g_fragWorldPos.xyz);\
781  \n vec3 ambient = vec3(0,0,0);\
782  \n vec3 diffuse = vec3(0,0,0);\
783  \n vec3 specular = vec3(0,0,0);\
784  \n vec3 vertLightDirection;\
785  \n vec3 normal = normalize((in_textureToEye[0] * vec4(gradient.xyz, 0.0)).xyz);\
786  \n vec3 lightDir;\
787  \n for (int lightNum = 0; lightNum < in_numberOfLights; lightNum++)\
788  \n {\
789  \n float attenuation = 1.0;\
790  \n // directional\
791  \n lightDir = in_lightDirection[lightNum];\
792  \n if (in_lightPositional[lightNum] == 0)\
793  \n {\
794  \n vertLightDirection = lightDir;\
795  \n }\
796  \n else\
797  \n {\
798  \n vertLightDirection = (g_fragWorldPos.xyz - in_lightPosition[lightNum]);\
799  \n float distance = length(vertLightDirection);\
800  \n vertLightDirection = normalize(vertLightDirection);\
801  \n attenuation = 1.0 /\
802  \n (in_lightAttenuation[lightNum].x\
803  \n + in_lightAttenuation[lightNum].y * distance\
804  \n + in_lightAttenuation[lightNum].z * distance * distance);\
805  \n // per OpenGL standard cone angle is 90 or less for a spot light\
806  \n if (in_lightConeAngle[lightNum] <= 90.0)\
807  \n {\
808  \n float coneDot = dot(vertLightDirection, lightDir);\
809  \n // if inside the cone\
810  \n if (coneDot >= cos(radians(in_lightConeAngle[lightNum])))\
811  \n {\
812  \n attenuation = attenuation * pow(coneDot, in_lightExponent[lightNum]);\
813  \n }\
814  \n else\
815  \n {\
816  \n attenuation = 0.0;\
817  \n }\
818  \n }\
819  \n }\
820  \n // diffuse and specular lighting\
821  \n float nDotL = dot(normal, vertLightDirection);\
822  \n if (nDotL < 0.0 && in_twoSidedLighting)\
823  \n {\
824  \n nDotL = -nDotL;\
825  \n }\
826  \n if (nDotL > 0.0)\
827  \n {\
828  \n float df = max(0.0, attenuation * nDotL);\
829  \n diffuse += (df * in_lightDiffuseColor[lightNum]);\
830  \n }\
831  \n vec3 h = normalize(vertLightDirection + viewDirection);\
832  \n float nDotH = dot(normal, h);\
833  \n if (nDotH < 0.0 && in_twoSidedLighting)\
834  \n {\
835  \n nDotH = -nDotH;\
836  \n }\
837  \n if (nDotH > 0.0)\
838  \n {\
839  \n float sf = attenuation * pow(nDotH, in_shininess[component]);\
840  \n specular += (sf * in_lightSpecularColor[lightNum]);\
841  \n }\
842  \n ambient += in_lightAmbientColor[lightNum];\
843  \n }\
844  \n finalColor.xyz = in_ambient[component] * ambient +\
845  \n in_diffuse[component] * diffuse * color.rgb +\
846  \n in_specular[component] * specular;\
847  ");
848  }
849  }
850  else
851  {
852  shaderStr += std::string("\n finalColor = vec4(color.rgb, 0.0);");
853  }
854 
855  auto glMapper = vtkOpenGLGPUVolumeRayCastMapper::SafeDownCast(mapper);
856  // For 1D transfers only (2D transfer functions hold scalar and
857  // gradient-magnitude opacities combined in the same table).
858  // For multiple inputs, a different computeGradientOpacity() signature
859  // is defined.
860  if (transferMode == vtkVolumeProperty::TF_1D && glMapper->GetInputCount() == 1)
861  {
862  if (noOfComponents == 1 || !independentComponents)
863  {
864  if (volProperty->HasGradientOpacity())
865  {
866  shaderStr += std::string("\
867  \n if (gradient.w >= 0.0 && label == 0.0)\
868  \n {\
869  \n color.a *= computeGradientOpacity(gradient);\
870  \n }");
871  }
872  if (volProperty->HasLabelGradientOpacity())
873  {
874  shaderStr += std::string("\
875  \n if (gradient.w >= 0.0 && label > 0.0)\
876  \n {\
877  \n color.a *= computeGradientOpacityForLabel(gradient, label);\
878  \n }");
879  }
880  }
881  else if (noOfComponents > 1 && independentComponents && volProperty->HasGradientOpacity())
882  {
883  shaderStr += std::string("\
884  \n if (gradient.w >= 0.0)\
885  \n {\
886  \n for (int i = 0; i < in_noOfComponents; ++i)\
887  \n {\
888  \n color.a = color.a *\
889  \n computeGradientOpacity(gradient, i) * in_componentWeight[i];\
890  \n }\
891  \n }");
892  }
893  }
894 
895  shaderStr += std::string("\
896  \n finalColor.a = color.a;\
897  \n return finalColor;\
898  \n }");
899 
900  return shaderStr;
901 }
902 
903 //--------------------------------------------------------------------------
905  vtkVolume* vtkNotUsed(vol), int vtkNotUsed(noOfComponents))
906 {
907  if (!ren->GetActiveCamera()->GetParallelProjection())
908  {
909  return std::string("\
910  \nvec3 computeRayDirection()\
911  \n {\
912  \n return normalize(ip_vertexPos.xyz - g_eyePosObj.xyz);\
913  \n }");
914  }
915  else
916  {
917  return std::string("\
918  \nuniform vec3 in_projectionDirection;\
919  \nvec3 computeRayDirection()\
920  \n {\
921  \n return normalize((in_inverseVolumeMatrix[0] *\
922  \n vec4(in_projectionDirection, 0.0)).xyz);\
923  \n }");
924  }
925 }
926 
927 //--------------------------------------------------------------------------
929  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
930  int independentComponents, std::map<int, std::string> colorTableMap)
931 {
932  std::ostringstream ss;
933  ss << "uniform sampler2D " << ArrayBaseName(colorTableMap[0]) << "[" << noOfComponents << "];\n";
934 
935  std::string shaderStr = ss.str();
936  if (noOfComponents == 1)
937  {
938  shaderStr += std::string("\
939  \nvec4 computeColor(vec4 scalar, float opacity)\
940  \n {\
941  \n return computeLighting(vec4(texture2D(" +
942  colorTableMap[0] + ",\
943  \n vec2(scalar.w, 0.0)).xyz, opacity), 0, 0);\
944  \n }");
945  return shaderStr;
946  }
947  else if (noOfComponents > 1 && independentComponents)
948  {
949  std::ostringstream toString;
950 
951  shaderStr += std::string("\
952  \nvec4 computeColor(vec4 scalar, float opacity, int component)\
953  \n {");
954 
955  for (int i = 0; i < noOfComponents; ++i)
956  {
957  toString << i;
958  shaderStr += std::string("\
959  \n if (component == " +
960  toString.str() + ")");
961 
962  shaderStr += std::string("\
963  \n {\
964  \n return computeLighting(vec4(texture2D(\
965  \n " +
966  colorTableMap[i]);
967  shaderStr += std::string(", vec2(\
968  \n scalar[" +
969  toString.str() + "],0.0)).xyz,\
970  \n opacity)," +
971  toString.str() + ", 0);\
972  \n }");
973 
974  // Reset
975  toString.str("");
976  toString.clear();
977  }
978 
979  shaderStr += std::string("\n }");
980  return shaderStr;
981  }
982  else if (noOfComponents == 2 && !independentComponents)
983  {
984  shaderStr += std::string("\
985  \nvec4 computeColor(vec4 scalar, float opacity)\
986  \n {\
987  \n return computeLighting(vec4(texture2D(" +
988  colorTableMap[0] + ",\
989  \n vec2(scalar.x, 0.0)).xyz,\
990  \n opacity), 0, 0);\
991  \n }");
992  return shaderStr;
993  }
994  else
995  {
996  shaderStr += std::string("\
997  \nvec4 computeColor(vec4 scalar, float opacity)\
998  \n {\
999  \n return computeLighting(vec4(scalar.xyz, opacity), 0, 0);\
1000  \n }");
1001  return shaderStr;
1002  }
1003 }
1004 
1005 //--------------------------------------------------------------------------
1007 {
1008  std::ostringstream ss;
1009  int i = 0;
1010  for (auto& item : inputs)
1011  {
1012  auto prop = item.second.Volume->GetProperty();
1013  if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_1D)
1014  continue;
1015 
1016  auto& map = item.second.RGBTablesMap;
1017  const auto numComp = map.size();
1018  ss << "uniform sampler2D " << ArrayBaseName(map[0]) << "[" << numComp << "];\n";
1019  i++;
1020  }
1021 
1022  ss << "vec3 computeColor(const in float scalar, const in sampler2D colorTF)\n"
1023  "{\n"
1024  " return texture2D(colorTF, vec2(scalar, 0)).rgb;\n"
1025  "}\n";
1026  return ss.str();
1027 }
1028 
1029 //--------------------------------------------------------------------------
1031 {
1032  std::ostringstream ss;
1033  int i = 0;
1034  for (auto& item : inputs)
1035  {
1036  auto prop = item.second.Volume->GetProperty();
1037  if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_1D)
1038  continue;
1039 
1040  auto& map = item.second.OpacityTablesMap;
1041  const auto numComp = map.size();
1042  ss << "uniform sampler2D " << ArrayBaseName(map[0]) << "[" << numComp << "];\n";
1043  i++;
1044  }
1045 
1046  ss << "float computeOpacity(const in float scalar, const in sampler2D opacityTF)\n"
1047  "{\n"
1048  " return texture2D(opacityTF, vec2(scalar, 0)).r;\n"
1049  "}\n";
1050  return ss.str();
1051 }
1052 
1053 //--------------------------------------------------------------------------
1056 {
1057  std::ostringstream ss;
1058 
1059  int i = 0;
1060  for (auto& item : inputs)
1061  {
1062  auto prop = item.second.Volume->GetProperty();
1063  if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_1D || !prop->HasGradientOpacity())
1064  continue;
1065 
1066  auto& map = item.second.GradientOpacityTablesMap;
1067  const auto numComp = map.size();
1068  ss << "uniform sampler2D " << ArrayBaseName(map[0]) << "[" << numComp << "];\n";
1069  i++;
1070  }
1071 
1072  ss << "float computeGradientOpacity(const in float scalar, const in sampler2D opacityTF)\n"
1073  "{\n"
1074  " return texture2D(opacityTF, vec2(scalar, 0)).r;\n"
1075  "}\n";
1076  return ss.str();
1077 }
1078 
1079 //--------------------------------------------------------------------------
1081  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
1082  int independentComponents, std::map<int, std::string> opacityTableMap)
1083 {
1084  std::ostringstream ss;
1085  ss << "uniform sampler2D " << ArrayBaseName(opacityTableMap[0]) << "[" << noOfComponents
1086  << "];\n";
1087 
1088  std::string shaderStr = ss.str();
1089  if (noOfComponents > 1 && independentComponents)
1090  {
1091  shaderStr += std::string("\
1092  \nfloat computeOpacity(vec4 scalar, int component)\
1093  \n{");
1094 
1095  for (int i = 0; i < noOfComponents; ++i)
1096  {
1097  std::ostringstream toString;
1098  toString << i;
1099  shaderStr += std::string("\
1100  \n if (component == " +
1101  toString.str() + ")");
1102 
1103  shaderStr += std::string("\
1104  \n {\
1105  \n return texture2D(" +
1106  opacityTableMap[i]);
1107 
1108  shaderStr += std::string(",vec2(scalar[" + toString.str() + "], 0)).r;\
1109  \n }");
1110  }
1111 
1112  shaderStr += std::string("\n}");
1113  return shaderStr;
1114  }
1115  else if (noOfComponents == 2 && !independentComponents)
1116  {
1117  shaderStr += std::string("\
1118  \nfloat computeOpacity(vec4 scalar)\
1119  \n{\
1120  \n return texture2D(" +
1121  opacityTableMap[0] + ", vec2(scalar.y, 0)).r;\
1122  \n}");
1123  return shaderStr;
1124  }
1125  else
1126  {
1127  shaderStr += std::string("\
1128  \nfloat computeOpacity(vec4 scalar)\
1129  \n{\
1130  \n return texture2D(" +
1131  opacityTableMap[0] + ", vec2(scalar.w, 0)).r;\
1132  \n}");
1133  return shaderStr;
1134  }
1135 }
1136 
1137 //--------------------------------------------------------------------------
1139  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
1140  int independentComponents, std::map<int, std::string> colorTableMap)
1141 {
1142  if (noOfComponents == 1)
1143  {
1144  // Single component
1145  return std::string("vec4 computeColor(vec4 scalar, float opacity)\n"
1146  "{\n"
1147  " vec4 color = texture2D(" +
1148  colorTableMap[0] +
1149  ",\n"
1150  " vec2(scalar.w, g_gradients_0[0].w));\n"
1151  " return computeLighting(color, 0, 0);\n"
1152  "}\n");
1153  }
1154  else if (noOfComponents > 1 && independentComponents)
1155  {
1156  // Multiple independent components
1157  std::string shaderStr;
1158  shaderStr += std::string("vec4 computeColor(vec4 scalar, float opacity, int component)\n"
1159  "{\n");
1160 
1161  for (int i = 0; i < noOfComponents; ++i)
1162  {
1163  std::ostringstream toString;
1164  toString << i;
1165  std::string const num = toString.str();
1166  shaderStr += std::string(" if (component == " + num +
1167  ")\n"
1168  " {\n"
1169  " vec4 color = texture2D(" +
1170  colorTableMap[i] +
1171  ",\n"
1172  " vec2(scalar[" +
1173  num + "], g_gradients_0[" + num +
1174  "].w));\n"
1175  " return computeLighting(color, " +
1176  num +
1177  ", 0);\n"
1178  " }\n");
1179  }
1180  shaderStr += std::string("}\n");
1181 
1182  return shaderStr;
1183  }
1184  else if (noOfComponents == 2 && !independentComponents)
1185  {
1186  // Dependent components (Luminance/ Opacity)
1187  return std::string("vec4 computeColor(vec4 scalar, float opacity)\n"
1188  "{\n"
1189  " vec4 color = texture2D(" +
1190  colorTableMap[0] +
1191  ",\n"
1192  " vec2(scalar.x, g_gradients_0[0].w));\n"
1193  " return computeLighting(color, 0, 0);\n"
1194  "}\n");
1195  }
1196  else
1197  {
1198  return std::string("vec4 computeColor(vec4 scalar, float opacity)\n"
1199  "{\n"
1200  " return computeLighting(vec4(scalar.xyz, opacity), 0, 0);\n"
1201  "}\n");
1202  }
1203 }
1204 
1206 {
1207  std::ostringstream ss;
1208  int i = 0;
1209  for (auto& item : inputs)
1210  {
1211  auto prop = item.second.Volume->GetProperty();
1212  if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_2D)
1213  continue;
1214 
1215  auto& map = item.second.TransferFunctions2DMap;
1216  const auto numComp = map.size();
1217  ss << "uniform sampler2D " << ArrayBaseName(map[0]) << "[" << numComp << "];\n";
1218  i++;
1219  }
1220 
1221  return ss.str();
1222 }
1223 
1224 //--------------------------------------------------------------------------
1226  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
1227  int independentComponents, std::map<int, std::string> opacityTableMap)
1228 {
1229  std::ostringstream toString;
1230  if (noOfComponents > 1 && independentComponents)
1231  {
1232  // Multiple independent components
1233  toString << "float computeOpacity(vec4 scalar, int component)\n"
1234  "{\n";
1235 
1236  for (int i = 0; i < noOfComponents; ++i)
1237  {
1238  toString << " if (component == " << i
1239  << ")\n"
1240  " {\n"
1241  " return texture2D("
1242  << opacityTableMap[i]
1243  << ",\n"
1244  " vec2(scalar["
1245  << i << "], g_gradients_0[" << i
1246  << "].w)).a;\n"
1247  " }\n";
1248  }
1249 
1250  toString << "}\n";
1251  }
1252  else if (noOfComponents == 2 && !independentComponents)
1253  {
1254  // Dependent components (Luminance/ Opacity)
1255  toString << "float computeOpacity(vec4 scalar)\n"
1256  "{\n"
1257  " return texture2D(" +
1258  opacityTableMap[0] +
1259  ",\n"
1260  " vec2(scalar.y, g_gradients_0[0].w)).a;\n"
1261  "}\n";
1262  }
1263  else
1264  {
1265  // Dependent compoennts (RGBA) || Single component
1266  toString << "float computeOpacity(vec4 scalar)\n"
1267  "{\n"
1268  " return texture2D(" +
1269  opacityTableMap[0] +
1270  ",\n"
1271  " vec2(scalar.a, g_gradients_0[0].w)).a;\n"
1272  "}\n";
1273  }
1274  return toString.str();
1275 }
1276 
1277 //--------------------------------------------------------------------------
1279  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
1280 {
1281  return std::string();
1282 }
1283 
1284 //--------------------------------------------------------------------------
1286  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
1287 {
1289  {
1290  return std::string("\
1291  \n bool l_firstValue;\
1292  \n vec4 l_maxValue;");
1293  }
1295  {
1296  return std::string("\
1297  \n bool l_firstValue;\
1298  \n vec4 l_minValue;");
1299  }
1301  {
1302  return std::string("\
1303  \n uvec4 l_numSamples;\
1304  \n vec4 l_avgValue;");
1305  }
1306  else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
1307  {
1308  return std::string("\
1309  \n vec4 l_sumValue;");
1310  }
1311  else if (mapper->GetBlendMode() == vtkVolumeMapper::ISOSURFACE_BLEND)
1312  {
1313  return std::string("\
1314  \n int l_initialIndex = 0;\
1315  \n float l_normValues[NUMBER_OF_CONTOURS + 2];");
1316  }
1317  else
1318  {
1319  return std::string();
1320  }
1321 }
1322 
1323 //--------------------------------------------------------------------------
1325  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
1326 {
1328  {
1329  return std::string("\
1330  \n // We get data between 0.0 - 1.0 range\
1331  \n l_firstValue = true;\
1332  \n l_maxValue = vec4(0.0);");
1333  }
1335  {
1336  return std::string("\
1337  \n //We get data between 0.0 - 1.0 range\
1338  \n l_firstValue = true;\
1339  \n l_minValue = vec4(1.0);");
1340  }
1342  {
1343  return std::string("\
1344  \n //We get data between 0.0 - 1.0 range\
1345  \n l_avgValue = vec4(0.0);\
1346  \n // Keep track of number of samples\
1347  \n l_numSamples = uvec4(0);");
1348  }
1349  else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
1350  {
1351  return std::string("\
1352  \n //We get data between 0.0 - 1.0 range\
1353  \n l_sumValue = vec4(0.0);");
1354  }
1355  else if (mapper->GetBlendMode() == vtkVolumeMapper::ISOSURFACE_BLEND)
1356  {
1357  return std::string("\
1358  \n#if NUMBER_OF_CONTOURS\
1359  \n l_normValues[0] = -1e20; //-infinity\
1360  \n l_normValues[NUMBER_OF_CONTOURS+1] = +1e20; //+infinity\
1361  \n for (int i = 0; i < NUMBER_OF_CONTOURS; i++)\
1362  \n {\
1363  \n l_normValues[i+1] = (in_isosurfacesValues[i] - in_scalarsRange[0].x) / \
1364  \n (in_scalarsRange[0].y - in_scalarsRange[0].x);\
1365  \n }\
1366  \n#endif\
1367  ");
1368  }
1369  else
1370  {
1371  return std::string();
1372  }
1373 }
1374 
1375 //--------------------------------------------------------------------------
1376 std::string GradientCacheDec(vtkRenderer* vtkNotUsed(ren), vtkVolume* vtkNotUsed(vol),
1377  vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, int independentComponents = 0)
1378 {
1379  const int numInputs = static_cast<int>(inputs.size());
1380  const int comp = numInputs == 1 ?
1381  // Dependent components use a single opacity lut.
1382  (!independentComponents ? 1 : numInputs)
1383  :
1384  // Independent components not supported with multiple-inputs
1385  1;
1386 
1387  std::ostringstream toShader;
1388  for (const auto& item : inputs)
1389  {
1390  auto& input = item.second;
1391  if (input.Volume->GetProperty()->HasGradientOpacity())
1392  {
1393  toShader << "vec4 " << input.GradientCacheName << "[" << comp << "];\n";
1394  }
1395  }
1396 
1397  return toShader.str();
1398 }
1399 
1400 //--------------------------------------------------------------------------
1401 std::string PreComputeGradientsImpl(vtkRenderer* vtkNotUsed(ren), vtkVolume* vtkNotUsed(vol),
1402  int noOfComponents = 1, int independentComponents = 0)
1403 {
1404  std::ostringstream shader;
1405  if (independentComponents)
1406  {
1407  if (noOfComponents == 1)
1408  {
1409  shader << "g_gradients_0[0] = computeGradient(g_dataPos, 0, in_volume[0], 0);\n";
1410  }
1411  else
1412  {
1413  // Multiple components
1414  shader << "for (int comp = 0; comp < in_noOfComponents; comp++)\n"
1415  "{\n"
1416  " g_gradients_0[comp] = computeGradient(g_dataPos, comp, in_volume[0], 0);\n"
1417  "}\n";
1418  }
1419  }
1420  else
1421  {
1422  shader << "g_gradients_0[0] = computeGradient(g_dataPos, 0, in_volume[0], 0);\n";
1423  }
1424 
1425  return shader.str();
1426 }
1427 
1428 //--------------------------------------------------------------------------
1431 {
1432  std::ostringstream toShaderStr;
1433  toShaderStr << " if (!g_skip)\n"
1434  " {\n"
1435  " vec3 texPos;\n";
1436 
1437  switch (mapper->GetBlendMode())
1438  {
1440  default:
1441  {
1442  int i = 0;
1443  for (auto& item : inputs)
1444  {
1445  auto& input = item.second;
1446  auto property = input.Volume->GetProperty();
1447  // Transformation index. Index 0 refers to the global bounding-box.
1448  const auto idx = i + 1;
1449  toShaderStr <<
1450  // From global texture coordinates (bbox) to volume_i texture coords.
1451  // texPos = T * g_dataPos
1452  // T = T_dataToTex1 * T_worldToData * T_bboxTexToWorld;
1453  " texPos = (in_cellToPoint[" << idx << "] * in_inverseTextureDatasetMatrix[" << idx
1454  << "] * in_inverseVolumeMatrix[" << idx
1455  << "] *\n"
1456  " in_volumeMatrix[0] * in_textureDatasetMatrix[0] * "
1457  "vec4(g_dataPos.xyz, 1.0)).xyz;\n"
1458  " if ((all(lessThanEqual(texPos, vec3(1.0))) &&\n"
1459  " all(greaterThanEqual(texPos, vec3(0.0)))))\n"
1460  " {\n"
1461  " vec4 scalar = texture3D(in_volume["
1462  << i
1463  << "], texPos);\n"
1464  " scalar = scalar * in_volume_scale["
1465  << i << "] + in_volume_bias[" << i
1466  << "];\n"
1467  " scalar = vec4(scalar.r);\n"
1468  " g_srcColor = vec4(0.0);\n";
1469 
1470  if (property->GetTransferFunctionMode() == vtkVolumeProperty::TF_1D)
1471  {
1472  toShaderStr << " g_srcColor.a = computeOpacity(scalar.r,"
1473  << input.OpacityTablesMap[0]
1474  << ");\n"
1475  " if (g_srcColor.a > 0.0)\n"
1476  " {\n"
1477  " g_srcColor.rgb = computeColor(scalar.r, "
1478  << input.RGBTablesMap[0] << ");\n";
1479 
1480  if (property->HasGradientOpacity())
1481  {
1482  const auto& grad = input.GradientCacheName;
1483  toShaderStr << " " << grad << "[0] = computeGradient(texPos, 0, "
1484  << "in_volume[" << i << "], " << i
1485  << ");\n"
1486  " if ("
1487  << grad
1488  << "[0].w >= 0.0)\n"
1489  " {\n"
1490  " g_srcColor.a *= computeGradientOpacity("
1491  << grad << "[0].w, " << input.GradientOpacityTablesMap[0]
1492  << ");\n"
1493  " }\n";
1494  }
1495  }
1496  else if (property->GetTransferFunctionMode() == vtkVolumeProperty::TF_2D)
1497  {
1498  const auto& grad = input.GradientCacheName;
1499  toShaderStr <<
1500  // Sample 2DTF directly
1501  " " << grad << "[0] = computeGradient(texPos, 0, "
1502  << "in_volume[" << i << "], " << i
1503  << ");\n"
1504  " g_srcColor = texture2D("
1505  << input.TransferFunctions2DMap[0] << ", vec2(scalar.r, "
1506  << input.GradientCacheName
1507  << "[0].w));\n"
1508  " if (g_srcColor.a > 0.0)\n"
1509  " {\n";
1510  }
1511 
1512  toShaderStr
1513  << " g_srcColor.rgb *= g_srcColor.a;\n"
1514  " g_fragColor = (1.0f - g_fragColor.a) * g_srcColor + g_fragColor;\n"
1515  " }\n"
1516  " }\n\n";
1517 
1518  i++;
1519  }
1520  }
1521  break;
1522  }
1523  toShaderStr << " }\n";
1524 
1525  return toShaderStr.str();
1526 }
1527 
1528 //--------------------------------------------------------------------------
1530  vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput, vtkVolumeTexture* mask, int maskType,
1531  int noOfComponents, int independentComponents = 0)
1532 {
1533  auto glMapper = vtkOpenGLGPUVolumeRayCastMapper::SafeDownCast(mapper);
1534 
1535  std::string shaderStr;
1536 
1537  shaderStr += std::string("\
1538  \n if (!g_skip)\
1539  \n {\
1540  \n vec4 scalar = texture3D(in_volume[0], g_dataPos);");
1541 
1542  // simulate old intensity textures
1543  if (noOfComponents == 1)
1544  {
1545  shaderStr += std::string("\
1546  \n scalar.r = scalar.r * in_volume_scale[0].r + in_volume_bias[0].r;\
1547  \n scalar = vec4(scalar.r);");
1548  }
1549  else
1550  {
1551  // handle bias and scale
1552  shaderStr += std::string("\
1553  \n scalar = scalar * in_volume_scale[0] + in_volume_bias[0];");
1554  }
1555 
1557  {
1558  if (noOfComponents > 1)
1559  {
1560  if (!independentComponents)
1561  {
1562  shaderStr += std::string("\
1563  \n if (l_maxValue.w < scalar.w || l_firstValue)\
1564  \n {\
1565  \n l_maxValue = scalar;\
1566  \n }\
1567  \n\
1568  \n if (l_firstValue)\
1569  \n {\
1570  \n l_firstValue = false;\
1571  \n }");
1572  }
1573  else
1574  {
1575  shaderStr += std::string("\
1576  \n for (int i = 0; i < in_noOfComponents; ++i)\
1577  \n {\
1578  \n if (l_maxValue[i] < scalar[i] || l_firstValue)\
1579  \n {\
1580  \n l_maxValue[i] = scalar[i];\
1581  \n }\
1582  \n }\
1583  \n if (l_firstValue)\
1584  \n {\
1585  \n l_firstValue = false;\
1586  \n }");
1587  }
1588  }
1589  else
1590  {
1591  shaderStr += std::string("\
1592  \n if (l_maxValue.w < scalar.x || l_firstValue)\
1593  \n {\
1594  \n l_maxValue.w = scalar.x;\
1595  \n }\
1596  \n\
1597  \n if (l_firstValue)\
1598  \n {\
1599  \n l_firstValue = false;\
1600  \n }");
1601  }
1602  }
1604  {
1605  if (noOfComponents > 1)
1606  {
1607  if (!independentComponents)
1608  {
1609  shaderStr += std::string("\
1610  \n if (l_minValue.w > scalar.w || l_firstValue)\
1611  \n {\
1612  \n l_minValue = scalar;\
1613  \n }\
1614  \n\
1615  \n if (l_firstValue)\
1616  \n {\
1617  \n l_firstValue = false;\
1618  \n }");
1619  }
1620  else
1621  {
1622  shaderStr += std::string("\
1623  \n for (int i = 0; i < in_noOfComponents; ++i)\
1624  \n {\
1625  \n if (l_minValue[i] < scalar[i] || l_firstValue)\
1626  \n {\
1627  \n l_minValue[i] = scalar[i];\
1628  \n }\
1629  \n }\
1630  \n if (l_firstValue)\
1631  \n {\
1632  \n l_firstValue = false;\
1633  \n }");
1634  }
1635  }
1636  else
1637  {
1638  shaderStr += std::string("\
1639  \n if (l_minValue.w > scalar.x || l_firstValue)\
1640  \n {\
1641  \n l_minValue.w = scalar.x;\
1642  \n }\
1643  \n\
1644  \n if (l_firstValue)\
1645  \n {\
1646  \n l_firstValue = false;\
1647  \n }");
1648  }
1649  }
1651  {
1652  if (noOfComponents > 1 && independentComponents)
1653  {
1654  shaderStr += std::string("\
1655  \n for (int i = 0; i < in_noOfComponents; ++i)\
1656  \n {\
1657  \n // Get the intensity in volume scalar range\
1658  \n float intensity = in_scalarsRange[i][0] +\
1659  \n (in_scalarsRange[i][1] -\
1660  \n in_scalarsRange[i][0]) * scalar[i];\
1661  \n if (in_averageIPRange.x <= intensity &&\
1662  \n intensity <= in_averageIPRange.y)\
1663  \n {\
1664  \n l_avgValue[i] += computeOpacity(scalar, i) * scalar[i];\
1665  \n ++l_numSamples[i];\
1666  \n }\
1667  \n }");
1668  }
1669  else
1670  {
1671  shaderStr += std::string("\
1672  \n // Get the intensity in volume scalar range\
1673  \n float intensity = in_scalarsRange[0][0] +\
1674  \n (in_scalarsRange[0][1] -\
1675  \n in_scalarsRange[0][0]) * scalar.x;\
1676  \n if (in_averageIPRange.x <= intensity &&\
1677  \n intensity <= in_averageIPRange.y)\
1678  \n {\
1679  \n l_avgValue.x += computeOpacity(scalar) * scalar.x;\
1680  \n ++l_numSamples.x;\
1681  \n }");
1682  }
1683  }
1684  else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
1685  {
1686  if (noOfComponents > 1 && independentComponents)
1687  {
1688  shaderStr += std::string("\
1689  \n for (int i = 0; i < in_noOfComponents; ++i)\
1690  \n {\
1691  \n float opacity = computeOpacity(scalar, i);\
1692  \n l_sumValue[i] = l_sumValue[i] + opacity * scalar[i];\
1693  \n }");
1694  }
1695  else
1696  {
1697  shaderStr += std::string("\
1698  \n float opacity = computeOpacity(scalar);\
1699  \n l_sumValue.x = l_sumValue.x + opacity * scalar.x;");
1700  }
1701  }
1702  else if (mapper->GetBlendMode() == vtkVolumeMapper::ISOSURFACE_BLEND)
1703  {
1704  shaderStr += std::string("\
1705  \n#if NUMBER_OF_CONTOURS\
1706  \n int maxComp = 0;");
1707 
1708  std::string compParamStr = "";
1709  if (noOfComponents > 1 && independentComponents)
1710  {
1711  shaderStr += std::string("\
1712  \n for (int i = 1; i < in_noOfComponents; ++i)\
1713  \n {\
1714  \n if (in_componentWeight[i] > in_componentWeight[maxComp])\
1715  \n maxComp = i;\
1716  \n }");
1717  compParamStr = ", maxComp";
1718  }
1719  shaderStr += std::string("\
1720  \n if (g_currentT == 0)\
1721  \n {\
1722  \n l_initialIndex = findIsoSurfaceIndex(scalar[maxComp], l_normValues);\
1723  \n }\
1724  \n else\
1725  \n {\
1726  \n float s;\
1727  \n bool shade = false;\
1728  \n l_initialIndex = clamp(l_initialIndex, 0, NUMBER_OF_CONTOURS);\
1729  \n if (scalar[maxComp] < l_normValues[l_initialIndex])\
1730  \n {\
1731  \n s = l_normValues[l_initialIndex];\
1732  \n l_initialIndex--;\
1733  \n shade = true;\
1734  \n }\
1735  \n if (scalar[maxComp] > l_normValues[l_initialIndex+1])\
1736  \n {\
1737  \n s = l_normValues[l_initialIndex+1];\
1738  \n l_initialIndex++;\
1739  \n shade = true;\
1740  \n }\
1741  \n if (shade == true)\
1742  \n {\
1743  \n vec4 vs = vec4(s);\
1744  \n g_srcColor.a = computeOpacity(vs " +
1745  compParamStr + ");\
1746  \n g_srcColor = computeColor(vs, g_srcColor.a " +
1747  compParamStr + ");\
1748  \n g_srcColor.rgb *= g_srcColor.a;\
1749  \n g_fragColor = (1.0f - g_fragColor.a) * g_srcColor + g_fragColor;\
1750  \n }\
1751  \n }\
1752  \n#endif");
1753  }
1754  else if (mapper->GetBlendMode() == vtkVolumeMapper::SLICE_BLEND)
1755  {
1756  shaderStr += std::string("\
1757  \n // test if the intersection is inside the volume bounds\
1758  \n if (any(greaterThan(g_dataPos, vec3(1.0))) || any(lessThan(g_dataPos, vec3(0.0))))\
1759  \n {\
1760  \n discard;\
1761  \n }\
1762  \n float opacity = computeOpacity(scalar);\
1763  \n g_fragColor = computeColor(scalar, opacity);\
1764  \n g_fragColor.rgb *= opacity;\
1765  \n g_exit = true;");
1766  }
1767  else if (mapper->GetBlendMode() == vtkVolumeMapper::COMPOSITE_BLEND)
1768  {
1769  if (noOfComponents > 1 && independentComponents)
1770  {
1771  shaderStr += std::string("\
1772  \n vec4 color[4]; vec4 tmp = vec4(0.0);\
1773  \n float totalAlpha = 0.0;\
1774  \n for (int i = 0; i < in_noOfComponents; ++i)\
1775  \n {\
1776  ");
1777  if (glMapper->GetUseDepthPass() &&
1778  glMapper->GetCurrentPass() == vtkOpenGLGPUVolumeRayCastMapper::DepthPass)
1779  {
1780  shaderStr += std::string("\
1781  \n // Data fetching from the red channel of volume texture\
1782  \n float opacity = computeOpacity(scalar, i);\
1783  \n if (opacity > 0.0)\
1784  \n {\
1785  \n g_srcColor.a = opacity;\
1786  \n }\
1787  \n }");
1788  }
1789  else if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
1790  {
1791  shaderStr += std::string("\
1792  \n // Data fetching from the red channel of volume texture\
1793  \n color[i][3] = computeOpacity(scalar, i);\
1794  \n color[i] = computeColor(scalar, color[i][3], i);\
1795  \n totalAlpha += color[i][3] * in_componentWeight[i];\
1796  \n }\
1797  \n if (totalAlpha > 0.0)\
1798  \n {\
1799  \n for (int i = 0; i < in_noOfComponents; ++i)\
1800  \n {\
1801  \n // Only let visible components contribute to the final color\
1802  \n if (in_componentWeight[i] <= 0) continue;\
1803  \n\
1804  \n tmp.x += color[i].x * color[i].w * in_componentWeight[i];\
1805  \n tmp.y += color[i].y * color[i].w * in_componentWeight[i];\
1806  \n tmp.z += color[i].z * color[i].w * in_componentWeight[i];\
1807  \n tmp.w += ((color[i].w * color[i].w)/totalAlpha);\
1808  \n }\
1809  \n }\
1810  \n g_fragColor = (1.0f - g_fragColor.a) * tmp + g_fragColor;");
1811  }
1812  }
1813  else if (glMapper->GetUseDepthPass() &&
1814  glMapper->GetCurrentPass() == vtkOpenGLGPUVolumeRayCastMapper::DepthPass)
1815  {
1816  shaderStr += std::string("\
1817  \n g_srcColor = vec4(0.0);\
1818  \n g_srcColor.a = computeOpacity(scalar);");
1819  }
1820  else
1821  {
1822  if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
1823  {
1824  shaderStr += std::string("\
1825  \n g_srcColor = vec4(0.0);\
1826  \n g_srcColor.a = computeOpacity(scalar);\
1827  \n if (g_srcColor.a > 0.0)\
1828  \n {\
1829  \n g_srcColor = computeColor(scalar, g_srcColor.a);");
1830  }
1831 
1832  shaderStr += std::string("\
1833  \n // Opacity calculation using compositing:\
1834  \n // Here we use front to back compositing scheme whereby\
1835  \n // the current sample value is multiplied to the\
1836  \n // currently accumulated alpha and then this product\
1837  \n // is subtracted from the sample value to get the\
1838  \n // alpha from the previous steps. Next, this alpha is\
1839  \n // multiplied with the current sample colour\
1840  \n // and accumulated to the composited colour. The alpha\
1841  \n // value from the previous steps is then accumulated\
1842  \n // to the composited colour alpha.\
1843  \n g_srcColor.rgb *= g_srcColor.a;\
1844  \n g_fragColor = (1.0f - g_fragColor.a) * g_srcColor + g_fragColor;");
1845 
1846  if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
1847  {
1848  shaderStr += std::string("\
1849  \n }");
1850  }
1851  }
1852  }
1853  else
1854  {
1855  shaderStr += std::string();
1856  }
1857 
1858  shaderStr += std::string("\
1859  \n }");
1860  return shaderStr;
1861 }
1862 
1863 //--------------------------------------------------------------------------
1865  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
1866 {
1867  return std::string("\
1868  \n // Special coloring mode which renders the Prop Id in fragments that\
1869  \n // have accumulated certain level of opacity. Used during the selection\
1870  \n // pass vtkHardwareSelection::ACTOR_PASS.\
1871  \n if (g_fragColor.a > 3.0/ 255.0)\
1872  \n {\
1873  \n gl_FragData[0] = vec4(in_propId, 1.0);\
1874  \n }\
1875  \n else\
1876  \n {\
1877  \n gl_FragData[0] = vec4(0.0);\
1878  \n }\
1879  \n return;");
1880 };
1881 
1882 //--------------------------------------------------------------------------
1884  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
1885 {
1886  return std::string("\
1887  \n // Special coloring mode which renders the voxel index in fragments that\
1888  \n // have accumulated certain level of opacity. Used during the selection\
1889  \n // pass vtkHardwareSelection::ID_LOW24.\
1890  \n if (g_fragColor.a > 3.0/ 255.0)\
1891  \n {\
1892  \n uvec3 volumeDim = uvec3(in_textureExtentsMax - in_textureExtentsMin);\
1893  \n uvec3 voxelCoords = uvec3(volumeDim * g_dataPos);\
1894  \n // vtkHardwareSelector assumes index 0 to be empty space, so add uint(1).\
1895  \n uint idx = volumeDim.x * volumeDim.y * voxelCoords.z +\
1896  \n volumeDim.x * voxelCoords.y + voxelCoords.x + uint(1);\
1897  \n gl_FragData[0] = vec4(float(idx % uint(256)) / 255.0,\
1898  \n float((idx / uint(256)) % uint(256)) / 255.0,\
1899  \n float((idx / uint(65536)) % uint(256)) / 255.0, 1.0);\
1900  \n }\
1901  \n else\
1902  \n {\
1903  \n gl_FragData[0] = vec4(0.0);\
1904  \n }\
1905  \n return;");
1906 };
1907 
1908 //--------------------------------------------------------------------------
1910  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
1911 {
1912  return std::string("\
1913  \n // Special coloring mode which renders the voxel index in fragments that\
1914  \n // have accumulated certain level of opacity. Used during the selection\
1915  \n // pass vtkHardwareSelection::ID_MID24.\
1916  \n if (g_fragColor.a > 3.0/ 255.0)\
1917  \n {\
1918  \n uvec3 volumeDim = uvec3(in_textureExtentsMax - in_textureExtentsMin);\
1919  \n uvec3 voxelCoords = uvec3(volumeDim * g_dataPos);\
1920  \n // vtkHardwareSelector assumes index 0 to be empty space, so add uint(1).\
1921  \n uint idx = volumeDim.x * volumeDim.y * voxelCoords.z +\
1922  \n volumeDim.x * voxelCoords.y + voxelCoords.x + uint(1);\
1923  \n idx = ((idx & 0xff000000) >> 24);\
1924  \n gl_FragData[0] = vec4(float(idx % uint(256)) / 255.0,\
1925  \n float((idx / uint(256)) % uint(256)) / 255.0,\
1926  \n float(idx / uint(65536)) / 255.0, 1.0);\
1927  \n }\
1928  \n else\
1929  \n {\
1930  \n gl_FragData[0] = vec4(0.0);\
1931  \n }\
1932  \n return;");
1933 };
1934 
1935 //--------------------------------------------------------------------------
1937  vtkVolume* vtkNotUsed(vol), int noOfComponents, int independentComponents = 0)
1938 {
1940 
1941  if (glMapper->GetUseDepthPass() &&
1944  {
1945  return std::string();
1946  }
1948  {
1949  if (noOfComponents > 1 && independentComponents)
1950  {
1951  return std::string("\
1952  \n g_srcColor = vec4(0);\
1953  \n for (int i = 0; i < in_noOfComponents; ++i)\
1954  \n {\
1955  \n vec4 tmp = computeColor(l_maxValue, computeOpacity(l_maxValue, i), i);\
1956  \n g_srcColor[0] += tmp[0] * tmp[3] * in_componentWeight[i];\
1957  \n g_srcColor[1] += tmp[1] * tmp[3] * in_componentWeight[i];\
1958  \n g_srcColor[2] += tmp[2] * tmp[3] * in_componentWeight[i];\
1959  \n g_srcColor[3] += tmp[3] * in_componentWeight[i];\
1960  \n }\
1961  \n g_fragColor = g_srcColor;");
1962  }
1963  else
1964  {
1965  return std::string("\
1966  \n g_srcColor = computeColor(l_maxValue,\
1967  \n computeOpacity(l_maxValue));\
1968  \n g_fragColor.rgb = g_srcColor.rgb * g_srcColor.a;\
1969  \n g_fragColor.a = g_srcColor.a;");
1970  }
1971  }
1973  {
1974  if (noOfComponents > 1 && independentComponents)
1975  {
1976  return std::string("\
1977  \n g_srcColor = vec4(0);\
1978  \n for (int i = 0; i < in_noOfComponents; ++i)\
1979  \n {\
1980  \n vec4 tmp = computeColor(l_minValue, computeOpacity(l_minValue, i), i);\
1981  \n g_srcColor[0] += tmp[0] * tmp[3] * in_componentWeight[i];\
1982  \n g_srcColor[1] += tmp[1] * tmp[3] * in_componentWeight[i];\
1983  \n g_srcColor[2] += tmp[2] * tmp[3] * in_componentWeight[i];\
1984  \n g_srcColor[2] += tmp[3] * tmp[3] * in_componentWeight[i];\
1985  \n }\
1986  \n g_fragColor = g_srcColor;");
1987  }
1988  else
1989  {
1990  return std::string("\
1991  \n g_srcColor = computeColor(l_minValue,\
1992  \n computeOpacity(l_minValue));\
1993  \n g_fragColor.rgb = g_srcColor.rgb * g_srcColor.a;\
1994  \n g_fragColor.a = g_srcColor.a;");
1995  }
1996  }
1998  {
1999  if (noOfComponents > 1 && independentComponents)
2000  {
2001  return std::string("\
2002  \n for (int i = 0; i < in_noOfComponents; ++i)\
2003  \n {\
2004  \n if (l_numSamples[i] == uint(0))\
2005  \n {\
2006  \n continue;\
2007  \n }\
2008  \n l_avgValue[i] = l_avgValue[i] * in_componentWeight[i] /\
2009  \n l_numSamples[i];\
2010  \n if (i > 0)\
2011  \n {\
2012  \n l_avgValue[0] += l_avgValue[i];\
2013  \n }\
2014  \n }\
2015  \n l_avgValue[0] = clamp(l_avgValue[0], 0.0, 1.0);\
2016  \n g_fragColor = vec4(vec3(l_avgValue[0]), 1.0);");
2017  }
2018  else
2019  {
2020  return std::string("\
2021  \n if (l_numSamples.x == uint(0))\
2022  \n {\
2023  \n discard;\
2024  \n }\
2025  \n else\
2026  \n {\
2027  \n l_avgValue.x /= l_numSamples.x;\
2028  \n l_avgValue.x = clamp(l_avgValue.x, 0.0, 1.0);\
2029  \n g_fragColor = vec4(vec3(l_avgValue.x), 1.0);\
2030  \n }");
2031  }
2032  }
2033  else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
2034  {
2035  if (noOfComponents > 1 && independentComponents)
2036  {
2037  // Add all the components to get final color
2038  return std::string("\
2039  \n l_sumValue.x *= in_componentWeight.x;\
2040  \n for (int i = 1; i < in_noOfComponents; ++i)\
2041  \n {\
2042  \n l_sumValue.x += l_sumValue[i] * in_componentWeight[i];\
2043  \n }\
2044  \n l_sumValue.x = clamp(l_sumValue.x, 0.0, 1.0);\
2045  \n g_fragColor = vec4(vec3(l_sumValue.x), 1.0);");
2046  }
2047  else
2048  {
2049  return std::string("\
2050  \n l_sumValue.x = clamp(l_sumValue.x, 0.0, 1.0);\
2051  \n g_fragColor = vec4(vec3(l_sumValue.x), 1.0);");
2052  }
2053  }
2054  else
2055  {
2056  return std::string();
2057  }
2058 }
2059 
2060 //--------------------------------------------------------------------------
2062  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2063 {
2064  return std::string();
2065 }
2066 
2067 //--------------------------------------------------------------------------
2069  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2070 {
2071  return std::string("\
2072  \n const float g_opacityThreshold = 1.0 - 1.0 / 255.0;");
2073 }
2074 
2075 //--------------------------------------------------------------------------
2077  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2078 {
2079  return std::string("\
2080  \n uniform vec3 in_propId;");
2081 };
2082 
2083 //--------------------------------------------------------------------------
2085 {
2086  std::string shaderStr;
2087  shaderStr += std::string("\
2088  \n // Flag to indicate if the raymarch loop should terminate \
2089  \n bool stop = false;\
2090  \n\
2091  \n g_terminatePointMax = 0.0;\
2092  \n\
2093  \n#ifdef GL_ES\
2094  \n vec4 l_depthValue = vec4(1.0,1.0,1.0,1.0);\
2095  \n#else\
2096  \n vec4 l_depthValue = texture2D(in_depthSampler, fragTexCoord);\
2097  \n#endif\
2098  \n // Depth test\
2099  \n if(gl_FragCoord.z >= l_depthValue.x)\
2100  \n {\
2101  \n discard;\
2102  \n }\
2103  \n\
2104  \n // color buffer or max scalar buffer have a reduced size.\
2105  \n fragTexCoord = (gl_FragCoord.xy - in_windowLowerLeftCorner) *\
2106  \n in_inverseOriginalWindowSize;\
2107  \n");
2108 
2109  if (mapper->GetBlendMode() == vtkVolumeMapper::SLICE_BLEND)
2110  {
2111  vtkImplicitFunction* sliceFunc = vol->GetProperty()->GetSliceFunction();
2112  if (sliceFunc)
2113  {
2114  if (sliceFunc->IsA("vtkPlane"))
2115  {
2116  shaderStr += std::string("\
2117  \n\
2118  \n // Intersection with plane\
2119  \n float t = intersectRayPlane(ip_vertexPos, rayDir);\
2120  \n vec4 intersection = vec4(ip_vertexPos + t * rayDir, 1.0);\
2121  \n g_intersection = (in_inverseTextureDatasetMatrix[0] * intersection).xyz;\
2122  \n vec4 intersDC = in_projectionMatrix * in_modelViewMatrix * in_volumeMatrix[0] * intersection;\
2123  \n intersDC.xyz /= intersDC.w;\
2124  \n vec4 intersWin = NDCToWindow(intersDC.x, intersDC.y, intersDC.z);\
2125  \n if(intersWin.z >= l_depthValue.x)\
2126  \n {\
2127  \n discard;\
2128  \n }\
2129  \n");
2130  }
2131  else
2132  {
2133  vtkErrorWithObjectMacro(
2134  sliceFunc, "Implicit function type is not supported by this mapper.");
2135  }
2136  }
2137  }
2138 
2139  shaderStr += std::string("\
2140  \n // Compute max number of iterations it will take before we hit\
2141  \n // the termination point\
2142  \n\
2143  \n // Abscissa of the point on the depth buffer along the ray.\
2144  \n // point in texture coordinates\
2145  \n vec4 rayTermination = WindowToNDC(gl_FragCoord.x, gl_FragCoord.y, l_depthValue.x);\
2146  \n\
2147  \n // From normalized device coordinates to eye coordinates.\
2148  \n // in_projectionMatrix is inversed because of way VT\
2149  \n // From eye coordinates to texture coordinates\
2150  \n rayTermination = ip_inverseTextureDataAdjusted *\
2151  \n in_inverseVolumeMatrix[0] *\
2152  \n in_inverseModelViewMatrix *\
2153  \n in_inverseProjectionMatrix *\
2154  \n rayTermination;\
2155  \n g_rayTermination = rayTermination.xyz / rayTermination.w;\
2156  \n\
2157  \n // Setup the current segment:\
2158  \n g_dataPos = g_rayOrigin;\
2159  \n g_terminatePos = g_rayTermination;\
2160  \n\
2161  \n g_terminatePointMax = length(g_terminatePos.xyz - g_dataPos.xyz) /\
2162  \n length(g_dirStep);\
2163  \n g_currentT = 0.0;");
2164 
2165  return shaderStr;
2166 }
2167 
2168 //--------------------------------------------------------------------------
2170  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2171 {
2172  return std::string("\
2173  \n if(any(greaterThan(max(g_dirStep, vec3(0.0))*(g_dataPos - in_texMax[0]),vec3(0.0))) ||\
2174  \n any(greaterThan(min(g_dirStep, vec3(0.0))*(g_dataPos - in_texMin[0]),vec3(0.0))))\
2175  \n {\
2176  \n break;\
2177  \n }\
2178  \n\
2179  \n // Early ray termination\
2180  \n // if the currently composited colour alpha is already fully saturated\
2181  \n // we terminated the loop or if we have hit an obstacle in the\
2182  \n // direction of they ray (using depth buffer) we terminate as well.\
2183  \n if((g_fragColor.a > g_opacityThreshold) || \
2184  \n g_currentT >= g_terminatePointMax)\
2185  \n {\
2186  \n break;\
2187  \n }\
2188  \n ++g_currentT;");
2189 }
2190 
2191 //--------------------------------------------------------------------------
2193  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2194 {
2195  return std::string();
2196 }
2197 
2198 //--------------------------------------------------------------------------
2200  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2201 {
2202  return std::string();
2203 }
2204 
2205 //--------------------------------------------------------------------------
2207  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
2208 {
2209  if (!mapper->GetCropping())
2210  {
2211  return std::string();
2212  }
2213 
2214  return std::string("\
2215  \nuniform float in_croppingPlanes[6];\
2216  \nuniform int in_croppingFlags [32];\
2217  \nfloat croppingPlanesTexture[6];\
2218  \n\
2219  \n// X: axis = 0, Y: axis = 1, Z: axis = 2\
2220  \n// cp Cropping plane bounds (minX, maxX, minY, maxY, minZ, maxZ)\
2221  \nint computeRegionCoord(float cp[6], vec3 pos, int axis)\
2222  \n {\
2223  \n int cpmin = axis * 2;\
2224  \n int cpmax = cpmin + 1;\
2225  \n\
2226  \n if (pos[axis] < cp[cpmin])\
2227  \n {\
2228  \n return 1;\
2229  \n }\
2230  \n else if (pos[axis] >= cp[cpmin] &&\
2231  \n pos[axis] < cp[cpmax])\
2232  \n {\
2233  \n return 2;\
2234  \n }\
2235  \n else if (pos[axis] >= cp[cpmax])\
2236  \n {\
2237  \n return 3;\
2238  \n }\
2239  \n return 0;\
2240  \n }\
2241  \n\
2242  \nint computeRegion(float cp[6], vec3 pos)\
2243  \n {\
2244  \n return (computeRegionCoord(cp, pos, 0) +\
2245  \n (computeRegionCoord(cp, pos, 1) - 1) * 3 +\
2246  \n (computeRegionCoord(cp, pos, 2) - 1) * 9);\
2247  \n }");
2248 }
2249 
2250 //--------------------------------------------------------------------------
2252  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
2253 {
2254  if (!mapper->GetCropping())
2255  {
2256  return std::string();
2257  }
2258 
2259  return std::string("\
2260  \n // Convert cropping region to texture space\
2261  \n mat4 datasetToTextureMat = in_inverseTextureDatasetMatrix[0];\
2262  \n\
2263  \n vec4 tempCrop = vec4(in_croppingPlanes[0], 0.0, 0.0, 1.0);\
2264  \n tempCrop = datasetToTextureMat * tempCrop;\
2265  \n if (tempCrop[3] != 0.0)\
2266  \n {\
2267  \n tempCrop[0] /= tempCrop[3];\
2268  \n }\
2269  \n croppingPlanesTexture[0] = tempCrop[0];\
2270  \n\
2271  \n tempCrop = vec4(in_croppingPlanes[1], 0.0, 0.0, 1.0);\
2272  \n tempCrop = datasetToTextureMat * tempCrop;\
2273  \n if (tempCrop[3] != 0.0)\
2274  \n {\
2275  \n tempCrop[0] /= tempCrop[3];\
2276  \n }\
2277  \n croppingPlanesTexture[1] = tempCrop[0];\
2278  \n\
2279  \n tempCrop = vec4(0.0, in_croppingPlanes[2], 0.0, 1.0);\
2280  \n tempCrop = datasetToTextureMat * tempCrop;\
2281  \n if (tempCrop[3] != 0.0)\
2282  \n {\
2283  \n tempCrop[1] /= tempCrop[3];\
2284  \n }\
2285  \n croppingPlanesTexture[2] = tempCrop[1];\
2286  \n\
2287  \n tempCrop = vec4(0.0, in_croppingPlanes[3], 0.0, 1.0);\
2288  \n tempCrop = datasetToTextureMat * tempCrop;\
2289  \n if (tempCrop[3] != 0.0)\
2290  \n {\
2291  \n tempCrop[1] /= tempCrop[3];\
2292  \n }\
2293  \n croppingPlanesTexture[3] = tempCrop[1];\
2294  \n\
2295  \n tempCrop = vec4(0.0, 0.0, in_croppingPlanes[4], 1.0);\
2296  \n tempCrop = datasetToTextureMat * tempCrop;\
2297  \n if (tempCrop[3] != 0.0)\
2298  \n {\
2299  \n tempCrop[2] /= tempCrop[3];\
2300  \n }\
2301  \n croppingPlanesTexture[4] = tempCrop[2];\
2302  \n\
2303  \n tempCrop = vec4(0.0, 0.0, in_croppingPlanes[5], 1.0);\
2304  \n tempCrop = datasetToTextureMat * tempCrop;\
2305  \n if (tempCrop[3] != 0.0)\
2306  \n {\
2307  \n tempCrop[2] /= tempCrop[3];\
2308  \n }\
2309  \n croppingPlanesTexture[5] = tempCrop[2];");
2310 }
2311 
2312 //--------------------------------------------------------------------------
2314  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
2315 {
2316  if (!mapper->GetCropping())
2317  {
2318  return std::string();
2319  }
2320 
2321  return std::string("\
2322  \n // Determine region\
2323  \n int regionNo = computeRegion(croppingPlanesTexture, g_dataPos);\
2324  \n\
2325  \n // Do & operation with cropping flags\
2326  \n // Pass the flag that its Ok to sample or not to sample\
2327  \n if (in_croppingFlags[regionNo] == 0)\
2328  \n {\
2329  \n // Skip this voxel\
2330  \n g_skip = true;\
2331  \n }");
2332 }
2333 
2334 //--------------------------------------------------------------------------
2336  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2337 {
2338  return std::string();
2339 }
2340 
2341 //--------------------------------------------------------------------------
2343  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2344 {
2345  return std::string();
2346 }
2347 
2348 //--------------------------------------------------------------------------
2350  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
2351 {
2352  if (!mapper->GetClippingPlanes())
2353  {
2354  return std::string();
2355  }
2356 
2357  return std::string("\
2358  \n /// We support only 8 clipping planes for now\
2359  \n /// The first value is the size of the data array for clipping\
2360  \n /// planes (origin, normal)\
2361  \n uniform float in_clippingPlanes[49];\
2362  \n uniform float in_clippedVoxelIntensity;\
2363  \n\
2364  \n int clip_numPlanes;\
2365  \n vec3 clip_rayDirObj;\
2366  \n mat4 clip_texToObjMat;\
2367  \n mat4 clip_objToTexMat;\
2368  \n\
2369  \n// Tighten the sample range as needed to account for clip planes. \
2370  \n// Arguments are in texture coordinates. \
2371  \n// Returns true if the range is at all valid after clipping. If not, \
2372  \n// the fragment should be discarded. \
2373  \nbool AdjustSampleRangeForClipping(inout vec3 startPosTex, inout vec3 stopPosTex) \
2374  \n{ \
2375  \n vec4 startPosObj = vec4(0.0);\
2376  \n {\
2377  \n startPosObj = clip_texToObjMat * vec4(startPosTex - g_rayJitter, 1.0);\
2378  \n startPosObj = startPosObj / startPosObj.w;\
2379  \n startPosObj.w = 1.0;\
2380  \n }\
2381  \n\
2382  \n vec4 stopPosObj = vec4(0.0);\
2383  \n {\
2384  \n stopPosObj = clip_texToObjMat * vec4(stopPosTex, 1.0);\
2385  \n stopPosObj = stopPosObj / stopPosObj.w;\
2386  \n stopPosObj.w = 1.0;\
2387  \n }\
2388  \n\
2389  \n for (int i = 0; i < clip_numPlanes; i = i + 6)\
2390  \n {\
2391  \n vec3 planeOrigin = vec3(in_clippingPlanes[i + 1],\
2392  \n in_clippingPlanes[i + 2],\
2393  \n in_clippingPlanes[i + 3]);\
2394  \n vec3 planeNormal = normalize(vec3(in_clippingPlanes[i + 4],\
2395  \n in_clippingPlanes[i + 5],\
2396  \n in_clippingPlanes[i + 6]));\
2397  \n\
2398  \n // Abort if the entire segment is clipped:\
2399  \n // (We can do this before adjusting the term point, since it'll \
2400  \n // only move further into the clipped area)\
2401  \n float startDistance = dot(planeNormal, planeOrigin - startPosObj.xyz);\
2402  \n float stopDistance = dot(planeNormal, planeOrigin - stopPosObj.xyz);\
2403  \n bool startClipped = startDistance > 0.0;\
2404  \n bool stopClipped = stopDistance > 0.0;\
2405  \n if (startClipped && stopClipped)\
2406  \n {\
2407  \n return false;\
2408  \n }\
2409  \n\
2410  \n float rayDotNormal = dot(clip_rayDirObj, planeNormal);\
2411  \n bool frontFace = rayDotNormal > 0;\
2412  \n\
2413  \n // Move the start position further from the eye if needed:\
2414  \n if (frontFace && // Observing from the clipped side (plane's front face)\
2415  \n startDistance > 0.0) // Ray-entry lies on the clipped side.\
2416  \n {\
2417  \n // Scale the point-plane distance to the ray direction and update the\
2418  \n // entry point.\
2419  \n float rayScaledDist = startDistance / rayDotNormal;\
2420  \n startPosObj = vec4(startPosObj.xyz + rayScaledDist * clip_rayDirObj, 1.0);\
2421  \n vec4 newStartPosTex = clip_objToTexMat * vec4(startPosObj.xyz, 1.0);\
2422  \n newStartPosTex /= newStartPosTex.w;\
2423  \n startPosTex = newStartPosTex.xyz;\
2424  \n startPosTex += g_rayJitter;\
2425  \n }\
2426  \n\
2427  \n // Move the end position closer to the eye if needed:\
2428  \n if (!frontFace && // Observing from the unclipped side (plane's back face)\
2429  \n stopDistance > 0.0) // Ray-entry lies on the unclipped side.\
2430  \n {\
2431  \n // Scale the point-plane distance to the ray direction and update the\
2432  \n // termination point.\
2433  \n float rayScaledDist = stopDistance / rayDotNormal;\
2434  \n stopPosObj = vec4(stopPosObj.xyz + rayScaledDist * clip_rayDirObj, 1.0);\
2435  \n vec4 newStopPosTex = clip_objToTexMat * vec4(stopPosObj.xyz, 1.0);\
2436  \n newStopPosTex /= newStopPosTex.w;\
2437  \n stopPosTex = newStopPosTex.xyz;\
2438  \n }\
2439  \n }\
2440  \n\
2441  \n if (any(greaterThan(startPosTex, in_texMax[0])) ||\
2442  \n any(lessThan(startPosTex, in_texMin[0])))\
2443  \n {\
2444  \n return false;\
2445  \n }\
2446  \n\
2447  \n return true;\
2448  \n}\
2449  \n");
2450 }
2451 
2452 //--------------------------------------------------------------------------
2454 {
2455  if (!mapper->GetClippingPlanes())
2456  {
2457  return std::string();
2458  }
2459 
2460  std::string shaderStr;
2461  if (!ren->GetActiveCamera()->GetParallelProjection())
2462  {
2463  shaderStr = std::string("\
2464  \n vec4 tempClip = in_volumeMatrix[0] * vec4(rayDir, 0.0);\
2465  \n if (tempClip.w != 0.0)\
2466  \n {\
2467  \n tempClip = tempClip/tempClip.w;\
2468  \n tempClip.w = 1.0;\
2469  \n }\
2470  \n clip_rayDirObj = normalize(tempClip.xyz);");
2471  }
2472  else
2473  {
2474  shaderStr = std::string("\
2475  clip_rayDirObj = normalize(in_projectionDirection);");
2476  }
2477 
2478  shaderStr += std::string("\
2479  \n clip_numPlanes = int(in_clippingPlanes[0]);\
2480  \n clip_texToObjMat = in_volumeMatrix[0] * in_textureDatasetMatrix[0];\
2481  \n clip_objToTexMat = in_inverseTextureDatasetMatrix[0] * in_inverseVolumeMatrix[0];\
2482  \n\
2483  \n // Adjust for clipping.\
2484  \n if (!AdjustSampleRangeForClipping(g_rayOrigin, g_rayTermination))\
2485  \n { // entire ray is clipped.\
2486  \n discard;\
2487  \n }\
2488  \n\
2489  \n // Update the segment post-clip:\
2490  \n g_dataPos = g_rayOrigin;\
2491  \n g_terminatePos = g_rayTermination;\
2492  \n g_terminatePointMax = length(g_terminatePos.xyz - g_dataPos.xyz) /\
2493  \n length(g_dirStep);\
2494  \n");
2495 
2496  return shaderStr;
2497 }
2498 
2499 //--------------------------------------------------------------------------
2501  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2502 {
2503  return std::string();
2504 }
2505 
2506 //--------------------------------------------------------------------------
2508  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2509 {
2510  return std::string();
2511 }
2512 
2513 //--------------------------------------------------------------------------
2514 std::string BinaryMaskDeclaration(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper),
2515  vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput, vtkVolumeTexture* mask,
2516  int vtkNotUsed(maskType))
2517 {
2518  if (!mask || !maskInput)
2519  {
2520  return std::string();
2521  }
2522  else
2523  {
2524  return std::string("uniform sampler3D in_mask;");
2525  }
2526 }
2527 
2528 //--------------------------------------------------------------------------
2530  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput,
2531  vtkVolumeTexture* mask, int maskType)
2532 {
2533  if (!mask || !maskInput || maskType == vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2534  {
2535  return std::string();
2536  }
2537  else
2538  {
2539  return std::string("\
2540  \nvec4 maskValue = texture3D(in_mask, g_dataPos);\
2541  \nif(maskValue.r <= 0.0)\
2542  \n {\
2543  \n g_skip = true;\
2544  \n }");
2545  }
2546 }
2547 
2548 //--------------------------------------------------------------------------
2550  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput,
2551  vtkVolumeTexture* mask, int maskType)
2552 {
2553  if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2554  {
2555  return std::string();
2556  }
2557  else
2558  {
2559  return std::string("\
2560  \nuniform float in_maskBlendFactor;\
2561  \nuniform sampler2D in_labelMapTransfer;\
2562  \nuniform float in_mask_scale;\
2563  \nuniform float in_mask_bias;\
2564  \nuniform int in_labelMapNumLabels;\
2565  \n");
2566  }
2567 }
2568 
2569 //--------------------------------------------------------------------------
2571  vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput,
2572  vtkVolumeTexture* mask, int maskType, int noOfComponents)
2573 {
2574  if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2575  {
2576  return std::string();
2577  }
2578  else
2579  {
2580  std::string shaderStr = std::string("\
2581  \nvec4 scalar = texture3D(in_volume[0], g_dataPos);");
2582 
2583  // simulate old intensity textures
2584  if (noOfComponents == 1)
2585  {
2586  shaderStr += std::string("\
2587  \n scalar.r = scalar.r * in_volume_scale[0].r + in_volume_bias[0].r;\
2588  \n scalar = vec4(scalar.r);");
2589  }
2590  else
2591  {
2592  // handle bias and scale
2593  shaderStr += std::string("\
2594  \n scalar = scalar * in_volume_scale[0] + in_volume_bias[0];");
2595  }
2596 
2597  // Assumeing single component scalar for label texture lookup.
2598  // This can be extended to composite color obtained from all components
2599  // in the scalar array.
2600  return shaderStr + std::string("\
2601  \nif (in_maskBlendFactor == 0.0)\
2602  \n {\
2603  \n g_srcColor = computeColor(scalar, computeOpacity(scalar));\
2604  \n }\
2605  \nelse\
2606  \n {\
2607  \n float opacity = computeOpacity(scalar);\
2608  \n // Get the mask value at this same location\
2609  \n vec4 maskValue = texture3D(in_mask, g_dataPos);\
2610  \n maskValue.r = maskValue.r * in_mask_scale + in_mask_bias;\
2611  \n // Quantize the height of the labelmap texture over number of labels\
2612  \n if (in_labelMapNumLabels > 0)\
2613  \n {\
2614  \n maskValue.r =\
2615  \n floor(maskValue.r * in_labelMapNumLabels) /\
2616  \n in_labelMapNumLabels;\
2617  \n }\
2618  \n else\
2619  \n {\
2620  \n maskValue.r = 0.0;\
2621  \n }\
2622  \n if(maskValue.r == 0.0)\
2623  \n {\
2624  \n g_srcColor = computeColor(scalar, opacity);\
2625  \n }\
2626  \n else\
2627  \n {\
2628  \n g_srcColor = texture2D(in_labelMapTransfer,\
2629  \n vec2(scalar.r, maskValue.r));\
2630  \n g_srcColor = computeLighting(g_srcColor, 0, maskValue.r);\
2631  \n if (in_maskBlendFactor < 1.0)\
2632  \n {\
2633  \n g_srcColor = (1.0 - in_maskBlendFactor) *\
2634  \n computeColor(scalar, opacity) +\
2635  \n in_maskBlendFactor * g_srcColor;\
2636  \n }\
2637  \n }\
2638  \n }");
2639  }
2640 }
2641 
2642 //--------------------------------------------------------------------------
2644  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2645 {
2646  return std::string("uniform bool in_clampDepthToBackface;\n"
2647  "vec3 l_opaqueFragPos;\n"
2648  "bool l_updateDepth;\n");
2649 }
2650 
2651 //--------------------------------------------------------------------------
2653  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2654 {
2655  return std::string("\
2656  \n l_opaqueFragPos = vec3(-1.0);\
2657  \n if(in_clampDepthToBackface)\
2658  \n {\
2659  \n l_opaqueFragPos = g_dataPos;\
2660  \n }\
2661  \n l_updateDepth = true;");
2662 }
2663 
2664 //--------------------------------------------------------------------------
2666  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2667 {
2668  return std::string("\
2669  \n if(!g_skip && g_srcColor.a > 0.0 && l_updateDepth)\
2670  \n {\
2671  \n l_opaqueFragPos = g_dataPos;\
2672  \n l_updateDepth = false;\
2673  \n }");
2674 }
2675 
2676 //--------------------------------------------------------------------------
2678  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2679 {
2680  return std::string("\
2681  \n if (l_opaqueFragPos == vec3(-1.0))\
2682  \n {\
2683  \n gl_FragData[1] = vec4(1.0);\
2684  \n }\
2685  \n else\
2686  \n {\
2687  \n vec4 depthValue = in_projectionMatrix * in_modelViewMatrix *\
2688  \n in_volumeMatrix[0] * in_textureDatasetMatrix[0] *\
2689  \n vec4(l_opaqueFragPos, 1.0);\
2690  \n depthValue /= depthValue.w;\
2691  \n gl_FragData[1] = vec4(vec3(0.5 * (gl_DepthRange.far -\
2692  \n gl_DepthRange.near) * depthValue.z + 0.5 *\
2693  \n (gl_DepthRange.far + gl_DepthRange.near)), 1.0);\
2694  \n }");
2695 }
2696 
2697 //--------------------------------------------------------------------------
2699  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2700 {
2701  return std::string("\
2702  \n vec3 l_isoPos = g_dataPos;");
2703 }
2704 
2705 //--------------------------------------------------------------------------
2707  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2708 {
2709  return std::string("\
2710  \n if(!g_skip && g_srcColor.a > 0.0)\
2711  \n {\
2712  \n l_isoPos = g_dataPos;\
2713  \n g_exit = true; g_skip = true;\
2714  \n }");
2715 }
2716 
2717 //--------------------------------------------------------------------------
2719  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2720 {
2721  return std::string("\
2722  \n vec4 depthValue = in_projectionMatrix * in_modelViewMatrix *\
2723  \n in_volumeMatrix[0] * in_textureDatasetMatrix[0] *\
2724  \n vec4(l_isoPos, 1.0);\
2725  \n gl_FragData[0] = vec4(l_isoPos, 1.0);\
2726  \n gl_FragData[1] = vec4(vec3((depthValue.z/depthValue.w) * 0.5 + 0.5),\
2727  \n 1.0);");
2728 }
2729 
2730 //---------------------------------------------------------------------------
2732  vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2733 {
2734  return std::string("\
2735  \n initializeRayCast();\
2736  \n castRay(-1.0, -1.0);\
2737  \n finalizeRayCast();");
2738 }
2739 
2740 //---------------------------------------------------------------------------
2742  const std::vector<std::string>& varNames, const size_t usedNames)
2743 {
2744  std::string shader = "\n";
2745  for (size_t i = 0; i < usedNames; i++)
2746  {
2747  shader += "uniform sampler2D " + varNames[i] + ";\n";
2748  }
2749  return shader;
2750 }
2751 
2752 //---------------------------------------------------------------------------
2754  const std::vector<std::string>& varNames, const size_t usedNames)
2755 {
2756  std::string shader = "\n";
2757  for (size_t i = 0; i < usedNames; i++)
2758  {
2759  std::stringstream ss;
2760  ss << i;
2761  shader += " gl_FragData[" + ss.str() + "] = texture2D(" + varNames[i] + ", texCoord);\n";
2762  }
2763  shader += " return;\n";
2764  return shader;
2765 }
2766 }
2767 
2768 #endif // vtkVolumeShaderComposer_h
2769 // VTK-HeaderTest-Exclude: vtkVolumeShaderComposer.h
virtual vtkPlaneCollection * GetClippingPlanes()
virtual vtkTypeBool GetParallelProjection()
static vtkGPUVolumeRayCastMapper * SafeDownCast(vtkObjectBase *o)
virtual vtkTypeBool GetUseDepthPass()
topologically and geometrically regular array of data
Definition: vtkImageData.h:42
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)
abstract specification for renderers
Definition: vtkRenderer.h:68
vtkCamera * GetActiveCamera()
Get the current camera.
Abstract class for a volume mapper.
virtual vtkTypeBool GetCropping()
virtual int GetBlendMode()
represents the common properties for rendering a volume.
virtual int GetDisableGradientOpacity(int index)
virtual int GetUseClippedVoxelIntensity()
bool HasGradientOpacity(int index=0)
Check whether or not we have the gradient opacity.
int GetShade(int index)
virtual int GetTransferFunctionMode()
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()
@ 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 ComputeOpacity2DDeclaration(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol), int noOfComponents, int independentComponents, std::map< int, std::string > opacityTableMap)
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 ComputeColor2DDeclaration(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol), int noOfComponents, int independentComponents, std::map< int, std::string > colorTableMap)
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 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 ComputeGradientOpacityMulti1DDecl(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs)
std::string BaseDeclarationFragment(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs, int vtkNotUsed(numberOfLights), int lightingComplexity, int noOfComponents, int independentComponents)