vtkOpenVRRenderWindow.h 13.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/*=========================================================================

Program:   Visualization Toolkit

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.

=========================================================================*/
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
/**
 * @class   vtkOpenVRRenderWindow
 * @brief   OpenVR rendering window
 *
 *
 * vtkOpenVRRenderWindow is a concrete implementation of the abstract
 * class vtkRenderWindow. vtkOpenVRRenderer interfaces to the
 * OpenVR graphics library
 *
 * This class and its similar classes are designed to be drop in
 * replacements for VTK. If you link to this module and turn on
 * the CMake option VTK_OPENVR_OBJECT_FACTORY, the object
 * factory mechanism should replace the core rendering classes such as
 * RenderWindow with OpenVR specialized versions. The goal is for VTK
 * programs to be able to use the OpenVR library with little to no
 * changes.
 *
 * This class handles the bulk of interfacing to OpenVR. It supports one
 * renderer currently. The renderer is assumed to cover the entire window
 * which is what makes sense to VR. Overlay renderers can probably be
 * made to work with this but consider how overlays will appear in a
 * HMD if they do not track the viewpoint etc. This class is based on
 * sample code from the OpenVR project.
37 38 39 40 41 42 43 44 45 46 47 48
 *
 * OpenVR provides HMD and controller positions in "Physical" coordinate
 * system.
 * Origin: user's eye position at the time of calibration.
 * Axis directions: x = user's right; y = user's up; z = user's back.
 * Unit: meter.
 *
 * Renderer shows actors in World coordinate system. Transformation between
 * Physical and World coordinate systems is defined by PhysicalToWorldMatrix.
 * This matrix determines the user's position and orientation in the rendered
 * scene and scaling (magnification) of rendered actors.
 *
49
*/
50 51 52 53 54 55 56 57 58 59 60

#ifndef vtkOpenVRRenderWindow_h
#define vtkOpenVRRenderWindow_h

#include "vtkRenderingOpenVRModule.h" // For export macro
#include "vtkOpenGLRenderWindow.h"

#include <openvr.h> // for ivars
#include <vector> // ivars
#include "vtkOpenGLHelper.h" // used for ivars
#include "vtk_glew.h" // used for methods
Ken Martin's avatar
Ken Martin committed
61
#include "vtkEventData.h" // for enums
62

Ken Martin's avatar
Ken Martin committed
63
class vtkCamera;
64
class vtkMatrix4x4;
65
class vtkOpenVRModel;
Ken Martin's avatar
Ken Martin committed
66
class vtkOpenVROverlay;
67 68 69 70 71 72
class vtkOpenGLVertexBufferObject;
class vtkTransform;

class VTKRENDERINGOPENVR_EXPORT vtkOpenVRRenderWindow : public vtkOpenGLRenderWindow
{
public:
73 74 75 76 77
  enum
    {
    PhysicalToWorldMatrixModified = vtkCommand::UserEvent + 200
    };

78 79 80 81
  static vtkOpenVRRenderWindow *New();
  vtkTypeMacro(vtkOpenVRRenderWindow,vtkOpenGLRenderWindow);
  void PrintSelf(ostream& os, vtkIndent indent);

Ken Martin's avatar
Ken Martin committed
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
  /**
   * Get the system pointer
   */
  vr::IVRSystem *GetHMD() { return this->HMD; };

  /**
   * Draw the overlay
   */
  void RenderOverlay();

  //@{
  /**
   * Set/Get the overlay to use on the VR dashboard
   */
  vtkGetObjectMacro(DashboardOverlay, vtkOpenVROverlay);
  void SetDashboardOverlay(vtkOpenVROverlay *);
  //@}

  /**
101 102 103
   * Update the HMD pose based on hardware pose and physical to world transform.
   * VR camera properties are directly modified based on physical to world to
   * simulate \sa PhysicalTranslation, \sa PhysicalScale, etc.
Ken Martin's avatar
Ken Martin committed
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
   */
  void UpdateHMDMatrixPose();

  //@{
  /**
   * Get the frame buffers used for rendering
   */
  GLuint GetLeftRenderBufferId()
    { return this->LeftEyeDesc.m_nRenderFramebufferId; };
  GLuint GetLeftResolveBufferId()
    { return this->LeftEyeDesc.m_nResolveFramebufferId; };
  GLuint GetRightRenderBufferId()
    { return this->RightEyeDesc.m_nRenderFramebufferId; };
  GLuint GetRightResolveBufferId()
    { return this->RightEyeDesc.m_nResolveFramebufferId; };
  void GetRenderBufferSize(int &width, int &height)
    {
    width = this->Size[0];
    height = this->Size[1];
    };
  //@}

