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