cancel
Showing results for 
Search instead for 
Did you mean: 

Drift Correction - Replace the Tracker with MoCap Data

xflagx
Honored Guest
Hello everyone,

I try to build a Walking VR Environment where people are able to walk through (quite large 12x15 meter) real space and experience a corresponding VR. I've got a PhaseSpace Motion Capture System which works quite well, carrying the Camera through the VR. (I'm using the latest Version of Unity 5.3.2 - but it might be a general issue)

Regarding the practical implications I'm not allowed to use the Camera shipped with the Rift.
So I got the Yaw Drift issue... :? Sometimes... but reproducable :geek:

First attempt to solve the issue: Using the UnityEngine,VR.InputTracking.Recenter() every time the orientation passes a reference point results in glitches and seems to be uncomfortable...

After reading the well written article* focusing the drift topic, the following question came to my mind.

Is it possible to feed the drift correction with my own reference points - create by a Motion Capture System.
Or more specific:
Are there some API calls allowing to pass some kind of data overriding the tracker data? With other words... Can I use my own tracker based on the Motion Capture information?

I just found the opportunity to disable the tracker which is fairly not enough.

Any suggestion or comment is welcome! If there is a solution for that - it will be part of an free and open source piece of software 8-)

Thanks in advance!

* https://developer.oculus.com/blog/magnetometer/
17 REPLIES 17

vrdaveb
Oculus Staff
Yes, you can override our tracking data. The best way right now is to write a C# function (void myHandler()) and assign it to the event OVRCameraRig.UpdatedAnchors in one of your scripts. UpdatedAnchors fires each frame, immediately after we've set the tracking data for that frame. In the function, you can do anything you want to the OVRCameraRig anchor poses, such as zero them out or apply a different tracking method. However, I would recommend keeping the rotation data. If you don't, there will be a slight wobble due to TimeWarp. We will fix this in a future SDK.

xflagx
Honored Guest
Thanks for the reply,

I've tried a few things, for instance, removing the UpdateAnchor() Method completely but the Camera still get updated with the rotation. It seems impossible to override the rotation data in any way. It seems that the camera gets updated with some kind of magic behind the scenes...

The core issue is, that I've another MoCap Tracking System which should track the orientation of the upper body.
As long the CameraRig is a Child of the Upper Body the orientation of the rift on the Y axis gets updated twice... caused by the child (CameraRig - representing the HEAD) parent (body) transformations... which is very bad... It should be possible to rotate the forward vector of the player controller independent from the rift by rotating the - real upper body. But I stuck with this problem :cry:

Any ideas on that?

I found a piece of code which describe the other way around - the Rift orientation describes the forward direction... from the OVRPlayerController

	
/// <summary>
/// Invoked by OVRCameraRig's UpdatedAnchors callback. Allows the Hmd rotation to update the facing direction of the player.
/// </summary>

public void UpdateTransform(OVRCameraRig rig)
{
Transform root = CameraRig.trackingSpace;
Transform centerEye = CameraRig.centerEyeAnchor;

Vector3 prevPos = root.position;
Quaternion prevRot = root.rotation;

// Original
transform.rotation = Quaternion.Euler(0.0f, centerEye.rotation.eulerAngles.y, 0.0f);

root.position = prevPos;
root.rotation = prevRot;

}



What I need


delta = deltaRotationBetween(root, centerEye)
centerEye.rotation = Quaternion.Euler(0.0f, centerEye.rotation.eulerAngles.y - delta, 0.0f);

Which is not working 😞

vrdaveb
Oculus Staff
"xflagx" wrote:
It seems that the camera gets updated with some kind of magic behind the scenes.
Yes, Unity internally sets the local position, rotation, and FOV of the Camera to match tracking data and TimeWarp expectations just before Update gets called. This is done to ensure the right relationship between head motion and optical flow, without which users may get severely uncomfortable. In your code snippet, I don't see you registering your UpdatedTransform method with the OVRCameraRig.UpdatedAnchors event. Try something like this:
using UnityEngine;
using System.Collections;

public class TrackingModeChanger : MonoBehaviour {

void Awake()
{
foreach (var rig in GameObject.FindObjectsOfType<OVRCameraRig>())
rig.UpdatedAnchors += OnUpdatedAnchors;
}

void Update ()
{
OVRManager.tracker.isEnabled = !Input.GetKey(KeyCode.P);
}

void OnUpdatedAnchors(OVRCameraRig rig)
{
OVRPose pose = rig.centerEyeAnchor.ToOVRPose(true).Inverse();

//FIXME: concatenate your desired pose onto "pose".

rig.trackingSpace.FromOVRPose(pose, true);
}
}

xflagx
Honored Guest
Thanks again!

I tested it and the following code does the job...


private void Rig_UpdatedAnchors(OVRCameraRig obj)
{
OVRPose pose = rig.centerEyeAnchor.ToOVRPose(true).Inverse();

//FIXME: concatenate your desired pose onto "pose".

// The following works
pose.orientation = Quaternion.Inverse(Quaternion.Euler(1, realWorldUpperBody.rotation.eulerAngles.y, 1) * pose.orientation) * pose.orientation;

rig.trackingSpace.FromOVRPose(pose, true);
}


I'm not sure that I have the issue you described. I will investigate that...
If you don't, there will be a slight wobble due to TimeWarp.


Anyway, big thanks for your help!

pasta
Honored Guest
Hello vrdaveb,

Sorry to revive an old thread, but i have a question about your statement:

