This is because the default tracking origin for different platforms is different.
The origin represents a fixed point in the real world. All tracking values, like the position or rotation of a headset are reported relative to this fixed point. So when a controller’s position in Unity is [0.0, 1.5, 1.0], that controller is physically 1.5 meters above, and 1 meter in front of this invisible, fixed point. Depending on the SDK, that fixed point can be the location of the headset when the application started (Device tracking origin), a location on the floor that is either at the center of a tracking boundary, or directly below the headset on application start if no boundary is set (Floor tracking origin), or it can be a nearby point in space selected by the SDK and updated based on distance from previous origin (Unbounded tracking origin). It sounds like sometimes you are using an SDK set to use the ‘Floor’ tracking origin. This puts the 0,0,0 point where you’d expect the headset to be, and then places the actual headset way above that, up to 2m if you are tall (and standing). Sometimes it can be off to the left or right, especially if your setup is like mine and the actual space that I sit down is often far from the center of the tracking boundary. It sounds like you are expecting it to be in Device tracking origin mode, where the headset starts at that 0,0,0 point.
I would suggest setting the tracking origin to Device on startup (using the sample above). As well, what you are doing with the Holder object is a good practice. In the XR Interaction Toolkit the same ‘holder’ object is called a player rig. It let’s you treat the entire real world tracking space as a single game object. Want to move the real world tracked objects? Just move the holder! This type of movement, where you move the rig or holder object in such a way that you have the tracked headset in the actual desired location, is a common technique, and how the XR Interaction Toolkit, and other locomotion systems handle VR teleportation.
If you want to go a little further than that, you can listen for a change in user presence. Something like this:
bool userWasPresent;
void Update()
{
// First we get a headset
var device = InputDevices.GetDeviceAtXRNode(XRNode.Head);
if (!device.isValid)
{
userWasPresent = false;
return;
}
// Then we see if this device has a user presence sensor. If not, we assume the user is always present.
var userPresent = true;
if (device.TryGetFeatureValue(CommonUsages.userPresence, out bool featureValue))
userPresent = featureValue;
// Headset JUST put on this frame. Also triggered the first frame
if (!userWasPresent & userPresent)
ResetPosition();
userWasPresent = userPresent;
}
This should perform a reset the first frame that a headset is available. As well, if the device supports user presence, will also perform a reset for the first frame that the headset is put on. This means if they remove the headset, put it down for a moment, and put it back on, you can detect that and make sure the scene is right in front of the user on that first frame he’s back in the world.