1 /*========================================================================= 2 3 Program: Visualization Toolkit 4 5 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 6 All rights reserved. 7 See Copyright.txt or http://www.kitware.com/Copyright.htm for details. 8 9 This software is distributed WITHOUT ANY WARRANTY; without even 10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 11 PURPOSE. See the above copyright notice for more information. 12 13 =========================================================================*/ 14 /** 15 * @class vtkOpenVRRenderWindow 16 * @brief OpenVR rendering window 17 * 18 * 19 * vtkOpenVRRenderWindow is a concrete implementation of the abstract 20 * class vtkRenderWindow. vtkOpenVRRenderer interfaces to the 21 * OpenVR graphics library 22 * 23 * This class and its similar classes are designed to be drop in 24 * replacements for VTK. If you link to this module and turn on 25 * the CMake option VTK_OPENVR_OBJECT_FACTORY, the object 26 * factory mechanism should replace the core rendering classes such as 27 * RenderWindow with OpenVR specialized versions. The goal is for VTK 28 * programs to be able to use the OpenVR library with little to no 29 * changes. 30 * 31 * This class handles the bulk of interfacing to OpenVR. It supports one 32 * renderer currently. The renderer is assumed to cover the entire window 33 * which is what makes sense to VR. Overlay renderers can probably be 34 * made to work with this but consider how overlays will appear in a 35 * HMD if they do not track the viewpoint etc. This class is based on 36 * sample code from the OpenVR project. 37 * 38 * OpenVR provides HMD and controller positions in "Physical" coordinate 39 * system. 40 * Origin: user's eye position at the time of calibration. 41 * Axis directions: x = user's right; y = user's up; z = user's back. 42 * Unit: meter. 43 * 44 * Renderer shows actors in World coordinate system. Transformation between 45 * Physical and World coordinate systems is defined by PhysicalToWorldMatrix. 46 * This matrix determines the user's position and orientation in the rendered 47 * scene and scaling (magnification) of rendered actors. 48 * 49 */ 50 51 #ifndef vtkOpenVRRenderWindow_h 52 #define vtkOpenVRRenderWindow_h 53 54 #include "vtkRenderingOpenVRModule.h" // For export macro 55 #include "vtkOpenGLRenderWindow.h" 56 57 #include <openvr.h> // for ivars 58 #include <vector> // ivars 59 #include "vtkOpenGLHelper.h" // used for ivars 60 #include "vtk_glew.h" // used for methods 61 #include "vtkEventData.h" // for enums 62 63 class vtkCamera; 64 class vtkMatrix4x4; 65 class vtkOpenVRModel; 66 class vtkOpenVROverlay; 67 class vtkOpenGLVertexBufferObject; 68 class vtkTransform; 69 70 class VTKRENDERINGOPENVR_EXPORT vtkOpenVRRenderWindow : public vtkOpenGLRenderWindow 71 { 72 public: 73 enum 74 { 75 PhysicalToWorldMatrixModified = vtkCommand::UserEvent + 200 76 }; 77 78 static vtkOpenVRRenderWindow *New(); 79 vtkTypeMacro(vtkOpenVRRenderWindow,vtkOpenGLRenderWindow); 80 void PrintSelf(ostream& os, vtkIndent indent); 81 82 /** 83 * Get the system pointer 84 */ GetHMD()85 vr::IVRSystem *GetHMD() { return this->HMD; }; 86 87 /** 88 * Draw the overlay 89 */ 90 void RenderOverlay(); 91 92 //@{ 93 /** 94 * Set/Get the overlay to use on the VR dashboard 95 */ 96 vtkGetObjectMacro(DashboardOverlay, vtkOpenVROverlay); 97 void SetDashboardOverlay(vtkOpenVROverlay *); 98 //@} 99 100 /** 101 * Update the HMD pose based on hardware pose and physical to world transform. 102 * VR camera properties are directly modified based on physical to world to 103 * simulate \sa PhysicalTranslation, \sa PhysicalScale, etc. 104 */ 105 void UpdateHMDMatrixPose(); 106 107 //@{ 108 /** 109 * Get the frame buffers used for rendering 110 */ GetLeftRenderBufferId()111 GLuint GetLeftRenderBufferId() 112 { return this->LeftEyeDesc.m_nRenderFramebufferId; }; GetLeftResolveBufferId()113 GLuint GetLeftResolveBufferId() 114 { return this->LeftEyeDesc.m_nResolveFramebufferId; }; GetRightRenderBufferId()115 GLuint GetRightRenderBufferId() 116 { return this->RightEyeDesc.m_nRenderFramebufferId; }; GetRightResolveBufferId()117 GLuint GetRightResolveBufferId() 118 { return this->RightEyeDesc.m_nResolveFramebufferId; }; GetRenderBufferSize(int & width,int & height)119 void GetRenderBufferSize(int &width, int &height) 120 { 121 width = this->Size[0]; 122 height = this->Size[1]; 123 }; 124 //@} 125 126 /** 127 * Get the VRModel corresponding to the tracked device 128 */ 129 vtkOpenVRModel *GetTrackedDeviceModel(vtkEventDataDevice idx); GetTrackedDeviceModel(vr::TrackedDeviceIndex_t idx)130 vtkOpenVRModel *GetTrackedDeviceModel(vr::TrackedDeviceIndex_t idx) { 131 return this->TrackedDeviceToRenderModel[idx]; }; 132 133 /** 134 * Get the openVR Render Models 135 */ GetOpenVRRenderModels()136 vr::IVRRenderModels * GetOpenVRRenderModels() { 137 return this->OpenVRRenderModels; }; 138 139 /** 140 * Get the index corresponding to the tracked device 141 */ 142 vr::TrackedDeviceIndex_t GetTrackedDeviceIndexForDevice(vtkEventDataDevice dev); 143 144 /** 145 * Get the most recent pose corresponding to the tracked device 146 */ 147 void GetTrackedDevicePose(vtkEventDataDevice idx, vr::TrackedDevicePose_t **pose); GetTrackedDevicePose(vr::TrackedDeviceIndex_t idx)148 vr::TrackedDevicePose_t &GetTrackedDevicePose(vr::TrackedDeviceIndex_t idx) { 149 return this->TrackedDevicePose[idx]; }; 150 151 /** 152 * Initialize the HMD to World setting and camera settings so 153 * that the VR world view most closely matched the view from 154 * the provided camera. This method is useful for initialing 155 * a VR world from an existing on screen window and camera. 156 * The Renderer and its camera must already be created and 157 * set when this is called. 158 */ 159 void InitializeViewFromCamera(vtkCamera *cam); 160 161 //@{ 162 /** 163 * Set/get physical coordinate system in world coordinate system. 164 * 165 * View direction is the -Z axis of the physical coordinate system 166 * in world coordinate system. 167 * \sa SetPhysicalViewUp, \sa SetPhysicalTranslation, 168 * \sa SetPhysicalScale, \sa SetPhysicalToWorldMatrix 169 */ 170 virtual void SetPhysicalViewDirection(double,double,double); 171 virtual void SetPhysicalViewDirection(double[3]); 172 vtkGetVector3Macro(PhysicalViewDirection, double); 173 //@} 174 175 //@{ 176 /** 177 * Set/get physical coordinate system in world coordinate system. 178 * 179 * View up is the +Y axis of the physical coordinate system 180 * in world coordinate system. 181 * \sa SetPhysicalViewDirection, \sa SetPhysicalTranslation, 182 * \sa SetPhysicalScale, \sa SetPhysicalToWorldMatrix 183 */ 184 virtual void SetPhysicalViewUp(double,double,double); 185 virtual void SetPhysicalViewUp(double[3]); 186 vtkGetVector3Macro(PhysicalViewUp, double); 187 //@} 188 189 //@{ 190 /** 191 * Set/get physical coordinate system in world coordinate system. 192 * 193 * Position of the physical coordinate system origin 194 * in world coordinates. 195 * \sa SetPhysicalViewDirection, \sa SetPhysicalViewUp, 196 * \sa SetPhysicalScale, \sa SetPhysicalToWorldMatrix 197 */ 198 virtual void SetPhysicalTranslation(double,double,double); 199 virtual void SetPhysicalTranslation(double[3]); 200 vtkGetVector3Macro(PhysicalTranslation, double); 201 //@} 202 203 //@{ 204 /** 205 * Set/get physical coordinate system in world coordinate system. 206 * 207 * Ratio of distance in world coordinate and physical and system 208 * (PhysicalScale = distance_World / distance_Physical). 209 * Example: if world coordinate system is in mm then 210 * PhysicalScale = 1000.0 makes objects appear in real size. 211 * PhysicalScale = 100.0 makes objects appear 10x larger than real size. 212 */ 213 virtual void SetPhysicalScale(double); 214 vtkGetMacro(PhysicalScale, double); 215 //@} 216 217 /** 218 * Set physical to world transform matrix. Members calculated and set from the matrix: 219 * \sa PhysicalViewDirection, \sa PhysicalViewUp, \sa PhysicalTranslation, \sa PhysicalScale 220 * The x axis scale is used for \sa PhysicalScale 221 */ 222 void SetPhysicalToWorldMatrix(vtkMatrix4x4* matrix); 223 /** 224 * Get physical to world transform matrix. Members used to calculate the matrix: 225 * \sa PhysicalViewDirection, \sa PhysicalViewUp, \sa PhysicalTranslation, \sa PhysicalScale 226 */ 227 void GetPhysicalToWorldMatrix(vtkMatrix4x4* matrix); 228 229 //@{ 230 /** 231 * When on the camera will track the HMD position. 232 * On is the default. 233 */ 234 vtkSetMacro(TrackHMD, bool); 235 vtkGetMacro(TrackHMD, bool); 236 //@} 237 238 /** 239 * Add a renderer to the list of renderers. 240 */ 241 virtual void AddRenderer(vtkRenderer *) override; 242 243 /** 244 * Begin the rendering process. 245 */ 246 virtual void Start(void); 247 248 /** 249 * Update the system, if needed, due to stereo rendering. For some stereo 250 * methods, subclasses might need to switch some hardware settings here. 251 */ 252 virtual void StereoUpdate(); 253 254 /** 255 * Intermediate method performs operations required between the rendering 256 * of the left and right eye. 257 */ 258 virtual void StereoMidpoint(); 259 260 /** 261 * Handles work required once both views have been rendered when using 262 * stereo rendering. 263 */ 264 virtual void StereoRenderComplete(); 265 266 /** 267 * End the rendering process and display the image. 268 */ 269 void Frame(void); 270 271 /** 272 * Initialize the rendering window. This will setup all system-specific 273 * resources. This method and Finalize() must be symmetric and it 274 * should be possible to call them multiple times, even changing WindowId 275 * in-between. This is what WindowRemap does. 276 */ 277 virtual void Initialize(void); 278 279 /** 280 * Finalize the rendering window. This will shutdown all system-specific 281 * resources. After having called this, it should be possible to destroy 282 * a window that was used for a SetWindowId() call without any ill effects. 283 */ 284 virtual void Finalize(void); 285 286 /** 287 * Make this windows OpenGL context the current context. 288 */ 289 void MakeCurrent(); 290 291 /** 292 * Tells if this window is the current OpenGL context for the calling thread. 293 */ 294 virtual bool IsCurrent(); 295 296 /** 297 * Get report of capabilities for the render window 298 */ ReportCapabilities()299 const char *ReportCapabilities() { return "OpenVR System";}; 300 301 /** 302 * Is this render window using hardware acceleration? 0-false, 1-true 303 */ IsDirect()304 int IsDirect() { return 1; }; 305 306 /** 307 * Check to see if a mouse button has been pressed or mouse wheel activated. 308 * All other events are ignored by this method. 309 * Maybe should return 1 always? 310 */ GetEventPending()311 virtual int GetEventPending() { return 0;}; 312 313 /** 314 * Get the current size of the screen in pixels. 315 */ 316 virtual int *GetScreenSize(); 317 318 //@{ 319 /** 320 * Set the size of the window in pixels. 321 */ 322 virtual void SetSize(int,int); SetSize(int a[2])323 virtual void SetSize(int a[2]) {vtkOpenGLRenderWindow::SetSize(a);}; 324 //@} 325 326 //@{ 327 /** 328 * Set the position of the window. 329 */ 330 virtual void SetPosition(int,int); SetPosition(int a[2])331 virtual void SetPosition(int a[2]) {vtkOpenGLRenderWindow::SetPosition(a);}; 332 //@} 333 334 // implement required virtual functions SetWindowInfo(const char *)335 void SetWindowInfo(const char *) {}; SetNextWindowInfo(const char *)336 void SetNextWindowInfo(const char *) {}; SetParentInfo(const char *)337 void SetParentInfo(const char *) {}; GetGenericDisplayId()338 virtual void *GetGenericDisplayId() {return (void *)this->HelperWindow->GetGenericDisplayId();}; GetGenericWindowId()339 virtual void *GetGenericWindowId() {return (void *)this->HelperWindow->GetGenericWindowId();}; GetGenericParentId()340 virtual void *GetGenericParentId() {return (void *)nullptr;}; GetGenericContext()341 virtual void *GetGenericContext() { return (void *)this->HelperWindow->GetGenericContext(); }; GetGenericDrawable()342 virtual void *GetGenericDrawable() {return (void *)this->HelperWindow->GetGenericDrawable();}; SetDisplayId(void *)343 virtual void SetDisplayId(void *) {}; SetWindowId(void *)344 void SetWindowId(void *) {}; SetParentId(void *)345 void SetParentId(void *) {}; HideCursor()346 void HideCursor() {}; ShowCursor()347 void ShowCursor() {}; SetFullScreen(vtkTypeBool)348 virtual void SetFullScreen(vtkTypeBool) {}; WindowRemap(void)349 virtual void WindowRemap(void) {}; SetNextWindowId(void *)350 virtual void SetNextWindowId(void *) {}; 351 352 /** 353 * Does this render window support OpenGL? 0-false, 1-true 354 */ SupportsOpenGL()355 virtual int SupportsOpenGL() { return 1; }; 356 357 /** 358 * Overridden to not release resources that would interfere with an external 359 * application's rendering. Avoiding round trip. 360 */ 361 void Render(); 362 363 /** 364 * Set/Get the window to use for the openGL context 365 */ 366 vtkGetObjectMacro(HelperWindow, vtkOpenGLRenderWindow); 367 void SetHelperWindow(vtkOpenGLRenderWindow *val); 368 369 // Get the state object used to keep track of 370 // OpenGL state 371 vtkOpenGLState *GetState() override; 372 373 protected: 374 vtkOpenVRRenderWindow(); 375 ~vtkOpenVRRenderWindow(); 376 377 /** 378 * Free up any graphics resources associated with this window 379 * a value of nullptr means the context may already be destroyed 380 */ 381 virtual void ReleaseGraphicsResources(vtkRenderWindow *); 382 CreateAWindow()383 virtual void CreateAWindow() {}; DestroyWindow()384 virtual void DestroyWindow() {}; 385 386 std::string m_strDriver; 387 std::string m_strDisplay; 388 vr::IVRSystem *HMD; 389 vr::IVRRenderModels *OpenVRRenderModels; 390 391 struct FramebufferDesc 392 { 393 GLuint m_nDepthBufferId; 394 GLuint m_nRenderTextureId; 395 GLuint m_nRenderFramebufferId; 396 GLuint m_nResolveTextureId; 397 GLuint m_nResolveFramebufferId; 398 }; 399 FramebufferDesc LeftEyeDesc; 400 FramebufferDesc RightEyeDesc; 401 bool CreateFrameBuffer( int nWidth, int nHeight, 402 FramebufferDesc &framebufferDesc ); 403 404 // convert a device index to a human string 405 std::string GetTrackedDeviceString( 406 vr::IVRSystem *pHmd, 407 vr::TrackedDeviceIndex_t unDevice, 408 vr::TrackedDeviceProperty prop, 409 vr::TrackedPropertyError *peError = nullptr ); 410 411 // devices may have polygonal models 412 // load them 413 vtkOpenVRModel *FindOrLoadRenderModel(const char *modelName ); 414 void RenderModels(); 415 std::vector<vtkOpenVRModel * > VTKRenderModels; 416 vtkOpenVRModel *TrackedDeviceToRenderModel[ vr::k_unMaxTrackedDeviceCount ]; 417 vr::TrackedDevicePose_t TrackedDevicePose[ vr::k_unMaxTrackedDeviceCount ]; 418 419 // used in computing the pose 420 vtkTransform *HMDTransform; 421 /// -Z axis of the Physical to World matrix 422 double PhysicalViewDirection[3]; 423 /// Y axis of the Physical to World matrix 424 double PhysicalViewUp[3]; 425 /// Inverse of the translation component of the Physical to World matrix, in mm 426 double PhysicalTranslation[3]; 427 /// Scale of the Physical to World matrix 428 double PhysicalScale; 429 430 // for the overlay 431 vtkOpenVROverlay *DashboardOverlay; 432 433 bool TrackHMD; 434 435 vtkOpenGLRenderWindow *HelperWindow; 436 437 438 private: 439 vtkOpenVRRenderWindow(const vtkOpenVRRenderWindow&) = delete; 440 void operator=(const vtkOpenVRRenderWindow&) = delete; 441 }; 442 443 444 #endif 445