View Issue Details [ Jump to Notes ] | [ Print ] | ||||||||
ID | Project | Category | View Status | Date Submitted | Last Update | ||||
0014750 | VTK | (No Category) | public | 2014-05-22 08:49 | 2016-07-06 12:48 | ||||
Reporter | Stephan Rademacher | ||||||||
Assigned To | Aashish Chaudhary | ||||||||
Priority | normal | Severity | minor | Reproducibility | have not tried | ||||
Status | closed | Resolution | fixed | ||||||
Platform | OS | OS Version | |||||||
Product Version | 5.10.1 | ||||||||
Target Version | Fixed in Version | 7.0.0 | |||||||
Summary | 0014750: vtkGPUVolumeRayCastMapper offsets the near plane too much | ||||||||
Description | In vtkOpenGLGPUVolumeRayCastMapper::ClipBoundingBox the near plane is offset by a small value. The comment says this is done in order to avoid hardware clipping of the near plane due to floating-point precision. This offset is 0.001 times the camera plane normal. 0.001 was arbitrarily chosen (according to the comment). There is a check afterwards to make sure 0.001 is not larger than the distance between near and far plane. That is not sufficient however: The datasets we are rendering are all very small in real world dimensions, mostly around 500 micrometers in all dimensions. This results in a very small spacing, which leads to a small distance between near and far plane. 0.001 times the camera plane normal is a very large chunk of that distance, meaning that a large part of the dataset is clipped away. Ironically, rendering even smaller datasets (100 micrometers for example) works fine, because then 0.001 is larger than the distance between near and far plane, and the check sets the offset to (far - near) / 1000.0. Rendering datasets larger than 1000 micrometers works fine, because 0.001 is a small enough value. So our datasets just happen to be in the "bad" region :) I propose changing the code from: double offset=0.001; // some arbitrary small value. if(offset>=distNearFar) { offset=distNearFar/1000.0; } to: offset = distNearFar/1000.0; if (0.001 < offset) { // 0.001 is enough to avoid floating point precision problems. offset = 0.001; } or something better. I wrote a small program to demonstrate the effect. IronProt.vtk is rendered, but with a modified spacing, so that its real world dimensions are 500 micro meters. At startup the program uses vtkVolumeRayCastMapper, showing that CPU raycasting works fine. Pressing "9" switches to vtkGPUVolumeRayCastMapper, demonstrating the bug. Pressing "8" switches back to the CPU raycaster. #include "vtkCamera.h" #include "vtkColorTransferFunction.h" #include "vtkCommand.h" #include "vtkGPUVolumeRayCastMapper.h" #include "vtkImageChangeInformation.h" #include "vtkPiecewiseFunction.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkSmartPointer.h" #include "vtkStructuredPoints.h" #include "vtkStructuredPointsReader.h" #include "vtkVolume.h" #include "vtkVolumeProperty.h" #include "vtkVolumeRayCastCompositeFunction.h" #include "vtkVolumeRayCastMapper.h" class MyCallBack: public vtkCommand { public: static MyCallBack *New() { return new MyCallBack; } virtual void Execute(vtkObject* caller, unsigned long eventId, void* callData) { if (eventId != vtkCommand::KeyPressEvent) return; vtkRenderWindowInteractor* interactor = static_cast<vtkRenderWindowInteractor*>(caller); if (interactor == NULL) return; char* pressedKey = interactor->GetKeySym(); if (strcmp(pressedKey, "8") == 0) { volume->SetMapper(cpuRayCaster); renderWindow->Render(); std::cout << "Changed to CPU RayCasting" << std::endl; } else if (strcmp(pressedKey, "9") == 0) { volume->SetMapper(gpuRayCaster); renderWindow->Render(); std::cout << "Changed to GPU RayCasting" << std::endl; } } vtkSmartPointer<vtkVolume> volume; vtkSmartPointer<vtkVolumeRayCastMapper> cpuRayCaster; vtkSmartPointer<vtkGPUVolumeRayCastMapper> gpuRayCaster; vtkSmartPointer<vtkRenderWindow> renderWindow; }; int main() { vtkSmartPointer<vtkStructuredPointsReader> pointsReader = vtkSmartPointer<vtkStructuredPointsReader>::New(); pointsReader->SetFileName("ironProt.vtk"); pointsReader->Update(); int dims[3]; pointsReader->GetOutput()->GetDimensions(dims); double desiredBounds = 0.0005; double desiredSpacing[3]; desiredSpacing[0] = desiredBounds / (double)dims[0]; desiredSpacing[1] = desiredBounds / (double)dims[1]; desiredSpacing[2] = desiredBounds / (double)dims[2]; vtkSmartPointer<vtkImageChangeInformation> imageChangeInfo = vtkSmartPointer<vtkImageChangeInformation>::New(); imageChangeInfo->SetInputConnection(pointsReader->GetOutputPort() ); imageChangeInfo->SetOutputSpacing(desiredSpacing); double sampleDistance = 1e-6; double scalarOpacityUnitDistance = 1e-6; vtkSmartPointer<vtkVolumeRayCastMapper> cpuRayCaster = vtkSmartPointer<vtkVolumeRayCastMapper>::New(); cpuRayCaster->SetInputConnection(imageChangeInfo->GetOutputPort() ); cpuRayCaster->SetSampleDistance(sampleDistance); cpuRayCaster->SetAutoAdjustSampleDistances(1); vtkSmartPointer<vtkVolumeRayCastCompositeFunction> compFunction = vtkSmartPointer<vtkVolumeRayCastCompositeFunction>::New(); cpuRayCaster->SetVolumeRayCastFunction(compFunction); vtkSmartPointer<vtkGPUVolumeRayCastMapper> gpuRayCaster = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New(); gpuRayCaster->SetInputConnection(imageChangeInfo->GetOutputPort() ); gpuRayCaster->SetSampleDistance(sampleDistance); gpuRayCaster->SetAutoAdjustSampleDistances(1); vtkSmartPointer<vtkColorTransferFunction> colorTransferFunction = vtkSmartPointer<vtkColorTransferFunction>::New(); colorTransferFunction->AddRGBPoint( 0.0, 0.0, 0.0, 0.0); colorTransferFunction->AddRGBPoint( 64.0, 1.0, 0.0, 0.0); colorTransferFunction->AddRGBPoint(128.0, 0.0, 0.0, 1.0); colorTransferFunction->AddRGBPoint(192.0, 0.0, 1.0, 0.0); colorTransferFunction->AddRGBPoint(255.0, 0.0, 0.2, 0.0); vtkSmartPointer<vtkPiecewiseFunction> opacityTransferFunction = vtkSmartPointer<vtkPiecewiseFunction>::New(); opacityTransferFunction->AddPoint(0, 0.0); opacityTransferFunction->AddPoint(255, 1.0); vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New(); volumeProperty->SetColor(colorTransferFunction); volumeProperty->SetScalarOpacity(opacityTransferFunction); volumeProperty->SetScalarOpacityUnitDistance(scalarOpacityUnitDistance); vtkSmartPointer<vtkVolume> volume = vtkSmartPointer<vtkVolume>::New(); volume->SetMapper(cpuRayCaster); volume->SetProperty(volumeProperty); vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New(); renderer->AddActor(volume); renderer->SetBackground(1.0, 1.0, 1.0); // Set the camera to a position demonstrating the effect. vtkSmartPointer<vtkCamera> camera = renderer->GetActiveCamera(); double viewUp[3] = {-1.0, -1.0, -1.0}; double position[3] = {1000.0, 1000.0, -1000.0}; double focalPoint[3] = {0.0, 0.0, 0.0}; camera->SetPosition(position); camera->SetViewUp(viewUp); camera->SetFocalPoint(focalPoint); renderer->ResetCamera(); vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->SetSize(800, 600); renderWindow->AddRenderer(renderer); vtkSmartPointer<vtkRenderWindowInteractor> interactor= vtkSmartPointer<vtkRenderWindowInteractor>::New(); interactor->SetRenderWindow(renderWindow); vtkSmartPointer<MyCallBack> callback = vtkSmartPointer<MyCallBack>::New(); callback->cpuRayCaster = cpuRayCaster; callback->gpuRayCaster = gpuRayCaster; callback->renderWindow = renderWindow; callback->volume = volume; interactor->AddObserver("KeyPressEvent", callback); renderWindow->Render(); interactor->Start(); } I have attached the result of the program. | ||||||||
Tags | No tags attached. | ||||||||
Project | TBD | ||||||||
Type | incorrect functionality | ||||||||
Attached Files | ClippingProblem.jpg [^] (54,611 bytes) 2014-05-22 08:49
| ||||||||
Relationships | |
Relationships |
Notes | |
(0033408) Berk Geveci (administrator) 2014-10-01 20:26 |
Aashish: please verify that this is not an issue with the new mapper. |
(0033416) Aashish Chaudhary (developer) 2014-10-02 08:34 |
Nice.. as this explains one of the issues we found yesterday and I was looking at the same exact code to understand the logistics. The code and the explanation here is very useful. I will push a fix. |
(0033592) Stephan Rademacher (reporter) 2014-10-06 05:25 |
Thanks for taking time to look at this issue! Could you please clarify what this "new mapper" is? Is vtkGPUVolumeRaycastMapper going to be replaced/made obsolete in 6.x? And will this fix only be for the new mapper, or also for vtkGPUVolumeRaycastMapper? |
(0034573) Sankhesh Jhaveri (manager) 2015-06-17 15:56 |
Hi Stephan, The new mapper that Berk referred to is the same vtkGPUVolumeRayCastMapper but using the OpenGL2 backend. I've pushed a fix for this issue here: https://gitlab.kitware.com/vtk/vtk/merge_requests/320 [^] |
(0034736) Stephan Rademacher (reporter) 2015-07-10 09:35 |
Hi Sankhesh, thanks for the reply. So if understood correctly, the fix will be for vtkGPUVolumeRayCastMapper, but it will only be in VTK 6.x. We are using VTK 5.10 at the moment (and upgrading to 6.x will probably not happen in the near future because of the code breaking changes in 6.x), so we will not immediately benefit from the fix. Thanks to VTK being open source, this is not too bad though. We manage our own version of 5.10 with a few bug fixes (including this one). I'd prefer an unmodified version of VTK, but this is working fine. I read on the mailing list that you're considering maintaining VTK 6.3 for a longer period of time (meaning bug fixes are merged into it), which I think is a great idea. Late adopters like us will surely benefit. |
(0036202) Alvaro Sanchez (developer) 2016-07-06 12:48 |
The fix was merged into master. [https://gitlab.kitware.com/vtk/vtk/merge_requests/320/commits [^]] |
Notes |
Issue History | |||
Date Modified | Username | Field | Change |
2014-05-22 08:49 | Stephan Rademacher | New Issue | |
2014-05-22 08:49 | Stephan Rademacher | File Added: ClippingProblem.jpg | |
2014-10-01 20:26 | Berk Geveci | Assigned To | => Aashish Chaudhary |
2014-10-01 20:26 | Berk Geveci | Note Added: 0033408 | |
2014-10-02 08:34 | Aashish Chaudhary | Note Added: 0033416 | |
2014-10-06 05:25 | Stephan Rademacher | Note Added: 0033592 | |
2015-06-17 15:56 | Sankhesh Jhaveri | Note Added: 0034573 | |
2015-07-10 09:35 | Stephan Rademacher | Note Added: 0034736 | |
2016-07-06 12:48 | Alvaro Sanchez | Note Added: 0036202 | |
2016-07-06 12:48 | Alvaro Sanchez | Status | backlog => closed |
2016-07-06 12:48 | Alvaro Sanchez | Resolution | open => fixed |
2016-07-06 12:48 | Alvaro Sanchez | Fixed in Version | => 7.0.0 |
Issue History |
Copyright © 2000 - 2018 MantisBT Team |