  /**
  * Get the VRModel corresponding to the tracked device
  */
  vtkOpenVRModel *GetTrackedDeviceModel(vtkEventDataDevice idx);
  vtkOpenVRModel *GetTrackedDeviceModel(vr::TrackedDeviceIndex_t idx) {
    return this->TrackedDeviceToRenderModel[idx]; };

  /**
134
  * Get the openVR Render Models
Ken Martin's avatar
Ken Martin committed
135 136 137 138 139 140 141 142 143 144 145 146
  */
  vr::IVRRenderModels * GetOpenVRRenderModels() {
    return this->OpenVRRenderModels; };

  /**
  * Get the index corresponding to the tracked device
  */
  vr::TrackedDeviceIndex_t GetTrackedDeviceIndexForDevice(vtkEventDataDevice dev);

  /**
  * Get the most recent pose corresponding to the tracked device
  */
147
  void GetTrackedDevicePose(vtkEventDataDevice idx, vr::TrackedDevicePose_t **pose);
Ken Martin's avatar
Ken Martin committed
148 149 150 151
  vr::TrackedDevicePose_t &GetTrackedDevicePose(vr::TrackedDeviceIndex_t idx) {
    return this->TrackedDevicePose[idx]; };

  /**
152
   * Initialize the HMD to World setting and camera settings so
Ken Martin's avatar
Ken Martin committed
153 154 155 156 157 158 159 160 161 162
   * that the VR world view most closely matched the view from
   * the provided camera. This method is useful for initialing
   * a VR world from an existing on screen window and camera.
   * The Renderer and its camera must already be created and
   * set when this is called.
   */
  void InitializeViewFromCamera(vtkCamera *cam);

  //@{
  /**
163 164 165 166 167 168
   * Set/get physical coordinate system in world coordinate system.
   *
   * View direction is the -Z axis of the physical coordinate system
   * in world coordinate system.
   * \sa SetPhysicalViewUp, \sa SetPhysicalTranslation,
   * \sa SetPhysicalScale, \sa SetPhysicalToWorldMatrix
Ken Martin's avatar
Ken Martin committed
169
   */
170 171
  virtual void SetPhysicalViewDirection(double,double,double);
  virtual void SetPhysicalViewDirection(double[3]);
Ken Martin's avatar
Ken Martin committed
172
  vtkGetVector3Macro(PhysicalViewDirection, double);
173 174 175 176 177 178 179 180 181 182 183
  //@}

  //@{
  /**
   * Set/get physical coordinate system in world coordinate system.
   *
   * View up is the +Y axis of the physical coordinate system
   * in world coordinate system.
   * \sa SetPhysicalViewDirection, \sa SetPhysicalTranslation,
   * \sa SetPhysicalScale, \sa SetPhysicalToWorldMatrix
   */
184 185
  virtual void SetPhysicalViewUp(double,double,double);
  virtual void SetPhysicalViewUp(double[3]);
Ken Martin's avatar
Ken Martin committed
186
  vtkGetVector3Macro(PhysicalViewUp, double);
187 188 189 190 191 192 193 194 195 196 197
  //@}

  //@{
  /**
   * Set/get physical coordinate system in world coordinate system.
   *
   * Position of the physical coordinate system origin
   * in world coordinates.
   * \sa SetPhysicalViewDirection, \sa SetPhysicalViewUp,
   * \sa SetPhysicalScale, \sa SetPhysicalToWorldMatrix
   */
198 199
  virtual void SetPhysicalTranslation(double,double,double);
  virtual void SetPhysicalTranslation(double[3]);
Ken Martin's avatar
Ken Martin committed
200
  vtkGetVector3Macro(PhysicalTranslation, double);
201 202 203 204 205 206 207 208 209 210 211 212
  //@}

