/data/git-repository/acgl/templates/GLFWExamples/ features an example of how to integrate the Oculus Rift HMD. If the camera is controlled with a GenericCamera object from ACGL supporting the Rift should be quite simple. The following has to be done each frame in general to support the Rift:
Get the current head transformation from the Rift and set this as the cameras rotation
Render the view of the left eye
Render the view of the right eye
Render the two views in a distorted way side-by-side for the Rift
The Rift example features a special class named SimpleRiftController to assist with this task. In most cases the details about the camera parameters needed for the two renderings as well as the query of the Rifts orientation and the details about the distorted rendering can be hidden inside of the camera class and the SimpleRiftController.
Step by Step
Add the Oculus SDK to your project. You don't need special drivers as the display is just another screen and the headtracker can be read as a standard USB device. Copy the rift/extern/LibOVR folder from the GLFWExamples to your project and add
to your CMakeLists.txt (you might have to adjust the path). The include will also set the needed additional libs as long as you only add new libs to the LIBRARIES variable and don't replace it (see the examples CMakeLists.txt of the Rift example). Note that libudev-dev is needed for compiling the SDK on Linux. If this isn't already installed on a specific lab machine, ask Robert or Jan.
Define ACGL_USE_OCULUS_RIFT (e.g. ADD_DEFINITIONS(-DACGL_USE_OCULUS_RIFT) ) to add the SimpleRiftController class in ACGL (it's located in HardwareSupport). Add it to your project and also copy the distortion shaders from the GLFWExample in case you want to adjust them!
Replace the camera: You can either provide your camera to the SimpleRiftController or (recommended) use the camera that comes with the controller. To do so, just call getCamera() instead of creating your own. Note that the Controller uses a HMDCamera instead of a GenericCamera but this is derived from the GenericCamera so you can still use the same API everywhere. The "old" API will control the "neck" of the player while the SimpleRiftController sets the head rotation and getViewMatrix and getProjectionMatrix will return the matrices that already account for the Rift rotation and special projection parameters.
Call updateCamera() from the SimpleRiftController each frame so the Controller can query the hardware and set the rotation of the head.
Call setEye( GenericCamera::EYE_LEFT ) to the camera and render the left image, then call setEye( GenericCamera::EYE_RIGHT ) and render the right image. Do this either into the same framebuffer side-by-side (see glViewport to only render to a part of the viewport) or render into two textures by binding a different framebuffer for the last render pass.
Call from the SimpleRiftControllerrenderDistorted( ... ) with one texture as a parameter for side-by-side content or two textures for rendering into a "left" and a "right" image. You will find examples of both techniques in the Rift example.
Optimizing the Rendering
With the default settings you might notice that the Rift does not use up much of the frame and inside of the Rift you will see the border of the rendering (depending on the lenses you use etc.). To increase the space used for rendering (and also increasing the rendered field of view), use setDistortionScaleFactor, 1.0 is the default and around 1.75 is often enough. If this is set however, the center of the screen gets subsampled and artifacts become visible (more visible during movements inside of the Rift). To counter this, increase the resolution at which the image gets rendered. You can render the side-by-side texture or the two textures of the two eyes in any resolution you want, e.g. go FullHD for both screens combined for a 1280x800 Rift.
The hardware of the first devkit can be used as a 1280x800 or 1920x1080 screen. As 1280x800 is the native resolution, this should be used. Best results are archived when the Rift is the only display and no VSync is used for a minimum of latency. However, while developing the Rift can be used either in clone view or as an overlay of the main screen covering a part of the main screen. This way you can move the windowed game into the corner covered by the Rift.
You can adjust the inter pupillary distance (distance between the pupils in meters) at the camera.
The distortion can be switched off at the SimpleRiftController for debugging (turns rendering into side-by-side).
The chromatic aberration can be switched off at the SimpleRiftController (e.g. for screenshots).
The HMDCamera has settings to control the offset from the neck to the eyes to simulate a more realistic control (we don't rotate around the eyes). See setNeckToEyeVerticalDistanceand and setNeckToEyeHorizontalDistance.
setOutputViewportSize() of the SimpleRiftController should be set to the size of the output window. This should be the native Rift resolution and can be scaled to anything.
Try to get 60 FPS, the difference between 30 and 60 is clearly visible when using a HMD.
Think about where to place your UI elements (in 3D space). The center of projection is not the center of the screens so you need to use the special projection matrices from the HMDCamera and need to place UI elements in the scene. Also keep in mind that text has to be large to be readable.
Try using a gamepad instead of a keyboard/mouse for input - players won't find the keys again after lifting the hands from the keyboard...
Don't use forced camera movements: When the camera gets controlled by your game logic and doesn't match up with the head movements the users will get dizzy quite fast (we're talking seconds here). Also: no static spash screens, everything should be static in 3D so the player can move the head and the content should be fixed in 3D, not in screen space.
Playing can disorient you, start playing sitting down. Asking a novel player to stand on a BalanceBoard waving there hands for a kinect while wearing a Rift is not a good idea...
The rotation of the Rift is relative to the position it was positioned while starting the application. There should be an option added to reset this neutral position, will be added soon.
If the Rift is connected but does not get recognized, try to unplug the USB and plug it in again. If the problem does not go away, make sure the Resolution is set to the native Rift resolution (1280*800) and not FullHD!
Windows and MacOS X
The SDK also supports MacOS X and Windows and our code should work there too but wasn't tested on them yet. You might have to adjust the CMakeLists files and you will probably have to add additional libs for linkage.