NadCat
NadCat

Reputation: 11

Unity VR - Teleportation script doesn't precisely teleport to where I'm pointing to

I'm pretty new when it comes to Unity and VR. I have to implement a teleport script and pretty much the only thing I know is that I can't move the camera itself because any changes to that are overwritten instantly. Instead, I use the XR Origin object as a locomotion platform and move that. The script is added as a component to the right hand and essentially just takes the XR Origin object and an XR Ray Interactor component from the hand and when I press the trigger it moves the XR Origin position to the position where the ray hits a teleportation area.

var hit = rayInteractor.TryGetHitInfo(out Vector3 position, out _, out _, out _);
if (hit && triggerPress.action.ReadValue<float>() == 1f)
    {
        player.transform.position = position;
    }

However, the actual camera does not end up in the correct position as can be seen by debug output:

Camera: (0.84, 0.92, -0.94), XROrigin: (1.74, 0.00, -2.55), ray hit position: (1.74, 0.00, -2.55)

I do understand why that happens. The XR Origin object is a 1m² area and the camera can be at any point within that area so when I change the position of the XR Origin object the camera might simply not be in the middle of the object. I can fix that by setting the XR Origin scale to 0.1 for X and Z and that does result in pretty much perfect precision:

Camera: (4.02, 0.97, 0.14), XROrigin: (4.09, 0.00, 0.00), ray hit position: (4.09, 0.00, 0.00)

However, that also breaks the visuals. The hand is way too small and super far away from the camera:

in both screenshots the headset is at head height and the controller is lying on a table

How would I go about writing a teleport script that manages to teleport me to the exact location without breaking any visuals? Is there some trick I don't know about? Most tutorials are completely useless to me cause I need the teleportation to happen in VS and not just in Unity itself

Edit: here's a screenshot showing how extreme the differences are at times red circle marks where I actually ended up at

Edit 2: So two ideas how to fix it: 1) maybe the camera is set to a fixed position within the XR Origin object and I just need to adjust the starting positin of the camera and 2) I could just calculate the difference between camera and destination and add that to the XR Origin position. I can't test either until next week, though

Upvotes: 0

Views: 524

Answers (1)

derHugo
derHugo

Reputation: 90813

I think if you only move the XROrigin your camera still maintains the same offset relative to it as before.

What I mean by that is

  • Let's assume you start at XROrigin (0,0,0) and Camera (1, 0, 0) (because you already walked to the right)
  • Now you run your script and move XROrigin (0, 0, 1)

I would expect your camera to actually end up at (1, 0, 1) maintaining the offset.

I think what you should use instead is XROrigin.MoveCameraToWorldLocation(Vector3)

This function moves the camera to the world location provided by desiredWorldLocation. It does this by moving the XR Origin object so that the camera's world location matches the desiredWorldLocation

var hit = rayInteractor.TryGetHitInfo(out Vector3 position, out _, out _, out _);
if (hit && triggerPress.action.ReadValue<float>() == 1f)
{
    player.GetComponent<XROrigin>().MoveCameraToWorldLocation(position);
}

might want to maintain current camera height though

var hit = rayInteractor.TryGetHitInfo(out Vector3 position, out _, out _, out _);
if (hit && triggerPress.action.ReadValue<float>() == 1f)
{
    var xrOrigin = player.GetComponent<XROrigin>();
    position.y = xrOrigin.Camera.transform.position.y;
    xrOrigin.MoveCameraToWorldLocation(position);
}

NOTE: Regarding triggerPress.action.ReadValue<float>() == 1f this might fail due to floating point precision. You should rather configure your action accordingly to only be triggered at a certain threshold in the first place and then rather use triggerPress.action.trigerred

Upvotes: 0

Related Questions