However, I would recommend keeping the rotation data. If you don't,
there will be a slight wobble due to TimeWarp. We will fix this in a
future SDK.
I am looking at using a modified form of the rotation data.  Has the fix for timewarp wobble been implemented in the latest SDK?  If not, when do you think that might happen?  Is there a workaround?  It has been six months since the last post, so I thought I would check.

Thanks!

vrdaveb
Oculus Staff
Sorry, the ability to disable rotation tracking was never prioritized. It's unlikely to get fixed in the near future. However, if you are tracking rotation at all with your own system, the high-frequency data from TimeWarp should complement it and reduce latency rather than cause wobble. You can set whatever position and rotation you want as follows:

using UnityEngine;
using System.Collections;

public class FakeTracking : MonoBehaviour
{
public OVRPose centerEyePose = OVRPose.identity;
public OVRPose leftEyePose = OVRPose.identity;
public OVRPose rightEyePose = OVRPose.identity;
public OVRPose leftHandPose = OVRPose.identity;
public OVRPose rightHandPose = OVRPose.identity;
public OVRPose trackerPose = OVRPose.identity;

void Awake()
{
OVRCameraRig rig = GameObject.FindObjectOfType<OVRCameraRig>();

if (rig != null)
rig.UpdatedAnchors += OnUpdatedAnchors;
}

void OnUpdatedAnchors(OVRCameraRig rig)
{
if (!enabled)
return;

//This doesn't work because VR camera poses are read-only.
//rig.centerEyeAnchor.FromOVRPose(OVRPose.identity);

//Instead, invert out the current pose and multiply in the desired pose.
OVRPose pose = rig.centerEyeAnchor.ToOVRPose(true).Inverse();
pose = centerEyePose * pose;
rig.trackingSpace.FromOVRPose(pose, true);

//OVRPose referenceFrame = pose.Inverse();

//The rest of the nodes are updated by OVRCameraRig, not Unity, so they're easy.
rig.leftEyeAnchor.FromOVRPose(leftEyePose);
rig.rightEyeAnchor.FromOVRPose(rightEyePose);
rig.leftHandAnchor.FromOVRPose(leftHandPose);
rig.rightHandAnchor.FromOVRPose(rightHandPose);
rig.trackerAnchor.FromOVRPose(trackerPose);
}
}


pasta
Honored Guest
Thanks vrdaveb.

Here is the code at the bottom that I tried which is very closely based on your code.  I ran it at 10 fps with this line commented thus not modifying the rotation data:

        correctedCenterEyePose.orientation *= Quaternion.Euler(-38.25f, 0.0f, 0.0f);

, I could see that async timewarp was working because stationary object were pretty smooth (ie looked to stay in place) and did not lurch and snap back after 1/10th of a second as I turned my head.

If I uncommented the above line and ran at 10 fps, it seems like async timewarp is turned off.  Stationary objects in VR appear to lurch and then snap back over 1/10th of a second as I turned my head.

Maybe I missed something, but is there a way to keep the async timewarp on after the center eye pose orientation has been modified in Unity?  I think I managed to do this in the Oculus SDK, but would prefer to do it in Unity.
using UnityEngine;
using System.Collections;

public class FakeTracking : MonoBehaviour
{
    public OVRPose centerEyePose = OVRPose.identity;
    public OVRPose leftEyePose = OVRPose.identity;
    public OVRPose rightEyePose = OVRPose.identity;
    public OVRPose leftHandPose = OVRPose.identity;
    public OVRPose rightHandPose = OVRPose.identity;
    public OVRPose trackerPose = OVRPose.identity;

    void Awake()
    {
        OVRCameraRig rig = GameObject.FindObjectOfType<OVRCameraRig>();

        if (rig != null)
            rig.UpdatedAnchors += OnUpdatedAnchors;
        // print("in awake");
    }

    void OnUpdatedAnchors(OVRCameraRig rig)
    {
        if (!enabled)
            return;

        //This doesn't work because VR camera poses are read-only.
        //rig.centerEyeAnchor.FromOVRPose(OVRPose.identity);

        //Instead, invert out the current pose and multiply in the desired pose.
        OVRPose pose = rig.centerEyeAnchor.ToOVRPose(true).Inverse();
        OVRPose correctedCenterEyePose;

        correctedCenterEyePose.position = rig.centerEyeAnchor.ToOVRPose(true).position;
        correctedCenterEyePose.orientation = rig.centerEyeAnchor.ToOVRPose(true).orientation;
        correctedCenterEyePose.orientation *= Quaternion.Euler(-38.25f, 0.0f, 0.0f);
        // pose = centerEyePose * pose;
        pose = correctedCenterEyePose * pose;
        rig.trackingSpace.FromOVRPose(pose, true);

        //OVRPose referenceFrame = pose.Inverse();

        //The rest of the nodes are updated by OVRCameraRig, not Unity, so they're easy.
        rig.leftEyeAnchor.FromOVRPose(leftEyePose);
        rig.rightEyeAnchor.FromOVRPose(rightEyePose);
        rig.leftHandAnchor.FromOVRPose(leftHandPose);
        rig.rightHandAnchor.FromOVRPose(rightHandPose);
        rig.trackerAnchor.FromOVRPose(trackerPose);
    }
}




pasta
Honored Guest
Also, not sure if it is relevant, but in my situation, the display board is not level when a person looks straight ahead.  Thanks!

vrdaveb
Oculus Staff
There's no way to turn ATW *off*, actually. If you are rendering at 10Hz, maybe try sleeping for 100ms each frame.