/*========================================================================= Program: Visualization Toolkit Module: TestGPURayCastMultiVolumeOverlapping.cxx 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. =========================================================================*/ /** * Tests rendering 3 overlapping volumes as inputs in vtkGPUVolumeRCMapper * vtkMultiVolume. */ #include "vtkAxesActor.h" #include "vtkCamera.h" #include "vtkColorTransferFunction.h" #include "vtkCommand.h" #include "vtkConeSource.h" #include "vtkGPUVolumeRayCastMapper.h" #include "vtkImageResample.h" #include "vtkImageResize.h" #include "vtkInteractorStyleTrackballCamera.h" #include "vtkMultiVolume.h" #include "vtkNew.h" #include "vtkPiecewiseFunction.h" #include "vtkRegressionTestImage.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkRenderer.h" #include "vtkTestUtilities.h" #include "vtkVolume16Reader.h" #include "vtkVolumeProperty.h" #include "vtkXMLImageDataReader.h" #include "vtkAbstractMapper.h" #include "vtkImageData.h" #include "vtkOutlineFilter.h" #include "vtkPolyDataMapper.h" #include "vtkMath.h" #include namespace { class MoveRotateCommand : public vtkCommand { public: static MoveRotateCommand* New() { return new MoveRotateCommand; } void Execute(vtkObject* caller, unsigned long eventId, void* /*data*/) override { switch (eventId) { case vtkCommand::KeyPressEvent: { auto interactor = vtkRenderWindowInteractor::SafeDownCast(caller); const std::string key = interactor->GetKeySym(); double times[3] = { 0, 0, 0 }; double timesAngle[3] = { 0, 0, 0 }; // Translations if (key == "Left") { times[0] = -1; } else if (key == "Right") { times[0] = 1; } else if (key == "Down") { times[1] = -1; } else if (key == "Up") { times[1] = 1; } else if (key == "n") { times[2] = -1; } else if (key == "m") { times[2] = 1; } // Rotations else if (key == "a") { timesAngle[0] = -1; } else if (key == "s") { timesAngle[0] = 1; } else if (key == "z") { timesAngle[1] = -1; } else if (key == "x") { timesAngle[1] = 1; } else if (key == "c") { timesAngle[2] = -1; } else if (key == "v") { timesAngle[2] = 1; } else break; const double deltaX = times[0] * Delta; const double deltaY = times[1] * Delta; const double deltaZ = times[2] * Delta; const auto pos = this->Volume->GetPosition(); this->Volume->SetPosition(pos[0] + deltaX, pos[1] + deltaY, pos[2] + deltaZ); const double rotX = timesAngle[0] * DeltaAngle; this->Volume->RotateX(rotX); const double rotY = timesAngle[1] * DeltaAngle; this->Volume->RotateY(rotY); const double rotZ = timesAngle[2] * DeltaAngle; this->Volume->RotateZ(rotZ); } break; } this->RenderWindow->Render(); }; void SetVolume(vtkProp3D* vol) { this->Volume = vol; } vtkRenderWindow* RenderWindow = nullptr; vtkProp3D* Volume = nullptr; double Delta = 10.0; double DeltaAngle = 5.0; }; } //////////////////////////////////////////////////////////////////////////////// int TestGPURayCastMultiVolumeOverlapping(int argc, char* argv[]) { // Load data vtkNew reader; reader->SetDataDimensions(64, 64); reader->SetImageRange(1, 93); reader->SetDataByteOrderToLittleEndian(); char* fname = vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/headsq/quarter"); reader->SetFilePrefix(fname); delete[] fname; reader->SetDataSpacing(3.2, 3.2, 1.5); vtkNew vaseSource; const char* volumeFile = vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/vase_1comp.vti"); vaseSource->SetFileName(volumeFile); delete[] volumeFile; vtkSmartPointer xmlReader = vtkSmartPointer::New(); char* filename = vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/hncma-atlas.vti"); xmlReader->SetFileName(filename); xmlReader->Update(); delete[] filename; filename = nullptr; // Geometry vtkNew coneSource; coneSource->SetRadius(30.); coneSource->SetHeight(50.); coneSource->SetResolution(40); vtkNew coneMapper; coneMapper->SetInputConnection(coneSource->GetOutputPort()); vtkNew cone; cone->SetMapper(coneMapper); cone->RotateX(35.); cone->RotateY(-245.); cone->SetPosition(160., 90., -30.); vtkNew axis; axis->SetTotalLength(100., 100., 100.); axis->SetNormalizedTipLength(0.1, 0.1, 0.1); axis->SetNormalizedShaftLength(1., 1., 1.); axis->AxisLabelsOff(); axis->SetConeRadius(0.5); // Volume 0 (upsampled headmr) // --------------------------- vtkNew headmrSource; headmrSource->SetInputConnection(reader->GetOutputPort()); headmrSource->SetResizeMethodToOutputDimensions(); headmrSource->SetOutputDimensions(128, 128, 128); headmrSource->Update(); vtkNew ctf; ctf->AddRGBPoint(0, 0.0, 0.0, 0.0); ctf->AddRGBPoint(500, 1.0, 0.5, 0.3); ctf->AddRGBPoint(1000, 1.0, 0.5, 0.3); ctf->AddRGBPoint(1150, 1.0, 1.0, 0.9); vtkNew pf; pf->AddPoint(0, 0.00); pf->AddPoint(500, 0.15); pf->AddPoint(1000, 0.15); pf->AddPoint(1150, 0.85); vtkNew gf; gf->AddPoint(0, 0.0); gf->AddPoint(90, 0.1); gf->AddPoint(100, 0.7); vtkNew vol; vol->GetProperty()->SetScalarOpacity(pf); vol->GetProperty()->SetColor(ctf); vol->GetProperty()->SetGradientOpacity(gf); vol->GetProperty()->SetInterpolationType(VTK_LINEAR_INTERPOLATION); vol->GetProperty()->ShadeOn(); // Volume 1 (vase) // ----------------------------- vtkNew ctf1; ctf1->AddRGBPoint(0, 0.0, 0.0, 0.0); ctf1->AddRGBPoint(500, 0.1, 1.0, 0.3); ctf1->AddRGBPoint(1000, 0.1, 1.0, 0.3); ctf1->AddRGBPoint(1150, 1.0, 1.0, 0.9); vtkNew pf1; pf1->AddPoint(0, 0.0); pf1->AddPoint(500, 1.0); vtkNew gf1; gf1->AddPoint(0, 0.0); gf1->AddPoint(550, 1.0); vtkNew vol1; vol1->GetProperty()->SetScalarOpacity(pf1); vol1->GetProperty()->SetColor(ctf1); vol1->GetProperty()->SetGradientOpacity(gf1); vol1->GetProperty()->SetInterpolationType(VTK_LINEAR_INTERPOLATION); // this is actually not used, the shader looks at the property of the first volume // vol1->GetProperty()->ShadeOn(); vol1->RotateX(-55.); vol1->SetPosition(80., 50., 130.); // Volume 2 (brain) // ----------------------------- vtkNew pf2; pf1->AddPoint(0, 0.0); pf1->AddPoint(5022, 0.09); vtkNew ctf2; ctf2->AddRGBPoint(0, 1.0, 0.3, 0.2); ctf2->AddRGBPoint(2511, 0.3, 0.2, 0.9); ctf2->AddRGBPoint(5022, 0.5, 0.6, 1.0); vtkNew gf2; gf2->AddPoint(0, 0.0); gf2->AddPoint(550, 0.5); vtkNew vol2; vol2->GetProperty()->SetScalarOpacity(pf2); vol2->GetProperty()->SetColor(ctf2); vol2->GetProperty()->SetGradientOpacity(gf2); vol2->GetProperty()->SetInterpolationType(VTK_LINEAR_INTERPOLATION); // this is actually not used, the shader looks at the property of the first volume // vol2->GetProperty()->ShadeOn(); vol2->SetScale(0.8, 0.8, 0.8); vol2->SetPosition(210., 200., -90.); vol2->RotateX(90.); vol2->RotateY(-95.); vol2->RotateZ(-5.); // Multi volume instance // --------------------- // Create an overlapping volume prop (add specific properties to each // entity). vtkNew overlappingVol; vtkNew mapper; mapper->UseJitteringOn(); overlappingVol->SetMapper(mapper); mapper->SetInputConnection(0, headmrSource->GetOutputPort()); overlappingVol->SetVolume(vol, 0); mapper->SetInputConnection(2, vaseSource->GetOutputPort()); overlappingVol->SetVolume(vol1, 2); mapper->SetInputConnection(4, xmlReader->GetOutputPort()); overlappingVol->SetVolume(vol2, 4); // Rendering context vtkNew renWin; renWin->SetSize(512, 512); renWin->SetMultiSamples(0); vtkNew ren; renWin->AddRenderer(ren); ren->SetBackground(1.0, 1.0, 1.0); ren->AddActor(axis); ren->AddActor(cone); ren->AddVolume(overlappingVol); vtkNew iren; iren->SetRenderWindow(renWin); vtkNew moveComm; moveComm->SetVolume(vol1); moveComm->RenderWindow = renWin; iren->AddObserver(vtkCommand::KeyPressEvent, moveComm); vtkNew style; iren->SetInteractorStyle(style); auto cam = ren->GetActiveCamera(); cam->SetFocalPoint(41.9596, -17.9662, 78.5903); cam->SetPosition(373.891, 619.954, -53.5932); cam->SetViewUp(-0.0358384, -0.184856, -0.982112); renWin->Render(); int retVal = vtkTesting::Test(argc, argv, renWin, 90); if (retVal == vtkRegressionTester::DO_INTERACTOR) { iren->Start(); } return !((retVal == vtkTesting::PASSED) || (retVal == vtkTesting::DO_INTERACTOR)); }