A couple of weeks ago, I wrote about a quick and easy calibration method. This calibration method allowed us to not only map a virtual space to a physical space with reasonable accuracy, but synchronize a virtual space between multiple users.
However, as I used this method in practice with the new Oculus Quest, I noticed a couple of problems that slowed down the flow. Because the calibration offsets are generated in the software’s virtual space, this means whenever the virtual space changes, our calibration is no longer valid. When does the virtual space get reset? On the Oculus Quest, it seems to reset whenever:
- The user quits the application and starts it again.
- The Oculus button is pressed and held for a couple seconds.
- The Quest is removed from the head and goes into sleep mode.
- The Quest is removed from the guardian space for an extended period of time or creates a new guardian.
Despite my best efforts to disable this resetting, it seemed like the Quest continued to do this. I found some settings in the OVR Unity library that suggest they could disable these features, but unfortunately it did not fix the problem.
(The rest of this post documents a workaround for this. If you know of a way to address the above issues, feel free to leave a comment below!)
However, I did notice something interesting. Even though the space was reset in the application, the guardian would remain consistent. I could put the headset into sleep mode and wake it up, I could leave the space and re-enter it, I could re-center the device using the Oculus button, and through all of that, the guardian would stay in place.
If you aren’t aware of what I mean by “the guardian,” it is a boundary defined by the user which acts as a safe zone in VR. By keeping the defined guardian area clear of physical objects, one can ensure that they will have a safe experience in VR and will not have to worry about tripping or bumping into anything.
In the OVR Unity API, we can get the points which define the boundary on the ground plane by calling
OVRBoundary.GetGeometry(). Since this is returned in the Unity virtual coordinate system, it will change whenever the virtual space is reset. However, the general shape of it always remains the same.
For a general set of points, we can analyze the shape of the points by looking at the covariance and eigenvectors of the point set. For an overview of this sort of analysis, you can read this blog post here. Once we get the eigenvectors, we can understand how the shape is rotated within our space.
Whenever we calibrate our space using our simple calibration method, we can see how the guardian is rotated within our calibrated space. This position and rotational offset defines a relationship that anchors our calibration to the guardian. We can use this relationship to maintain our calibration state. If we ever detect that the guardian has changed rotation and position relative to our calibrated space, then we can re-adjust our calibration to once again match the relationship we established with the guardian.
Now that we know this, we can save this data to a file and reload it whenever the app starts up. This way, we only need to recalibrate when we change our guardian, but overall, the whole process becomes much smoother!