GodotVR / godot_oculus_mobile

Godot Oculus mobile drivers (Oculus Go / Oculus Quest)
MIT License
169 stars 34 forks source link

Lag between ARVRCamera and ARVROrigin when moving #138

Open clktmr opened 2 years ago

clktmr commented 2 years ago

Moving the ARVROrigin in _process() causes a visible delay of the controllers and other child nodes of ARVROrigin. This can be reproduced by the asset's example scene arvr_origin.tscn. The same happens when the parent of ARVROrigin is moving, although in that case the workaround described in godot_openvr/issues/44 can "fix" this.

Apparently the ARVRCamera uses the ARVROrigin's translation from the last frame. From what I've already read this seems to be caused by updating the HMD tracking data right before rendering. Please help me understand this, why is the ARVROrigin's translation relevant to tracking. I would assume it doesn't matter because tracking is always done relative to the ARVROrigin.

A simple solution is to do all the movement in _physics_process(), but that requires to run _process() and _physics_process() at the same rate. Is that considered best practice?

BastiaanOlij commented 2 years ago

This is a rather annoying problem in the core that we've only discovered recently and still aren't sure why it is happening. The positions of the camera and controller are updated behind the scenes inside their own process functions. Behind the scenes Godot maintains both the local transform of the object (relative to its parent) and the global position of the object (used for rendering). If the position of the ARVROrigin is changed during _process but before the controller positions are updated, it seems to be using the old global position of the origin point to determine the new global position of the controller.

I never ran into this myself because I do all repositioning of the ARVROrigin node as a response to controller inputs which are handled in scripts on the controllers and the repositioning is thus applied after the tracking updates the position of the controllers and this delay does not happen and as a result this issue remained undiscovered for years as people based their projects on my code :). Have a look at https://github.com/GodotVR/godot-xr-tools or the demo project on the OpenVR repo to see how that is put together.

If you do have a reason to have movement logic more central, say you're controlling your character with a gamepad, the easy workaround is just to implement that logic on a node added after the controllers, so:

ARVROrigin
  - ARVRCamera
  - ARVRController left
  - ARVRController right
  - ControlNode <-- implement _process here

Your other solution of doing it in _physics_process is also sound but yes, you have to ensure the update rate of physics is equal or higher than the refresh rate of your HMD. This is good practice anyway especially if your character is attached to a physics controlled entity like driving a car, or you'll get visible stuttering as the cars position isn't updated every rendered frame.

The head tracking is updated right before rendering but this isn't actually a problem because that does work correctly in relation to the origin point, here there is only a problem if you have child node on the ARVRCamera as they are not updated along side it.

This is all solved in Godot 4 where all tracking updates now happen before _physics_process and _process even run but this is not a change easily back ported to Godot 3.

The world_scale issue is also different, here the problem is that there isn't yet a mechanism for directly applying the new tracking transforms as a result to changing the scale. Still working on that one.

clktmr commented 2 years ago

Thanks for the in-depth response. This makes much more sense now.

The workaround is easily applicable to my use-case. Feel free to close this issue as wont-fix.

Since it was a known issue, is it documented elsewhere? I was surprised to not find anything about it, although I stumbled over it so early.

BastiaanOlij commented 2 years ago

There are issues on the main godot issue tracker for this but mostly it just comes up in discussions on Discord from time to time. Most people either have physics control the player position (driving sims, flight sims), or have the logic on the controllers, so the problem doesn't eventuate. It actually wasn't until a few months back someone was able to provide me with a good example and suddenly the lightbulb went on.

It's a weird issue because it sounds like the way Godot updates the global transforms internally has an issue, I haven't had time yet to really dive into that part of the code yet but I'm guessing it doesn't update the global transforms immediately when you change an objects transform because it can be a very costly exercise when there are many transform updates in a larger tree of objects.