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