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