diff --git a/Rendering/Volume/Testing/Data/Baseline/TestGPURayCastIndependentComponent.png.md5 b/Rendering/Volume/Testing/Data/Baseline/TestGPURayCastIndependentComponent.png.md5 new file mode 100644 index 00000000000..302cee81ae6 --- /dev/null +++ b/Rendering/Volume/Testing/Data/Baseline/TestGPURayCastIndependentComponent.png.md5 @@ -0,0 +1 @@ +78563a50396d621fd24dfed38106d820 diff --git a/Rendering/Volume/Testing/Python/CMakeLists.txt b/Rendering/Volume/Testing/Python/CMakeLists.txt index f9d41e29d6a..46425cd7b5d 100644 --- a/Rendering/Volume/Testing/Python/CMakeLists.txt +++ b/Rendering/Volume/Testing/Python/CMakeLists.txt @@ -11,6 +11,7 @@ set (GenericVolumePythonTests volRCRotateClip.py VolumePickerCrop.py VolumePicker.py,NO_RT + TestGPURayCastIndependentComponent.py,NO_RT ) # These tests are only built when the rendering backend is OpenGL diff --git a/Rendering/Volume/Testing/Python/TestGPURayCastIndependentComponent.py b/Rendering/Volume/Testing/Python/TestGPURayCastIndependentComponent.py new file mode 100755 index 00000000000..da7991bfe64 --- /dev/null +++ b/Rendering/Volume/Testing/Python/TestGPURayCastIndependentComponent.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +''' +========================================================================= + + Program: Visualization Toolkit + Module: TestGPURayCastIndependentComponent.py + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +========================================================================= +''' + +import sys +import vtk +import vtk.test.Testing +from vtk.util.misc import vtkGetDataRoot +VTK_DATA_ROOT = vtkGetDataRoot() + +''' + Prevent .pyc files from being created. + Stops the vtk source being polluted + by .pyc files. +''' +sys.dont_write_bytecode = True + +class TestGPURayCastIndependentComponent(vtk.test.Testing.vtkTest): + + def test(self): + dataRoot = vtkGetDataRoot() + reader = vtk.vtkXMLImageDataReader() + reader.SetFileName("" + str(dataRoot) + "/Data/vase_4comp.vti") + + volume = vtk.vtkVolume() + #mapper = vtk.vtkFixedPointVolumeRayCastMapper() + mapper = vtk.vtkGPUVolumeRayCastMapper() + mapper.SetSampleDistance(0.1) + mapper.SetAutoAdjustSampleDistances(0) + ren = vtk.vtkRenderer() + renWin = vtk.vtkRenderWindow() + iRen = vtk.vtkRenderWindowInteractor() + + # Set connections + mapper.SetInputConnection(reader.GetOutputPort()); + volume.SetMapper(mapper) + ren.AddViewProp(volume) + renWin.AddRenderer(ren) + iRen.SetRenderWindow(renWin) + + # Define opacity transfer function and color functions + opacityFunc1 = vtk.vtkPiecewiseFunction() + opacityFunc1.AddPoint(0.0, 0.0); + opacityFunc1.AddPoint(60.0, 0.1); + opacityFunc1.AddPoint(255.0, 0.0); + + opacityFunc2 = vtk.vtkPiecewiseFunction() + opacityFunc2.AddPoint(0.0, 0.0); + opacityFunc2.AddPoint(60.0, 0.0); + opacityFunc2.AddPoint(120.0, 0.1); + opacityFunc1.AddPoint(255.0, 0.0); + + opacityFunc3 = vtk.vtkPiecewiseFunction() + opacityFunc3.AddPoint(0.0, 0.0); + opacityFunc3.AddPoint(120.0, 0.0); + opacityFunc3.AddPoint(180.0, 0.1); + opacityFunc3.AddPoint(255.0, 0.0); + + opacityFunc4 = vtk.vtkPiecewiseFunction() + opacityFunc4.AddPoint(0.0, 0.0); + opacityFunc4.AddPoint(180.0, 0.0); + opacityFunc4.AddPoint(255.0, 0.1); + + # Color transfer functions + color1 = vtk.vtkColorTransferFunction() + color1.AddRGBPoint(0.0, 1.0, 0.0, 0.0); + color1.AddRGBPoint(60.0, 1.0, 0.0, 0.0); + + color2 = vtk.vtkColorTransferFunction() + color2.AddRGBPoint(60.0, 0.0, 0.0, 1.0); + color2.AddRGBPoint(120.0, 0.0, 0.0, 1.0); + + color3 = vtk.vtkColorTransferFunction() + color3.AddRGBPoint(120.0, 0.0, 1.0, 0.0); + color3.AddRGBPoint(180.0, 0.0, 1.0, 0.0); + + color4 = vtk.vtkColorTransferFunction() + color4.AddRGBPoint(180.0, 0.0, 0.0, 0.0); + color4.AddRGBPoint(239.0, 0.0, 0.0, 0.0); + + # Now set the opacity and the color + volumeProperty = volume.GetProperty() + volumeProperty.SetIndependentComponents(1) + volumeProperty.SetScalarOpacity(0, opacityFunc1) + volumeProperty.SetScalarOpacity(1, opacityFunc2) + volumeProperty.SetScalarOpacity(2, opacityFunc3) + volumeProperty.SetScalarOpacity(3, opacityFunc4) + volumeProperty.SetColor(0, color1) + volumeProperty.SetColor(1, color2) + volumeProperty.SetColor(2, color3) + volumeProperty.SetColor(3, color4) + + iRen.Initialize(); + ren.SetBackground(0.1,0.4,0.2) + ren.ResetCamera() + renWin.Render() + + img_file = "TestGPURayCastIndependentComponent.png" + vtk.test.Testing.compareImage( + iRen.GetRenderWindow(), vtk.test.Testing.getAbsImagePath(img_file), threshold=10) + vtk.test.Testing.interact() + +if __name__ == "__main__": + vtk.test.Testing.main([(TestGPURayCastIndependentComponent, 'test')]) diff --git a/Rendering/Volume/vtkGPUVolumeRayCastMapper.cxx b/Rendering/Volume/vtkGPUVolumeRayCastMapper.cxx index c8e66d6e066..c696ca079c0 100644 --- a/Rendering/Volume/vtkGPUVolumeRayCastMapper.cxx +++ b/Rendering/Volume/vtkGPUVolumeRayCastMapper.cxx @@ -374,10 +374,9 @@ int vtkGPUVolumeRayCastMapper::ValidateRender(vtkRenderer *ren, int numberOfComponents = 0; if ( goodSoFar ) { - numberOfComponents=scalars->GetNumberOfComponents(); - if( !( numberOfComponents==1 || - (numberOfComponents==4 && - vol->GetProperty()->GetIndependentComponents()==0))) + numberOfComponents = scalars->GetNumberOfComponents(); + if( !(numberOfComponents ==1 || + numberOfComponents == 4) ) { goodSoFar = 0; vtkErrorMacro(<< "Only one component scalars, or four " diff --git a/Rendering/VolumeOpenGL2/shaders/raycasterfs.glsl b/Rendering/VolumeOpenGL2/shaders/raycasterfs.glsl index 4cf4c739e27..aaa6a281df1 100644 --- a/Rendering/VolumeOpenGL2/shaders/raycasterfs.glsl +++ b/Rendering/VolumeOpenGL2/shaders/raycasterfs.glsl @@ -34,7 +34,7 @@ varying vec3 ip_vertexPos; /// ////////////////////////////////////////////////////////////////////////////// -vec4 g_fragColor; +vec4 g_fragColor = vec4(0.0); ////////////////////////////////////////////////////////////////////////////// /// diff --git a/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.cxx b/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.cxx index 5925b747fa0..a76a20367a3 100644 --- a/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.cxx +++ b/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.cxx @@ -15,9 +15,9 @@ #include "vtkOpenGLGPUVolumeRayCastMapper.h" -#include "vtkOpenGLGradientOpacityTable.h" -#include "vtkOpenGLOpacityTable.h" -#include "vtkOpenGLRGBTable.h" +#include "vtkOpenGLVolumeGradientOpacityTable.h" +#include "vtkOpenGLVolumeOpacityTable.h" +#include "vtkOpenGLVolumeRGBTable.h" #include "vtkVolumeShaderComposer.h" #include "vtkVolumeStateRAII.h" @@ -97,7 +97,7 @@ class vtkOpenGLGPUVolumeRayCastMapper::vtkInternal this->DepthTextureObject = 0; this->TextureWidth = 1024; this->ActualSampleDistance = 1.0; - this->RGBTable = 0; + this->RGBTables = 0; this->OpacityTables = 0; this->Mask1RGBTable = 0; this->Mask2RGBTable = 0; @@ -125,10 +125,10 @@ class vtkOpenGLGPUVolumeRayCastMapper::vtkInternal //-------------------------------------------------------------------------- ~vtkInternal() { - if (this->RGBTable) + if (this->RGBTables) { - delete this->RGBTable; - this->RGBTable = 0; + delete this->RGBTables; + this->RGBTables = 0; } if(this->Mask1RGBTable!=0) @@ -198,7 +198,7 @@ class vtkOpenGLGPUVolumeRayCastMapper::vtkInternal static void ToFloat(const T& in1, const T& in2, const T& in3, float (&out)[3]); template - static void ToFloat(T* in, float* out, int numberOfComponents); + static void ToFloat(T* in, float* out, int noOfComponents); template static void ToFloat(T (&in)[3], float (&out)[3]); template @@ -208,7 +208,8 @@ class vtkOpenGLGPUVolumeRayCastMapper::vtkInternal static void VtkToGlMatrix(vtkMatrix4x4* in, float (&out)[16], int row = 4, int col = 4); - void Initialize(vtkRenderer* ren, vtkVolume* vol); + void Initialize(vtkRenderer* ren, vtkVolume* vol, + int noOfComponents, int independentComponents); bool LoadVolume(vtkRenderer* ren, vtkImageData* imageData, vtkDataArray* scalars); @@ -223,22 +224,23 @@ class vtkOpenGLGPUVolumeRayCastMapper::vtkInternal // Update transfer color function based on the incoming inputs and number of // scalar components. - // TODO Deal with numberOfScalarComponents > 1 + // TODO Deal with noOfComponents > 1 int UpdateColorTransferFunction(vtkRenderer* ren, vtkVolume* vol, - int numberOfScalarComponents); + int noOfComponents, + unsigned int component); // Update opacity transfer function (not gradient opacity) int UpdateOpacityTransferFunction(vtkRenderer* ren, vtkVolume* vol, - int numberOfScalarComponents, - unsigned int level); + int noOfComponents, + unsigned int component); // Update gradient opacity function int UpdateGradientOpacityTransferFunction(vtkRenderer* ren, vtkVolume* vol, - int numberOfScalarComponents, - unsigned int level); + int noOfComponents, + unsigned int component); // Update noise texture (used to reduce rendering artifacts // specifically banding effects) @@ -324,11 +326,11 @@ class vtkOpenGLGPUVolumeRayCastMapper::vtkInternal std::ostringstream ExtensionsStringStream; - vtkOpenGLRGBTable* RGBTable; - vtkOpenGLOpacityTables* OpacityTables; - vtkOpenGLRGBTable* Mask1RGBTable; - vtkOpenGLRGBTable* Mask2RGBTable; - vtkOpenGLGradientOpacityTables* GradientOpacityTables; + vtkOpenGLVolumeRGBTables* RGBTables; + vtkOpenGLVolumeOpacityTables* OpacityTables; + vtkOpenGLVolumeRGBTable* Mask1RGBTable; + vtkOpenGLVolumeRGBTable* Mask2RGBTable; + vtkOpenGLVolumeGradientOpacityTables* GradientOpacityTables; vtkTimeStamp ShaderBuildTime; @@ -373,9 +375,9 @@ void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::ToFloat( //---------------------------------------------------------------------------- template void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::ToFloat( - T* in, float* out, int numberOfComponents) + T* in, float* out, int noOfComponents) { - for (int i = 0; i < numberOfComponents; ++i) + for (int i = 0; i < noOfComponents; ++i) { out[i] = static_cast(in[i]); } @@ -423,7 +425,8 @@ void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::VtkToGlMatrix( //---------------------------------------------------------------------------- void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::Initialize( - vtkRenderer* vtkNotUsed(ren), vtkVolume* vtkNotUsed(vol)) + vtkRenderer* vtkNotUsed(ren), vtkVolume* vol, int + noOfComponents, int independentComponents) { GLenum err = glewInit(); if (GLEW_OK != err) @@ -435,25 +438,53 @@ void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::Initialize( err = glGetError(); // Create RGB lookup table - this->RGBTable = new vtkOpenGLRGBTable(); + if (noOfComponents > 1 && independentComponents) + { + this->RGBTables = new vtkOpenGLVolumeRGBTables(noOfComponents); + } + else + { + this->RGBTables = new vtkOpenGLVolumeRGBTables(1); + } if (this->Parent->MaskInput != 0 && this->Parent->MaskType == LabelMapMaskType) { if(this->Mask1RGBTable == 0) { - this->Mask1RGBTable = new vtkOpenGLRGBTable(); + this->Mask1RGBTable = new vtkOpenGLVolumeRGBTable(); } if(this->Mask2RGBTable == 0) { - this->Mask2RGBTable = new vtkOpenGLRGBTable(); + this->Mask2RGBTable = new vtkOpenGLVolumeRGBTable(); } } - // TODO Currently we are supporting only one level - // Create opacity lookup table - this->OpacityTables = new vtkOpenGLOpacityTables(1); + // We support upto four components + if (noOfComponents > 1 && independentComponents) + { + this->OpacityTables = new vtkOpenGLVolumeOpacityTables(noOfComponents); + } + else + { + this->OpacityTables = new vtkOpenGLVolumeOpacityTables(1); + } + + if (noOfComponents > 1 && independentComponents) + { + // Assuming that all four components has gradient opacity for now + this->GradientOpacityTables = + new vtkOpenGLVolumeGradientOpacityTables(noOfComponents); + } + else + { + if (vol->GetProperty()->HasGradientOpacity()) + { + this->GradientOpacityTables = + new vtkOpenGLVolumeGradientOpacityTables(1); + } + } this->Initialized = true; } @@ -844,32 +875,34 @@ void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::ComputeBounds( //---------------------------------------------------------------------------- int vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::UpdateColorTransferFunction( - vtkRenderer* ren, vtkVolume* vol, int numberOfScalarComponents) + vtkRenderer* ren, vtkVolume* vol, int vtkNotUsed(noOfComponents), + unsigned int component) { + // Volume property cannot be null. + vtkVolumeProperty* volumeProperty = vol->GetProperty(); + // Build the colormap in a 1D texture. // 1D RGB-texture=mapping from scalar values to color values // build the table. - if(numberOfScalarComponents == 1) + vtkColorTransferFunction* colorTransferFunction = + volumeProperty->GetRGBTransferFunction(component); + + // Add points only if its not being added before + if (colorTransferFunction->GetSize() < 1) { - vtkVolumeProperty* volumeProperty = vol->GetProperty(); - vtkColorTransferFunction* colorTransferFunction = - volumeProperty->GetRGBTransferFunction(0); + colorTransferFunction->AddRGBPoint(this->ScalarsRange[0], 0.0, 0.0, 0.0); + colorTransferFunction->AddRGBPoint(this->ScalarsRange[1], 1.0, 1.0, 1.0); + } - // Add points only if its not being added before - if (colorTransferFunction->GetSize() < 1) - { - colorTransferFunction->AddRGBPoint(this->ScalarsRange[0], 0.0, 0.0, 0.0); - colorTransferFunction->AddRGBPoint(this->ScalarsRange[1], 1.0, 1.0, 1.0); - } + int filterVal = + volumeProperty->GetInterpolationType() == VTK_LINEAR_INTERPOLATION ? + vtkTextureObject::Linear : vtkTextureObject::Nearest; - int filterVal = - volumeProperty->GetInterpolationType() == VTK_LINEAR_INTERPOLATION ? - vtkTextureObject::Linear : vtkTextureObject::Nearest; - this->RGBTable->Update( - colorTransferFunction, this->ScalarsRange, - filterVal, - vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow())); - } + this->RGBTables->GetTable(component)->Update( + volumeProperty->GetRGBTransferFunction(component), + this->ScalarsRange, + filterVal, + vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow())); if (this->Parent->MaskInput != 0 && this->Parent->MaskType == LabelMapMaskType) @@ -895,20 +928,18 @@ int vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::UpdateColorTransferFunction( //---------------------------------------------------------------------------- int vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::UpdateOpacityTransferFunction( - vtkRenderer* ren, vtkVolume* vol, int vtkNotUsed(numberOfScalarComponents), - unsigned int level) + vtkRenderer* ren, vtkVolume* vol, int vtkNotUsed(noOfComponents), + unsigned int component) { if (!vol) { - std::cerr << "Invalid in_volume" << std::endl; return 1; } vtkVolumeProperty* volumeProperty = vol->GetProperty(); - vtkPiecewiseFunction* scalarOpacity = volumeProperty->GetScalarOpacity(); + vtkPiecewiseFunction* scalarOpacity = + volumeProperty->GetScalarOpacity(component); - // TODO: Do a better job to create the default opacity map - // Add points only if its not being added before if (scalarOpacity->GetSize() < 1) { scalarOpacity->AddPoint(this->ScalarsRange[0], 0.0); @@ -919,11 +950,11 @@ int vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::UpdateOpacityTransferFunction( volumeProperty->GetInterpolationType() == VTK_LINEAR_INTERPOLATION ? vtkTextureObject::Linear : vtkTextureObject::Nearest; - this->OpacityTables->GetTable(level)->Update( + this->OpacityTables->GetTable(component)->Update( scalarOpacity,this->Parent->BlendMode, this->ActualSampleDistance, this->ScalarsRange, - volumeProperty->GetScalarOpacityUnitDistance(), + volumeProperty->GetScalarOpacityUnitDistance(component), filterVal, vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow())); @@ -933,7 +964,7 @@ int vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::UpdateOpacityTransferFunction( //---------------------------------------------------------------------------- int vtkOpenGLGPUVolumeRayCastMapper::vtkInternal:: UpdateGradientOpacityTransferFunction(vtkRenderer* ren, vtkVolume* vol, - int vtkNotUsed(numberOfScalarComponents), unsigned int level) + int vtkNotUsed(noOfComponents), unsigned int component) { if (!vol) { @@ -942,22 +973,18 @@ int vtkOpenGLGPUVolumeRayCastMapper::vtkInternal:: vtkVolumeProperty* volumeProperty = vol->GetProperty(); - // TODO Currently checking on index 0 only - if (!volumeProperty->HasGradientOpacity()) + // TODO Currently we expect the all of the tables will + // be initialized once and if at that time, the gradient + // opacity was not enabled then it is not used later. + if (!volumeProperty->HasGradientOpacity(component) || + !this->GradientOpacityTables) { return 1; } - vtkPiecewiseFunction* gradientOpacity = volumeProperty->GetGradientOpacity(); - - if (!this->GradientOpacityTables && gradientOpacity) - { - // NOTE Handling only one component - this->GradientOpacityTables = new vtkOpenGLGradientOpacityTables(1); - } + vtkPiecewiseFunction* gradientOpacity = + volumeProperty->GetGradientOpacity(component); - // TODO: Do a better job to create the default opacity map - // Add points only if its not being added before if (gradientOpacity->GetSize() < 1) { gradientOpacity->AddPoint(this->ScalarsRange[0], 0.0); @@ -968,7 +995,7 @@ int vtkOpenGLGPUVolumeRayCastMapper::vtkInternal:: volumeProperty->GetInterpolationType() == VTK_LINEAR_INTERPOLATION ? vtkTextureObject::Linear : vtkTextureObject::Nearest; - this->GradientOpacityTables->GetTable(level)->Update( + this->GradientOpacityTables->GetTable(component)->Update( gradientOpacity, this->ActualSampleDistance, this->ScalarsRange, @@ -981,7 +1008,7 @@ int vtkOpenGLGPUVolumeRayCastMapper::vtkInternal:: //---------------------------------------------------------------------------- void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::UpdateNoiseTexture( - vtkRenderer* ren) + vtkRenderer* ren) { if (!this->NoiseTextureObject) { @@ -1769,11 +1796,11 @@ void vtkOpenGLGPUVolumeRayCastMapper::ReleaseGraphicsResources( } } - if(this->Impl->RGBTable) + if(this->Impl->RGBTables) { - this->Impl->RGBTable->ReleaseGraphicsResources(window); - delete this->Impl->RGBTable; - this->Impl->RGBTable = 0; + this->Impl->RGBTables->ReleaseGraphicsResources(window); + delete this->Impl->RGBTables; + this->Impl->RGBTables = 0; } if(this->Impl->Mask1RGBTable) @@ -1813,7 +1840,11 @@ void vtkOpenGLGPUVolumeRayCastMapper::BuildShader(vtkRenderer* ren, std::string vertexShader (raycastervs); std::string fragmentShader (raycasterfs); - if (vol->GetProperty()->GetShade()) + // Every volume should have a property (cannot be NULL); + vtkVolumeProperty* volumeProperty = vol->GetProperty(); + int independentComponents = volumeProperty->GetIndependentComponents(); + + if (volumeProperty->GetShade()) { vtkLightCollection* lc = ren->GetLights(); vtkLight* light; @@ -1848,104 +1879,259 @@ void vtkOpenGLGPUVolumeRayCastMapper::BuildShader(vtkRenderer* ren, } } - vertexShader = vtkvolume::replace(vertexShader, "//VTK::ComputeClipPos::Impl", - vtkvolume::ComputeClip(ren, this, vol), true); - vertexShader = vtkvolume::replace(vertexShader, "//VTK::ComputeTextureCoords::Impl", - vtkvolume::ComputeTextureCoords(ren, this, vol), true); - - vertexShader = vtkvolume::replace(vertexShader, "//VTK::Base::Dec", - vtkvolume::BaseGlobalsVert(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Base::Dec", + // Base methods replacements + //-------------------------------------------------------------------------- + vertexShader = vtkvolume::replace( + vertexShader, + "//VTK::ComputeClipPos::Impl", + vtkvolume::ComputeClip(ren, this, vol), + true); + + vertexShader = vtkvolume::replace( + vertexShader, + "//VTK::ComputeTextureCoords::Impl", + vtkvolume::ComputeTextureCoords(ren, this, vol), + true); + + vertexShader = vtkvolume::replace( + vertexShader, + "//VTK::Base::Dec", + vtkvolume::BaseGlobalsVert(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Base::Dec", vtkvolume::BaseGlobalsFrag(ren, this, vol, this->Impl->NumberOfLights, - this->Impl->LightComplexity), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Base::Init", - vtkvolume::BaseInit(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Base::Impl", - vtkvolume::BaseIncrement(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Base::Exit", - vtkvolume::BaseExit(ren, this, vol), true); - - vertexShader = vtkvolume::replace(vertexShader, "//VTK::Termination::Dec", - vtkvolume::TerminationGlobalsVert(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Termination::Dec", - vtkvolume::TerminationGlobalsFrag(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Terminate::Init", - vtkvolume::TerminationInit(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Terminate::Impl", - vtkvolume::TerminationIncrement(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Terminate::Exit", - vtkvolume::TerminationExit(ren, this, vol), true); - - vertexShader = vtkvolume::replace(vertexShader, "//VTK::Shading::Dec", - vtkvolume::ShadingGlobalsVert(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Shading::Dec", - vtkvolume::ShadingGlobalsFrag(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Shading::Init", - vtkvolume::ShadingInit(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Shading::Impl", + this->Impl->LightComplexity, noOfComponents, + independentComponents), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Base::Init", + vtkvolume::BaseInit(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Base::Impl", + vtkvolume::BaseIncrement(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Base::Exit", + vtkvolume::BaseExit(ren, this, vol), + true); + + // Termination methods replacements + //-------------------------------------------------------------------------- + vertexShader = vtkvolume::replace( + vertexShader, + "//VTK::Termination::Dec", + vtkvolume::TerminationGlobalsVert(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Termination::Dec", + vtkvolume::TerminationGlobalsFrag(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Terminate::Init", + vtkvolume::TerminationInit(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Terminate::Impl", + vtkvolume::TerminationIncrement(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Terminate::Exit", + vtkvolume::TerminationExit(ren, this, vol), + true); + + // Shading methods replacements + //-------------------------------------------------------------------------- + vertexShader = vtkvolume::replace( + vertexShader, + "//VTK::Shading::Dec", + vtkvolume::ShadingGlobalsVert(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Shading::Dec", + vtkvolume::ShadingGlobalsFrag(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Shading::Init", + vtkvolume::ShadingInit(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Shading::Impl", vtkvolume::ShadingIncrement(ren, this, vol, this->MaskInput, this->Impl->CurrentMask, - this->MaskType, noOfComponents), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Shading::Exit", - vtkvolume::ShadingExit(ren, this, vol), true); - - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::ComputeOpacity::Dec", - vtkvolume::OpacityTransferFunc(ren, this, vol, noOfComponents), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::ComputeGradient::Dec", - vtkvolume::GradientsComputeFunc(ren, this, vol, noOfComponents), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::ColorTransferFunc::Dec", - vtkvolume::ColorTransferFunc(ren, this, vol, noOfComponents), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::ComputeLighting::Dec", + this->MaskType, noOfComponents, + independentComponents), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Shading::Exit", + vtkvolume::ShadingExit(ren, this, vol, noOfComponents, + independentComponents), + true); + + + // Compute methods replacements + //-------------------------------------------------------------------------- + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::ComputeOpacity::Dec", + vtkvolume::OpacityTransferFunc(ren, this, vol, noOfComponents, + independentComponents), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::ComputeGradient::Dec", + vtkvolume::GradientsComputeFunc(ren, this, vol, noOfComponents, + independentComponents), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::ColorTransferFunc::Dec", + vtkvolume::ColorTransferFunc(ren, this, vol, noOfComponents, + independentComponents), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::ComputeLighting::Dec", vtkvolume::LightComputeFunc(ren, this, vol, noOfComponents, + independentComponents, this->Impl->NumberOfLights, - this->Impl->LightComplexity), true); - fragmentShader = vtkvolume::replace(fragmentShader, - "//VTK::RayDirectionFunc::Dec", - vtkvolume::RayDirectionFunc(ren, this, vol,noOfComponents), true); - - vertexShader = vtkvolume::replace(vertexShader, "//VTK::Cropping::Dec", - vtkvolume::CroppingGlobalsVert(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Cropping::Dec", - vtkvolume::CroppingGlobalsFrag(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Cropping::Init", - vtkvolume::CroppingInit(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Cropping::Impl", - vtkvolume::CroppingIncrement(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Cropping::Exit", - vtkvolume::CroppingExit(ren, this, vol), true); - - vertexShader = vtkvolume::replace(vertexShader, "//VTK::Clipping::Dec", - vtkvolume::ClippingGlobalsVert(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Clipping::Dec", - vtkvolume::ClippingGlobalsFrag(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Clipping::Init", - vtkvolume::ClippingInit(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Clipping::Impl", - vtkvolume::ClippingIncrement(ren, this, vol), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::Clipping::Exit", - vtkvolume::ClippingExit(ren, this, vol), true); - - fragmentShader = vtkvolume::replace(fragmentShader, - "//VTK::BinaryMask::Dec", + this->Impl->LightComplexity), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::RayDirectionFunc::Dec", + vtkvolume::RayDirectionFunc(ren, this, vol,noOfComponents), + true); + + // Cropping methods replacements + //-------------------------------------------------------------------------- + vertexShader = vtkvolume::replace( + vertexShader, + "//VTK::Cropping::Dec", + vtkvolume::CroppingGlobalsVert(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Cropping::Dec", + vtkvolume::CroppingGlobalsFrag(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Cropping::Init", + vtkvolume::CroppingInit(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Cropping::Impl", + vtkvolume::CroppingIncrement(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Cropping::Exit", + vtkvolume::CroppingExit(ren, this, vol), + true); + + // Clipping methods replacements + //-------------------------------------------------------------------------- + vertexShader = vtkvolume::replace( + vertexShader, + "//VTK::Clipping::Dec", + vtkvolume::ClippingGlobalsVert(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Clipping::Dec", + vtkvolume::ClippingGlobalsFrag(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Clipping::Init", + vtkvolume::ClippingInit(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Clipping::Impl", + vtkvolume::ClippingIncrement(ren, this, vol), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::Clipping::Exit", + vtkvolume::ClippingExit(ren, this, vol), + true); + + // Masking methods replacements + //-------------------------------------------------------------------------- + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::BinaryMask::Dec", vtkvolume::BinaryMaskGlobalsFrag(ren, this, vol, this->MaskInput, this->Impl->CurrentMask, - this->MaskType), true); - fragmentShader = vtkvolume::replace(fragmentShader, "//VTK::BinaryMask::Impl", + this->MaskType), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::BinaryMask::Impl", vtkvolume::BinaryMaskIncrement(ren, this, vol, this->MaskInput, this->Impl->CurrentMask, - this->MaskType), true); + this->MaskType), + true); - fragmentShader = vtkvolume::replace(fragmentShader, - "//VTK::CompositeMask::Dec", + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::CompositeMask::Dec", vtkvolume::CompositeMaskGlobalsFrag(ren, this, vol, this->MaskInput, this->Impl->CurrentMask, - this->MaskType), true); - fragmentShader = vtkvolume::replace(fragmentShader, - "//VTK::CompositeMask::Impl", + this->MaskType), + true); + + fragmentShader = vtkvolume::replace( + fragmentShader, + "//VTK::CompositeMask::Impl", vtkvolume::CompositeMaskIncrement(ren, this, vol, this->MaskInput, this->Impl->CurrentMask, - this->MaskType), true); + this->MaskType), + true); + // Now compile the shader + //-------------------------------------------------------------------------- this->Impl->ShaderProgram = this->Impl->ShaderCache->ReadyShader( vertexShader.c_str(), fragmentShader.c_str(), ""); if (!this->Impl->ShaderProgram->GetCompiled()) @@ -2044,15 +2230,14 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren, // Update in_volume first to make sure states are current vol->Update(); + // Get the input vtkImageData* input = this->GetTransformedInput(); - // Set OpenGL states - vtkVolumeStateRAII glState; + // Get the volume property (must have one) + vtkVolumeProperty* volumeProperty = vol->GetProperty(); - if (!this->Impl->IsInitialized()) - { - this->Impl->Initialize(ren, vol); - } + // Check whether we have independent components or not + int independentComponents = volumeProperty->GetIndependentComponents(); vtkDataArray* scalars = this->GetScalars(input, this->ScalarMode, @@ -2062,10 +2247,19 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren, this->CellFlag); // How many components are there? - int numberOfScalarComponents = scalars->GetNumberOfComponents(); + int noOfComponents = scalars->GetNumberOfComponents(); + + // Set OpenGL states + vtkVolumeStateRAII glState; + + if (!this->Impl->IsInitialized()) + { + this->Impl->Initialize(ren, vol, noOfComponents, + independentComponents); + } // If it is just one, then get the range from the scalars - if(numberOfScalarComponents == 1) + if(noOfComponents == 1) { // NOTE: here, we ignore the blank cells. scalars->GetRange(this->Impl->ScalarsRange); @@ -2128,7 +2322,7 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren, vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow()); this->Impl->ShaderCache = renWin->GetShaderCache(); - if (vol->GetProperty()->GetMTime() > + if (volumeProperty->GetMTime() > this->Impl->ShaderBuildTime.GetMTime() || this->GetMTime() > this->Impl->ShaderBuildTime.GetMTime() || ren->GetActiveCamera()->GetParallelProjection() != @@ -2136,7 +2330,7 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren, { this->Impl->LastProjectionParallel = ren->GetActiveCamera()->GetParallelProjection(); - this->BuildShader(ren, vol, numberOfScalarComponents); + this->BuildShader(ren, vol, noOfComponents); } // Bind the shader @@ -2148,16 +2342,19 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren, this->Impl->UpdateVolumeGeometry(ren, vol, input); // Update opacity transfer function - // TODO Passing level 0 for now - this->Impl->UpdateOpacityTransferFunction(ren, vol, - scalars->GetNumberOfComponents(), 0); + for (int i = 0; i < (independentComponents ? + noOfComponents : 1); ++i) + { + this->Impl->UpdateOpacityTransferFunction(ren, vol, + scalars->GetNumberOfComponents(), i); - this->Impl->UpdateGradientOpacityTransferFunction(ren, vol, - scalars->GetNumberOfComponents(), 0); + this->Impl->UpdateGradientOpacityTransferFunction(ren, vol, + scalars->GetNumberOfComponents(), i); - // Update transfer color functions - this->Impl->UpdateColorTransferFunction(ren, vol, - scalars->GetNumberOfComponents()); + // Update transfer color functions + this->Impl->UpdateColorTransferFunction(ren, vol, + scalars->GetNumberOfComponents(), i); + } // Update noise sampler texture this->Impl->UpdateNoiseTexture(ren); @@ -2172,6 +2369,7 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren, // Temporary variables float fvalue2[2]; float fvalue3[3]; + float fvalue4[4]; float fvalue16[16]; // Update sampling distance @@ -2208,6 +2406,12 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren, } // Pass constant uniforms at initialization + this->Impl->ShaderProgram->SetUniformi("in_noOfComponents", + noOfComponents); + this->Impl->ShaderProgram->SetUniformi("in_independentComponents", + independentComponents); + + // Step should be dependant on the bounds and not on the texture size // since we can have non uniform voxel size / spacing / aspect ratio vtkInternal::ToFloat(this->Impl->CellStep, fvalue3); @@ -2230,10 +2434,48 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren, this->Impl->ShaderProgram->SetUniformi("in_volume", this->Impl->VolumeTextureObject->GetTextureUnit()); - // TODO Supports only one table for now - this->Impl->OpacityTables->GetTable(0)->Bind(); - this->Impl->ShaderProgram->SetUniformi("in_opacityTransferFunc", - this->Impl->OpacityTables->GetTable(0)->GetTextureUnit()); + // Opacity, color, and gradient opacity samplers / textures + int opacitySamplers[4]; + int colorSamplers[4]; + int gradientOpacitySamplers[4]; + int numberOfSamplers = (independentComponents ? noOfComponents : 1); + for (int i = 0; i < numberOfSamplers; ++i) + { + this->Impl->OpacityTables->GetTable(i)->Bind(); + opacitySamplers[i] = + this->Impl->OpacityTables->GetTable(i)->GetTextureUnit(); + + if (this->BlendMode != vtkGPUVolumeRayCastMapper::ADDITIVE_BLEND) + { + this->Impl->RGBTables->GetTable(i)->Bind(); + colorSamplers[i] = + this->Impl->RGBTables->GetTable(i)->GetTextureUnit(); + } + + if (this->Impl->GradientOpacityTables) + { + gradientOpacitySamplers[i] = + this->Impl->GradientOpacityTables->GetTable(i)->GetTextureUnit(); + } + } + + this->Impl->ShaderProgram->SetUniform1iv("in_opacityTransferFunc", + numberOfSamplers, opacitySamplers); + vtkOpenGLCheckErrorMacro("failed at glBindTexture"); + + if (this->BlendMode != vtkGPUVolumeRayCastMapper::ADDITIVE_BLEND) + { + this->Impl->ShaderProgram->SetUniform1iv("in_colorTransferFunc", + numberOfSamplers, colorSamplers); + vtkOpenGLCheckErrorMacro("failed at glBindTexture"); + } + + if (this->Impl->GradientOpacityTables) + { + this->Impl->ShaderProgram->SetUniform1iv("in_gradientTransferFunc", + numberOfSamplers, gradientOpacitySamplers); + vtkOpenGLCheckErrorMacro("failed at glBindTexture"); + } this->Impl->NoiseTextureObject->Activate(); this->Impl->ShaderProgram->SetUniformi("in_noiseSampler", @@ -2243,12 +2485,6 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren, this->Impl->ShaderProgram->SetUniformi("in_depthSampler", this->Impl->DepthTextureObject->GetTextureUnit()); - if (this->Impl->GradientOpacityTables) - { - this->Impl->ShaderProgram->SetUniformi("in_gradientTransferFunc", - this->Impl->GradientOpacityTables->GetTable(0)->GetTextureUnit()); - } - if (this->Impl->CurrentMask) { this->Impl->CurrentMask->Bind(); @@ -2256,13 +2492,9 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren, "in_mask", this->Impl->CurrentMask->GetTextureUnit()); } - if(numberOfScalarComponents == 1 && - this->BlendMode!=vtkGPUVolumeRayCastMapper::ADDITIVE_BLEND) + if(noOfComponents == 1 && + this->BlendMode != vtkGPUVolumeRayCastMapper::ADDITIVE_BLEND) { - this->Impl->RGBTable->Bind(); - this->Impl->ShaderProgram->SetUniformi("in_colorTransferFunc", - this->Impl->RGBTable->GetTextureUnit()); - if (this->MaskInput != 0 && this->MaskType == LabelMapMaskType) { this->Impl->Mask1RGBTable->Bind(); @@ -2277,16 +2509,16 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren, } } - fvalue3[0] = fvalue3[1] = fvalue3[2] = vol->GetProperty()->GetAmbient(); + fvalue3[0] = fvalue3[1] = fvalue3[2] = volumeProperty->GetAmbient(); this->Impl->ShaderProgram->SetUniform3f("in_ambient", fvalue3); - fvalue3[0] = fvalue3[1] = fvalue3[2] = vol->GetProperty()->GetDiffuse(); + fvalue3[0] = fvalue3[1] = fvalue3[2] = volumeProperty->GetDiffuse(); this->Impl->ShaderProgram->SetUniform3f("in_diffuse", fvalue3); - fvalue3[0] = fvalue3[1] = fvalue3[2] = vol->GetProperty()->GetSpecular(); + fvalue3[0] = fvalue3[1] = fvalue3[2] = volumeProperty->GetSpecular(); this->Impl->ShaderProgram->SetUniform3f("in_specular", fvalue3); - fvalue3[0] = vol->GetProperty()->GetSpecularPower(); + fvalue3[0] = volumeProperty->GetSpecularPower(); this->Impl->ShaderProgram->SetUniformf("in_shininess", fvalue3[0]); // Look at the OpenGL Camera for the exact aspect computation @@ -2436,6 +2668,15 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren, this->Impl->ShaderProgram->SetUniformf("in_bias", (0.5 - (this->FinalColorLevel/this->FinalColorWindow))); + if (noOfComponents > 1 && independentComponents) + { + for (int i = 0; i < noOfComponents; ++i) + { + fvalue4[i] = static_cast(volumeProperty->GetComponentWeight(i)); + } + this->Impl->ShaderProgram->SetUniform4fv("in_componentWeight", 1, &fvalue4); + } + #ifndef __APPLE__ glBindVertexArray(this->Impl->CubeVAOId); #endif diff --git a/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.h b/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.h index aebd68a0201..26d5c9565cd 100644 --- a/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.h +++ b/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.h @@ -49,7 +49,7 @@ class VTKRENDERINGVOLUMEOPENGL2_EXPORT vtkOpenGLGPUVolumeRayCastMapper : vtkVolume *vtkNotUsed(vol), double vtkNotUsed(datasetBounds)[6], double vtkNotUsed(scalarRange)[2], - int vtkNotUsed(numberOfScalarComponents), + int vtkNotUsed(noOfComponents), unsigned int vtkNotUsed(numberOfLevels)) {} // \pre input is up-to-date @@ -58,7 +58,7 @@ class VTKRENDERINGVOLUMEOPENGL2_EXPORT vtkOpenGLGPUVolumeRayCastMapper : unsigned int vtkNotUsed(level)) {} virtual void PostRender(vtkRenderer *vtkNotUsed(ren), - int vtkNotUsed(numberOfScalarComponents)) {} + int vtkNotUsed(noOfComponents)) {} // Description: // Rendering volume on GPU diff --git a/Rendering/VolumeOpenGL2/vtkOpenGLGradientOpacityTable.h b/Rendering/VolumeOpenGL2/vtkOpenGLVolumeGradientOpacityTable.h similarity index 81% rename from Rendering/VolumeOpenGL2/vtkOpenGLGradientOpacityTable.h rename to Rendering/VolumeOpenGL2/vtkOpenGLVolumeGradientOpacityTable.h index a6c69ec0da1..8ccca5a0c64 100644 --- a/Rendering/VolumeOpenGL2/vtkOpenGLGradientOpacityTable.h +++ b/Rendering/VolumeOpenGL2/vtkOpenGLVolumeGradientOpacityTable.h @@ -1,7 +1,7 @@ /*========================================================================= Program: Visualization Toolkit - Module: vtkOpenGLGradientOpacityTable.h + Module: vtkOpenGLVolumeGradientOpacityTable.h Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. @@ -13,8 +13,8 @@ =========================================================================*/ -#ifndef vtkOpenGLGradientOpacityTable_h_ -#define vtkOpenGLGradientOpacityTable_h_ +#ifndef vtkOpenGLVolumeGradientOpacityTable_h_ +#define vtkOpenGLVolumeGradientOpacityTable_h_ #include #include @@ -23,11 +23,11 @@ #include //---------------------------------------------------------------------------- -class vtkOpenGLGradientOpacityTable +class vtkOpenGLVolumeGradientOpacityTable { public: //-------------------------------------------------------------------------- - vtkOpenGLGradientOpacityTable(int width = 1024) + vtkOpenGLVolumeGradientOpacityTable(int width = 1024) { this->TextureObject = 0; this->TextureWidth = width; @@ -38,7 +38,7 @@ class vtkOpenGLGradientOpacityTable } //-------------------------------------------------------------------------- - ~vtkOpenGLGradientOpacityTable() + ~vtkOpenGLVolumeGradientOpacityTable() { if (this->TextureObject) { @@ -157,30 +157,30 @@ class vtkOpenGLGradientOpacityTable int LastInterpolation; double LastRange[2]; private: - vtkOpenGLGradientOpacityTable(const vtkOpenGLGradientOpacityTable&); - vtkOpenGLGradientOpacityTable& operator=(const vtkOpenGLGradientOpacityTable&); + vtkOpenGLVolumeGradientOpacityTable(const vtkOpenGLVolumeGradientOpacityTable&); + vtkOpenGLVolumeGradientOpacityTable& operator=(const vtkOpenGLVolumeGradientOpacityTable&); }; //----------------------------------------------------------------------------- -class vtkOpenGLGradientOpacityTables +class vtkOpenGLVolumeGradientOpacityTables { public: //-------------------------------------------------------------------------- - vtkOpenGLGradientOpacityTables(unsigned int numberOfTables) + vtkOpenGLVolumeGradientOpacityTables(unsigned int numberOfTables) { - this->Tables = new vtkOpenGLGradientOpacityTable[numberOfTables]; + this->Tables = new vtkOpenGLVolumeGradientOpacityTable[numberOfTables]; this->NumberOfTables = numberOfTables; } //-------------------------------------------------------------------------- - ~vtkOpenGLGradientOpacityTables() + ~vtkOpenGLVolumeGradientOpacityTables() { delete [] this->Tables; } // Get opacity table at a given index. //-------------------------------------------------------------------------- - vtkOpenGLGradientOpacityTable* GetTable(unsigned int i) + vtkOpenGLVolumeGradientOpacityTable* GetTable(unsigned int i) { if (i >= this->NumberOfTables) { @@ -206,17 +206,17 @@ class vtkOpenGLGradientOpacityTables } private: unsigned int NumberOfTables; - vtkOpenGLGradientOpacityTable* Tables; + vtkOpenGLVolumeGradientOpacityTable* Tables; - // vtkOpenGLGradientOpacityTables (Not implemented) - vtkOpenGLGradientOpacityTables(); + // vtkOpenGLVolumeGradientOpacityTables (Not implemented) + vtkOpenGLVolumeGradientOpacityTables(); - // vtkOpenGLGradientOpacityTables (Not implemented) - vtkOpenGLGradientOpacityTables(const vtkOpenGLGradientOpacityTables &other); + // vtkOpenGLVolumeGradientOpacityTables (Not implemented) + vtkOpenGLVolumeGradientOpacityTables(const vtkOpenGLVolumeGradientOpacityTables &other); // operator = (Not implemented) - vtkOpenGLGradientOpacityTables &operator=(const vtkOpenGLGradientOpacityTables &other); + vtkOpenGLVolumeGradientOpacityTables &operator=(const vtkOpenGLVolumeGradientOpacityTables &other); }; -#endif // vtkOpenGLGradientOpacityTable_h_ -// VTK-HeaderTest-Exclude: vtkOpenGLGradientOpacityTable.h +#endif // vtkOpenGLVolumeGradientOpacityTable_h_ +// VTK-HeaderTest-Exclude: vtkOpenGLVolumeGradientOpacityTable.h diff --git a/Rendering/VolumeOpenGL2/vtkOpenGLOpacityTable.h b/Rendering/VolumeOpenGL2/vtkOpenGLVolumeOpacityTable.h similarity index 88% rename from Rendering/VolumeOpenGL2/vtkOpenGLOpacityTable.h rename to Rendering/VolumeOpenGL2/vtkOpenGLVolumeOpacityTable.h index 67e678a42e5..6ddee1923ed 100644 --- a/Rendering/VolumeOpenGL2/vtkOpenGLOpacityTable.h +++ b/Rendering/VolumeOpenGL2/vtkOpenGLVolumeOpacityTable.h @@ -1,7 +1,7 @@ /*========================================================================= Program: Visualization Toolkit - Module: vtkOpenGLOpacityTable.h + Module: vtkOpenGLVolumeOpacityTable.h Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. @@ -23,11 +23,11 @@ #include //---------------------------------------------------------------------------- -class vtkOpenGLOpacityTable +class vtkOpenGLVolumeOpacityTable { public: //-------------------------------------------------------------------------- - vtkOpenGLOpacityTable(int width = 1024) + vtkOpenGLVolumeOpacityTable(int width = 1024) { this->TextureObject = 0; this->LastBlendMode = vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND; @@ -39,7 +39,7 @@ class vtkOpenGLOpacityTable } //-------------------------------------------------------------------------- - ~vtkOpenGLOpacityTable() + ~vtkOpenGLVolumeOpacityTable() { if (this->TextureObject) { @@ -199,30 +199,30 @@ class vtkOpenGLOpacityTable int LastInterpolation; double LastRange[2]; private: - vtkOpenGLOpacityTable(const vtkOpenGLOpacityTable&); - vtkOpenGLOpacityTable& operator=(const vtkOpenGLOpacityTable&); + vtkOpenGLVolumeOpacityTable(const vtkOpenGLVolumeOpacityTable&); + vtkOpenGLVolumeOpacityTable& operator=(const vtkOpenGLVolumeOpacityTable&); }; //---------------------------------------------------------------------------- -class vtkOpenGLOpacityTables +class vtkOpenGLVolumeOpacityTables { public: //-------------------------------------------------------------------------- - vtkOpenGLOpacityTables(unsigned int numberOfTables) + vtkOpenGLVolumeOpacityTables(unsigned int numberOfTables) { - this->Tables = new vtkOpenGLOpacityTable[numberOfTables]; + this->Tables = new vtkOpenGLVolumeOpacityTable[numberOfTables]; this->NumberOfTables = numberOfTables; } //-------------------------------------------------------------------------- - ~vtkOpenGLOpacityTables() + ~vtkOpenGLVolumeOpacityTables() { delete [] this->Tables; } // brief Get opacity table at a given index. //-------------------------------------------------------------------------- - vtkOpenGLOpacityTable* GetTable(unsigned int i) + vtkOpenGLVolumeOpacityTable* GetTable(unsigned int i) { if (i >= this->NumberOfTables) { @@ -249,17 +249,17 @@ class vtkOpenGLOpacityTables private: unsigned int NumberOfTables; - vtkOpenGLOpacityTable *Tables; + vtkOpenGLVolumeOpacityTable *Tables; - // vtkOpenGLOpacityTables (Not implemented) - vtkOpenGLOpacityTables(); + // vtkOpenGLVolumeOpacityTables (Not implemented) + vtkOpenGLVolumeOpacityTables(); - // vtkOpenGLOpacityTables (Not implemented) - vtkOpenGLOpacityTables(const vtkOpenGLOpacityTables &other); + // vtkOpenGLVolumeOpacityTables (Not implemented) + vtkOpenGLVolumeOpacityTables(const vtkOpenGLVolumeOpacityTables &other); // operator = (Not implemented) - vtkOpenGLOpacityTables &operator=(const vtkOpenGLOpacityTables &other); + vtkOpenGLVolumeOpacityTables &operator=(const vtkOpenGLVolumeOpacityTables &other); }; #endif // vtkOpenGLVolumeOpacityTable_h_ -// VTK-HeaderTest-Exclude: vtkOpenGLOpacityTable.h +// VTK-HeaderTest-Exclude: vtkOpenGLVolumeOpacityTable.h diff --git a/Rendering/VolumeOpenGL2/vtkOpenGLRGBTable.h b/Rendering/VolumeOpenGL2/vtkOpenGLVolumeRGBTable.h similarity index 68% rename from Rendering/VolumeOpenGL2/vtkOpenGLRGBTable.h rename to Rendering/VolumeOpenGL2/vtkOpenGLVolumeRGBTable.h index ae7022abefe..14e78948b8b 100644 --- a/Rendering/VolumeOpenGL2/vtkOpenGLRGBTable.h +++ b/Rendering/VolumeOpenGL2/vtkOpenGLVolumeRGBTable.h @@ -1,7 +1,7 @@ /*========================================================================= Program: Visualization Toolkit - Module: vtkOpenGLRGBTable.h + Module: vtkOpenGLVolumeRGBTable.h Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. @@ -13,19 +13,19 @@ =========================================================================*/ -#ifndef vtkOpenGLRGBTable_h_ -#define vtkOpenGLRGBTable_h_ +#ifndef vtkOpenGLVolumeRGBTable_h_ +#define vtkOpenGLVolumeRGBTable_h_ #include #include #include //---------------------------------------------------------------------------- -class vtkOpenGLRGBTable +class vtkOpenGLVolumeRGBTable { public: //-------------------------------------------------------------------------- - vtkOpenGLRGBTable() + vtkOpenGLVolumeRGBTable() { this->TextureWidth = 1024; this->NumberOfColorComponents = 3; @@ -36,7 +36,7 @@ class vtkOpenGLRGBTable } //-------------------------------------------------------------------------- - ~vtkOpenGLRGBTable() + ~vtkOpenGLVolumeRGBTable() { if (this->TextureObject) { @@ -151,5 +151,63 @@ class vtkOpenGLRGBTable vtkTimeStamp BuildTime; }; -#endif // vtkOpenGLRGBTable_h_ -// VTK-HeaderTest-Exclude: vtkOpenGLRGBTable.h +//---------------------------------------------------------------------------- +class vtkOpenGLVolumeRGBTables +{ +public: + //-------------------------------------------------------------------------- + vtkOpenGLVolumeRGBTables(unsigned int numberOfTables) + { + this->Tables = new vtkOpenGLVolumeRGBTable[numberOfTables]; + this->NumberOfTables = numberOfTables; + } + + //-------------------------------------------------------------------------- + ~vtkOpenGLVolumeRGBTables() + { + delete [] this->Tables; + } + + // brief Get opacity table at a given index. + //-------------------------------------------------------------------------- + vtkOpenGLVolumeRGBTable* GetTable(unsigned int i) + { + if (i >= this->NumberOfTables) + { + return NULL; + } + return &this->Tables[i]; + } + + // Get number of opacity tables. + //-------------------------------------------------------------------------- + unsigned int GetNumberOfTables() + { + return this->NumberOfTables; + } + + //-------------------------------------------------------------------------- + void ReleaseGraphicsResources(vtkWindow *window) + { + for (unsigned int i = 0; i NumberOfTables; ++i) + { + this->Tables[i].ReleaseGraphicsResources(window); + } + } + +private: + unsigned int NumberOfTables; + vtkOpenGLVolumeRGBTable* Tables; + + // vtkOpenGLVolumeRGBTables (Not implemented) + vtkOpenGLVolumeRGBTables(); + + // vtkOpenGLVolumeRGBTables (Not implemented) + vtkOpenGLVolumeRGBTables(const vtkOpenGLVolumeRGBTables &other); + + // operator = (Not implemented) + vtkOpenGLVolumeRGBTables &operator=(const vtkOpenGLVolumeRGBTables &other); +}; + +#endif // vtkOpenGLVolumeRGBTable_h_ +// VTK-HeaderTest-Exclude: vtkOpenGLVolumeRGBTable.h diff --git a/Rendering/VolumeOpenGL2/vtkVolumeShaderComposer.h b/Rendering/VolumeOpenGL2/vtkVolumeShaderComposer.h index 302226d21ca..f3ad87eba48 100644 --- a/Rendering/VolumeOpenGL2/vtkVolumeShaderComposer.h +++ b/Rendering/VolumeOpenGL2/vtkVolumeShaderComposer.h @@ -100,11 +100,15 @@ namespace vtkvolume vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), int vtkNotUsed(numberOfLights), - int lightingComplexity) + int lightingComplexity, + int noOfComponents, + bool independentComponents) { std::string shaderStr = std::string("\ \n// Volume dataset\ \nuniform sampler3D in_volume;\ + \nuniform int in_noOfComponents;\ + \nuniform int in_independentComponents;\ \n\ \nuniform sampler2D in_noiseSampler;\ \nuniform sampler2D in_depthSampler;\ @@ -189,6 +193,12 @@ namespace vtkvolume "); } + if (noOfComponents > 1 && independentComponents) + { + shaderStr += std::string("\ + uniform vec4 in_componentWeight;"); + } + return shaderStr; } @@ -247,10 +257,11 @@ namespace vtkvolume std::string GradientsComputeFunc(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vol, - int vtkNotUsed(numberOfComponents)) + int noOfComponents, + int independentComponents) { std::string shaderStr; - if (vol->GetProperty()->HasGradientOpacity()) + if (noOfComponents == 1 && vol->GetProperty()->HasGradientOpacity()) { shaderStr += std::string("\ \nuniform sampler1D in_gradientTransferFunc;\ @@ -260,6 +271,17 @@ namespace vtkvolume \n }" ); } + else if (noOfComponents > 1 && independentComponents && + vol->GetProperty()->HasGradientOpacity()) + { + shaderStr += std::string("\ + \nuniform sampler1D in_gradientTransferFunc[4];\ + \nfloat computeGradientOpacity(vec4 grad, int component)\ + \n {\ + \n return texture1D(in_gradientTransferFunc[component], grad.w).w;\ + \n }" + ); + } if (vol->GetProperty()->GetShade() && !vol->GetProperty()->HasGradientOpacity()) @@ -290,7 +312,7 @@ namespace vtkvolume \n {\ \n vec3 g1;\ \n vec4 g2;\ - \n vec3 xvec = vec3(in_cellStep[0], 0.0, 0.0);\ + \n vec3 xvec = vec3(in_cellStep[0], 0.0, 0.0);\ \n vec3 yvec = vec3(0.0, in_cellStep[1], 0.0);\ \n vec3 zvec = vec3(0.0, 0.0, in_cellStep[2]);\ \n g1.x = texture3D(in_volume, vec3(g_dataPos + xvec)).x;\ @@ -363,7 +385,8 @@ namespace vtkvolume std::string LightComputeFunc(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vol, - int vtkNotUsed(numberOfComponents), + int noOfComponents, + int independentComponents, int vtkNotUsed(numberOfLights), int lightingComplexity) { @@ -575,16 +598,29 @@ namespace vtkvolume ); } - if (volProperty->HasGradientOpacity()) + if (noOfComponents == 1 && volProperty->HasGradientOpacity()) { shaderStr += std::string("\ \n if (gradient.w >= 0.0)\ \n {\ \n color.a = color.a *\ - \n texture1D(in_gradientTransferFunc, gradient.w).w;\ + \n computeGradientOpacity(gradient);\ \n }" ); } + else if (noOfComponents > 1 && independentComponents && + volProperty->HasGradientOpacity()) + { + shaderStr += std::string("\ + \n if (gradient.w >= 0.0)\ + \n {\ + \n for (int i = 0; i < in_noOfComponents; ++i)\ + \n {\ + \n color.a = color.a *\ + \n computeGradientOpacity(gradient, i) * in_componentWeight[i];\ + \n }" + ); + } shaderStr += std::string("\ \n return vec4(finalColor, color.a);\ @@ -624,7 +660,8 @@ namespace vtkvolume std::string ColorTransferFunc(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), - int numberOfComponents) + int numberOfComponents, + int independentComponents = 0) { if (numberOfComponents == 1) { @@ -637,26 +674,52 @@ namespace vtkvolume \n computeOpacity(scalar)));\ \n }"); } - + else if (numberOfComponents > 1 && independentComponents) + { return std::string("\ - \nvec4 computeColor(vec4 scalar)\ + \nuniform sampler1D in_colorTransferFunc[4];\ + \nvec4 computeColor(vec4 scalar, int component)\ \n {\ - \n return computeLighting(vec4(scalar.xyz, computeOpacity(scalar)));\ + \n return computeLighting(vec4(texture1D(\ + \n in_colorTransferFunc[component],\ + \n scalar[component]).xyz,\ + \n computeOpacity(scalar, component)));\ \n }"); + } + + return std::string("\ + \nvec4 computeColor(vec4 scalar)\ + \n {\ + \n return computeLighting(vec4(scalar.xyz, computeOpacity(scalar)));\ + \n }"); } //-------------------------------------------------------------------------- std::string OpacityTransferFunc(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* vtkNotUsed(mapper), vtkVolume* vtkNotUsed(vol), - int vtkNotUsed(numberOfComponents)) + int numberOfComponents, + int independentComponents = 0) { - return std::string("\ - \nuniform sampler1D in_opacityTransferFunc;\ - \nfloat computeOpacity(vec4 scalar)\ - \n {\ - \n return texture1D(in_opacityTransferFunc, scalar.w).w;\ - \n }"); + if (numberOfComponents > 1 && independentComponents) + { + return std::string("\ + \nuniform sampler1D in_opacityTransferFunc[4];\ + \nfloat computeOpacity(vec4 scalar, int component)\ + \n {\ + \n return texture1D(in_opacityTransferFunc[component],\ + \n scalar[component]).w;\ + \n }"); + } + else + { + return std::string("\ + \nuniform sampler1D in_opacityTransferFunc;\ + \nfloat computeOpacity(vec4 scalar)\ + \n {\ + \n return texture1D(in_opacityTransferFunc, scalar.w).w;\ + \n }"); + } } //-------------------------------------------------------------------------- @@ -713,7 +776,8 @@ namespace vtkvolume vtkVolume* vtkNotUsed(vol), vtkImageData* maskInput, vtkVolumeMask* mask, int maskType, - int noOfComponents) + int noOfComponents, + int independentComponents = 0) { std::string shaderStr = std::string("\ \n if (!l_skip)\ @@ -776,29 +840,63 @@ namespace vtkvolume } else if (mapper->GetBlendMode() == vtkVolumeMapper::COMPOSITE_BLEND) { - if (!mask || !maskInput || - maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType) + if (noOfComponents > 1 && independentComponents) { shaderStr += std::string("\ - \n // Data fetching from the red channel of volume texture\ - \n vec4 scalar = texture3D(in_volume, g_dataPos);\ - \n vec4 g_srcColor = computeColor(scalar);" - ); + \n vec4 color[4]; vec4 tmp = vec4(0.0);\ + \n float totalAlpha = 0.0;\ + \n for (int i = 0; i < in_noOfComponents; ++i)\ + \n {\ + "); + if (!mask || !maskInput || + maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType) + { + shaderStr += std::string("\ + \n // Data fetching from the red channel of volume texture\ + \n vec4 scalar = texture3D(in_volume, g_dataPos);\ + \n color[i] = vec4(computeColor(scalar, i));\ + \n totalAlpha += color[i][3] * in_componentWeight[i];\ + \n }\ + \n if (totalAlpha > 0.0)\ + \n {\ + \n for (int i = 0; i < in_noOfComponents; ++i)\ + \n {\ + \n tmp.x += color[i].x * color[i].w * in_componentWeight[i] ;\ + \n tmp.y += color[i].y * color[i].w * in_componentWeight[i];\ + \n tmp.z += color[i].z * color[i].w * in_componentWeight[i];\ + \n tmp.w += ((color[i].w * color[i].w)/totalAlpha);\ + \n }\ + \n }\ + \n g_fragColor = (1.0f - g_fragColor.a) * tmp + g_fragColor;" + ); + } } + else + { + if (!mask || !maskInput || + maskType != vtkGPUVolumeRayCastMapper::LabelMapMaskType) + { + shaderStr += std::string("\ + \n // Data fetching from the red channel of volume texture\ + \n vec4 scalar = texture3D(in_volume, g_dataPos);\ + \n vec4 g_srcColor = computeColor(scalar);" + ); + } - shaderStr += std::string("\ - \n // Opacity calculation using compositing:\ - \n // here we use front to back compositing scheme whereby the current\ - \n // sample value is multiplied to the currently accumulated alpha\ - \n // and then this product is subtracted from the sample value to\ - \n // get the alpha from the previous steps.\ - \n // Next, this alpha is multiplied with the current sample colour\ - \n // and accumulated to the composited colour. The alpha value from\ - \n // the previous steps is then accumulated to the composited colour\ - \n // alpha.\ - \n g_srcColor.rgb *= g_srcColor.a;\ - \n g_fragColor = (1.0f - g_fragColor.a) * g_srcColor + g_fragColor;" - ); + shaderStr += std::string("\ + \n // Opacity calculation using compositing:\ + \n // here we use front to back compositing scheme whereby the current\ + \n // sample value is multiplied to the currently accumulated alpha\ + \n // and then this product is subtracted from the sample value to\ + \n // get the alpha from the previous steps.\ + \n // Next, this alpha is multiplied with the current sample colour\ + \n // and accumulated to the composited colour. The alpha value from\ + \n // the previous steps is then accumulated to the composited colour\ + \n // alpha.\ + \n g_srcColor.rgb *= g_srcColor.a;\ + \n g_fragColor = (1.0f - g_fragColor.a) * g_srcColor + g_fragColor;" + ); + } } else { @@ -814,29 +912,71 @@ namespace vtkvolume //-------------------------------------------------------------------------- std::string ShadingExit(vtkRenderer* vtkNotUsed(ren), vtkVolumeMapper* mapper, - vtkVolume* vtkNotUsed(vol)) + vtkVolume* vtkNotUsed(vol), + int noOfComponents, + int independentComponents = 0) { if (mapper->GetBlendMode() == vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND) { - return std::string("\ - \n vec4 g_srcColor = vec4(computeColor(l_maxValue).xyz,\ - \n computeOpacity(l_maxValue));\ - \n g_fragColor.rgb = g_srcColor.rgb * g_srcColor.a;\ - \n g_fragColor.a = g_srcColor.a;" - ); + if (noOfComponents > 1 && independentComponents) + { + return std::string("\ + \n for (int i = 0; i < in_noOfComponents; ++i)\ + \n {\ + \n vec4 g_srcColor = vec4(0);\ + \n for (int i = 0; i < in_noOfComponents; ++i)\ + \n {\ + \n vec4 tmp = vec4(computeColor(l_maxValue, i);\ + \n g_srcColor[0] += tmp[0] * tmp[3] * in_componentWeight[i];\ + \n g_srcColor[1] += tmp[1] * tmp[3] * in_componentWeight[i];\ + \n g_srcColor[2] += tmp[2] * tmp[3] * in_componentWeight[i];\ + \n g_srcColor[2] += tmp[3] * tmp[3] * in_componentWeight[i];\ + \n }\ + \n }" + ); + } + else + { + return std::string("\ + \n vec4 g_srcColor = vec4(computeColor(l_maxValue).xyz,\ + \n computeOpacity(l_maxValue));\ + \n g_fragColor.rgb = g_srcColor.rgb * g_srcColor.a;\ + \n g_fragColor.a = g_srcColor.a;" + ); + } } else if (mapper->GetBlendMode() == vtkVolumeMapper::MINIMUM_INTENSITY_BLEND) { - return std::string("\ - \n vec4 g_srcColor = vec4(computeColor(l_minValue).xyz,\ - \n computeOpacity(l_minValue));\ - \n g_fragColor.rgb = g_srcColor.rgb * g_srcColor.a;\ - \n g_fragColor.a = g_srcColor.a;" - ); + if (noOfComponents > 1 && independentComponents) + { + return std::string ("\ + \n for (int i = 0; i < in_noOfComponents; ++i)\ + \n {\ + \n vec4 g_srcColor = vec4(0);\ + \n for (int i = 0; i < in_noOfComponents; ++i)\ + \n {\ + \n vec4 tmp = vec4(computeColor(l_maxValue, i);\ + \n g_srcColor[0] += tmp[0] * tmp[3] * in_componentWeight[i];\ + \n g_srcColor[1] += tmp[1] * tmp[3] * in_componentWeight[i];\ + \n g_srcColor[2] += tmp[2] * tmp[3] * in_componentWeight[i];\ + \n g_srcColor[2] += tmp[3] * tmp[3] * in_componentWeight[i];\ + \n }\ + \n }" + ); + } + else + { + return std::string ("\ + \n vec4 g_srcColor = vec4(computeColor(l_minValue).xyz,\ + \n computeOpacity(l_minValue));\ + \n g_fragColor.rgb = g_srcColor.rgb * g_srcColor.a;\ + \n g_fragColor.a = g_srcColor.a;" + ); + } } else if (mapper->GetBlendMode() == vtkVolumeMapper::ADDITIVE_BLEND) { - return std::string("\ + return std::string ("\ \n l_sumValue = clamp(l_sumValue, 0.0, 1.0);\ \n g_fragColor = vec4(vec3(l_sumValue), 1.0);" );