  //@{
  /**
   * Set/get physical coordinate system in world coordinate system.
   *
   * Ratio of distance in world coordinate and physical and system
   * (PhysicalScale = distance_World / distance_Physical).
   * Example: if world coordinate system is in mm then
   * PhysicalScale = 1000.0 makes objects appear in real size.
   * PhysicalScale = 100.0 makes objects appear 10x larger than real size.
   */
213
  virtual void SetPhysicalScale(double);
Ken Martin's avatar
Ken Martin committed
214 215 216
  vtkGetMacro(PhysicalScale, double);
  //@}

217 218 219 220 221 222 223 224 225 226 227 228
  /**
  * Set physical to world transform matrix. Members calculated and set from the matrix:
  * \sa PhysicalViewDirection, \sa PhysicalViewUp, \sa PhysicalTranslation, \sa PhysicalScale
  * The x axis scale is used for \sa PhysicalScale
  */
  void SetPhysicalToWorldMatrix(vtkMatrix4x4* matrix);
  /**
  * Get physical to world transform matrix. Members used to calculate the matrix:
  * \sa PhysicalViewDirection, \sa PhysicalViewUp, \sa PhysicalTranslation, \sa PhysicalScale
  */
  void GetPhysicalToWorldMatrix(vtkMatrix4x4* matrix);

Ken Martin's avatar
Ken Martin committed
229 230 231 232 233 234 235 236 237
  //@{
  /**
   * When on the camera will track the HMD position.
   * On is the default.
   */
  vtkSetMacro(TrackHMD, bool);
  vtkGetMacro(TrackHMD, bool);
  //@}

238 239 240 241 242
  /**
   * Add a renderer to the list of renderers.
   */
  virtual void AddRenderer(vtkRenderer *) override;

243 244 245
  /**
   * Begin the rendering process.
   */
246 247
  virtual void Start(void);

248 249 250 251
  /**
   * Update the system, if needed, due to stereo rendering. For some stereo
   * methods, subclasses might need to switch some hardware settings here.
   */
252 253
  virtual void StereoUpdate();

254 255 256 257
  /**
   * Intermediate method performs operations required between the rendering
   * of the left and right eye.
   */
258 259
  virtual void StereoMidpoint();

260 261 262 263
  /**
   * Handles work required once both views have been rendered when using
   * stereo rendering.
   */
264 265
  virtual void StereoRenderComplete();

266 267 268
  /**
   * End the rendering process and display the image.
   */
269 270
  void Frame(void);

271 272 273 274 275 276
  /**
   * Initialize the rendering window.  This will setup all system-specific
   * resources.  This method and Finalize() must be symmetric and it
   * should be possible to call them multiple times, even changing WindowId
   * in-between.  This is what WindowRemap does.
   */
277 278
  virtual void Initialize(void);

279 280 281 282 283
  /**
   * Finalize the rendering window.  This will shutdown all system-specific
   * resources.  After having called this, it should be possible to destroy
   * a window that was used for a SetWindowId() call without any ill effects.
   */
284 285
  virtual void Finalize(void);

286 287 288
  /**
   * Make this windows OpenGL context the current context.
   */
289 290
  void MakeCurrent();

291 292 293
  /**
   * Tells if this window is the current OpenGL context for the calling thread.
   */
294 295
  virtual bool IsCurrent();

296 297 298
  /**
   * Get report of capabilities for the render window
   */
299 300
  const char *ReportCapabilities() { return "OpenVR System";};

301 302 303
  /**
   * Is this render window using hardware acceleration? 0-false, 1-true
   */
304 305
  int IsDirect() { return 1; };

306 307 308
  /**
   * Check to see if a mouse button has been pressed or mouse wheel activated.
   * All other events are ignored by this method.
Kunda's avatar
Kunda committed
309
   * Maybe should return 1 always?
310
   */
311 312
  virtual  int GetEventPending() { return 0;};

313 314 315
  /**
   * Get the current size of the screen in pixels.
   */
316 317
  virtual int *GetScreenSize();

318 319 320 321
  //@{
  /**
   * Set the size of the window in pixels.
   */
322 323
  virtual void SetSize(int,int);
  virtual void SetSize(int a[2]) {vtkOpenGLRenderWindow::SetSize(a);};
324
  //@}
325

326 327 328 329
    //@{
    /**
     * Set the position of the window.
     */
330 331
  virtual void SetPosition(int,int);
  virtual void SetPosition(int a[2]) {vtkOpenGLRenderWindow::SetPosition(a);};
332
    //@}
333 334

