<div dir="ltr"><div><div><div><div><div>I've now realized that I've made a blunder. In order to get the two volumes to look the same, I should of course set the ScalarOpacityUnitDistance to the *same* value for both volumes.<br><br></div>The attached PNG shows the result when I set the ScalarOpacityUnitDistance to 0.006 (the spacing of the higher-resolution volume) for both volumes (code below).<br><br></div>The volumes now look very similar opacity-wise, but they are still not quite equal. The (0-255) HSV values of the left/right volumes are (0, 95, 100) and (0, 93, 100), so the right one (the low res one) is still a little less opaque than the left one.<br><br></div><div>Anyone who can explain where this discrepancy comes from?<br><br></div><div>My question is really: How can two volumes with the exact same shape (a cube) and bounds in VTK world coordinates looks different opacity-wise, when they are rendered with the same opacity transfer function and have the same ScalarOpacityUnitDistance<span class=""> s</span>et?<br></div><div><br></div>Elvis<br><br><br></div>main.cpp:<br><br>#include <algorithm><br><br>#include <vtkCamera.h><br>#include <vtkColorTransferFunction.h><br>#include <vtkGPUVolumeRayCastMapper.h><br>#include <vtkImageData.h><br>#include <vtkImageInterpolator.h><br>#include <vtkImageResize.h><br>#include <vtkPiecewiseFunction.h><br>#include <vtkRenderer.h><br>#include <vtkRenderWindow.h><br>#include <vtkRenderWindowInteractor.h><br>#include <vtkSmartPointer.h><br>#include <vtkVolume.h><br>#include <vtkVolumeProperty.h><br><br>// Create a volume from the given image<br>vtkSmartPointer<vtkVolume> createVolume(vtkSmartPointer<vtkImageData> image) {<br> auto color = vtkSmartPointer<vtkColorTransferFunction>::New();<br> color->AddRGBPoint(0.0, 1.0, 0.0, 0.0);<br> color->AddRGBPoint(1.0, 1.0, 0.0, 0.0);<br><br> auto opacity = vtkSmartPointer<vtkPiecewiseFunction>::New();<br> opacity->AddPoint(0.0, 0.1);<br> opacity->AddPoint(1.0, 0.1);<br><br> auto property = vtkSmartPointer<vtkVolumeProperty>::New();<br> property->SetColor(color);<br> property->SetScalarOpacity(opacity);<br> property->SetInterpolationTypeToLinear();<br> property->ShadeOff();<br> property->SetScalarOpacityUnitDistance(0.006);<br><br> auto mapper = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();<br> mapper->SetInputData(image);<br><br> auto volume = vtkSmartPointer<vtkVolume>::New();<br> volume->SetMapper(mapper);<br> volume->SetProperty(property);<br><br> return volume;<br>}<br><br>int main(int argc, char *argv[]) {<br><br> // Create a 30x30x30 volume<br> auto image = vtkSmartPointer<vtkImageData>::New();<br> image->SetDimensions(30, 30, 30);<br> image->SetSpacing(0.006, 0.006, 0.006);<br> image->AllocateScalars(VTK_FLOAT, 1);<br><br> auto imagePtr = static_cast<float *>(image->GetScalarPointer());<br> std::fill_n(imagePtr, 30 * 30 * 30, 1.0);<br><br> auto volume = createVolume(image);<br><br> // Create a smaller (10x10x10) version<br> auto interpolator = vtkSmartPointer<vtkImageInterpolator>::New();<br> interpolator->SetInterpolationModeToLinear();<br><br> auto resize = vtkSmartPointer<vtkImageResize>::New();<br> resize->SetInputData(image);<br> resize->SetOutputDimensions(10, 10, 10);<br> resize->SetInterpolator(interpolator);<br> resize->Update();<br><br> auto smallVolume = createVolume(resize->GetOutput());<br> smallVolume->SetPosition(0.2, 0, 0);<br><br> // Render the two volumes<br> auto renderer = vtkSmartPointer<vtkRenderer>::New();<br> renderer->SetBackground(1.0, 1.0, 1.0);<br> renderer->AddVolume(volume);<br> renderer->AddVolume(smallVolume);<br> renderer->ResetCamera();<br><br> auto camera = renderer->GetActiveCamera();<br> camera->SetParallelProjection(1);<br><br> auto window = vtkSmartPointer<vtkRenderWindow>::New();<br> window->AddRenderer(renderer);<br> window->SetSize(800, 400);<br><br> auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();<br> interactor->SetRenderWindow(window);<br> interactor->Start();<br><br> return 0;<br>}<br><br><br></div>CMakeLists.txt:<br><br>cmake_minimum_required(VERSION 3.1)<br> <br>project(TestCase)<br> <br>set(CMAKE_CXX_STANDARD 11)<br>set(CMAKE_CXX_STANDARD_REQUIRED ON)<br><br>find_package(VTK COMPONENTS<br> vtkCommonCore<br> vtkCommonDataModel<br> vtkCommonExecutionModel<br> vtkInteractionStyle<br> vtkImagingCore<br> vtkRenderingCore<br> vtkRenderingOpenGL2<br> vtkRenderingVolume<br> vtkRenderingVolumeOpenGL2<br>)<br><br>add_executable(TestCase main.cpp)<br> <br>target_link_libraries(TestCase PUBLIC<br> vtkCommonCore<br> vtkCommonDataModel<br> vtkCommonExecutionModel<br> vtkImagingCore<br> vtkInteractionStyle<br> vtkRenderingCore<br> vtkRenderingOpenGL2<br> vtkRenderingVolume<br> vtkRenderingVolumeOpenGL2<br>)<br><br>target_include_directories(TestCase PUBLIC<br> ${VTK_INCLUDE_DIRS}<br>)<br><br><br>target_compile_definitions(TestCase PUBLIC<br> ${VTK_DEFINITIONS}<br>)<br><div><div><div><div><div><div><div><div class="gmail_extra"><br><div class="gmail_quote">2017-02-09 14:45 GMT+01:00 Elvis Stansvik <span dir="ltr"><<a href="mailto:elvis.stansvik@orexplore.com" target="_blank">elvis.stansvik@orexplore.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div><div><div><div><div><div>Hi all,<br><br>The following example shows a 30x30x30 volume rendered, and next to it a downscaled version of it (but using an identical opacity/transfer function). Notice how in the result (attached), the downscaled version is less opaque. This is despite me using<br><br> SetScalarOpacityUnitDistance(<wbr>image->GetSpacing()[0])<br><br></div>to set the scalar opacity unit distance to the spacing of the respective image. I would thought calling SetScalarOpacityUnitDistance like this would ensure both volumes look the same (apart from resolution).<br><br></div>How can I make both volumes look the same opacity-wise when using the same transfer functions?<br><br></div>Thanks in advance,<br></div>Elvis<br><br></div>main.cpp:<br><br><br>#include <algorithm><br><br>#include <vtkCamera.h><br>#include <vtkColorTransferFunction.h><br>#include <vtkGPUVolumeRayCastMapper.h><br>#include <vtkImageData.h><br>#include <vtkImageResize.h><br>#include <vtkPiecewiseFunction.h><br>#include <vtkRenderer.h><br>#include <vtkRenderWindow.h><br>#include <vtkRenderWindowInteractor.h><br>#include <vtkSmartPointer.h><br>#include <vtkVolume.h><br>#include <vtkVolumeProperty.h><br><br>// Create a volume from the given image<br>vtkSmartPointer<vtkVolume> createVolume(vtkSmartPointer<<wbr>vtkImageData> image) {<br> auto color = vtkSmartPointer<<wbr>vtkColorTransferFunction>::<wbr>New();<br> color->AddRGBPoint(0.0, 1.0, 0.0, 0.0);<br> color->AddRGBPoint(1.0, 1.0, 0.0, 0.0);<br><br> auto opacity = vtkSmartPointer<<wbr>vtkPiecewiseFunction>::New();<br> opacity->AddPoint(0.0, 0.1);<br> opacity->AddPoint(1.0, 0.1);<br><br> auto property = vtkSmartPointer<<wbr>vtkVolumeProperty>::New();<br> property->SetColor(color);<br> property->SetScalarOpacity(<wbr>opacity);<br> property-><wbr>SetInterpolationTypeToLinear()<wbr>;<br> property->ShadeOff();<br> property-><wbr>SetScalarOpacityUnitDistance(<wbr>image->GetSpacing()[0]);<br><br> auto mapper = vtkSmartPointer<<wbr>vtkGPUVolumeRayCastMapper>::<wbr>New();<br> mapper->SetInputData(image);<br><br> auto volume = vtkSmartPointer<vtkVolume>::<wbr>New();<br> volume->SetMapper(mapper);<br> volume->SetProperty(property);<br><br> return volume;<br>}<br><br>int main(int argc, char *argv[]) {<br><br> // Create a 30x30x30 volume<br> auto image = vtkSmartPointer<vtkImageData>:<wbr>:New();<br> image->SetDimensions(30, 30, 30);<br> image->SetSpacing(0.006, 0.006, 0.006);<br> image->AllocateScalars(VTK_<wbr>FLOAT, 1);<br><br> auto imagePtr = static_cast<float *>(image->GetScalarPointer());<br> std::fill_n(imagePtr, 30 * 30 * 30, 1.0);<br><br> auto volume = createVolume(image);<br><br> // Create a smaller (10x10x10) version<br> auto resize = vtkSmartPointer<<wbr>vtkImageResize>::New();<br> resize->SetInputData(image);<br> resize->SetOutputDimensions(<wbr>10, 10, 10);<br> resize->Update();<br><br> auto smallVolume = createVolume(resize-><wbr>GetOutput());<br> smallVolume->SetPosition(0.2, 0, 0);<br><br> // Render the two volumes<br> auto renderer = vtkSmartPointer<vtkRenderer>::<wbr>New();<br> renderer->SetBackground(1.0, 1.0, 1.0);<br> renderer->AddVolume(volume);<br> renderer->AddVolume(<wbr>smallVolume);<br> renderer->ResetCamera();<br><br> auto camera = renderer->GetActiveCamera();<br> camera->SetParallelProjection(<wbr>1);<br><br> auto window = vtkSmartPointer<<wbr>vtkRenderWindow>::New();<br> window->AddRenderer(renderer);<br> window->SetSize(800, 400);<br><br> auto interactor = vtkSmartPointer<<wbr>vtkRenderWindowInteractor>::<wbr>New();<br> interactor->SetRenderWindow(<wbr>window);<br> interactor->Start();<br><br> return 0;<br>}<br><br><br></div>CMakeLists.txt:<br><br><br>cmake_minimum_required(VERSION 3.1)<br> <br>project(TestCase)<br> <br>set(CMAKE_CXX_STANDARD 11)<br>set(CMAKE_CXX_STANDARD_<wbr>REQUIRED ON)<br><br>find_package(VTK COMPONENTS<br> vtkCommonCore<br> vtkCommonDataModel<br> vtkCommonExecutionModel<br> vtkInteractionStyle<br> vtkImagingCore<br> vtkRenderingCore<br> vtkRenderingOpenGL2<br> vtkRenderingVolume<br> vtkRenderingVolumeOpenGL2<br>)<br><br>add_executable(TestCase main.cpp)<br> <br>target_link_libraries(TestCase PUBLIC<br> vtkCommonCore<br> vtkCommonDataModel<br> vtkCommonExecutionModel<br> vtkImagingCore<br> vtkInteractionStyle<br> vtkRenderingCore<br> vtkRenderingOpenGL2<br> vtkRenderingVolume<br> vtkRenderingVolumeOpenGL2<br>)<br><br>target_include_directories(<wbr>TestCase PUBLIC<br> ${VTK_INCLUDE_DIRS}<br>)<br><br><br>target_compile_definitions(<wbr>TestCase PUBLIC<br> ${VTK_DEFINITIONS}<br>)<br></div>
</blockquote></div><br></div></div></div></div></div></div></div></div></div>