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