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