Reseting view/origin for roomscale

When I reset view/origin for roomscale for Oculus (PC), it seems that the whole play area is relocated, ie. instead of being wherever I was relative to my boundary, OpenXR gives pose just like I would be in the centre of the play area. And there is no way to learn where play area should be.

As my game relies heavily on actual location within the boundary, resetting view/origin breaks a lot. One could argue that the player should not reset view. Or that’s it not consistent with other APIs.

If I do the same thing with Oculus SDK or VRAPI, I get still results against the play area. Well, that’s not entirely true, as the origin might be offset, ie. not at 0,0,0 but there’s enough information to know where I am relative to the actual boundary. With OpenXR, there’s no play area anchoring and resetting moves us around.

I use resetting view for the menu to show stuff in front of the player, works especially well on Quest where resetting happens without any popups.

Some details: I have two reference spaces, one is XR_REFERENCE_SPACE_TYPE_VIEW to be view/head. The other is XR_REFERENCE_SPACE_TYPE_STAGE for roomscale.

Is that the intended behaviour? I suspect it might be a bug?

What I’d expect, one of two:

  1. When reset happens, comes XrEventDataReferenceSpaceChangePending event, it should only indicate that something like that happened but the pose should be still relative to original play area and it’s up to the programmer to handle resetting inside the game.
  2. Or xrGetReferenceSpaceBoundsRect should return not only the size of the play area but also location and orientation of its centre.

According to the spec, the origin of a XR_REFERENCE_SPACE_TYPE_STAGE is always the center of the rectangular play area. By that it seems the behavior you are experiencing conforms to the spec.

From what I understand, functions to reset the roomscale origin are designed to be tools for the player to allow them to relocate the play area to a location they want to play the game in, as opposed to developer tools for controlling the camera. It might be a better option to move the player around relative to the game world instead Alternatively implement a reset function in-engine by adding an additional layer of transforms between the tracking space and the root transform of the player object, and manipulating that.

What you described is fine for LOCAL. I mean this is what LOCAL is intended for. But for STAGE it’s unsafe to recenter it this way. And according to spec:

XR_REFERENCE_SPACE_TYPE_STAGE. The STAGE reference space is a runtime-defined flat, rectangular space that is empty and can be walked around on

If you recenter it this way, most likely, by definition that space will go outside the boundary and the user will end up walking into a wall, window, you name it.

Also, it is inconsistent with how the same button works with other implementations.

There’s also no information about an actual offset used to recenter the space and depending on last head transform for larger spaces is unsafe as with small rotation between readouts, for 10x10 spaces after a few such operations you may still end up with an area that reaches beyond the boundary.

My game uses the play area. The whole thing. User may walk through it and the game, within its world, makes it impossible to walk outside. You basically walk in circles. That’s why precise play area info is extremely important to remain being safe for the user.

I also have the functionality implemented to adjust the play area in any way required but this I consider a temporary solution for Oculus on PC not providing Quest’s boundary/play area. But this is a completely different issue. Wanted to mention it as “I got offsets covered”.

This is exactly how it should work for local reference space but it shouldn’t change 0,0,0 for stage reference space. With this working as it does now, there’s no difference between the two.

The workaround might be to restart the session.

Yeah, I agree that it’s an unsafe implementation. The spec suggests that the user can redefine the STAGE pose during the application runtime though. Guessing Oculus expects that the user takes care to recenter it in a safe location.

Maybe the spec could be improved with a feature to allow disabling reference space relocation.

I stand corrected, there is a way to get the transform from one space to another, it’s part of XrEventDataReferenceSpaceChangePending struct: poseInPreviousSpace. I’ll just use the functionality I have. I guess that complete redefinition of space is handled via poseValid set to false.

Still, as you suggested, if there was a way to not relocate reference space (but still get the event about it), it would make it safer and easier. And the stage space’s 0,0,0 would be still in the centre of the safe space.

Or maybe a new event “reset view” because that’s exactly what holding right menu/system button is called within Oculus, not recentering play area but resetting view.

Thank you very much for your insight as it pointed a few very important facts and in the end lead me to take a look once again into the specs and find a solution.

Turns out that if you try to recenter in roomscale, poseValid is set to false. Odd thing is that referenceSpaceType in that structure is set to XR_REFERENCE_SPACE_TYPE_LOCAL but still manages to change XR_REFERENCE_SPACE_TYPE_STAGE's origin. Recreating STAGE reference space does not work.

So many questions.

  1. Why user can redefine STAGE at runtime making it placed outside the boundary that was defined? What’s the purpose of that?
  2. Is poseValid actually filled? When does it happen?
  3. Why there is such a difference between Oculus and OpenXR when it comes to resetting view?
  4. Bonus question: why foveated rendering does not work on Quest when using OpenXR?

For 1. I can think of the use case when the user wants to play in a different room, moves there and resets the play area. A runtime could even be devised that switches between different predefined play areas depending on which room the player goes to.

As for the other questions, it’s unlikely that anyone other than Oculus could answer them.

This would work fine as long as you wouldn’t end up in 0,0,0. Ie. STAGE is placed properly in the play area you went to. But it’s not. But yeah, this is exactly what this event is about. I imagine that then there are two such events. One with referenceSpaceType is set to STAGE, another with LOCAL.

And I agree that only Oculus can answer that (as long as other issues: foveated rendering, input initialisation, invalidating some of the inputs that are valid for specific devices) and I am using various channels to get to them as through the most official remain silent on that.

For time being, I use last head pose, drop it to XY plane to get an offset between spaces. There seems to be a very small seemingly random offset added but that’s exactly what I was predicting will happen and is the reason I consider this approach being merely a hacky workaround.