iMSTK
Interactive Medical Simulation Toolkit
imstkVTKOpenVRViewer.cpp
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #include "imstkVTKOpenVRViewer.h"
8 #include "imstkCamera.h"
9 #include "imstkDeviceControl.h"
10 #include "imstkLogger.h"
11 #include "imstkOpenVRDeviceClient.h"
12 #include "imstkScene.h"
13 #include "imstkVTKInteractorStyleVR.h"
14 #include "imstkVTKRenderer.h"
15 
16 #include "imstkVtkOpenVRRenderWindowInteractorImstk.h"
17 
18 #include <chrono>
19 #include <vtkMatrix4x4.h>
20 #include <vtkOpenVRModel.h>
21 #include <vtkOpenVRRenderer.h>
22 #include <vtkOpenVRRenderWindow.h>
23 
24 namespace imstk
25 {
26 VTKOpenVRViewer::VTKOpenVRViewer(std::string name) : AbstractVTKViewer(name)
27 {
28  // Create the interactor style
29  auto vrInteractorStyle = vtkSmartPointer<vtkInteractorStyleVR>::New();
30  m_vtkInteractorStyle = vrInteractorStyle;
31 
32  // Create the interactor
33  auto iren = vtkSmartPointer<vtkOpenVRRenderWindowInteractorImstk>::New();
34  iren->SetInteractorStyle(m_vtkInteractorStyle);
35 
36  // Create the RenderWindow
37  m_vtkRenderWindow = vtkSmartPointer<vtkOpenVRRenderWindow>::New();
38  m_vtkRenderWindow->SetInteractor(iren);
39  iren->SetRenderWindow(m_vtkRenderWindow);
40  m_vtkRenderWindow->HideCursor();
41 
42  m_vrDeviceClients.push_back(vrInteractorStyle->getLeftControllerDeviceClient());
43  m_vrDeviceClients.push_back(vrInteractorStyle->getRightControllerDeviceClient());
44  m_vrDeviceClients.push_back(vrInteractorStyle->getHmdDeviceClient());
45 }
46 
47 void
48 VTKOpenVRViewer::setActiveScene(std::shared_ptr<Scene> scene)
49 {
50  // If already current scene
51  if (scene == m_activeScene)
52  {
53  LOG(WARNING) << scene->getName() << " already is the viewer current scene.";
54  return;
55  }
56 
57  // If the current scene has a renderer, remove it
58  if (m_activeScene)
59  {
60  auto vtkRenderer = std::dynamic_pointer_cast<VTKRenderer>(this->getActiveRenderer())->getVtkRenderer();
61  if (m_vtkRenderWindow->HasRenderer(vtkRenderer))
62  {
63  m_vtkRenderWindow->RemoveRenderer(vtkRenderer);
64  }
65  }
66 
67  // Update current scene
68  m_activeScene = scene;
69 
70  // Create renderer if it doesn't exist
71  if (!m_rendererMap.count(m_activeScene))
72  {
73  m_rendererMap[m_activeScene] = std::make_shared<VTKRenderer>(m_activeScene, true);
74  // If we already ran past init, then init it here
75  if (m_init)
76  {
77  m_rendererMap[m_activeScene]->initialize();
78  }
79  }
80 
81  // Cast to VTK renderer
82  auto vtkRenderer = std::dynamic_pointer_cast<VTKRenderer>(this->getActiveRenderer())->getVtkRenderer();
83 
84  // Set renderer to renderWindow
85  m_vtkRenderWindow->AddRenderer(vtkRenderer);
86  m_vtkInteractorStyle->SetCurrentRenderer(vtkRenderer);
87 }
88 
89 void
90 VTKOpenVRViewer::setPhysicalToWorldTransform(const Mat4d& physicalToWorldMatrix)
91 {
92  vtkSmartPointer<vtkOpenVRRenderWindow> renWin =
93  vtkOpenVRRenderWindow::SafeDownCast(m_vtkRenderWindow);
94  vtkNew<vtkMatrix4x4> mat;
95  for (int i = 0; i < 4; i++)
96  {
97  for (int j = 0; j < 4; j++)
98  {
99  mat->SetElement(i, j, physicalToWorldMatrix(i, j));
100  }
101  }
102  renWin->SetPhysicalToWorldMatrix(mat);
103 }
104 
105 Mat4d
106 VTKOpenVRViewer::getPhysicalToWorldTransform()
107 {
108  vtkSmartPointer<vtkOpenVRRenderWindow> renWin =
109  vtkOpenVRRenderWindow::SafeDownCast(m_vtkRenderWindow);
110  Mat4d transform;
111  vtkNew<vtkMatrix4x4> mat;
112  renWin->GetPhysicalToWorldMatrix(mat);
113  for (int i = 0; i < 4; i++)
114  {
115  for (int j = 0; j < 4; j++)
116  {
117  transform(i, j) = mat->GetElement(i, j);
118  }
119  }
120  return transform;
121 }
122 
123 void
124 VTKOpenVRViewer::setRenderingMode(const Renderer::Mode mode)
125 {
126  if (!m_activeScene)
127  {
128  LOG(WARNING) << "Missing scene, can not set rendering mode.\n"
129  << "Use Viewer::setCurrentScene to setup scene.";
130  return;
131  }
132 
133  // Setup renderer
134  this->getActiveRenderer()->setMode(mode, true);
135 
136  if (mode == Renderer::Mode::Debug)
137  {
138  if (!m_activeScene->hasEntity(m_debugEntity))
139  {
140  m_activeScene->addSceneObject(m_debugEntity);
141  }
142  }
143  else if (mode == Renderer::Mode::Simulation)
144  {
145  if (m_activeScene->hasEntity(m_debugEntity))
146  {
147  m_activeScene->removeSceneObject(m_debugEntity);
148  }
149  }
150 
151  updateModule();
152 }
153 
154 void
155 VTKOpenVRViewer::processEvents()
156 {
157  // Custom call to only process input events, do not perform a render
158  auto iren = vtkOpenVRRenderWindowInteractorImstk::SafeDownCast(m_vtkRenderWindow->GetInteractor());
159  auto ren = std::dynamic_pointer_cast<imstk::VTKRenderer>(getActiveRenderer());
160  iren->DoOneEvent(vtkOpenVRRenderWindow::SafeDownCast(m_vtkRenderWindow), ren->getVtkRenderer(), false);
161 }
162 
163 bool
164 VTKOpenVRViewer::initModule()
165 {
166  if (!AbstractVTKViewer::initModule())
167  {
168  return false;
169  }
170 
171  std::shared_ptr<VTKRenderer> ren = getActiveVtkRenderer();
172  ren->initialize();
173 
174  // VR interactor doesn't support timers, here we throw timer event every update
175  // another option would be to conform VTKs VR interactor
176  auto iren = vtkOpenVRRenderWindowInteractorImstk::SafeDownCast(m_vtkRenderWindow->GetInteractor());
177  //iren->Start(); // Cannot use
178  if (iren->HasObserver(vtkCommand::StartEvent))
179  {
180  iren->InvokeEvent(vtkCommand::StartEvent, nullptr);
181  return true;
182  }
183 
184  auto renWin = vtkOpenVRRenderWindow::SafeDownCast(m_vtkRenderWindow);
185  renWin->Initialize();
186 
187  iren->Initialize();
188 
189  // Hide the device overlays
190  // \todo: Display devices in debug mode
191  renWin->Render(); // Must do one render to initialize vtkOpenVRModel's to then hide the devices
192 
193  // Actions must be added after initialization of interactor
194  vtkInteractorStyleVR* iStyle = vtkInteractorStyleVR::SafeDownCast(m_vtkInteractorStyle);
195  iStyle->addButtonActions();
196  iStyle->addMovementActions();
197 
198  // Hide all controller models
199  for (uint32_t i = 0; i < vr::k_unMaxTrackedDeviceCount; i++)
200  {
201  vtkVRModel* trackedDeviceModel = renWin->GetTrackedDeviceModel(i);
202  if (trackedDeviceModel != nullptr)
203  {
204  trackedDeviceModel->SetVisibility(false);
205  }
206  }
207 
208  return true;
209 }
210 
211 void
212 VTKOpenVRViewer::updateModule()
213 {
214  auto ren = std::dynamic_pointer_cast<imstk::VTKRenderer>(getActiveRenderer());
215  if (ren == nullptr)
216  {
217  return;
218  }
219 
220  // For the VR view we can't supply the camera with a view matrix only
221  // Final view = HMD view * user view
222  // User view is the usual view set by the user
223  // HMD view is the hardware view from the headset pose
224  // This means the view in Camera is not the final
225  //
226  // Inconvienent as some code may want to use that
227  std::shared_ptr<Camera> cam = getActiveScene()->getActiveCamera();
228  const Mat4d& view = cam->getView();
229  setPhysicalToWorldTransform(view);
230 
231  // Update cam (copy back hmd info)
232  ren->updateCamera();
233 
234  // Call visual update on every scene object
235  getActiveScene()->updateVisuals(getDt());
236  // Update all the rendering delegates
237  ren->updateRenderDelegates();
238 
239  updateFps();
240 
241  // Render
242  //m_vtkRenderWindow->GetInteractor()->Render();
243  m_vtkRenderWindow->Render();
244 }
245 
246 std::shared_ptr<OpenVRDeviceClient>
247 VTKOpenVRViewer::getVRDeviceClient(int deviceType)
248 {
249  auto iter = std::find_if(m_vrDeviceClients.begin(), m_vrDeviceClients.end(),
250  [&](const std::shared_ptr<OpenVRDeviceClient>& deviceClient)
251  {
252  return static_cast<int>(deviceClient->getDeviceType()) == deviceType;
253  });
254  return (iter == m_vrDeviceClients.end()) ? nullptr : *iter;
255 }
256 } // namespace imstk
Compound Geometry.
void addButtonActions()
Adds button actions.
Mode
Enumerations for the render mode.
Definition: imstkRenderer.h:47
VTK Interactor style for VR.
void addMovementActions()
Adds thumbstick movement actions.
Wraps a vtkRenderer.