Monday, August 18, 2014

Developing for Oculus Rift DK2

I've purchased an Oculus Rift Development Kit 2. In a sense it feels like going back to my thirties. Much of my professional career was in Virtual Reality. I can't remember for how long exactly, but I think it was for 8 years or so, that I developed software and ran VR projects for SARA's CAVE. See below for a picture or me, mining genomics data that we visualized for Johnson&Johnson.

Since 2007, my career has been in Video Games. Even though I had been making games since 1982, it took me 25 years of hobby game development before I decided to do this for a living. And since 2010 I do this independently as a private enterprise. Back to 2014: my two careers have crossed, and I find myself actually developing Games for Virtual Reality. A younger me would have labeled this as heaven, but the years at SARA have made me cautious about the adoption rate of VR. This current VR revival could be another one that is destined to go out like a candle.

This web page will function as a development log. I intend to document peculiarities, problems and solutions that are bound to pop up during DK2 development. If you just want to play my VR game, download The Little Plane That Could.

Windows Driver issues

  • When using the 'Direct' Rift Display Mode, I get extreme chromatic shifts. The different channels R/G/B are rendered all over the place, not converging what so ever. 'Extended Desktop' display mode works better.
  • The SDK precompiled example runs badly, the jitter is horrible and is only alleviated a bit if I toggle multi sampling. It's hard to say which mode (ON or OFF) reduces jitter, because both look exactly the same, with the same level of aliasing.

Development under Windows

  • After installing windows runtime and sdk, the latest firmware can be flashed to the device.
  • The SDK example 'Oculus Room Tiny' is intended as the minimalistic code to base your first VR app on. It comes with a Visual Studio 2013 solution. Unfortunately this does not build out of the box. But what is worse: it is a D3D app, and not an OpenGL based app. The SDK seems to support both, but unfortunately the sample is in D3D only. Bummer!
  • Building Oculus Room Tiny yields a: Cannot open include file: 'AtlBase.h'
  • Linking the sample also fails: fatal error LNK1104: cannot open file 'atls.lib'
  • To fix these compiler and linker errors, you need to install a Windows Driver Kit, as described on Stack Overflow.
  • If you want to link your own app against libOVR, you need to add these to the linker input: libovr.lib (libovrd.lib for Debug), ws2_32.lib and winmm.lib.
  • The Rift display mode (Extended Desktop vs Direct) seems to mess with OpenGL context creation. When 'Extended Desktop' is enabled, SDL_GL_CreateContext() can create a 3.2 Core profile context. If I ask for a 3.2 Core profile when the mode is set to 'Direct', then SDL_GL_CreateContext() crashes with an access violation at address 0.

Development under GNU/Linux

  • Let's start with some good news: Oculus intends to release DK2 SDKs for Windows, OSX and Linux. The bad news: so far no Linux SDK for the DK2 has appeared. It was labeled as 'soon' but has been delayed quite a bit now.

General Development issues

  • You can create the projection matrix for each eye with a call to ovrMatrix4f_Projection() but you need to transpose the result before using.
  • You can build the view matrix for each eye using the eyePose from ovrHmd_GetEyePose(). Strangely enough you still need to shift the position of the eye with the intra occular distance. Like the project matrix, the view matrix need transposing as well.

Tuesday, August 12, 2014

Routers with restrictive NAT spoiling online gameplay.

I have published an online tank simulator for both iOS and Android. On the app store it is called Buggy Bang Bang! and was renamed as Six Wheels and a Gun on Google play. Players on iOS and Android can even play each other, as they are all pooled on the same lobby server. I wrote the lobby server code myself using Python.

A neat thing about my networking code (C for the clients, Python for the lobby server) is that it is 100% UDP based. There is not a single TCP connection used, just some UDP packets that get exchanged with both server and opponent's client. Two players playing my game are typically on a LAN behind a router that does NAT (Network Address Translation) and this complicates things. It means that the only way they can connect to each other is to have them both connect to a server on the internet, with a public IP. This server will then see datagrams coming in on some random ports, and can tell both parties what these ports are. This is the concept behind UDP hole punching.

Things go wrong if your router is too restrictive. It may do Symmetric NAT, or Restricted Cone NAT. If this happens, the players will not find each other on the ports as described by their common server. In my game, it will result in two buggies that refuse to move and after 12 seconds, the match will time out and record this as a 'forfeit' by the other party. Moral of the story: if you play my game and the HUD controls don't show up with the buggies just sitting there, then your router or your opponent's router will not play ball. So far my approach to this is: too bad it happens, better luck next time. If you want, read the manual of your router and change the NAT type.

UPDATE

I've been adding a new feature to S.W.a.a.G. that detects restrictive NATs. Instead of pairing up a user with a bad NAT, we nominate two players for a session. If one of them fails to punch a hole in the firewall, the match will not be started. The players are informed of the situation with either of these two messages:

  • YOUR NAT SEEMS TOO RESTRICTIVE.
  • OPPONENT NAT SEEMS TOO RESTRICTIVE.
So at least the players will know what is going on. If it is your opponent, you can just retry, and hopefully get paired with another user.