VTK  9.1.0
vtkVolumeShaderComposer.h
Go to the documentation of this file.
1/*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkVolumeShaderComposer.h
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14=========================================================================*/
15
16#ifndef vtkVolumeShaderComposer_h
17#define vtkVolumeShaderComposer_h
18#include <vtkCamera.h>
19#include <vtkImplicitFunction.h>
21#include <vtkRectilinearGrid.h>
22#include <vtkRenderer.h>
23#include <vtkUniformGrid.h>
24#include <vtkVolume.h>
26#include <vtkVolumeMapper.h>
27#include <vtkVolumeProperty.h>
28#include <vtkVolumeTexture.h>
29
30#include <map>
31#include <sstream>
32#include <string>
33
34namespace
35{
36bool HasGradientOpacity(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs)
37{
38 for (auto& item : inputs)
39 {
40 vtkVolumeProperty* volProp = item.second.Volume->GetProperty();
41 const bool gradOp = (volProp->HasGradientOpacity() || volProp->HasLabelGradientOpacity()) &&
42 !volProp->GetDisableGradientOpacity();
43 if (gradOp)
44 return true;
45 }
46 return false;
47}
48
50{
51 for (auto& item : inputs)
52 {
53 vtkVolumeProperty* volProp = item.second.Volume->GetProperty();
54 const bool lighting = volProp->GetShade() == 1;
55 if (lighting)
56 return true;
57 }
58 return false;
59}
60
61bool UseClippedVoxelIntensity(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs)
62{
63 for (auto& item : inputs)
64 {
65 vtkVolumeProperty* volProp = item.second.Volume->GetProperty();
66 const bool useClippedVoxelIntensity = volProp->GetUseClippedVoxelIntensity() == 1;
67 if (useClippedVoxelIntensity)
68 {
69 return true;
70 }
71 }
72 return false;
73}
74
75const std::string ArrayBaseName(const std::string& arrayName)
76{
77 const std::string base = arrayName.substr(0, arrayName.length() - 3);
78 return base;
79}
80}
81
82// NOTE:
83// In this code, we referred to various spaces described below:
84// Object space: Raw coordinates in space defined by volume matrix
85// Dataset space: Raw coordinates
86// Eye space: Coordinates in eye space (as referred in computer graphics)
87
88namespace vtkvolume
89{
90//--------------------------------------------------------------------------
92 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
93{
94 return std::string(
95 " //Transform vertex (data coordinates) to clip coordinates\n"
96 " // p_clip = T_ProjViewModel * T_dataToWorld * p_data\n"
97 " vec4 pos = in_projectionMatrix * in_modelViewMatrix * in_volumeMatrix[0] *\n"
98 " vec4(in_vertexPos.xyz, 1.0);\n"
99 " gl_Position = pos;\n");
100}
101
102//--------------------------------------------------------------------------
104 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
105{
106 return std::string(
107 " // Transform vertex (data coordinates) to texture coordinates.\n"
108 " // p_texture = T_dataToTex * p_data\n"
109 " vec3 uvx = sign(in_cellSpacing[0]) * (in_inverseTextureDatasetMatrix[0] *\n"
110 " vec4(in_vertexPos, 1.0)).xyz;\n"
111 "\n"
112 " // For point dataset, we offset the texture coordinate\n"
113 " // to account for OpenGL treating voxel at the center of the cell.\n"
114 " // Transform cell tex-coordinates to point tex-coordinates (cellToPoint\n"
115 " // is an identity matrix in the case of cell data).\n"
116 " ip_textureCoords = (in_cellToPoint[0] * vec4(uvx, 1.0)).xyz;\n"
117 " ip_inverseTextureDataAdjusted = in_cellToPoint[0] * in_inverseTextureDatasetMatrix[0];\n");
118}
119
120//--------------------------------------------------------------------------
121std::string BaseDeclarationVertex(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper,
122 vtkVolume* vtkNotUsed(vol), bool multipleInputs)
123{
124 auto gpuMapper = vtkGPUVolumeRayCastMapper::SafeDownCast(mapper);
125 const int numInputs = gpuMapper->GetInputCount();
126
127 std::ostringstream ss;
128 ss << "uniform vec3 in_cellSpacing[" << numInputs
129 << "];\n"
130 "uniform mat4 in_modelViewMatrix;\n"
131 "uniform mat4 in_projectionMatrix;\n";
132
133 const int numTransf = multipleInputs ? numInputs + 1 : 1;
134 ss << "uniform mat4 in_volumeMatrix[" << numTransf
135 << "];\n"
136 "uniform mat4 in_inverseTextureDatasetMatrix["
137 << numTransf
138 << "];\n"
139 "uniform mat4 in_cellToPoint["
140 << numTransf
141 << "];\n"
142 "\n"
143 "//This variable could be 'invariant varying' but it is declared\n"
144 "//as 'varying' to avoid compiler compatibility issues.\n"
145 "out mat4 ip_inverseTextureDataAdjusted;\n";
146
147 return ss.str();
148}
149
150//--------------------------------------------------------------------------
151std::string BaseDeclarationFragment(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper,
152 vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, int vtkNotUsed(numberOfLights),
153 int lightingComplexity, int noOfComponents, int independentComponents)
154{
155 const int numInputs = static_cast<int>(inputs.size());
156
157 std::ostringstream toShaderStr;
158 toShaderStr << "uniform sampler3D in_volume[" << numInputs << "];\n";
159
160 toShaderStr << "uniform vec4 in_volume_scale[" << numInputs
161 << "];\n"
162 "uniform vec4 in_volume_bias["
163 << numInputs << "];\n";
164
166 {
167 toShaderStr << "uniform sampler1D in_coordTexs;\n";
168 toShaderStr << "uniform vec3 in_coordTexSizes;\n";
169 toShaderStr << "uniform vec3 in_coordsScale;\n";
170 toShaderStr << "uniform vec3 in_coordsBias;\n";
171 }
172
173 if (mapper->GetInput()->GetPointGhostArray() || mapper->GetInput()->GetCellGhostArray())
174 {
175 toShaderStr << "uniform sampler3D in_blanking;\n";
176 }
177
178 toShaderStr << "uniform int in_noOfComponents;\n"
179 "\n"
180 "uniform sampler2D in_depthSampler;\n"
181 "\n"
182 "// Camera position\n"
183 "uniform vec3 in_cameraPos;\n";
184
186 if (glMapper->GetUseJittering())
187 {
188 toShaderStr << "uniform sampler2D in_noiseSampler;\n";
189 }
190
191 // For multiple inputs (numInputs > 1), an additional transformation is
192 // needed for the bounding-box.
193 const int numTransf = (numInputs > 1) ? numInputs + 1 : 1;
194 toShaderStr << "uniform mat4 in_volumeMatrix[" << numTransf
195 << "];\n"
196 "uniform mat4 in_inverseVolumeMatrix["
197 << numTransf
198 << "];\n"
199 "uniform mat4 in_textureDatasetMatrix["
200 << numTransf
201 << "];\n"
202 "uniform mat4 in_inverseTextureDatasetMatrix["
203 << numTransf
204 << "];\n"
205 "uniform mat4 in_textureToEye["
206 << numTransf
207 << "];\n"
208 "uniform vec3 in_texMin["
209 << numTransf
210 << "];\n"
211 "uniform vec3 in_texMax["
212 << numTransf
213 << "];\n"
214 "uniform mat4 in_cellToPoint["
215 << numTransf << "];\n";
216
217 toShaderStr << "// view and model matrices\n"
218 "uniform mat4 in_projectionMatrix;\n"
219 "uniform mat4 in_inverseProjectionMatrix;\n"
220 "uniform mat4 in_modelViewMatrix;\n"
221 "uniform mat4 in_inverseModelViewMatrix;\n"
222 "in mat4 ip_inverseTextureDataAdjusted;\n"
223 "\n"
224 "// Ray step size\n"
225 "uniform vec3 in_cellStep["
226 << numInputs << "];\n";
227
228 toShaderStr << "uniform vec2 in_scalarsRange[" << numInputs * 4
229 << "];\n"
230 "uniform vec3 in_cellSpacing["
231 << numInputs
232 << "];\n"
233 "\n"
234 "// Sample distance\n"
235 "uniform float in_sampleDistance;\n"
236 "\n"
237 "// Scales\n"
238 "uniform vec2 in_windowLowerLeftCorner;\n"
239 "uniform vec2 in_inverseOriginalWindowSize;\n"
240 "uniform vec2 in_inverseWindowSize;\n"
241 "uniform vec3 in_textureExtentsMax;\n"
242 "uniform vec3 in_textureExtentsMin;\n"
243 "\n"
244 "// Material and lighting\n"
245 "uniform vec3 in_diffuse[4];\n"
246 "uniform vec3 in_ambient[4];\n"
247 "uniform vec3 in_specular[4];\n"
248 "uniform float in_shininess[4];\n"
249 "\n"
250 "// Others\n"
251 "vec3 g_rayJitter = vec3(0.0);\n"
252 "\n"
253 "uniform vec2 in_averageIPRange;\n";
254
255 toShaderStr << "vec4 g_eyePosObjs[" << numInputs << "];\n";
256
257 const bool hasGradientOpacity = HasGradientOpacity(inputs);
258 if (lightingComplexity > 0 || hasGradientOpacity)
259 {
260 toShaderStr << "uniform bool in_twoSidedLighting;\n";
261 }
262
263 if (lightingComplexity == 3)
264 {
265 toShaderStr << "vec4 g_fragWorldPos;\n"
266 "uniform int in_numberOfLights;\n"
267 "uniform vec3 in_lightAmbientColor[6];\n"
268 "uniform vec3 in_lightDiffuseColor[6];\n"
269 "uniform vec3 in_lightSpecularColor[6];\n"
270 "uniform vec3 in_lightDirection[6];\n"
271 "uniform vec3 in_lightPosition[6];\n"
272 "uniform vec3 in_lightAttenuation[6];\n"
273 "uniform float in_lightConeAngle[6];\n"
274 "uniform float in_lightExponent[6];\n"
275 "uniform int in_lightPositional[6];\n";
276 }
277 else if (lightingComplexity == 2)
278 {
279 toShaderStr << "vec4 g_fragWorldPos;\n"
280 "uniform int in_numberOfLights;\n"
281 "uniform vec3 in_lightAmbientColor[6];\n"
282 "uniform vec3 in_lightDiffuseColor[6];\n"
283 "uniform vec3 in_lightSpecularColor[6];\n"
284 "uniform vec3 in_lightDirection[6];\n";
285 }
286 else
287 {
288 toShaderStr << "uniform vec3 in_lightAmbientColor[1];\n"
289 "uniform vec3 in_lightDiffuseColor[1];\n"
290 "uniform vec3 in_lightSpecularColor[1];\n"
291 "vec4 g_lightPosObj["
292 << numInputs
293 << "];\n"
294 "vec3 g_ldir["
295 << numInputs
296 << "];\n"
297 "vec3 g_vdir["
298 << numInputs
299 << "];\n"
300 "vec3 g_h["
301 << numInputs << "];\n";
302 }
303
304 if (noOfComponents > 1 && independentComponents)
305 {
306 toShaderStr << "uniform vec4 in_componentWeight;\n";
307 }
308
310 glMapper->GetUseDepthPass())
311 {
312 toShaderStr << "uniform sampler2D in_depthPassSampler;\n";
313 }
314
316 {
317 toShaderStr << "#if NUMBER_OF_CONTOURS\n"
318 "uniform float in_isosurfacesValues[NUMBER_OF_CONTOURS];\n"
319 "\n"
320 "int findIsoSurfaceIndex(float scalar, float array[NUMBER_OF_CONTOURS+2])\n"
321 "{\n"
322 " int index = NUMBER_OF_CONTOURS >> 1;\n"
323 " while (scalar > array[index]) ++index;\n"
324 " while (scalar < array[index]) --index;\n"
325 " return index;\n"
326 "}\n"
327 "#endif\n";
328 }
329 else if (glMapper->GetBlendMode() == vtkVolumeMapper::SLICE_BLEND)
330 {
331 vtkVolume* vol = inputs.begin()->second.Volume;
332 vtkImplicitFunction* func = vol->GetProperty()->GetSliceFunction();
333
334 if (func && func->IsA("vtkPlane"))
335 {
336 toShaderStr
337 << "uniform vec3 in_slicePlaneOrigin;\n"
338 "uniform vec3 in_slicePlaneNormal;\n"
339 "vec3 g_intersection;\n"
340 "\n"
341 "float intersectRayPlane(vec3 rayOrigin, vec3 rayDir)\n"
342 "{\n"
343 " vec4 planeNormal = in_inverseVolumeMatrix[0] * vec4(in_slicePlaneNormal, 0.0);\n"
344 " float denom = dot(planeNormal.xyz, rayDir);\n"
345 " if (abs(denom) > 1e-6)\n"
346 " {\n"
347 " vec4 planeOrigin = in_inverseVolumeMatrix[0] * vec4(in_slicePlaneOrigin, 1.0);\n"
348 " return dot(planeOrigin.xyz - rayOrigin, planeNormal.xyz) / denom;\n"
349 " }\n"
350 " return -1.0;\n"
351 "}\n";
352 }
353 }
354
355 return toShaderStr.str();
356}
357
358//--------------------------------------------------------------------------
359std::string BaseInit(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper,
360 vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, int lightingComplexity)
361{
363 vtkVolume* vol = inputs.begin()->second.Volume;
364 const int numInputs = static_cast<int>(inputs.size());
365
366 std::ostringstream shaderStr;
369 {
370 shaderStr << "\
371 \n //\
372 \n vec2 fragTexCoord2 = (gl_FragCoord.xy - in_windowLowerLeftCorner) *\
373 \n in_inverseWindowSize;\
374 \n vec4 depthValue = texture2D(in_depthPassSampler, fragTexCoord2);\
375 \n vec4 rayOrigin = WindowToNDC(gl_FragCoord.x, gl_FragCoord.y, depthValue.x);\
376 \n\
377 \n // From normalized device coordinates to eye coordinates.\
378 \n // in_projectionMatrix is inversed because of way VT\
379 \n // From eye coordinates to texture coordinates\
380 \n rayOrigin = in_inverseTextureDatasetMatrix[0] *\
381 \n in_inverseVolumeMatrix[0] *\
382 \n in_inverseModelViewMatrix *\
383 \n in_inverseProjectionMatrix *\
384 \n rayOrigin;\
385 \n rayOrigin /= rayOrigin.w;\
386 \n g_rayOrigin = rayOrigin.xyz;";
387 }
388 else
389 {
390 shaderStr << "\
391 \n // Get the 3D texture coordinates for lookup into the in_volume dataset\
392 \n g_rayOrigin = ip_textureCoords.xyz;";
393 }
394
395 shaderStr << "\
396 \n\
397 \n // Eye position in dataset space\
398 \n g_eyePosObj = in_inverseVolumeMatrix[0] * vec4(in_cameraPos, 1.0);";
399 for (int i = 0; i < numInputs; ++i)
400 {
401 // In multi-volume case the first volume matrix is of the bounding box
402 shaderStr << "\
403 \n g_eyePosObjs["
404 << i << "] = in_inverseVolumeMatrix[" << (numInputs > 1 ? i + 1 : i)
405 << "] * vec4(in_cameraPos, 1.0);";
406 }
407 shaderStr << "\n\
408 \n // Getting the ray marching direction (in dataset space)\
409 \n vec3 rayDir = computeRayDirection();\
410 \n\
411 \n // 2D Texture fragment coordinates [0,1] from fragment coordinates.\
412 \n // The frame buffer texture has the size of the plain buffer but \
413 \n // we use a fraction of it. The texture coordinate is less than 1 if\
414 \n // the reduction factor is less than 1.\
415 \n // Device coordinates are between -1 and 1. We need texture\
416 \n // coordinates between 0 and 1. The in_depthSampler\
417 \n // buffer has the original size buffer.\
418 \n vec2 fragTexCoord = (gl_FragCoord.xy - in_windowLowerLeftCorner) *\
419 \n in_inverseWindowSize;\
420 \n\
421 \n // Multiply the raymarching direction with the step size to get the\
422 \n // sub-step size we need to take at each raymarching step\
423 \n g_dirStep = (ip_inverseTextureDataAdjusted *\
424 \n vec4(rayDir, 0.0)).xyz * in_sampleDistance;\
425 \n";
426
428 {
429 // Intersection is computed with g_rayOrigin, so we should not modify it with Slice mode
430 if (glMapper->GetUseJittering())
431 {
432 shaderStr << "\
433 \n float jitterValue = texture2D(in_noiseSampler, gl_FragCoord.xy /\
434 vec2(textureSize(in_noiseSampler, 0))).x;\
435 \n g_rayJitter = g_dirStep * jitterValue;\
436 \n";
437 }
438 else
439 {
440 shaderStr << "\
441 \n g_rayJitter = g_dirStep;\
442 \n";
443 }
444 shaderStr << "\
445 \n g_rayOrigin += g_rayJitter;\
446 \n";
447 }
448
449 shaderStr << "\
450 \n // Flag to determine if voxel should be considered for the rendering\
451 \n g_skip = false;";
452
453 if (vol->GetProperty()->GetShade() && lightingComplexity == 1)
454 {
455 shaderStr << "\
456 \n // Light position in dataset space";
457 for (int i = 0; i < numInputs; ++i)
458 {
459 // In multi-volume case the first volume matrix is of the bounding box
460 shaderStr << "\
461 \n g_lightPosObj["
462 << i << "] = (in_inverseVolumeMatrix[" << (numInputs > 1 ? i + 1 : i) << "] *\
463 \n vec4(in_cameraPos, 1.0));\
464 \n g_ldir["
465 << i << "] = normalize(g_lightPosObj[" << i << "].xyz - ip_vertexPos);\
466 \n g_vdir["
467 << i << "] = normalize(g_eyePosObjs[" << i << "].xyz - ip_vertexPos);\
468 \n g_h["
469 << i << "] = normalize(g_ldir[" << i << "] + g_vdir[" << i << "]);";
470 }
471 }
472
473 return shaderStr.str();
474}
475
476//--------------------------------------------------------------------------
478 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
479{
481
482 std::string str("\
483 \n g_skip = false;");
484
485 // Blanking support
487 bool blankCells = (dataSet->GetCellGhostArray() != nullptr);
488 bool blankPoints = (dataSet->GetPointGhostArray() != nullptr);
489 if (blankPoints || blankCells)
490 {
491 str += std::string("\
492 \n // Check whether the neighboring points/cells are blank.\
493 \n // Note the half cellStep because texels are point centered.\
494 \n vec3 xvec = vec3(in_cellStep[0].x/2.0, 0.0, 0.0);\
495 \n vec3 yvec = vec3(0.0, in_cellStep[0].y/2.0, 0.0);\
496 \n vec3 zvec = vec3(0.0, 0.0, in_cellStep[0].z/2.0);\
497 \n vec3 texPosPVec[3];\
498 \n texPosPVec[0] = g_dataPos + xvec;\
499 \n texPosPVec[1] = g_dataPos + yvec;\
500 \n texPosPVec[2] = g_dataPos + zvec;\
501 \n vec3 texPosNVec[3];\
502 \n texPosNVec[0] = g_dataPos - xvec;\
503 \n texPosNVec[1] = g_dataPos - yvec;\
504 \n texPosNVec[2] = g_dataPos - zvec;\
505 \n vec4 blankValue = texture3D(in_blanking, g_dataPos);\
506 \n vec4 blankValueXP = texture3D(in_blanking, texPosPVec[0]);\
507 \n vec4 blankValueYP = texture3D(in_blanking, texPosPVec[1]);\
508 \n vec4 blankValueZP = texture3D(in_blanking, texPosPVec[2]);\
509 \n vec4 blankValueXN = texture3D(in_blanking, texPosNVec[0]);\
510 \n vec4 blankValueYN = texture3D(in_blanking, texPosNVec[1]);\
511 \n vec4 blankValueZN = texture3D(in_blanking, texPosNVec[2]);\
512 \n vec3 blankValuePx;\
513 \n blankValuePx[0] = blankValueXP.x;\
514 \n blankValuePx[1] = blankValueYP.x;\
515 \n blankValuePx[2] = blankValueZP.x;\
516 \n vec3 blankValuePy;\
517 \n blankValuePy[0] = blankValueXP.y;\
518 \n blankValuePy[1] = blankValueYP.y;\
519 \n blankValuePy[2] = blankValueZP.y;\
520 \n vec3 blankValueNx;\
521 \n blankValueNx[0] = blankValueXN.x;\
522 \n blankValueNx[1] = blankValueYN.x;\
523 \n blankValueNx[2] = blankValueZN.x;\
524 \n vec3 blankValueNy;\
525 \n blankValueNy[0] = blankValueXN.y;\
526 \n blankValueNy[1] = blankValueYN.y;\
527 \n blankValueNy[2] = blankValueZN.y;\
528 \n");
529 if (blankPoints)
530 {
531 str += std::string("\
532 \n // If the current or neighboring points\
533 \n // (that belong to cells that share this texel) are blanked,\
534 \n // skip the texel. In other words, if point 1 were blank,\
535 \n // texels 0, 1 and 2 would have to be skipped.\
536 \n if (blankValue.x > 0.0 ||\
537 \n any(greaterThan(blankValueNx, vec3(0.0))) ||\
538 \n any(greaterThan(blankValuePx, vec3(0.0))))\
539 \n {\
540 \n // skip this texel\
541 \n g_skip = true;\
542 \n }\
543 \n");
544 if (blankCells)
545 {
546 str += std::string("\
547 \n // If the current or previous cells (that share this texel)\
548 \n // are blanked, skip the texel. In other words, if cell 1\
549 \n // is blanked, texels 1 and 2 would have to be skipped.\
550 \n else if (blankValue.y > 0.0 ||\
551 \n any(greaterThan(blankValuePy, vec3(0.0))) ||\
552 \n any(greaterThan(blankValueNy, vec3(0.0))))\
553 \n {\
554 \n // skip this texel\
555 \n g_skip = true;\
556 \n }\
557 \n");
558 }
559 }
560 else 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 if (blankValue.x > 0.0 ||\
567 \n any(greaterThan(blankValueNx, vec3(0.0))) ||\
568 \n any(greaterThan(blankValuePx, vec3(0.0))))\
569 \n {\
570 \n // skip this texel\
571 \n g_skip = true;\
572 \n }\
573 \n");
574 }
575 }
576
578 {
579 str += std::string("\
580 \n g_dataPos = g_intersection;\
581 \n");
582 }
583
584 return str;
585}
586
587//--------------------------------------------------------------------------
588std::string BaseExit(
589 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
590{
591 return std::string();
592}
593
594//--------------------------------------------------------------------------
595std::string ComputeGradientOpacity1DDecl(vtkVolume* vol, int noOfComponents,
596 int independentComponents, std::map<int, std::string> gradientTableMap)
597{
598 auto volProperty = vol->GetProperty();
599 std::ostringstream ss;
600 if (volProperty->HasGradientOpacity())
601 {
602 ss << "uniform sampler2D " << ArrayBaseName(gradientTableMap[0]) << "[" << noOfComponents
603 << "];\n";
604 }
605 bool useLabelGradientOpacity =
606 (volProperty->HasLabelGradientOpacity() && (noOfComponents == 1 || !independentComponents));
607 if (useLabelGradientOpacity)
608 {
609 ss << "uniform sampler2D in_labelMapGradientOpacity;\n";
610 }
611
612 std::string shaderStr = ss.str();
613 if (volProperty->HasGradientOpacity() && (noOfComponents == 1 || !independentComponents))
614 {
615 shaderStr += std::string("\
616 \nfloat computeGradientOpacity(vec4 grad)\
617 \n {\
618 \n return texture2D(" +
619 gradientTableMap[0] + ", vec2(grad.w, 0.0)).r;\
620 \n }");
621 }
622 else if (noOfComponents > 1 && independentComponents && volProperty->HasGradientOpacity())
623 {
624 shaderStr += std::string("\
625 \nfloat computeGradientOpacity(vec4 grad, int component)\
626 \n {");
627
628 for (int i = 0; i < noOfComponents; ++i)
629 {
630 std::ostringstream toString;
631 toString << i;
632 shaderStr += std::string("\
633 \n if (component == " +
634 toString.str() + ")");
635
636 shaderStr += std::string("\
637 \n {\
638 \n return texture2D(" +
639 gradientTableMap[i] + ", vec2(grad.w, 0.0)).r;\
640 \n }");
641 }
642
643 shaderStr += std::string("\
644 \n }");
645 }
646
647 if (useLabelGradientOpacity)
648 {
649 shaderStr += std::string("\
650 \nfloat computeGradientOpacityForLabel(vec4 grad, float label)\
651 \n {\
652 \n return texture2D(in_labelMapGradientOpacity, vec2(grad.w, label)).r;\
653 \n }");
654 }
655
656 return shaderStr;
657}
658
659//--------------------------------------------------------------------------
662{
663 const bool hasLighting = HasLighting(inputs);
664 const bool hasGradientOp = HasGradientOpacity(inputs);
665
666 std::string shaderStr;
667 if (hasLighting || hasGradientOp)
668 {
669 shaderStr += std::string(
670 "// c is short for component\n"
671 "vec4 computeGradient(in vec3 texPos, in int c, in sampler3D volume,in int index)\n"
672 "{\n"
673 " // Approximate Nabla(F) derivatives with central differences.\n"
674 " vec3 g1; // F_front\n"
675 " vec3 g2; // F_back\n"
676 " vec3 xvec = vec3(in_cellStep[index].x, 0.0, 0.0);\n"
677 " vec3 yvec = vec3(0.0, in_cellStep[index].y, 0.0);\n"
678 " vec3 zvec = vec3(0.0, 0.0, in_cellStep[index].z);\n"
679 " vec3 texPosPvec[3];\n"
680 " texPosPvec[0] = texPos + xvec;\n"
681 " texPosPvec[1] = texPos + yvec;\n"
682 " texPosPvec[2] = texPos + zvec;\n"
683 " vec3 texPosNvec[3];\n"
684 " texPosNvec[0] = texPos - xvec;\n"
685 " texPosNvec[1] = texPos - yvec;\n"
686 " texPosNvec[2] = texPos - zvec;\n"
687 " g1.x = texture3D(volume, vec3(texPosPvec[0]))[c];\n"
688 " g1.y = texture3D(volume, vec3(texPosPvec[1]))[c];\n"
689 " g1.z = texture3D(volume, vec3(texPosPvec[2]))[c];\n"
690 " g2.x = texture3D(volume, vec3(texPosNvec[0]))[c];\n"
691 " g2.y = texture3D(volume, vec3(texPosNvec[1]))[c];\n"
692 " g2.z = texture3D(volume, vec3(texPosNvec[2]))[c];\n"
693 "\n");
694 if (UseClippedVoxelIntensity(inputs) && mapper->GetClippingPlanes())
695 {
696 shaderStr +=
697 std::string(" vec4 g1ObjDataPos[3], g2ObjDataPos[3];\n"
698 " for (int i = 0; i < 3; ++i)\n"
699 " {\n"
700 " g1ObjDataPos[i] = clip_texToObjMat * vec4(texPosPvec[i], 1.0);\n"
701 " if (g1ObjDataPos[i].w != 0.0)\n"
702 " {\n"
703 " g1ObjDataPos[i] /= g1ObjDataPos[i].w;\n"
704 " }\n"
705 " g2ObjDataPos[i] = clip_texToObjMat * vec4(texPosNvec[i], 1.0);\n"
706 " if (g2ObjDataPos[i].w != 0.0)\n"
707 " {\n"
708 " g2ObjDataPos[i] /= g2ObjDataPos[i].w;\n"
709 " }\n"
710 " }\n"
711 "\n"
712 " for (int i = 0; i < clip_numPlanes && !g_skip; i = i + 6)\n"
713 " {\n"
714 " vec3 planeOrigin = vec3(in_clippingPlanes[i + 1],\n"
715 " in_clippingPlanes[i + 2],\n"
716 " in_clippingPlanes[i + 3]);\n"
717 " vec3 planeNormal = normalize(vec3(in_clippingPlanes[i + 4],\n"
718 " in_clippingPlanes[i + 5],\n"
719 " in_clippingPlanes[i + 6]));\n"
720 " for (int j = 0; j < 3; ++j)\n"
721 " {\n"
722 " if (dot(vec3(planeOrigin - g1ObjDataPos[j].xyz), planeNormal) > 0)\n"
723 " {\n"
724 " g1[j] = in_clippedVoxelIntensity;\n"
725 " }\n"
726 " if (dot(vec3(planeOrigin - g2ObjDataPos[j].xyz), planeNormal) > 0)\n"
727 " {\n"
728 " g2[j] = in_clippedVoxelIntensity;\n"
729 " }\n"
730 " }\n"
731 " }\n"
732 "\n");
733 }
734 shaderStr += std::string(" // Apply scale and bias to the fetched values.\n"
735 " g1 = g1 * in_volume_scale[index][c] + in_volume_bias[index][c];\n"
736 " g2 = g2 * in_volume_scale[index][c] + in_volume_bias[index][c];\n"
737 "\n");
738 if (!hasGradientOp)
739 {
740 shaderStr +=
741 std::string(" // Central differences: (F_front - F_back) / 2h\n"
742 " // This version of computeGradient() is only used for lighting\n"
743 " // calculations (only direction matters), hence the difference is\n"
744 " // not scaled by 2h and a dummy gradient mag is returned (-1.).\n"
745 " return vec4((g1 - g2) / in_cellSpacing[index], -1.0);\n"
746 "}\n");
747 }
748 else
749 {
750 shaderStr += std::string(
751 " // Scale values the actual scalar range.\n"
752 " float range = in_scalarsRange[4*index+c][1] - in_scalarsRange[4*index+c][0];\n"
753 " g1 = in_scalarsRange[4*index+c][0] + range * g1;\n"
754 " g2 = in_scalarsRange[4*index+c][0] + range * g2;\n"
755 "\n"
756 " // Central differences: (F_front - F_back) / 2h\n"
757 " g2 = g1 - g2;\n"
758 "\n"
759 " float avgSpacing = (in_cellSpacing[index].x +\n"
760 " in_cellSpacing[index].y + in_cellSpacing[index].z) / 3.0;\n"
761 " vec3 aspect = in_cellSpacing[index] * 2.0 / avgSpacing;\n"
762 " g2 /= aspect;\n"
763 " float grad_mag = length(g2);\n"
764 "\n"
765 " // Handle normalizing with grad_mag == 0.0\n"
766 " g2 = grad_mag > 0.0 ? normalize(g2) : vec3(0.0);\n"
767 "\n"
768 " // Since the actual range of the gradient magnitude is unknown,\n"
769 " // assume it is in the range [0, 0.25 * dataRange].\n"
770 " range = range != 0 ? range : 1.0;\n"
771 " grad_mag = grad_mag / (0.25 * range);\n"
772 " grad_mag = clamp(grad_mag, 0.0, 1.0);\n"
773 "\n"
774 " return vec4(g2.xyz, grad_mag);\n"
775 "}\n");
776 }
777 }
778 else
779 {
780 shaderStr += std::string(
781 "vec4 computeGradient(in vec3 texPos, in int c, in sampler3D volume, in int index)\n"
782 "{\n"
783 " return vec4(0.0);\n"
784 "}\n");
785 }
786
787 return shaderStr;
788}
789
790//--------------------------------------------------------------------------
791std::string ComputeLightingDeclaration(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper,
792 vtkVolume* vol, int noOfComponents, int independentComponents, int vtkNotUsed(numberOfLights),
793 int lightingComplexity)
794{
795 vtkVolumeProperty* volProperty = vol->GetProperty();
796 std::string shaderStr = std::string("\
797 \nvec4 computeLighting(vec4 color, int component, float label)\
798 \n {\
799 \n vec4 finalColor = vec4(0.0);");
800
801 // Shading for composite blending only
802 int const shadeReqd = volProperty->GetShade() &&
806
807 int const transferMode = volProperty->GetTransferFunctionMode();
808
809 if (shadeReqd || volProperty->HasGradientOpacity() || volProperty->HasLabelGradientOpacity())
810 {
811 switch (transferMode)
812 {
814 shaderStr += std::string(
815 " // Compute gradient function only once\n"
816 " vec4 gradient = computeGradient(g_dataPos, component, in_volume[0], 0);\n");
817 break;
819 shaderStr += std::string(" // TransferFunction2D is enabled so the gradient for\n"
820 " // each component has already been cached\n"
821 " vec4 gradient = g_gradients_0[component];\n");
822 break;
823 }
824 }
825
826 if (shadeReqd)
827 {
828 if (lightingComplexity == 1)
829 {
830 shaderStr += std::string("\
831 \n vec3 diffuse = vec3(0.0);\
832 \n vec3 specular = vec3(0.0);\
833 \n vec3 normal = gradient.xyz;\
834 \n float normalLength = length(normal);\
835 \n if (normalLength > 0.0)\
836 \n {\
837 \n normal = normalize(normal);\
838 \n }\
839 \n else\
840 \n {\
841 \n normal = vec3(0.0, 0.0, 0.0);\
842 \n }\
843 \n float nDotL = dot(normal, g_ldir[0]);\
844 \n float nDotH = dot(normal, g_h[0]);\
845 \n if (nDotL < 0.0 && in_twoSidedLighting)\
846 \n {\
847 \n nDotL = -nDotL;\
848 \n }\
849 \n if (nDotH < 0.0 && in_twoSidedLighting)\
850 \n {\
851 \n nDotH = -nDotH;\
852 \n }\
853 \n if (nDotL > 0.0)\
854 \n {\
855 \n diffuse = nDotL * in_diffuse[component] *\
856 \n in_lightDiffuseColor[0] * color.rgb;\
857 \n }\
858 \n specular = pow(nDotH, in_shininess[component]) *\
859 \n in_specular[component] *\
860 \n in_lightSpecularColor[0];\
861 \n // For the headlight, ignore the light's ambient color\
862 \n // for now as it is causing the old mapper tests to fail\
863 \n finalColor.xyz = in_ambient[component] * color.rgb +\
864 \n diffuse + specular;\
865 \n");
866 }
867 else if (lightingComplexity == 2)
868 {
869 shaderStr += std::string("\
870 \n g_fragWorldPos = in_modelViewMatrix * in_volumeMatrix[0] *\
871 \n in_textureDatasetMatrix[0] * vec4(-g_dataPos, 1.0);\
872 \n if (g_fragWorldPos.w != 0.0)\
873 \n {\
874 \n g_fragWorldPos /= g_fragWorldPos.w;\
875 \n }\
876 \n vec3 vdir = normalize(g_fragWorldPos.xyz);\
877 \n vec3 normal = gradient.xyz;\
878 \n vec3 ambient = vec3(0.0);\
879 \n vec3 diffuse = vec3(0.0);\
880 \n vec3 specular = vec3(0.0);\
881 \n float normalLength = length(normal);\
882 \n if (normalLength > 0.0)\
883 \n {\
884 \n normal = normalize((in_textureToEye[0] * vec4(normal, 0.0)).xyz);\
885 \n }\
886 \n else\
887 \n {\
888 \n normal = vec3(0.0, 0.0, 0.0);\
889 \n }\
890 \n for (int lightNum = 0; lightNum < in_numberOfLights; lightNum++)\
891 \n {\
892 \n vec3 ldir = in_lightDirection[lightNum].xyz;\
893 \n vec3 h = normalize(ldir + vdir);\
894 \n float nDotH = dot(normal, h);\
895 \n if (nDotH < 0.0 && in_twoSidedLighting)\
896 \n {\
897 \n nDotH = -nDotH;\
898 \n }\
899 \n float nDotL = dot(normal, ldir);\
900 \n if (nDotL < 0.0 && in_twoSidedLighting)\
901 \n {\
902 \n nDotL = -nDotL;\
903 \n }\
904 \n if (nDotL > 0.0)\
905 \n {\
906 \n diffuse += in_lightDiffuseColor[lightNum] * nDotL;\
907 \n }\
908 \n if (nDotH > 0.0)\
909 \n {\
910 \n specular = in_lightSpecularColor[lightNum] *\
911 \n pow(nDotH, in_shininess[component]);\
912 \n }\
913 \n ambient += in_lightAmbientColor[lightNum];\
914 \n }\
915 \n finalColor.xyz = in_ambient[component] * ambient +\
916 \n in_diffuse[component] * diffuse * color.rgb +\
917 \n in_specular[component] * specular;");
918 }
919 else if (lightingComplexity == 3)
920 {
921 shaderStr += std::string("\
922 \n g_fragWorldPos = in_modelViewMatrix * in_volumeMatrix[0] *\
923 \n in_textureDatasetMatrix[0] * vec4(g_dataPos, 1.0);\
924 \n if (g_fragWorldPos.w != 0.0)\
925 \n {\
926 \n g_fragWorldPos /= g_fragWorldPos.w;\
927 \n }\
928 \n vec3 viewDirection = normalize(-g_fragWorldPos.xyz);\
929 \n vec3 ambient = vec3(0,0,0);\
930 \n vec3 diffuse = vec3(0,0,0);\
931 \n vec3 specular = vec3(0,0,0);\
932 \n vec3 vertLightDirection;\
933 \n vec3 normal = normalize((in_textureToEye[0] * vec4(gradient.xyz, 0.0)).xyz);\
934 \n vec3 lightDir;\
935 \n for (int lightNum = 0; lightNum < in_numberOfLights; lightNum++)\
936 \n {\
937 \n float attenuation = 1.0;\
938 \n // directional\
939 \n lightDir = in_lightDirection[lightNum];\
940 \n if (in_lightPositional[lightNum] == 0)\
941 \n {\
942 \n vertLightDirection = lightDir;\
943 \n }\
944 \n else\
945 \n {\
946 \n vertLightDirection = (g_fragWorldPos.xyz - in_lightPosition[lightNum]);\
947 \n float distance = length(vertLightDirection);\
948 \n vertLightDirection = normalize(vertLightDirection);\
949 \n attenuation = 1.0 /\
950 \n (in_lightAttenuation[lightNum].x\
951 \n + in_lightAttenuation[lightNum].y * distance\
952 \n + in_lightAttenuation[lightNum].z * distance * distance);\
953 \n // per OpenGL standard cone angle is 90 or less for a spot light\
954 \n if (in_lightConeAngle[lightNum] <= 90.0)\
955 \n {\
956 \n float coneDot = dot(vertLightDirection, lightDir);\
957 \n // if inside the cone\
958 \n if (coneDot >= cos(radians(in_lightConeAngle[lightNum])))\
959 \n {\
960 \n attenuation = attenuation * pow(coneDot, in_lightExponent[lightNum]);\
961 \n }\
962 \n else\
963 \n {\
964 \n attenuation = 0.0;\
965 \n }\
966 \n }\
967 \n }\
968 \n // diffuse and specular lighting\
969 \n float nDotL = dot(normal, vertLightDirection);\
970 \n if (nDotL < 0.0 && in_twoSidedLighting)\
971 \n {\
972 \n nDotL = -nDotL;\
973 \n }\
974 \n if (nDotL > 0.0)\
975 \n {\
976 \n float df = max(0.0, attenuation * nDotL);\
977 \n diffuse += (df * in_lightDiffuseColor[lightNum]);\
978 \n }\
979 \n vec3 h = normalize(vertLightDirection + viewDirection);\
980 \n float nDotH = dot(normal, h);\
981 \n if (nDotH < 0.0 && in_twoSidedLighting)\
982 \n {\
983 \n nDotH = -nDotH;\
984 \n }\
985 \n if (nDotH > 0.0)\
986 \n {\
987 \n float sf = attenuation * pow(nDotH, in_shininess[component]);\
988 \n specular += (sf * in_lightSpecularColor[lightNum]);\
989 \n }\
990 \n ambient += in_lightAmbientColor[lightNum];\
991 \n }\
992 \n finalColor.xyz = in_ambient[component] * ambient +\
993 \n in_diffuse[component] * diffuse * color.rgb +\
994 \n in_specular[component] * specular;\
995 ");
996 }
997 }
998 else
999 {
1000 shaderStr += std::string("\n finalColor = vec4(color.rgb, 0.0);");
1001 }
1002
1003 auto glMapper = vtkOpenGLGPUVolumeRayCastMapper::SafeDownCast(mapper);
1004 // For 1D transfers only (2D transfer functions hold scalar and
1005 // gradient-magnitude opacities combined in the same table).
1006 // For multiple inputs, a different computeGradientOpacity() signature
1007 // is defined.
1008 if (transferMode == vtkVolumeProperty::TF_1D && glMapper->GetInputCount() == 1)
1009 {
1010 if (noOfComponents == 1 || !independentComponents)
1011 {
1012 if (volProperty->HasGradientOpacity())
1013 {
1014 shaderStr += std::string("\
1015 \n if (gradient.w >= 0.0 && label == 0.0)\
1016 \n {\
1017 \n color.a *= computeGradientOpacity(gradient);\
1018 \n }");
1019 }
1020 if (volProperty->HasLabelGradientOpacity())
1021 {
1022 shaderStr += std::string("\
1023 \n if (gradient.w >= 0.0 && label > 0.0)\
1024 \n {\
1025 \n color.a *= computeGradientOpacityForLabel(gradient, label);\
1026 \n }");
1027 }
1028 }
1029 else if (noOfComponents > 1 && independentComponents && volProperty->HasGradientOpacity())
1030 {
1031 shaderStr += std::string("\
1032 \n if (gradient.w >= 0.0)\
1033 \n {\
1034 \n for (int i = 0; i < in_noOfComponents; ++i)\
1035 \n {\
1036 \n color.a = color.a *\
1037 \n computeGradientOpacity(gradient, i) * in_componentWeight[i];\
1038 \n }\
1039 \n }");
1040 }
1041 }
1042
1043 shaderStr += std::string("\
1044 \n finalColor.a = color.a;\
1045 \n return finalColor;\
1046 \n }");
1047
1048 return shaderStr;
1049}
1050
1051//--------------------------------------------------------------------------
1053 vtkVolume* vol, int noOfComponents, int independentComponents, int vtkNotUsed(numberOfLights),
1054 int lightingComplexity)
1055{
1056 vtkVolumeProperty* volProperty = vol->GetProperty();
1057 std::string shaderStr = std::string("\
1058 \nvec4 computeLighting(vec3 texPos, vec4 color, const in sampler2D gradientTF, const in sampler3D volume, const int volIdx, int component)\
1059 \n {\
1060 \n vec4 finalColor = vec4(0.0);");
1061
1062 // Shading for composite blending only
1063 int const shadeReqd = volProperty->GetShade() &&
1066
1067 int const transferMode = volProperty->GetTransferFunctionMode();
1068
1069 if ((shadeReqd || volProperty->HasGradientOpacity()) && transferMode == vtkVolumeProperty::TF_1D)
1070 {
1071 shaderStr +=
1072 std::string(" // Compute gradient function only once\n"
1073 " vec4 gradient = computeGradient(texPos, component, volume, volIdx);\n");
1074 }
1075
1076 if (shadeReqd && lightingComplexity == 1)
1077 {
1078 shaderStr += std::string("\
1079 \n vec3 diffuse = vec3(0.0);\
1080 \n vec3 specular = vec3(0.0);\
1081 \n vec3 normal = gradient.xyz;\
1082 \n float normalLength = length(normal);\
1083 \n if (normalLength > 0.0)\
1084 \n {\
1085 \n normal = normalize(normal);\
1086 \n }\
1087 \n else\
1088 \n {\
1089 \n normal = vec3(0.0, 0.0, 0.0);\
1090 \n }\
1091 \n float nDotL = dot(normal, g_ldir[volIdx]);\
1092 \n float nDotH = dot(normal, g_h[volIdx]);\
1093 \n if (nDotL < 0.0 && in_twoSidedLighting)\
1094 \n {\
1095 \n nDotL = -nDotL;\
1096 \n }\
1097 \n if (nDotH < 0.0 && in_twoSidedLighting)\
1098 \n {\
1099 \n nDotH = -nDotH;\
1100 \n }\
1101 \n if (nDotL > 0.0)\
1102 \n {\
1103 \n diffuse = nDotL * in_diffuse[component] *\
1104 \n in_lightDiffuseColor[0] * color.rgb;\
1105 \n }\
1106 \n specular = pow(nDotH, in_shininess[component]) *\
1107 \n in_specular[component] *\
1108 \n in_lightSpecularColor[0];\
1109 \n // For the headlight, ignore the light's ambient color\
1110 \n // for now as it is causing the old mapper tests to fail\
1111 \n finalColor.xyz = in_ambient[component] * color.rgb +\
1112 \n diffuse + specular;\
1113 \n");
1114 }
1115 else
1116 {
1117 shaderStr += std::string("\n finalColor = vec4(color.rgb, 0.0);");
1118 }
1119
1120 // For 1D transfers only (2D transfer functions hold scalar and
1121 // gradient-magnitude opacities combined in the same table).
1122 if (transferMode == vtkVolumeProperty::TF_1D)
1123 {
1124 if (volProperty->HasGradientOpacity() && (noOfComponents == 1 || !independentComponents))
1125 {
1126 shaderStr += std::string("\
1127 \n if (gradient.w >= 0.0)\
1128 \n {\
1129 \n color.a = color.a *\
1130 \n computeGradientOpacity(gradient, gradientTF);\
1131 \n }");
1132 }
1133 }
1134
1135 shaderStr += std::string("\
1136 \n finalColor.a = color.a;\
1137 \n return clamp(finalColor, 0.0, 1.0);\
1138 \n }");
1139
1140 return shaderStr;
1141}
1142
1143//--------------------------------------------------------------------------
1144std::string ComputeRayDirectionDeclaration(vtkRenderer* ren, vtkVolumeMapper* vtkNotUsed(mapper),
1145 vtkVolume* vtkNotUsed(vol), int vtkNotUsed(noOfComponents))
1146{
1148 {
1149 return std::string("\
1150 \nvec3 computeRayDirection()\
1151 \n {\
1152 \n return normalize(ip_vertexPos.xyz - g_eyePosObj.xyz);\
1153 \n }");
1154 }
1155 else
1156 {
1157 return std::string("\
1158 \nuniform vec3 in_projectionDirection;\
1159 \nvec3 computeRayDirection()\
1160 \n {\
1161 \n return normalize((in_inverseVolumeMatrix[0] *\
1162 \n vec4(in_projectionDirection, 0.0)).xyz);\
1163 \n }");
1164 }
1165}
1166
1167//--------------------------------------------------------------------------
1168std::string ComputeColorDeclaration(vtkRenderer* vtkNotUsed(ren),
1169 vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
1170 int independentComponents, std::map<int, std::string> colorTableMap)
1171{
1172 std::ostringstream ss;
1173 ss << "uniform sampler2D " << ArrayBaseName(colorTableMap[0]) << "[" << noOfComponents << "];\n";
1174
1175 std::string shaderStr = ss.str();
1176 if (noOfComponents == 1)
1177 {
1178 shaderStr += std::string("\
1179 \nvec4 computeColor(vec4 scalar, float opacity)\
1180 \n {\
1181 \n return clamp(computeLighting(vec4(texture2D(" +
1182 colorTableMap[0] + ",\
1183 \n vec2(scalar.w, 0.0)).xyz, opacity), 0, 0.0), 0.0, 1.0);\
1184 \n }");
1185 return shaderStr;
1186 }
1187 else if (noOfComponents > 1 && independentComponents)
1188 {
1189 std::ostringstream toString;
1190
1191 shaderStr += std::string("\
1192 \nvec4 computeColor(vec4 scalar, float opacity, int component)\
1193 \n {");
1194
1195 for (int i = 0; i < noOfComponents; ++i)
1196 {
1197 toString << i;
1198 shaderStr += std::string("\
1199 \n if (component == " +
1200 toString.str() + ")");
1201
1202 shaderStr += std::string("\
1203 \n {\
1204 \n return clamp(computeLighting(vec4(texture2D(\
1205 \n " +
1206 colorTableMap[i]);
1207 shaderStr += std::string(", vec2(\
1208 \n scalar[" +
1209 toString.str() + "],0.0)).xyz,\
1210 \n opacity)," +
1211 toString.str() + ", 0.0), 0.0, 1.0);\
1212 \n }");
1213
1214 // Reset
1215 toString.str("");
1216 toString.clear();
1217 }
1218
1219 shaderStr += std::string("\n }");
1220 return shaderStr;
1221 }
1222 else if (noOfComponents == 2 && !independentComponents)
1223 {
1224 shaderStr += std::string("\
1225 \nvec4 computeColor(vec4 scalar, float opacity)\
1226 \n {\
1227 \n return clamp(computeLighting(vec4(texture2D(" +
1228 colorTableMap[0] + ",\
1229 \n vec2(scalar.x, 0.0)).xyz,\
1230 \n opacity), 0, 0.0), 0.0, 1.0);\
1231 \n }");
1232 return shaderStr;
1233 }
1234 else
1235 {
1236 shaderStr += std::string("\
1237 \nvec4 computeColor(vec4 scalar, float opacity)\
1238 \n {\
1239 \n return clamp(computeLighting(vec4(scalar.xyz, opacity), 0, 0.0), 0.0, 1.0);\
1240 \n }");
1241 return shaderStr;
1242 }
1243}
1244
1245//--------------------------------------------------------------------------
1247{
1248 std::ostringstream ss;
1249 int i = 0;
1250 int lastComponentMode = vtkVolumeInputHelper::INVALID;
1251 std::map<int, std::string> lastColorTableMap;
1252 for (auto& item : inputs)
1253 {
1254 auto prop = item.second.Volume->GetProperty();
1255 if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_1D)
1256 continue;
1257
1258 auto& map = item.second.RGBTablesMap;
1259 const auto numComp = map.size();
1260 ss << "uniform sampler2D " << ArrayBaseName(map[0]) << "[" << numComp << "];\n";
1261
1262 lastComponentMode = item.second.ComponentMode;
1263 lastColorTableMap = map;
1264 i++;
1265 }
1266
1267 if (lastComponentMode == vtkVolumeInputHelper::LA)
1268 {
1269 ss << "vec4 computeColor(vec4 scalar, const in sampler2D colorTF)\
1270 \n {\
1271 \n return clamp(computeLighting(vec4(texture2D(colorTF,\
1272 \n vec2(scalar.w, 0.0)).xyz, opacity), 0), 0.0, 1.0);\
1273 \n }\n";
1274 }
1275 else
1276 {
1277 ss << "vec4 computeColor(vec3 texPos, vec4 scalar, float opacity, const in sampler2D colorTF, "
1278 "const in sampler2D gradientTF, const in sampler3D volume, const int volIdx)\n"
1279 "{\n"
1280 " return clamp(computeLighting(texPos, vec4(texture2D(colorTF,\n"
1281 " vec2(scalar.w, 0.0)).xyz, opacity), gradientTF, volume, "
1282 "volIdx, 0), 0.0, 1.0);\n"
1283 "}\n";
1284 }
1285
1286 return ss.str();
1287}
1288
1289//--------------------------------------------------------------------------
1291{
1292 std::ostringstream ss;
1293 int i = 0;
1294 for (auto& item : inputs)
1295 {
1296 auto prop = item.second.Volume->GetProperty();
1297 if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_1D)
1298 continue;
1299
1300 auto& map = item.second.OpacityTablesMap;
1301 const auto numComp = map.size();
1302 ss << "uniform sampler2D " << ArrayBaseName(map[0]) << "[" << numComp << "];\n";
1303 i++;
1304 }
1305
1306 ss << "float computeOpacity(vec4 scalar, const in sampler2D opacityTF)\n"
1307 "{\n"
1308 " return texture2D(opacityTF, vec2(scalar.w, 0)).r;\n"
1309 "}\n";
1310 return ss.str();
1311}
1312
1313//--------------------------------------------------------------------------
1316{
1317 std::ostringstream ss;
1318
1319 int i = 0;
1320 for (auto& item : inputs)
1321 {
1322 auto prop = item.second.Volume->GetProperty();
1323 if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_1D || !prop->HasGradientOpacity())
1324 continue;
1325
1326 auto& map = item.second.GradientOpacityTablesMap;
1327 const auto numComp = map.size();
1328 ss << "uniform sampler2D " << ArrayBaseName(map[0]) << "[" << numComp << "];\n";
1329 i++;
1330 }
1331
1332 ss << "float computeGradientOpacity(vec4 grad, const in sampler2D gradientTF)\n"
1333 "{\n"
1334 " return texture2D(gradientTF, vec2(grad.w, 0.0)).r;\n"
1335 "}\n";
1336 return ss.str();
1337}
1338
1339//--------------------------------------------------------------------------
1340std::string ComputeOpacityDeclaration(vtkRenderer* vtkNotUsed(ren),
1341 vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
1342 int independentComponents, std::map<int, std::string> opacityTableMap)
1343{
1344 std::ostringstream ss;
1345 ss << "uniform sampler2D " << ArrayBaseName(opacityTableMap[0]) << "[" << noOfComponents
1346 << "];\n";
1347
1348 std::string shaderStr = ss.str();
1349 if (noOfComponents > 1 && independentComponents)
1350 {
1351 shaderStr += std::string("\
1352 \nfloat computeOpacity(vec4 scalar, int component)\
1353 \n{");
1354
1355 for (int i = 0; i < noOfComponents; ++i)
1356 {
1357 std::ostringstream toString;
1358 toString << i;
1359 shaderStr += std::string("\
1360 \n if (component == " +
1361 toString.str() + ")");
1362
1363 shaderStr += std::string("\
1364 \n {\
1365 \n return texture2D(" +
1366 opacityTableMap[i]);
1367
1368 shaderStr += std::string(",vec2(scalar[" + toString.str() + "], 0)).r;\
1369 \n }");
1370 }
1371
1372 shaderStr += std::string("\n}");
1373 return shaderStr;
1374 }
1375 else if (noOfComponents == 2 && !independentComponents)
1376 {
1377 shaderStr += std::string("\
1378 \nfloat computeOpacity(vec4 scalar)\
1379 \n{\
1380 \n return texture2D(" +
1381 opacityTableMap[0] + ", vec2(scalar.y, 0)).r;\
1382 \n}");
1383 return shaderStr;
1384 }
1385 else
1386 {
1387 shaderStr += std::string("\
1388 \nfloat computeOpacity(vec4 scalar)\
1389 \n{\
1390 \n return texture2D(" +
1391 opacityTableMap[0] + ", vec2(scalar.w, 0)).r;\
1392 \n}");
1393 return shaderStr;
1394 }
1395}
1396
1397//--------------------------------------------------------------------------
1398std::string ComputeColor2DYAxisDeclaration(int noOfComponents,
1399 int vtkNotUsed(independentComponents), std::map<int, std::string> colorTableMap)
1400{
1401 if (noOfComponents == 1)
1402 {
1403 // Single component
1404 return std::string(
1405 "vec4 computeColor(vec4 scalar, float opacity)\n"
1406 "{\n"
1407 " vec4 yscalar = texture3D(in_transfer2DYAxis, g_dataPos);\n"
1408 " yscalar.r = yscalar.r * in_transfer2DYAxis_scale.r + in_transfer2DYAxis_bias.r;\n"
1409 " yscalar = vec4(yscalar.r);\n"
1410 " vec4 color = texture2D(" +
1411 colorTableMap[0] +
1412 ",\n"
1413 " vec2(scalar.w, yscalar.w));\n"
1414 " return computeLighting(color, 0, 0);\n"
1415 "}\n");
1416 }
1417 return std::string("vec4 computeColor(vec4 scalar, float opacity)\n"
1418 "{\n"
1419 " return vec4(0, 0, 0, 0)\n"
1420 "}\n");
1421}
1422
1423//--------------------------------------------------------------------------
1424std::string ComputeColor2DDeclaration(vtkRenderer* vtkNotUsed(ren),
1425 vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
1426 int independentComponents, std::map<int, std::string> colorTableMap, int useGradient)
1427{
1428 if (!useGradient)
1429 {
1430 return ComputeColor2DYAxisDeclaration(noOfComponents, independentComponents, colorTableMap);
1431 }
1432 if (noOfComponents == 1)
1433 {
1434 // Single component
1435 return std::string("vec4 computeColor(vec4 scalar, float opacity)\n"
1436 "{\n"
1437 " vec4 color = texture2D(" +
1438 colorTableMap[0] +
1439 ",\n"
1440 " vec2(scalar.w, g_gradients_0[0].w));\n"
1441 " return computeLighting(color, 0, 0);\n"
1442 "}\n");
1443 }
1444 else if (noOfComponents > 1 && independentComponents)
1445 {
1446 // Multiple independent components
1447 std::string shaderStr;
1448 shaderStr += std::string("vec4 computeColor(vec4 scalar, float opacity, int component)\n"
1449 "{\n");
1450
1451 for (int i = 0; i < noOfComponents; ++i)
1452 {
1453 std::ostringstream toString;
1454 toString << i;
1455 std::string const num = toString.str();
1456 shaderStr += std::string(" if (component == " + num +
1457 ")\n"
1458 " {\n"
1459 " vec4 color = texture2D(" +
1460 colorTableMap[i] +
1461 ",\n"
1462 " vec2(scalar[" +
1463 num + "], g_gradients_0[" + num +
1464 "].w));\n"
1465 " return computeLighting(color, " +
1466 num +
1467 ", 0.0);\n"
1468 " }\n");
1469 }
1470 shaderStr += std::string("}\n");
1471
1472 return shaderStr;
1473 }
1474 else if (noOfComponents == 2 && !independentComponents)
1475 {
1476 // Dependent components (Luminance/ Opacity)
1477 return std::string("vec4 computeColor(vec4 scalar, float opacity)\n"
1478 "{\n"
1479 " vec4 color = texture2D(" +
1480 colorTableMap[0] +
1481 ",\n"
1482 " vec2(scalar.x, g_gradients_0[0].w));\n"
1483 " return computeLighting(color, 0, 0.0);\n"
1484 "}\n");
1485 }
1486 else
1487 {
1488 return std::string("vec4 computeColor(vec4 scalar, float opacity)\n"
1489 "{\n"
1490 " return computeLighting(vec4(scalar.xyz, opacity), 0, 0.0);\n"
1491 "}\n");
1492 }
1493}
1494
1495//--------------------------------------------------------------------------
1497{
1498 std::ostringstream ss;
1499 int i = 0;
1500 for (auto& item : inputs)
1501 {
1502 auto prop = item.second.Volume->GetProperty();
1503 if (prop->GetTransferFunctionMode() != vtkVolumeProperty::TF_2D)
1504 continue;
1505
1506 auto& map = item.second.TransferFunctions2DMap;
1507 const auto numComp = map.size();
1508 ss << "uniform sampler2D " << ArrayBaseName(map[0]) << "[" << numComp << "];\n";
1509 i++;
1510 }
1511
1512 std::string result = ss.str() +
1513 std::string("uniform sampler3D in_transfer2DYAxis;\n"
1514 "uniform vec4 in_transfer2DYAxis_scale;\n"
1515 "uniform vec4 in_transfer2DYAxis_bias;\n");
1516
1517 return result;
1518}
1519
1520//--------------------------------------------------------------------------
1521std::string ComputeOpacity2DDeclaration(vtkRenderer* vtkNotUsed(ren),
1522 vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int noOfComponents,
1523 int independentComponents, std::map<int, std::string> opacityTableMap, int useGradient)
1524{
1525 std::ostringstream toString;
1526 if (noOfComponents > 1 && independentComponents)
1527 {
1528 // Multiple independent components
1529 toString << "float computeOpacity(vec4 scalar, int component)\n"
1530 "{\n";
1531 if (!useGradient)
1532 {
1533 toString
1534 << "vec4 yscalar = texture3D(in_transfer2DYAxis, g_dataPos);\n"
1535 "for (int i = 0; i < 4; ++i)\n"
1536 "{\n"
1537 " yscalar[i] = yscalar[i] * in_transfer2DYAxis_scale[i] + in_transfer2DYAxis_bias[i];\n"
1538 "}\n";
1539 if (noOfComponents == 1)
1540 {
1541 toString << "yscalar = vec4(yscalar.r);\n";
1542 }
1543 }
1544
1545 for (int i = 0; i < noOfComponents; ++i)
1546 {
1547 if (useGradient)
1548 {
1549 toString << " if (component == " << i
1550 << ")\n"
1551 " {\n"
1552 " return texture2D("
1553 << opacityTableMap[i]
1554 << ",\n"
1555 " vec2(scalar["
1556 << i << "], g_gradients_0[" << i
1557 << "].w)).a;\n"
1558 " }\n";
1559 }
1560 else
1561 {
1562 toString << " if (component == " << i
1563 << ")\n"
1564 " {\n"
1565 " return texture2D("
1566 << opacityTableMap[i]
1567 << ",\n"
1568 " vec2(scalar["
1569 << i << "], yscalar[" << i
1570 << "])).a;\n"
1571 " }\n";
1572 }
1573 }
1574
1575 toString << "}\n";
1576 }
1577
1578 else if (noOfComponents == 2 && !independentComponents)
1579 {
1580 if (useGradient)
1581 {
1582 // Dependent components (Luminance/ Opacity)
1583 toString << "float computeOpacity(vec4 scalar)\n"
1584 "{\n"
1585 " return texture2D(" +
1586 opacityTableMap[0] +
1587 ",\n"
1588 " vec2(scalar.y, g_gradients_0[0].w)).a;\n"
1589 "}\n";
1590 }
1591 else
1592 {
1593 // Dependent components (Luminance/ Opacity)
1594 toString << "float computeOpacity(vec4 scalar)\n"
1595 "{\n"
1596 " return texture2D(" +
1597 opacityTableMap[0] +
1598 ",\n"
1599 " vec2(scalar.y, yscalar.y)).a;\n"
1600 "}\n";
1601 }
1602 }
1603
1604 else
1605 {
1606 if (useGradient)
1607 {
1608 // Dependent compoennts (RGBA) || Single component
1609 toString << "float computeOpacity(vec4 scalar)\n"
1610 "{\n"
1611 " return texture2D(" +
1612 opacityTableMap[0] +
1613 ",\n"
1614 " vec2(scalar.a, g_gradients_0[0].w)).a;\n"
1615 "}\n";
1616 }
1617 else
1618 {
1619 // Dependent compoennts (RGBA) || Single component
1620 toString
1621 << "float computeOpacity(vec4 scalar)\n"
1622 "{\n"
1623 " vec4 yscalar = texture3D(in_transfer2DYAxis, g_dataPos);\n"
1624 " yscalar.r = yscalar.r * in_transfer2DYAxis_scale.r + in_transfer2DYAxis_bias.r;\n"
1625 " yscalar = vec4(yscalar.r);\n"
1626 " return texture2D(" +
1627 opacityTableMap[0] +
1628 ",\n"
1629 " vec2(scalar.a, yscalar.w)).a;\n"
1630 "}\n";
1631 }
1632 }
1633 return toString.str();
1634}
1635
1636//--------------------------------------------------------------------------
1638 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
1639{
1640 return std::string();
1641}
1642
1643//--------------------------------------------------------------------------
1645 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
1646{
1648 {
1649 return std::string("\
1650 \n bool l_firstValue;\
1651 \n vec4 l_maxValue;");
1652 }
1654 {
1655 return std::string("\
1656 \n bool l_firstValue;\
1657 \n vec4 l_minValue;");
1658 }
1660 {
1661 return std::string("\
1662 \n uvec4 l_numSamples;\
1663 \n vec4 l_avgValue;");
1664 }
1665 else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
1666 {
1667 return std::string("\
1668 \n vec4 l_sumValue;");
1669 }
1670 else if (mapper->GetBlendMode() == vtkVolumeMapper::ISOSURFACE_BLEND)
1671 {
1672 return std::string("\
1673 \n int l_initialIndex = 0;\
1674 \n float l_normValues[NUMBER_OF_CONTOURS + 2];");
1675 }
1676 else
1677 {
1678 return std::string();
1679 }
1680}
1681
1682//--------------------------------------------------------------------------
1683std::string ShadingInit(
1684 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
1685{
1687 {
1688 return std::string("\
1689 \n // We get data between 0.0 - 1.0 range\
1690 \n l_firstValue = true;\
1691 \n l_maxValue = vec4(0.0);");
1692 }
1694 {
1695 return std::string("\
1696 \n //We get data between 0.0 - 1.0 range\
1697 \n l_firstValue = true;\
1698 \n l_minValue = vec4(1.0);");
1699 }
1701 {
1702 return std::string("\
1703 \n //We get data between 0.0 - 1.0 range\
1704 \n l_avgValue = vec4(0.0);\
1705 \n // Keep track of number of samples\
1706 \n l_numSamples = uvec4(0);");
1707 }
1708 else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
1709 {
1710 return std::string("\
1711 \n //We get data between 0.0 - 1.0 range\
1712 \n l_sumValue = vec4(0.0);");
1713 }
1714 else if (mapper->GetBlendMode() == vtkVolumeMapper::ISOSURFACE_BLEND)
1715 {
1716 return std::string("\
1717 \n#if NUMBER_OF_CONTOURS\
1718 \n l_normValues[0] = -1e20; //-infinity\
1719 \n l_normValues[NUMBER_OF_CONTOURS+1] = +1e20; //+infinity\
1720 \n for (int i = 0; i < NUMBER_OF_CONTOURS; i++)\
1721 \n {\
1722 \n l_normValues[i+1] = (in_isosurfacesValues[i] - in_scalarsRange[0].x) / \
1723 \n (in_scalarsRange[0].y - in_scalarsRange[0].x);\
1724 \n }\
1725 \n#endif\
1726 ");
1727 }
1728 else
1729 {
1730 return std::string();
1731 }
1732}
1733
1734//--------------------------------------------------------------------------
1735std::string GradientCacheDec(vtkRenderer* vtkNotUsed(ren), vtkVolume* vtkNotUsed(vol),
1736 vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, int independentComponents = 0)
1737{
1738 const int numInputs = static_cast<int>(inputs.size());
1739 const int comp = numInputs == 1 ?
1740 // Dependent components use a single opacity lut.
1741 (!independentComponents ? 1 : numInputs)
1742 :
1743 // Independent components not supported with multiple-inputs
1744 1;
1745
1746 std::ostringstream toShader;
1747 for (const auto& item : inputs)
1748 {
1749 auto& input = item.second;
1750 if (input.Volume->GetProperty()->HasGradientOpacity())
1751 {
1752 toShader << "vec4 " << input.GradientCacheName << "[" << comp << "];\n";
1753 }
1754 }
1755
1756 return toShader.str();
1757}
1758
1759//--------------------------------------------------------------------------
1760std::string PreComputeGradientsImpl(vtkRenderer* vtkNotUsed(ren), vtkVolume* vtkNotUsed(vol),
1761 int noOfComponents = 1, int independentComponents = 0)
1762{
1763 std::ostringstream shader;
1764 if (independentComponents)
1765 {
1766 if (noOfComponents == 1)
1767 {
1768 shader << "g_gradients_0[0] = computeGradient(g_dataPos, 0, in_volume[0], 0);\n";
1769 }
1770 else
1771 {
1772 // Multiple components
1773 shader << "for (int comp = 0; comp < in_noOfComponents; comp++)\n"
1774 "{\n"
1775 " g_gradients_0[comp] = computeGradient(g_dataPos, comp, in_volume[0], 0);\n"
1776 "}\n";
1777 }
1778 }
1779 else
1780 {
1781 shader << "g_gradients_0[0] = computeGradient(g_dataPos, 0, in_volume[0], 0);\n";
1782 }
1783
1784 return shader.str();
1785}
1786
1787//--------------------------------------------------------------------------
1790{
1791 std::ostringstream toShaderStr;
1792 toShaderStr << " if (!g_skip)\n"
1793 " {\n"
1794 " vec3 texPos;\n";
1795
1796 switch (mapper->GetBlendMode())
1797 {
1799 default:
1800 {
1801 int i = 0;
1802 for (auto& item : inputs)
1803 {
1804 auto& input = item.second;
1805 auto property = input.Volume->GetProperty();
1806 // Transformation index. Index 0 refers to the global bounding-box.
1807 const auto idx = i + 1;
1808 toShaderStr <<
1809 // From global texture coordinates (bbox) to volume_i texture coords.
1810 // texPos = T * g_dataPos
1811 // T = T_dataToTex1 * T_worldToData * T_bboxTexToWorld;
1812 " texPos = (in_cellToPoint[" << idx << "] * in_inverseTextureDatasetMatrix[" << idx
1813 << "] * in_inverseVolumeMatrix[" << idx
1814 << "] *\n"
1815 " in_volumeMatrix[0] * in_textureDatasetMatrix[0] * "
1816 "vec4(g_dataPos.xyz, 1.0)).xyz;\n"
1817 " if ((all(lessThanEqual(texPos, vec3(1.0))) &&\n"
1818 " all(greaterThanEqual(texPos, vec3(0.0)))))\n"
1819 " {\n"
1820 " vec4 scalar = texture3D(in_volume["
1821 << i
1822 << "], texPos);\n"
1823 " scalar = scalar * in_volume_scale["
1824 << i << "] + in_volume_bias[" << i
1825 << "];\n"
1826 " scalar = vec4(scalar.r);\n"
1827 " g_srcColor = vec4(0.0);\n";
1828
1829 if (property->GetTransferFunctionMode() == vtkVolumeProperty::TF_1D)
1830 {
1831 toShaderStr << " g_srcColor.a = computeOpacity(scalar,"
1832 << input.OpacityTablesMap[0]
1833 << ");\n"
1834 " if (g_srcColor.a > 0.0)\n"
1835 " {\n"
1836 " g_srcColor = computeColor(texPos, scalar, g_srcColor.a, "
1837 << input.RGBTablesMap[0] << ", " << input.GradientOpacityTablesMap[0] << ", "
1838 << "in_volume[" << i << "], " << i << ");\n";
1839
1840 if (property->HasGradientOpacity())
1841 {
1842 const auto& grad = input.GradientCacheName;
1843 toShaderStr << " " << grad << "[0] = computeGradient(texPos, 0, "
1844 << "in_volume[" << i << "], " << i
1845 << ");\n"
1846 " if ("
1847 << grad
1848 << "[0].w >= 0.0)\n"
1849 " {\n"
1850 " g_srcColor.a *= computeGradientOpacity("
1851 << grad << "[0], " << input.GradientOpacityTablesMap[0]
1852 << ");\n"
1853 " }\n";
1854 }
1855 }
1856 else if (property->GetTransferFunctionMode() == vtkVolumeProperty::TF_2D)
1857 {
1858 const auto& grad = input.GradientCacheName;
1859 toShaderStr <<
1860 // Sample 2DTF directly
1861 " " << grad << "[0] = computeGradient(texPos, 0, "
1862 << "in_volume[" << i << "], " << i
1863 << ");\n"
1864 " g_srcColor = texture2D("
1865 << input.TransferFunctions2DMap[0] << ", vec2(scalar.r, "
1866 << input.GradientCacheName
1867 << "[0].w));\n"
1868 " if (g_srcColor.a > 0.0)\n"
1869 " {\n";
1870 }
1871
1872 toShaderStr
1873 << " g_srcColor.rgb *= g_srcColor.a;\n"
1874 " g_fragColor = (1.0f - g_fragColor.a) * g_srcColor + g_fragColor;\n"
1875 " }\n"
1876 " }\n\n";
1877
1878 i++;
1879 }
1880 }
1881 break;
1882 }
1883 toShaderStr << " }\n";
1884
1885 return toShaderStr.str();
1886}
1887
1888//--------------------------------------------------------------------------
1889std::string ShadingSingleInput(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper,
1890 vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput, vtkVolumeTexture* mask, int maskType,
1891 int noOfComponents, int independentComponents = 0)
1892{
1893 auto glMapper = vtkOpenGLGPUVolumeRayCastMapper::SafeDownCast(mapper);
1894
1895 std::string shaderStr;
1896
1897 shaderStr += std::string("\
1898 \n if (!g_skip)\
1899 \n {\
1900 \n vec4 scalar;\
1901 \n");
1903 {
1904 shaderStr += std::string("\
1905 \n // Compute IJK vertex position for current sample in the rectilinear grid\
1906 \n vec4 dataPosWorld = in_volumeMatrix[0] * in_textureDatasetMatrix[0] * vec4(g_dataPos, 1.0);\
1907 \n dataPosWorld = dataPosWorld / dataPosWorld.w;\
1908 \n dataPosWorld.w = 1.0;\
1909 \n ivec3 ijk = ivec3(0);\
1910 \n vec3 ijkTexCoord = vec3(0.0);\
1911 \n vec3 pCoords = vec3(0.0);\
1912 \n vec3 xPrev, xNext, tmp;\
1913 \n int sz = textureSize(in_coordTexs, 0);\
1914 \n vec4 dataPosWorldScaled = dataPosWorld * vec4(in_coordsScale, 1.0) +\
1915 \n vec4(in_coordsBias, 1.0);\
1916 \n for (int j = 0; j < 3; ++j)\
1917 \n {\
1918 \n xPrev = texture1D(in_coordTexs, 0.0).xyz;\
1919 \n xNext = texture1D(in_coordTexs, (in_coordTexSizes[j] - 1) / sz).xyz;\
1920 \n if (xNext[j] < xPrev[j])\
1921 \n {\
1922 \n tmp = xNext;\
1923 \n xNext = xPrev;\
1924 \n xPrev = tmp;\
1925 \n }\
1926 \n for (int i = 0; i < int(in_coordTexSizes[j]); i++)\
1927 \n {\
1928 \n xNext = texture1D(in_coordTexs, (i + 0.5) / sz).xyz;\
1929 \n if (dataPosWorldScaled[j] >= xPrev[j] && dataPosWorldScaled[j] < xNext[j])\
1930 \n {\
1931 \n ijk[j] = i - 1;\
1932 \n pCoords[j] = (dataPosWorldScaled[j] - xPrev[j]) / (xNext[j] - xPrev[j]);\
1933 \n break;\
1934 \n }\
1935 \n else if (dataPosWorldScaled[j] == xNext[j])\
1936 \n {\
1937 \n ijk[j] = i - 1;\
1938 \n pCoords[j] = 1.0;\
1939 \n break;\
1940 \n }\
1941 \n xPrev = xNext;\
1942 \n }\
1943 \n ijkTexCoord[j] = (ijk[j] + pCoords[j]) / in_coordTexSizes[j];\
1944 \n }\
1945 \n scalar = texture3D(in_volume[0], sign(in_cellSpacing[0]) * ijkTexCoord);\
1946 \n");
1947 }
1948 else
1949 {
1950 shaderStr += std::string("\
1951 \n scalar = texture3D(in_volume[0], g_dataPos);\
1952 \n");
1953 }
1954
1955 // simulate old intensity textures
1956 if (noOfComponents == 1)
1957 {
1958 shaderStr += std::string("\
1959 \n scalar.r = scalar.r * in_volume_scale[0].r + in_volume_bias[0].r;\
1960 \n scalar = vec4(scalar.r);");
1961 }
1962 else
1963 {
1964 // handle bias and scale
1965 shaderStr += std::string("\
1966 \n scalar = scalar * in_volume_scale[0] + in_volume_bias[0];");
1967 }
1968
1970 {
1971 if (noOfComponents > 1)
1972 {
1973 if (!independentComponents)
1974 {
1975 shaderStr += std::string("\
1976 \n if (l_maxValue.w < scalar.w || l_firstValue)\
1977 \n {\
1978 \n l_maxValue = scalar;\
1979 \n }\
1980 \n\
1981 \n if (l_firstValue)\
1982 \n {\
1983 \n l_firstValue = false;\
1984 \n }");
1985 }
1986 else
1987 {
1988 shaderStr += std::string("\
1989 \n for (int i = 0; i < in_noOfComponents; ++i)\
1990 \n {\
1991 \n if (l_maxValue[i] < scalar[i] || l_firstValue)\
1992 \n {\
1993 \n l_maxValue[i] = scalar[i];\
1994 \n }\
1995 \n }\
1996 \n if (l_firstValue)\
1997 \n {\
1998 \n l_firstValue = false;\
1999 \n }");
2000 }
2001 }
2002 else
2003 {
2004 shaderStr += std::string("\
2005 \n if (l_maxValue.w < scalar.x || l_firstValue)\
2006 \n {\
2007 \n l_maxValue.w = scalar.x;\
2008 \n }\
2009 \n\
2010 \n if (l_firstValue)\
2011 \n {\
2012 \n l_firstValue = false;\
2013 \n }");
2014 }
2015 }
2017 {
2018 if (noOfComponents > 1)
2019 {
2020 if (!independentComponents)
2021 {
2022 shaderStr += std::string("\
2023 \n if (l_minValue.w > scalar.w || l_firstValue)\
2024 \n {\
2025 \n l_minValue = scalar;\
2026 \n }\
2027 \n\
2028 \n if (l_firstValue)\
2029 \n {\
2030 \n l_firstValue = false;\
2031 \n }");
2032 }
2033 else
2034 {
2035 shaderStr += std::string("\
2036 \n for (int i = 0; i < in_noOfComponents; ++i)\
2037 \n {\
2038 \n if (l_minValue[i] < scalar[i] || l_firstValue)\
2039 \n {\
2040 \n l_minValue[i] = scalar[i];\
2041 \n }\
2042 \n }\
2043 \n if (l_firstValue)\
2044 \n {\
2045 \n l_firstValue = false;\
2046 \n }");
2047 }
2048 }
2049 else
2050 {
2051 shaderStr += std::string("\
2052 \n if (l_minValue.w > scalar.x || l_firstValue)\
2053 \n {\
2054 \n l_minValue.w = scalar.x;\
2055 \n }\
2056 \n\
2057 \n if (l_firstValue)\
2058 \n {\
2059 \n l_firstValue = false;\
2060 \n }");
2061 }
2062 }
2064 {
2065 if (noOfComponents > 1 && independentComponents)
2066 {
2067 shaderStr += std::string("\
2068 \n for (int i = 0; i < in_noOfComponents; ++i)\
2069 \n {\
2070 \n // Get the intensity in volume scalar range\
2071 \n float intensity = in_scalarsRange[i][0] +\
2072 \n (in_scalarsRange[i][1] -\
2073 \n in_scalarsRange[i][0]) * scalar[i];\
2074 \n if (in_averageIPRange.x <= intensity &&\
2075 \n intensity <= in_averageIPRange.y)\
2076 \n {\
2077 \n l_avgValue[i] += computeOpacity(scalar, i) * scalar[i];\
2078 \n ++l_numSamples[i];\
2079 \n }\
2080 \n }");
2081 }
2082 else
2083 {
2084 shaderStr += std::string("\
2085 \n // Get the intensity in volume scalar range\
2086 \n float intensity = in_scalarsRange[0][0] +\
2087 \n (in_scalarsRange[0][1] -\
2088 \n in_scalarsRange[0][0]) * scalar.x;\
2089 \n if (in_averageIPRange.x <= intensity &&\
2090 \n intensity <= in_averageIPRange.y)\
2091 \n {\
2092 \n l_avgValue.x += computeOpacity(scalar) * scalar.x;\
2093 \n ++l_numSamples.x;\
2094 \n }");
2095 }
2096 }
2097 else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
2098 {
2099 if (noOfComponents > 1 && independentComponents)
2100 {
2101 shaderStr += std::string("\
2102 \n for (int i = 0; i < in_noOfComponents; ++i)\
2103 \n {\
2104 \n float opacity = computeOpacity(scalar, i);\
2105 \n l_sumValue[i] = l_sumValue[i] + opacity * scalar[i];\
2106 \n }");
2107 }
2108 else
2109 {
2110 shaderStr += std::string("\
2111 \n float opacity = computeOpacity(scalar);\
2112 \n l_sumValue.x = l_sumValue.x + opacity * scalar.x;");
2113 }
2114 }
2115 else if (mapper->GetBlendMode() == vtkVolumeMapper::ISOSURFACE_BLEND)
2116 {
2117 shaderStr += std::string("\
2118 \n#if NUMBER_OF_CONTOURS\
2119 \n int maxComp = 0;");
2120
2121 std::string compParamStr = "";
2122 if (noOfComponents > 1 && independentComponents)
2123 {
2124 shaderStr += std::string("\
2125 \n for (int i = 1; i < in_noOfComponents; ++i)\
2126 \n {\
2127 \n if (in_componentWeight[i] > in_componentWeight[maxComp])\
2128 \n maxComp = i;\
2129 \n }");
2130 compParamStr = ", maxComp";
2131 }
2132 shaderStr += std::string("\
2133 \n if (g_currentT == 0)\
2134 \n {\
2135 \n l_initialIndex = findIsoSurfaceIndex(scalar[maxComp], l_normValues);\
2136 \n }\
2137 \n else\
2138 \n {\
2139 \n float s;\
2140 \n bool shade = false;\
2141 \n l_initialIndex = clamp(l_initialIndex, 0, NUMBER_OF_CONTOURS);\
2142 \n if (scalar[maxComp] < l_normValues[l_initialIndex])\
2143 \n {\
2144 \n s = l_normValues[l_initialIndex];\
2145 \n l_initialIndex--;\
2146 \n shade = true;\
2147 \n }\
2148 \n if (scalar[maxComp] > l_normValues[l_initialIndex+1])\
2149 \n {\
2150 \n s = l_normValues[l_initialIndex+1];\
2151 \n l_initialIndex++;\
2152 \n shade = true;\
2153 \n }\
2154 \n if (shade == true)\
2155 \n {\
2156 \n vec4 vs = vec4(s);\
2157 \n g_srcColor.a = computeOpacity(vs " +
2158 compParamStr + ");\
2159 \n g_srcColor = computeColor(vs, g_srcColor.a " +
2160 compParamStr + ");\
2161 \n g_srcColor.rgb *= g_srcColor.a;\
2162 \n g_fragColor = (1.0f - g_fragColor.a) * g_srcColor + g_fragColor;\
2163 \n }\
2164 \n }\
2165 \n#endif");
2166 }
2167 else if (mapper->GetBlendMode() == vtkVolumeMapper::SLICE_BLEND)
2168 {
2169 shaderStr += std::string("\
2170 \n // test if the intersection is inside the volume bounds\
2171 \n if (any(greaterThan(g_dataPos, vec3(1.0))) || any(lessThan(g_dataPos, vec3(0.0))))\
2172 \n {\
2173 \n discard;\
2174 \n }\
2175 \n float opacity = computeOpacity(scalar);\
2176 \n g_fragColor = computeColor(scalar, opacity);\
2177 \n g_fragColor.rgb *= opacity;\
2178 \n g_exit = true;");
2179 }
2180 else if (mapper->GetBlendMode() == vtkVolumeMapper::COMPOSITE_BLEND)
2181 {
2182 if (noOfComponents > 1 && independentComponents)
2183 {
2184 shaderStr += std::string("\
2185 \n vec4 color[4]; vec4 tmp = vec4(0.0);\
2186 \n float totalAlpha = 0.0;\
2187 \n for (int i = 0; i < in_noOfComponents; ++i)\
2188 \n {\
2189 ");
2190 if (glMapper->GetUseDepthPass() &&
2191 glMapper->GetCurrentPass() == vtkOpenGLGPUVolumeRayCastMapper::DepthPass)
2192 {
2193 shaderStr += std::string("\
2194 \n // Data fetching from the red channel of volume texture\
2195 \n float opacity = computeOpacity(scalar, i);\
2196 \n if (opacity > 0.0)\
2197 \n {\
2198 \n g_srcColor.a = opacity;\
2199 \n }\
2200 \n }");
2201 }
2202 else if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2203 {
2204 shaderStr += std::string("\
2205 \n // Data fetching from the red channel of volume texture\
2206 \n color[i][3] = computeOpacity(scalar, i);\
2207 \n color[i] = computeColor(scalar, color[i][3], i);\
2208 \n totalAlpha += color[i][3] * in_componentWeight[i];\
2209 \n }\
2210 \n if (totalAlpha > 0.0)\
2211 \n {\
2212 \n for (int i = 0; i < in_noOfComponents; ++i)\
2213 \n {\
2214 \n // Only let visible components contribute to the final color\
2215 \n if (in_componentWeight[i] <= 0) continue;\
2216 \n\
2217 \n tmp.x += color[i].x * color[i].w * in_componentWeight[i];\
2218 \n tmp.y += color[i].y * color[i].w * in_componentWeight[i];\
2219 \n tmp.z += color[i].z * color[i].w * in_componentWeight[i];\
2220 \n tmp.w += ((color[i].w * color[i].w)/totalAlpha);\
2221 \n }\
2222 \n }\
2223 \n g_fragColor = (1.0f - g_fragColor.a) * tmp + g_fragColor;");
2224 }
2225 }
2226 else if (glMapper->GetUseDepthPass() &&
2227 glMapper->GetCurrentPass() == vtkOpenGLGPUVolumeRayCastMapper::DepthPass)
2228 {
2229 shaderStr += std::string("\
2230 \n g_srcColor = vec4(0.0);\
2231 \n g_srcColor.a = computeOpacity(scalar);");
2232 }
2233 else
2234 {
2235 if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2236 {
2237 shaderStr += std::string("\
2238 \n g_srcColor = vec4(0.0);\
2239 \n g_srcColor.a = computeOpacity(scalar);\
2240 \n if (g_srcColor.a > 0.0)\
2241 \n {\
2242 \n g_srcColor = computeColor(scalar, g_srcColor.a);");
2243 }
2244
2245 shaderStr += std::string("\
2246 \n // Opacity calculation using compositing:\
2247 \n // Here we use front to back compositing scheme whereby\
2248 \n // the current sample value is multiplied to the\
2249 \n // currently accumulated alpha and then this product\
2250 \n // is subtracted from the sample value to get the\
2251 \n // alpha from the previous steps. Next, this alpha is\
2252 \n // multiplied with the current sample colour\
2253 \n // and accumulated to the composited colour. The alpha\
2254 \n // value from the previous steps is then accumulated\
2255 \n // to the composited colour alpha.\
2256 \n g_srcColor.rgb *= g_srcColor.a;\
2257 \n g_fragColor = (1.0f - g_fragColor.a) * g_srcColor + g_fragColor;");
2258
2259 if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2260 {
2261 shaderStr += std::string("\
2262 \n }");
2263 }
2264 }
2265 }
2266 else
2267 {
2268 shaderStr += std::string();
2269 }
2270
2271 shaderStr += std::string("\
2272 \n }");
2273 return shaderStr;
2274}
2275
2276//--------------------------------------------------------------------------
2278 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2279{
2280 return std::string("\
2281 \n // Special coloring mode which renders the Prop Id in fragments that\
2282 \n // have accumulated certain level of opacity. Used during the selection\
2283 \n // pass vtkHardwareSelection::ACTOR_PASS.\
2284 \n if (g_fragColor.a > 3.0/ 255.0)\
2285 \n {\
2286 \n gl_FragData[0] = vec4(in_propId, 1.0);\
2287 \n }\
2288 \n else\
2289 \n {\
2290 \n gl_FragData[0] = vec4(0.0);\
2291 \n }\
2292 \n return;");
2293};
2294
2295//--------------------------------------------------------------------------
2297 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2298{
2299 return std::string("\
2300 \n // Special coloring mode which renders the voxel index in fragments that\
2301 \n // have accumulated certain level of opacity. Used during the selection\
2302 \n // pass vtkHardwareSelection::ID_LOW24.\
2303 \n if (g_fragColor.a > 3.0/ 255.0)\
2304 \n {\
2305 \n uvec3 volumeDim = uvec3(in_textureExtentsMax - in_textureExtentsMin);\
2306 \n uvec3 voxelCoords = uvec3(volumeDim * g_dataPos);\
2307 \n // vtkHardwareSelector assumes index 0 to be empty space, so add uint(1).\
2308 \n uint idx = volumeDim.x * volumeDim.y * voxelCoords.z +\
2309 \n volumeDim.x * voxelCoords.y + voxelCoords.x + uint(1);\
2310 \n gl_FragData[0] = vec4(float(idx % uint(256)) / 255.0,\
2311 \n float((idx / uint(256)) % uint(256)) / 255.0,\
2312 \n float((idx / uint(65536)) % uint(256)) / 255.0, 1.0);\
2313 \n }\
2314 \n else\
2315 \n {\
2316 \n gl_FragData[0] = vec4(0.0);\
2317 \n }\
2318 \n return;");
2319};
2320
2321//--------------------------------------------------------------------------
2323 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2324{
2325 return std::string("\
2326 \n // Special coloring mode which renders the voxel index in fragments that\
2327 \n // have accumulated certain level of opacity. Used during the selection\
2328 \n // pass vtkHardwareSelection::ID_MID24.\
2329 \n if (g_fragColor.a > 3.0/ 255.0)\
2330 \n {\
2331 \n uvec3 volumeDim = uvec3(in_textureExtentsMax - in_textureExtentsMin);\
2332 \n uvec3 voxelCoords = uvec3(volumeDim * g_dataPos);\
2333 \n // vtkHardwareSelector assumes index 0 to be empty space, so add uint(1).\
2334 \n uint idx = volumeDim.x * volumeDim.y * voxelCoords.z +\
2335 \n volumeDim.x * voxelCoords.y + voxelCoords.x + uint(1);\
2336 \n idx = ((idx & 0xff000000) >> 24);\
2337 \n gl_FragData[0] = vec4(float(idx % uint(256)) / 255.0,\
2338 \n float((idx / uint(256)) % uint(256)) / 255.0,\
2339 \n float(idx / uint(65536)) / 255.0, 1.0);\
2340 \n }\
2341 \n else\
2342 \n {\
2343 \n gl_FragData[0] = vec4(0.0);\
2344 \n }\
2345 \n return;");
2346};
2347
2348//--------------------------------------------------------------------------
2349std::string ShadingExit(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper,
2350 vtkVolume* vtkNotUsed(vol), int noOfComponents, int independentComponents = 0)
2351{
2353
2354 if (glMapper->GetUseDepthPass() &&
2357 {
2358 return std::string();
2359 }
2361 {
2362 if (noOfComponents > 1 && independentComponents)
2363 {
2364 return std::string("\
2365 \n g_srcColor = vec4(0);\
2366 \n for (int i = 0; i < in_noOfComponents; ++i)\
2367 \n {\
2368 \n vec4 tmp = computeColor(l_maxValue, computeOpacity(l_maxValue, i), i);\
2369 \n g_srcColor[0] += tmp[0] * tmp[3] * in_componentWeight[i];\
2370 \n g_srcColor[1] += tmp[1] * tmp[3] * in_componentWeight[i];\
2371 \n g_srcColor[2] += tmp[2] * tmp[3] * in_componentWeight[i];\
2372 \n g_srcColor[3] += tmp[3] * in_componentWeight[i];\
2373 \n }\
2374 \n g_fragColor = g_srcColor;");
2375 }
2376 else
2377 {
2378 return std::string("\
2379 \n g_srcColor = computeColor(l_maxValue,\
2380 \n computeOpacity(l_maxValue));\
2381 \n g_fragColor.rgb = g_srcColor.rgb * g_srcColor.a;\
2382 \n g_fragColor.a = g_srcColor.a;");
2383 }
2384 }
2386 {
2387 if (noOfComponents > 1 && independentComponents)
2388 {
2389 return std::string("\
2390 \n g_srcColor = vec4(0);\
2391 \n for (int i = 0; i < in_noOfComponents; ++i)\
2392 \n {\
2393 \n vec4 tmp = computeColor(l_minValue, computeOpacity(l_minValue, i), i);\
2394 \n g_srcColor[0] += tmp[0] * tmp[3] * in_componentWeight[i];\
2395 \n g_srcColor[1] += tmp[1] * tmp[3] * in_componentWeight[i];\
2396 \n g_srcColor[2] += tmp[2] * tmp[3] * in_componentWeight[i];\
2397 \n g_srcColor[2] += tmp[3] * tmp[3] * in_componentWeight[i];\
2398 \n }\
2399 \n g_fragColor = g_srcColor;");
2400 }
2401 else
2402 {
2403 return std::string("\
2404 \n g_srcColor = computeColor(l_minValue,\
2405 \n computeOpacity(l_minValue));\
2406 \n g_fragColor.rgb = g_srcColor.rgb * g_srcColor.a;\
2407 \n g_fragColor.a = g_srcColor.a;");
2408 }
2409 }
2411 {
2412 if (noOfComponents > 1 && independentComponents)
2413 {
2414 return std::string("\
2415 \n for (int i = 0; i < in_noOfComponents; ++i)\
2416 \n {\
2417 \n if (l_numSamples[i] == uint(0))\
2418 \n {\
2419 \n continue;\
2420 \n }\
2421 \n l_avgValue[i] = l_avgValue[i] * in_componentWeight[i] /\
2422 \n l_numSamples[i];\
2423 \n if (i > 0)\
2424 \n {\
2425 \n l_avgValue[0] += l_avgValue[i];\
2426 \n }\
2427 \n }\
2428 \n l_avgValue[0] = clamp(l_avgValue[0], 0.0, 1.0);\
2429 \n g_fragColor = vec4(vec3(l_avgValue[0]), 1.0);");
2430 }
2431 else
2432 {
2433 return std::string("\
2434 \n if (l_numSamples.x == uint(0))\
2435 \n {\
2436 \n discard;\
2437 \n }\
2438 \n else\
2439 \n {\
2440 \n l_avgValue.x /= l_numSamples.x;\
2441 \n l_avgValue.x = clamp(l_avgValue.x, 0.0, 1.0);\
2442 \n g_fragColor = vec4(vec3(l_avgValue.x), 1.0);\
2443 \n }");
2444 }
2445 }
2446 else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND)
2447 {
2448 if (noOfComponents > 1 && independentComponents)
2449 {
2450 // Add all the components to get final color
2451 return std::string("\
2452 \n l_sumValue.x *= in_componentWeight.x;\
2453 \n for (int i = 1; i < in_noOfComponents; ++i)\
2454 \n {\
2455 \n l_sumValue.x += l_sumValue[i] * in_componentWeight[i];\
2456 \n }\
2457 \n l_sumValue.x = clamp(l_sumValue.x, 0.0, 1.0);\
2458 \n g_fragColor = vec4(vec3(l_sumValue.x), 1.0);");
2459 }
2460 else
2461 {
2462 return std::string("\
2463 \n l_sumValue.x = clamp(l_sumValue.x, 0.0, 1.0);\
2464 \n g_fragColor = vec4(vec3(l_sumValue.x), 1.0);");
2465 }
2466 }
2467 else
2468 {
2469 return std::string();
2470 }
2471}
2472
2473//--------------------------------------------------------------------------
2475 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2476{
2477 return std::string();
2478}
2479
2480//--------------------------------------------------------------------------
2482 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2483{
2484 return std::string("\
2485 \n const float g_opacityThreshold = 1.0 - 1.0 / 255.0;");
2486}
2487
2488//--------------------------------------------------------------------------
2490 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2491{
2492 return std::string("\
2493 \n uniform vec3 in_propId;");
2494};
2495
2496//--------------------------------------------------------------------------
2497std::string TerminationInit(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vol)
2498{
2499 std::string shaderStr;
2500 shaderStr += std::string("\
2501 \n // Flag to indicate if the raymarch loop should terminate \
2502 \n bool stop = false;\
2503 \n\
2504 \n g_terminatePointMax = 0.0;\
2505 \n\
2506 \n vec4 l_depthValue = texture2D(in_depthSampler, fragTexCoord);\
2507 \n // Depth test\
2508 \n if(gl_FragCoord.z >= l_depthValue.x)\
2509 \n {\
2510 \n discard;\
2511 \n }\
2512 \n\
2513 \n // color buffer or max scalar buffer have a reduced size.\
2514 \n fragTexCoord = (gl_FragCoord.xy - in_windowLowerLeftCorner) *\
2515 \n in_inverseOriginalWindowSize;\
2516 \n");
2517
2519 {
2520 vtkImplicitFunction* sliceFunc = vol->GetProperty()->GetSliceFunction();
2521 if (sliceFunc)
2522 {
2523 if (sliceFunc->IsA("vtkPlane"))
2524 {
2525 shaderStr += std::string("\
2526 \n\
2527 \n // Intersection with plane\
2528 \n float t = intersectRayPlane(ip_vertexPos, rayDir);\
2529 \n vec4 intersection = vec4(ip_vertexPos + t * rayDir, 1.0);\
2530 \n g_intersection = (in_inverseTextureDatasetMatrix[0] * intersection).xyz;\
2531 \n vec4 intersDC = in_projectionMatrix * in_modelViewMatrix * in_volumeMatrix[0] * intersection;\
2532 \n intersDC.xyz /= intersDC.w;\
2533 \n vec4 intersWin = NDCToWindow(intersDC.x, intersDC.y, intersDC.z);\
2534 \n if(intersWin.z >= l_depthValue.x)\
2535 \n {\
2536 \n discard;\
2537 \n }\
2538 \n");
2539 }
2540 else
2541 {
2542 vtkErrorWithObjectMacro(
2543 sliceFunc, "Implicit function type is not supported by this mapper.");
2544 }
2545 }
2546 }
2547
2548 shaderStr += std::string("\
2549 \n // Compute max number of iterations it will take before we hit\
2550 \n // the termination point\
2551 \n\
2552 \n // Abscissa of the point on the depth buffer along the ray.\
2553 \n // point in texture coordinates\
2554 \n vec4 rayTermination = WindowToNDC(gl_FragCoord.x, gl_FragCoord.y, l_depthValue.x);\
2555 \n\
2556 \n // From normalized device coordinates to eye coordinates.\
2557 \n // in_projectionMatrix is inversed because of way VT\
2558 \n // From eye coordinates to texture coordinates\
2559 \n rayTermination = ip_inverseTextureDataAdjusted *\
2560 \n in_inverseVolumeMatrix[0] *\
2561 \n in_inverseModelViewMatrix *\
2562 \n in_inverseProjectionMatrix *\
2563 \n rayTermination;\
2564 \n g_rayTermination = rayTermination.xyz / rayTermination.w;\
2565 \n\
2566 \n // Setup the current segment:\
2567 \n g_dataPos = g_rayOrigin;\
2568 \n g_terminatePos = g_rayTermination;\
2569 \n\
2570 \n g_terminatePointMax = length(g_terminatePos.xyz - g_dataPos.xyz) /\
2571 \n length(g_dirStep);\
2572 \n g_currentT = 0.0;");
2573
2574 return shaderStr;
2575}
2576
2577//--------------------------------------------------------------------------
2579 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2580{
2581 return std::string("\
2582 \n if(any(greaterThan(max(g_dirStep, vec3(0.0))*(g_dataPos - in_texMax[0]),vec3(0.0))) ||\
2583 \n any(greaterThan(min(g_dirStep, vec3(0.0))*(g_dataPos - in_texMin[0]),vec3(0.0))))\
2584 \n {\
2585 \n break;\
2586 \n }\
2587 \n\
2588 \n // Early ray termination\
2589 \n // if the currently composited colour alpha is already fully saturated\
2590 \n // we terminated the loop or if we have hit an obstacle in the\
2591 \n // direction of they ray (using depth buffer) we terminate as well.\
2592 \n if((g_fragColor.a > g_opacityThreshold) || \
2593 \n g_currentT >= g_terminatePointMax)\
2594 \n {\
2595 \n break;\
2596 \n }\
2597 \n ++g_currentT;");
2598}
2599
2600//--------------------------------------------------------------------------
2602 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2603{
2604 return std::string();
2605}
2606
2607//--------------------------------------------------------------------------
2609 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2610{
2611 return std::string();
2612}
2613
2614//--------------------------------------------------------------------------
2616 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
2617{
2618 if (!mapper->GetCropping())
2619 {
2620 return std::string();
2621 }
2622
2623 return std::string("\
2624 \nuniform float in_croppingPlanes[6];\
2625 \nuniform int in_croppingFlags [32];\
2626 \nfloat croppingPlanesTexture[6];\
2627 \n\
2628 \n// X: axis = 0, Y: axis = 1, Z: axis = 2\
2629 \n// cp Cropping plane bounds (minX, maxX, minY, maxY, minZ, maxZ)\
2630 \nint computeRegionCoord(float cp[6], vec3 pos, int axis)\
2631 \n {\
2632 \n int cpmin = axis * 2;\
2633 \n int cpmax = cpmin + 1;\
2634 \n\
2635 \n if (pos[axis] < cp[cpmin])\
2636 \n {\
2637 \n return 1;\
2638 \n }\
2639 \n else if (pos[axis] >= cp[cpmin] &&\
2640 \n pos[axis] < cp[cpmax])\
2641 \n {\
2642 \n return 2;\
2643 \n }\
2644 \n else if (pos[axis] >= cp[cpmax])\
2645 \n {\
2646 \n return 3;\
2647 \n }\
2648 \n return 0;\
2649 \n }\
2650 \n\
2651 \nint computeRegion(float cp[6], vec3 pos)\
2652 \n {\
2653 \n return (computeRegionCoord(cp, pos, 0) +\
2654 \n (computeRegionCoord(cp, pos, 1) - 1) * 3 +\
2655 \n (computeRegionCoord(cp, pos, 2) - 1) * 9);\
2656 \n }");
2657}
2658
2659//--------------------------------------------------------------------------
2660std::string CroppingInit(
2661 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
2662{
2663 if (!mapper->GetCropping())
2664 {
2665 return std::string();
2666 }
2667
2668 return std::string("\
2669 \n // Convert cropping region to texture space\
2670 \n mat4 datasetToTextureMat = in_inverseTextureDatasetMatrix[0];\
2671 \n\
2672 \n vec4 tempCrop = vec4(in_croppingPlanes[0], 0.0, 0.0, 1.0);\
2673 \n tempCrop = datasetToTextureMat * tempCrop;\
2674 \n if (tempCrop[3] != 0.0)\
2675 \n {\
2676 \n tempCrop[0] /= tempCrop[3];\
2677 \n }\
2678 \n croppingPlanesTexture[0] = tempCrop[0];\
2679 \n\
2680 \n tempCrop = vec4(in_croppingPlanes[1], 0.0, 0.0, 1.0);\
2681 \n tempCrop = datasetToTextureMat * tempCrop;\
2682 \n if (tempCrop[3] != 0.0)\
2683 \n {\
2684 \n tempCrop[0] /= tempCrop[3];\
2685 \n }\
2686 \n croppingPlanesTexture[1] = tempCrop[0];\
2687 \n\
2688 \n tempCrop = vec4(0.0, in_croppingPlanes[2], 0.0, 1.0);\
2689 \n tempCrop = datasetToTextureMat * tempCrop;\
2690 \n if (tempCrop[3] != 0.0)\
2691 \n {\
2692 \n tempCrop[1] /= tempCrop[3];\
2693 \n }\
2694 \n croppingPlanesTexture[2] = tempCrop[1];\
2695 \n\
2696 \n tempCrop = vec4(0.0, in_croppingPlanes[3], 0.0, 1.0);\
2697 \n tempCrop = datasetToTextureMat * tempCrop;\
2698 \n if (tempCrop[3] != 0.0)\
2699 \n {\
2700 \n tempCrop[1] /= tempCrop[3];\
2701 \n }\
2702 \n croppingPlanesTexture[3] = tempCrop[1];\
2703 \n\
2704 \n tempCrop = vec4(0.0, 0.0, in_croppingPlanes[4], 1.0);\
2705 \n tempCrop = datasetToTextureMat * tempCrop;\
2706 \n if (tempCrop[3] != 0.0)\
2707 \n {\
2708 \n tempCrop[2] /= tempCrop[3];\
2709 \n }\
2710 \n croppingPlanesTexture[4] = tempCrop[2];\
2711 \n\
2712 \n tempCrop = vec4(0.0, 0.0, in_croppingPlanes[5], 1.0);\
2713 \n tempCrop = datasetToTextureMat * tempCrop;\
2714 \n if (tempCrop[3] != 0.0)\
2715 \n {\
2716 \n tempCrop[2] /= tempCrop[3];\
2717 \n }\
2718 \n croppingPlanesTexture[5] = tempCrop[2];");
2719}
2720
2721//--------------------------------------------------------------------------
2723 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
2724{
2725 if (!mapper->GetCropping())
2726 {
2727 return std::string();
2728 }
2729
2730 return std::string("\
2731 \n // Determine region\
2732 \n int regionNo = computeRegion(croppingPlanesTexture, g_dataPos);\
2733 \n\
2734 \n // Do & operation with cropping flags\
2735 \n // Pass the flag that its Ok to sample or not to sample\
2736 \n if (in_croppingFlags[regionNo] == 0)\
2737 \n {\
2738 \n // Skip this voxel\
2739 \n g_skip = true;\
2740 \n }");
2741}
2742
2743//--------------------------------------------------------------------------
2744std::string CroppingExit(
2745 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2746{
2747 return std::string();
2748}
2749
2750//--------------------------------------------------------------------------
2752 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2753{
2754 return std::string();
2755}
2756
2757//--------------------------------------------------------------------------
2759 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
2760{
2761 if (!mapper->GetClippingPlanes())
2762 {
2763 return std::string();
2764 }
2765
2766 return std::string("\
2767 \n /// We support only 8 clipping planes for now\
2768 \n /// The first value is the size of the data array for clipping\
2769 \n /// planes (origin, normal)\
2770 \n uniform float in_clippingPlanes[49];\
2771 \n uniform float in_clippedVoxelIntensity;\
2772 \n\
2773 \n int clip_numPlanes;\
2774 \n vec3 clip_rayDirObj;\
2775 \n mat4 clip_texToObjMat;\
2776 \n mat4 clip_objToTexMat;\
2777 \n\
2778 \n// Tighten the sample range as needed to account for clip planes. \
2779 \n// Arguments are in texture coordinates. \
2780 \n// Returns true if the range is at all valid after clipping. If not, \
2781 \n// the fragment should be discarded. \
2782 \nbool AdjustSampleRangeForClipping(inout vec3 startPosTex, inout vec3 stopPosTex) \
2783 \n{ \
2784 \n vec4 startPosObj = vec4(0.0);\
2785 \n {\
2786 \n startPosObj = clip_texToObjMat * vec4(startPosTex - g_rayJitter, 1.0);\
2787 \n startPosObj = startPosObj / startPosObj.w;\
2788 \n startPosObj.w = 1.0;\
2789 \n }\
2790 \n\
2791 \n vec4 stopPosObj = vec4(0.0);\
2792 \n {\
2793 \n stopPosObj = clip_texToObjMat * vec4(stopPosTex, 1.0);\
2794 \n stopPosObj = stopPosObj / stopPosObj.w;\
2795 \n stopPosObj.w = 1.0;\
2796 \n }\
2797 \n\
2798 \n for (int i = 0; i < clip_numPlanes; i = i + 6)\
2799 \n {\
2800 \n vec3 planeOrigin = vec3(in_clippingPlanes[i + 1],\
2801 \n in_clippingPlanes[i + 2],\
2802 \n in_clippingPlanes[i + 3]);\
2803 \n vec3 planeNormal = normalize(vec3(in_clippingPlanes[i + 4],\
2804 \n in_clippingPlanes[i + 5],\
2805 \n in_clippingPlanes[i + 6]));\
2806 \n\
2807 \n // Abort if the entire segment is clipped:\
2808 \n // (We can do this before adjusting the term point, since it'll \
2809 \n // only move further into the clipped area)\
2810 \n float startDistance = dot(planeNormal, planeOrigin - startPosObj.xyz);\
2811 \n float stopDistance = dot(planeNormal, planeOrigin - stopPosObj.xyz);\
2812 \n bool startClipped = startDistance > 0.0;\
2813 \n bool stopClipped = stopDistance > 0.0;\
2814 \n if (startClipped && stopClipped)\
2815 \n {\
2816 \n return false;\
2817 \n }\
2818 \n\
2819 \n float rayDotNormal = dot(clip_rayDirObj, planeNormal);\
2820 \n bool frontFace = rayDotNormal > 0.0;\
2821 \n\
2822 \n // Move the start position further from the eye if needed:\
2823 \n if (frontFace && // Observing from the clipped side (plane's front face)\
2824 \n startDistance > 0.0) // Ray-entry lies on the clipped side.\
2825 \n {\
2826 \n // Scale the point-plane distance to the ray direction and update the\
2827 \n // entry point.\
2828 \n float rayScaledDist = startDistance / rayDotNormal;\
2829 \n startPosObj = vec4(startPosObj.xyz + rayScaledDist * clip_rayDirObj, 1.0);\
2830 \n vec4 newStartPosTex = clip_objToTexMat * vec4(startPosObj.xyz, 1.0);\
2831 \n newStartPosTex /= newStartPosTex.w;\
2832 \n startPosTex = newStartPosTex.xyz;\
2833 \n startPosTex += g_rayJitter;\
2834 \n }\
2835 \n\
2836 \n // Move the end position closer to the eye if needed:\
2837 \n if (!frontFace && // Observing from the unclipped side (plane's back face)\
2838 \n stopDistance > 0.0) // Ray-entry lies on the unclipped side.\
2839 \n {\
2840 \n // Scale the point-plane distance to the ray direction and update the\
2841 \n // termination point.\
2842 \n float rayScaledDist = stopDistance / rayDotNormal;\
2843 \n stopPosObj = vec4(stopPosObj.xyz + rayScaledDist * clip_rayDirObj, 1.0);\
2844 \n vec4 newStopPosTex = clip_objToTexMat * vec4(stopPosObj.xyz, 1.0);\
2845 \n newStopPosTex /= newStopPosTex.w;\
2846 \n stopPosTex = newStopPosTex.xyz;\
2847 \n }\
2848 \n }\
2849 \n\
2850 \n if (any(greaterThan(startPosTex, in_texMax[0])) ||\
2851 \n any(lessThan(startPosTex, in_texMin[0])))\
2852 \n {\
2853 \n return false;\
2854 \n }\
2855 \n\
2856 \n return true;\
2857 \n}\
2858 \n");
2859}
2860
2861//--------------------------------------------------------------------------
2862std::string ClippingInit(vtkRenderer* ren, vtkVolumeMapper* mapper, vtkVolume* vtkNotUsed(vol))
2863{
2864 if (!mapper->GetClippingPlanes())
2865 {
2866 return std::string();
2867 }
2868
2869 std::string shaderStr;
2871 {
2872 shaderStr = std::string("\
2873 \n vec4 tempClip = in_volumeMatrix[0] * vec4(rayDir, 0.0);\
2874 \n if (tempClip.w != 0.0)\
2875 \n {\
2876 \n tempClip = tempClip/tempClip.w;\
2877 \n tempClip.w = 1.0;\
2878 \n }\
2879 \n clip_rayDirObj = normalize(tempClip.xyz);");
2880 }
2881 else
2882 {
2883 shaderStr = std::string("\
2884 clip_rayDirObj = normalize(in_projectionDirection);");
2885 }
2886
2887 shaderStr += std::string("\
2888 \n clip_numPlanes = int(in_clippingPlanes[0]);\
2889 \n clip_texToObjMat = in_volumeMatrix[0] * in_textureDatasetMatrix[0];\
2890 \n clip_objToTexMat = in_inverseTextureDatasetMatrix[0] * in_inverseVolumeMatrix[0];\
2891 \n\
2892 \n // Adjust for clipping.\
2893 \n if (!AdjustSampleRangeForClipping(g_rayOrigin, g_rayTermination))\
2894 \n { // entire ray is clipped.\
2895 \n discard;\
2896 \n }\
2897 \n\
2898 \n // Update the segment post-clip:\
2899 \n g_dataPos = g_rayOrigin;\
2900 \n g_terminatePos = g_rayTermination;\
2901 \n g_terminatePointMax = length(g_terminatePos.xyz - g_dataPos.xyz) /\
2902 \n length(g_dirStep);\
2903 \n");
2904
2905 return shaderStr;
2906}
2907
2908//--------------------------------------------------------------------------
2910 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2911{
2912 return std::string();
2913}
2914
2915//--------------------------------------------------------------------------
2916std::string ClippingExit(
2917 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
2918{
2919 return std::string();
2920}
2921
2922//--------------------------------------------------------------------------
2923std::string BinaryMaskDeclaration(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper),
2924 vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput, vtkVolumeTexture* mask,
2925 int vtkNotUsed(maskType))
2926{
2927 if (!mask || !maskInput)
2928 {
2929 return std::string();
2930 }
2931 else
2932 {
2933 return std::string("uniform sampler3D in_mask;");
2934 }
2935}
2936
2937//--------------------------------------------------------------------------
2938std::string BinaryMaskImplementation(vtkRenderer* vtkNotUsed(ren),
2939 vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput,
2940 vtkVolumeTexture* mask, int maskType)
2941{
2942 if (!mask || !maskInput || maskType == vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2943 {
2944 return std::string();
2945 }
2946 else
2947 {
2948 return std::string("\
2949 \nvec4 maskValue = texture3D(in_mask, g_dataPos);\
2950 \nif(maskValue.r <= 0.0)\
2951 \n {\
2952 \n g_skip = true;\
2953 \n }");
2954 }
2955}
2956
2957//--------------------------------------------------------------------------
2959 vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput,
2960 vtkVolumeTexture* mask, int maskType)
2961{
2962 if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2963 {
2964 return std::string();
2965 }
2966 else
2967 {
2968 return std::string("\
2969 \nuniform float in_maskBlendFactor;\
2970 \nuniform sampler2D in_labelMapTransfer;\
2971 \nuniform float in_mask_scale;\
2972 \nuniform float in_mask_bias;\
2973 \nuniform int in_labelMapNumLabels;\
2974 \n");
2975 }
2976}
2977
2978//--------------------------------------------------------------------------
2979std::string CompositeMaskImplementation(vtkRenderer* vtkNotUsed(ren),
2980 vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput,
2981 vtkVolumeTexture* mask, int maskType, int noOfComponents)
2982{
2983 if (!mask || !maskInput || maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType)
2984 {
2985 return std::string();
2986 }
2987 else
2988 {
2989 std::string shaderStr = std::string("\
2990 \nvec4 scalar = texture3D(in_volume[0], g_dataPos);");
2991
2992 // simulate old intensity textures
2993 if (noOfComponents == 1)
2994 {
2995 shaderStr += std::string("\
2996 \n scalar.r = scalar.r * in_volume_scale[0].r + in_volume_bias[0].r;\
2997 \n scalar = vec4(scalar.r);");
2998 }
2999 else
3000 {
3001 // handle bias and scale
3002 shaderStr += std::string("\
3003 \n scalar = scalar * in_volume_scale[0] + in_volume_bias[0];");
3004 }
3005
3006 // Assumeing single component scalar for label texture lookup.
3007 // This can be extended to composite color obtained from all components
3008 // in the scalar array.
3009 return shaderStr + std::string("\
3010 \nif (in_maskBlendFactor == 0.0)\
3011 \n {\
3012 \n g_srcColor.a = computeOpacity(scalar);\
3013 \n if (g_srcColor.a > 0)\
3014 \n {\
3015 \n g_srcColor = computeColor(scalar, g_srcColor.a);\
3016 \n }\
3017 \n }\
3018 \nelse\
3019 \n {\
3020 \n float opacity = computeOpacity(scalar);\
3021 \n // Get the mask value at this same location\
3022 \n vec4 maskValue = texture3D(in_mask, g_dataPos);\
3023 \n maskValue.r = maskValue.r * in_mask_scale + in_mask_bias;\
3024 \n // Quantize the height of the labelmap texture over number of labels\
3025 \n if (in_labelMapNumLabels > 0)\
3026 \n {\
3027 \n maskValue.r =\
3028 \n floor(maskValue.r * in_labelMapNumLabels) /\
3029 \n in_labelMapNumLabels;\
3030 \n }\
3031 \n else\
3032 \n {\
3033 \n maskValue.r = 0.0;\
3034 \n }\
3035 \n if(maskValue.r == 0.0)\
3036 \n {\
3037 \n g_srcColor.a = opacity;\
3038 \n if (g_srcColor.a > 0)\
3039 \n {\
3040 \n g_srcColor = computeColor(scalar, g_srcColor.a);\
3041 \n }\
3042 \n }\
3043 \n else\
3044 \n {\
3045 \n g_srcColor = texture2D(in_labelMapTransfer,\
3046 \n vec2(scalar.r, maskValue.r));\
3047 \n if (g_srcColor.a > 0)\
3048 \n {\
3049 \n g_srcColor = computeLighting(g_srcColor, 0, maskValue.r);\
3050 \n }\
3051 \n if (in_maskBlendFactor < 1.0)\
3052 \n {\
3053 \n vec4 color = opacity > 0 ? computeColor(scalar, opacity) : vec4(0);\
3054 \n g_srcColor = (1.0 - in_maskBlendFactor) * color +\
3055 \n in_maskBlendFactor * g_srcColor;\
3056 \n }\
3057 \n }\
3058 \n }");
3059 }
3060}
3061
3062//--------------------------------------------------------------------------
3064 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3065{
3066 return std::string("uniform bool in_clampDepthToBackface;\n"
3067 "vec3 l_opaqueFragPos;\n"
3068 "bool l_updateDepth;\n");
3069}
3070
3071//--------------------------------------------------------------------------
3073 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3074{
3075 return std::string("\
3076 \n l_opaqueFragPos = vec3(-1.0);\
3077 \n if(in_clampDepthToBackface)\
3078 \n {\
3079 \n l_opaqueFragPos = g_dataPos;\
3080 \n }\
3081 \n l_updateDepth = true;");
3082}
3083
3084//--------------------------------------------------------------------------
3086 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3087{
3088 return std::string("\
3089 \n if(!g_skip && g_srcColor.a > 0.0 && l_updateDepth)\
3090 \n {\
3091 \n l_opaqueFragPos = g_dataPos;\
3092 \n l_updateDepth = false;\
3093 \n }");
3094}
3095
3096//--------------------------------------------------------------------------
3098 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3099{
3100 return std::string("\
3101 \n if (l_opaqueFragPos == vec3(-1.0))\
3102 \n {\
3103 \n gl_FragData[1] = vec4(1.0);\
3104 \n }\
3105 \n else\
3106 \n {\
3107 \n vec4 depthValue = in_projectionMatrix * in_modelViewMatrix *\
3108 \n in_volumeMatrix[0] * in_textureDatasetMatrix[0] *\
3109 \n vec4(l_opaqueFragPos, 1.0);\
3110 \n depthValue /= depthValue.w;\
3111 \n gl_FragData[1] = vec4(vec3(0.5 * (gl_DepthRange.far -\
3112 \n gl_DepthRange.near) * depthValue.z + 0.5 *\
3113 \n (gl_DepthRange.far + gl_DepthRange.near)), 1.0);\
3114 \n }");
3115}
3116
3117//--------------------------------------------------------------------------
3118std::string DepthPassInit(
3119 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3120{
3121 return std::string("\
3122 \n vec3 l_isoPos = g_dataPos;");
3123}
3124
3125//--------------------------------------------------------------------------
3127 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3128{
3129 return std::string("\
3130 \n if(!g_skip && g_srcColor.a > 0.0)\
3131 \n {\
3132 \n l_isoPos = g_dataPos;\
3133 \n g_exit = true; g_skip = true;\
3134 \n }");
3135}
3136
3137//--------------------------------------------------------------------------
3138std::string DepthPassExit(
3139 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3140{
3141 return std::string("\
3142 \n vec4 depthValue = in_projectionMatrix * in_modelViewMatrix *\
3143 \n in_volumeMatrix[0] * in_textureDatasetMatrix[0] *\
3144 \n vec4(l_isoPos, 1.0);\
3145 \n gl_FragData[0] = vec4(l_isoPos, 1.0);\
3146 \n gl_FragData[1] = vec4(vec3((depthValue.z/depthValue.w) * 0.5 + 0.5),\
3147 \n 1.0);");
3148}
3149
3150//---------------------------------------------------------------------------
3152 vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol))
3153{
3154 return std::string("\
3155 \n initializeRayCast();\
3156 \n castRay(-1.0, -1.0);\
3157 \n finalizeRayCast();");
3158}
3159
3160//---------------------------------------------------------------------------
3162 const std::vector<std::string>& varNames, const size_t usedNames)
3163{
3164 std::string shader = "\n";
3165 for (size_t i = 0; i < usedNames; i++)
3166 {
3167 shader += "uniform sampler2D " + varNames[i] + ";\n";
3168 }
3169 return shader;
3170}
3171
3172//---------------------------------------------------------------------------
3174 const std::vector<std::string>& varNames, const size_t usedNames)
3175{
3176 std::string shader = "\n";
3177 for (size_t i = 0; i < usedNames; i++)
3178 {
3179 std::stringstream ss;
3180 ss << i;
3181 shader += " gl_FragData[" + ss.str() + "] = texture2D(" + varNames[i] + ", texCoord);\n";
3182 }
3183 shader += " return;\n";
3184 return shader;
3185}
3186}
3187
3188#endif // vtkVolumeShaderComposer_h
3189// 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)
topologically and geometrically regular array of data
Definition: vtkImageData.h:157
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
Definition: vtkRenderer.h:182
vtkCamera * GetActiveCamera()
Get the current camera.
Hold a reference to a vtkObjectBase instance.
Abstract class for a volume mapper.
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 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:144
virtual vtkVolumeProperty * GetProperty()
Set/Get the volume property.
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 ComputeLightingMultiDeclaration(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkVolume *vol, int noOfComponents, int independentComponents, int vtkNotUsed(numberOfLights), int lightingComplexity)
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 ComputeLightingDeclaration(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkVolume *vol, int noOfComponents, int independentComponents, int vtkNotUsed(numberOfLights), int lightingComplexity)
std::string CroppingDeclarationFragment(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkVolume *vtkNotUsed(vol))
std::string ComputeColorDeclaration(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol), int noOfComponents, int independentComponents, std::map< int, std::string > colorTableMap)
std::string 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 ImageSampleDeclarationFrag(const std::vector< std::string > &varNames, const size_t usedNames)
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 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 ComputeColorMultiDeclaration(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs)
std::string ClippingExit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string ComputeGradientDeclaration(vtkOpenGLGPUVolumeRayCastMapper *mapper, vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs)
std::string BaseInit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs, int lightingComplexity)
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 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 ComputeRayDirectionDeclaration(vtkRenderer *ren, vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol), int vtkNotUsed(noOfComponents))
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 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 ImageSampleImplementationFrag(const std::vector< std::string > &varNames, const size_t usedNames)
std::string CroppingExit(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *vtkNotUsed(mapper), vtkVolume *vtkNotUsed(vol))
std::string ClippingInit(vtkRenderer *ren, vtkVolumeMapper *mapper, vtkVolume *vtkNotUsed(vol))
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 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 BaseDeclarationFragment(vtkRenderer *vtkNotUsed(ren), vtkVolumeMapper *mapper, vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap &inputs, int vtkNotUsed(numberOfLights), int lightingComplexity, int noOfComponents, int independentComponents)