  // implement required virtual functions
335 336 337
  void SetWindowInfo(const char *) {};
  void SetNextWindowInfo(const char *) {};
  void SetParentInfo(const char *) {};
338 339
  virtual void *GetGenericDisplayId() {return (void *)this->HelperWindow->GetGenericDisplayId();};
  virtual void *GetGenericWindowId()  {return (void *)this->HelperWindow->GetGenericWindowId();};
Ken Martin's avatar
Ken Martin committed
340
  virtual void *GetGenericParentId()  {return (void *)nullptr;};
341 342
  virtual void *GetGenericContext() { return (void *)this->HelperWindow->GetGenericContext(); };
  virtual void *GetGenericDrawable()  {return (void *)this->HelperWindow->GetGenericDrawable();};
343 344 345 346 347
  virtual void SetDisplayId(void *) {};
  void  SetWindowId(void *) {};
  void  SetParentId(void *) {};
  void HideCursor() {};
  void ShowCursor() {};
348
  virtual void SetFullScreen(vtkTypeBool) {};
349 350 351
  virtual void WindowRemap(void) {};
  virtual void SetNextWindowId(void *) {};

352 353 354
  /**
   * Does this render window support OpenGL? 0-false, 1-true
   */
355 356
  virtual int SupportsOpenGL() { return 1; };

357 358 359 360
  /**
   * Overridden to not release resources that would interfere with an external
   * application's rendering. Avoiding round trip.
   */
361 362
  void Render();

363 364 365 366 367 368
  /**
   * Set/Get the window to use for the openGL context
   */
  vtkGetObjectMacro(HelperWindow, vtkOpenGLRenderWindow);
  void SetHelperWindow(vtkOpenGLRenderWindow *val);

369 370 371 372
  // Get the state object used to keep track of
  // OpenGL state
  vtkOpenGLState *GetState() override;

373 374 375 376
protected:
  vtkOpenVRRenderWindow();
  ~vtkOpenVRRenderWindow();

377 378
  /**
   * Free up any graphics resources associated with this window
Ken Martin's avatar
Ken Martin committed
379
   * a value of nullptr means the context may already be destroyed
380
   */
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
  virtual void ReleaseGraphicsResources(vtkRenderWindow *);

  virtual void CreateAWindow() {};
  virtual void DestroyWindow() {};

  std::string m_strDriver;
  std::string m_strDisplay;
  vr::IVRSystem *HMD;
  vr::IVRRenderModels *OpenVRRenderModels;

  struct FramebufferDesc
  {
    GLuint m_nDepthBufferId;
    GLuint m_nRenderTextureId;
    GLuint m_nRenderFramebufferId;
    GLuint m_nResolveTextureId;
    GLuint m_nResolveFramebufferId;
  };
  FramebufferDesc LeftEyeDesc;
  FramebufferDesc RightEyeDesc;
  bool CreateFrameBuffer( int nWidth, int nHeight,
    FramebufferDesc &framebufferDesc );

  // convert a device index to a human string
  std::string GetTrackedDeviceString(
    vr::IVRSystem *pHmd,
    vr::TrackedDeviceIndex_t unDevice,
    vr::TrackedDeviceProperty prop,
Ken Martin's avatar
Ken Martin committed
409
    vr::TrackedPropertyError *peError = nullptr );
410 411 412 413 414 415 416 417 418 419 420

  // devices may have polygonal models
  // load them
  vtkOpenVRModel *FindOrLoadRenderModel(const char *modelName );
  void RenderModels();
  std::vector<vtkOpenVRModel * > VTKRenderModels;
  vtkOpenVRModel *TrackedDeviceToRenderModel[ vr::k_unMaxTrackedDeviceCount ];
  vr::TrackedDevicePose_t TrackedDevicePose[ vr::k_unMaxTrackedDeviceCount ];

  // used in computing the pose
  vtkTransform *HMDTransform;
421
  /// -Z axis of the Physical to World matrix
Ken Martin's avatar
Ken Martin committed
422
  double PhysicalViewDirection[3];
423
  /// Y axis of the Physical to World matrix
Ken Martin's avatar
Ken Martin committed
424
  double PhysicalViewUp[3];
425
  /// Inverse of the translation component of the Physical to World matrix, in mm
Ken Martin's avatar
Ken Martin committed
426
  double PhysicalTranslation[3];
427
  /// Scale of the Physical to World matrix
Ken Martin's avatar
Ken Martin committed
428
  double PhysicalScale;
Ken Martin's avatar
Ken Martin committed
429 430 431

  // for the overlay
  vtkOpenVROverlay *DashboardOverlay;
432

Ken Martin's avatar
Ken Martin committed
433 434
  bool TrackHMD;

435 436 437
  vtkOpenGLRenderWindow *HelperWindow;


438
private:
439 440
  vtkOpenVRRenderWindow(const vtkOpenVRRenderWindow&) = delete;
  void operator=(const vtkOpenVRRenderWindow&) = delete;
441 442 443 444
};


#endif