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