Stunning
3D gaming headsets are something computer gamers were looking for for two decades and more. There never was a solution that was both affordable and offered good rendering quality. The Oculus Rift 3D headsets are about to change that; And even though I am less and less interested in playing and coding computer games, it stirred my interest. Yet I declined when being asked to add Oculus Rift support to D2X-XL, because I couldn't find a reason to purchase a 300 Euro development toolkit and sink a lot more time than I have already done into this old game when I wasn't even playing it anymore. So I set up a hurdle that noone would overcome, by saying that I would only add Oculus Rift support when someone donated a dev kit to me.
Well ... someone did, forcing me to sink way more time in it than I had wanted and expected into this endeavour.
Renderer
Before I could even start adding the specific stereo rendering code for the Oculus Rift, I had to dig quite deep into my renderer and adjust a bunch of things in it. This worked out pretty well though and could be tested without a dev kit, so I was more or less finished with that when the dev kit arrived. As a by-product, D2X-XL received a side-by-side rendering path for 3D TVs.
When the dev kit arrived, I had already figured most of what I had to do to make D2X-XL work with the Oculus Rift. I have to say that the dev kit is excellent. The hardware came in a nice, tidy plastic hardcase, the documentation is very good and the SDK is very well programmed and shields a game developer from most of the dirty work of integrating a piece of hardware with your software.
The Going Got Rough ...
When playing around with the Oculus Rift, I noticed a weird bug which turned out to be occurring in every side by side rendering stereo mode, and which really drove me crazy. I was hunting it for hours and hours, but I just couldn't figure what caused it. In the end it turned out that the current render target for some mysterious reason got deactivated. I had developed a suspicion that this might have been what was happening, but it was so illogical that trying to fix that was the last thing on my bug research list. Disabling and re-enabling it solved the issue. What is really weird is that everything worked just fine for anaglyph stereoscopic rendering which has an almost identical render path.
And Rougher ...
Work on the Rift render path still wasn't finished: The renderer must provide a lens adaptation. Both the projection and the distortion shader
need to shift each eye's frame slightly towards the center of the Rift's display. It took me quite a while to get the projection shift right,
and multiplying matrices in the right order helped a lot.
Each eye's view axis also needs to be slightly shifted away from the center of the scene. The shift has to correspond to the user's interpupillary distance (IPD), which can be anywhere between 54 mm and 72 mm, and which needs to be translated into the world units of the renderer. But what real word measure does one world unit of the Descent renderer correspond to? After thinking about it for a while and using the Pyro's dimensions gave me a clue. The Pyro is 4.7 Descent world units long. The Pyro is pretty small for a plane, rather like a limousine. So I decided that having one world unit correspond to one real world meter would be a healthy measure delivering good 3D rendering results. Since Descent uses fix point arithmetic with a resolution of 1 / 65536, 1 mm therefore roughly equivalents to 64 in the renderer arithmetic.
Applying shifts to the forward view vector based on that number and the user configured IPD seemed to work very well, and D2X-XL finally delivered properly rendered frames to the Rift. The last thing that had to be done here was to create the proper sense of distance that would correspond to how Descent levels appear when being played in regular pseudo 3D fashion.
HUD And Menus
Still, I was far from being done. The menus and all HUD elements needed to be properly rendered for stereoscopic 3D vision inside the Oculus Rift, or you would have a hard time reading them. Since the Rift has a pretty low resolution of only 640x800 pixels per eye, menu fonts also had to be scaled down. Fortunately the font manager I had written for D2X-XL offered such a feature already. Menus will be shifted by a fixed amount towards the center of screen for each eye - I hope this will work well for at least the majority of Oculus Rift users playing D2X-XL.
The HUD gave me more headaches. I decided to use a floating displacement, getting larger the further a HUD element was away from the screen center. Only after looking at the result of my work I understood that I had more or less wasted my time here: Funny enough, despite the nominally huge FOV of the Rift, your actual field of view is much smaller than with a regular 2D screen. That is because viewing the image displayed on the screen requires a very small fov, perceiving all information presented there close to the center of your vision, even the one at the screen borders. With the Rift, stuff displayed at the screen border is so far at the periphery of your vision that you cannot see it. The actual useable fov is probably a quarter of the nominal one (i.e. you won't see anything that is further than a quarter of the displayed scene's width/height from the center of the scene).
So most HUD elements are so far at the periphery of vision that they cannot be seen at all. That was a problem at least as the most vital game information (shields, energy, armed weapons was concerned. The result was a compromise were only that information would be displayed in an area visible to the Rift user. Since it is pretty obtrusive at least for the low resolution dev kit headset, it can by turned off in the cockpit options menu.
Head Tracking
The last thing to add was head tracking. Adding the head tracking code and changing the view direction of the player proved very simple. As usual, the devil was in the detail. Players tend to move their heads around a bit when playing a first person game, particularly a flying game: You try to peek around corners and anticipate the flight path through a curved tunnel. Now how to give the player feedback how far his view direction was off his flight direction? After some experimentation I decided to have the reticle slip to the side as the player looked away more and more from the flight direction, and display a shadow reticle in the center of the screen. If both reticles overlay, it means the player is looking straight forward. To compensate for small head movements and changes of posture, a deadzone can be applied to head tracking. It has a little side effect of the sight seeming to pop away from the flight direction when turning the head enough which I could not compensate for despite having the sight angle grow progressively, but it still makes flying with the headset much more comfortable and also gives a good clue when you are facing away from the flight direction.
D2X-XL automatically calibrates the Rift to the game when launcing a level, using its current orientation. If the Rift orientation strays too far from the ship orientation in the game, you can re-calibrate it by pressing CTRL+F10 in-game.
Limitations
Due to the limited view area of at least the 720p dev kit version of the Oculus Rift, D2X-XL will automatically switch to the cockpit-less fullscreen view when enabling Oculus Rift rendering. You will also only see the most vital information in the HUD, the only candy here being the radar that fits well with the Rift's 3D view. This might change once a 3D cockpit is available, since then all HUD elements will actually have a spatial position, and you can view them by simply moving your head a bit, but until then we will all have to live with these limitations.
Final Impression
Despite the limited field of view and horrible screen resolution of the Oculus Rift, playing with it is quite immersive and gives a taste of
what the high resolution customer version of the 3D headset might deliver. I am getting nauseous to the extent of feeling physically sick in
the stomach on a regular base when playing Descent with the Rift, and I am definitely used to playing first person games and stereo
rendering!
Minimal HUD
HUD with vital information
Shadow Reticle
The images look so distorted because the Oculus Rift hardware creates a pin-cushion distortion that needs to be compensated by the renderer. When viewed through an Oculus Rift, the scene looks perfectly orthogonal.