Different physics results on different systems (Oculus Rift vs Quest) [SOLVED]

Hello!

I’ve been working on a simple VR disc golf game for the Oculus platform. One of the aspects I’m trying to model is the turn and fade ratings of a disc.

All of the following commentary applies to a right-handed backhand throw…

The Turn rating of a disc dictates how far right a disc will turn while it is flying at higher velocity. The Fade rating dictates how far left a disc will turn as it slows down. During this entire time, the disc is spinning fairly rapidly. Below is the code which makes it happen, using AddTorque to both enforce this turn and correct wobble induced during the throw.

FixedUpdate

private void FixedUpdate()
    {
        if (!_isThrown) return;

        // check if the disc has come to rest and skip flight calculations if so
        if (Utility.FloatBetween(_rigidbody.velocity.sqrMagnitude, -.001f, .001f) &&
            Utility.FloatBetween(_rigidbody.angularVelocity.sqrMagnitude, -.001f, .001f))
        {
            return;
        }
     
        // a disc will fly whether it is upside down or not
        var discUpDir = transform.up;
        if (discUpDir.y < 0) discUpDir = -discUpDir;

        var velocity = _rigidbody.velocity;
        var angularVelocity = _rigidbody.angularVelocity;
        // because disc is spinning, we need to create our own transform.forward direction using velocity and the disc plane
        var discForwardDir = Vector3.ProjectOnPlane(velocity.normalized, discUpDir).normalized;

        var angleOfAttack = GetAngleOfAttack(velocity.normalized, discForwardDir);
        var discArea = GetDiscArea();

        var liftVector = GetLift(angleOfAttack, discArea, Rho, velocity, discUpDir, discForwardDir);
        var dragVector = GetDrag(angleOfAttack, discArea, Rho, velocity);
        var torqueVector = GetTorque(velocity, angularVelocity, discUpDir, discForwardDir);

        _rigidbody.AddForce(liftVector);
        _rigidbody.AddForce(dragVector);
        _rigidbody.AddTorque(torqueVector);
    }

GetTorque

private Vector3 GetTorque(Vector3 velocity, Vector3 angularVelocity, Vector3 discUpDir, Vector3 discForwardDir)
    {
        // the speed of maximum turn
        var turnMax = RatedSpeed;
        // the speed of maximum fade
        var fadeMax = turnMax / 1.5f;
        // the speed where the disc goes from turn to fade
        var fadePoint = ((turnMax - fadeMax) / 2f) + fadeMax;

        // converts speed to normalized between fade point and turn max or fade max
        var speedToNorm = 1f / (turnMax - fadePoint);
        var speed = velocity.magnitude;
        // value between 0 and 1 representing the amount of fade or turn to apply
        var turnAmnt = Mathf.Clamp(Mathf.Pow((speed - fadePoint) * speedToNorm , 2f), 0f, 1f);
     
        if (speed > fadePoint)
        {
            turnAmnt *= -TurnRating;
        }
        else
        {
            turnAmnt *= -FadeRating;
        }

        var discRightDir = Vector3.Cross(discUpDir, discForwardDir).normalized;

        var turnTorque =  .0008f * turnAmnt * discRightDir;

        var wobbleCorrectionTorque = GetWobbleCorrectionTorque(angularVelocity);
     
        return wobbleCorrectionTorque + turnTorque;
    }

    private Vector3 GetWobbleCorrectionTorque(Vector3 angularVelocity)
    {
        var localAngularVelocity = transform.InverseTransformVector(angularVelocity);
     
        var spinRate = localAngularVelocity.y;

        if (Math.Abs(spinRate) < 10f)
        {
            return Vector3.zero;
        }

        var dampenAmount = .001f * Mathf.Clamp(Mathf.Pow(Mathf.Abs(spinRate), 2f) / 400f, 0, 1);

        var localTorque = Vector3.zero;

        localTorque.x = -localAngularVelocity.x * dampenAmount;
        localTorque.z = -localAngularVelocity.z * dampenAmount;

        return transform.TransformVector(localTorque);
    }

Cool - and this works great on the Oculus Rift. You’ll notice that the torque for turning/fading is being applied around the right axis of the forward direction. I’m not perfectly sure why this works (I guessed because the disc is spinning and so by the time the front-side dips down, it has rotated to the side).

So here are the results on the Oculus Rift:

Works great. This disc begins fading left as it loses velocity. Then I went ahead and loaded it up on the quest using the same disc:

It is a bit hard to see, but the disc now fades right instead of left! I even throw a forehand at the end (which reverses the turn and fade directions) and its also opposite.

So I figured that maybe the Oculus Quest is just not able to keep up with the physics computation that I’m putting every fixed update. Initially I was using 1/90 for my fixed timestep. So I went ahead and lowered it to 1/45 and still got the same behavior (correct on the Rift and incorrect on the Quest). The footage above is shot at 1/72.

So I’m looking for some help and ideas on what could be happening. Even if the Quest is slowing down the physics step, shouldn’t that be accounted for when using Physics functions like AddTorque? I keep thinking that maybe the issue is that the Torque is being applied too late in the rotation on the Quest, making it apply to the opposite side that it should, but again, wouldn’t the angular velocity that’s spinning the disc also slow down in the same amount if that were true? Wouldn’t I be able to see this on the Rift when I change the fixed timestep to something like 1/45?

Any advice & thoughts are appreciated!

I figured it out - well - kind of.

For whatever reason, the oculus quest touch controllers (same as the rift s) are indicating a negative turn instead of a positive turn as the rift s are. There is something wonky here - but it’s not on the unity physics side (thankfully).

The angular velocity readings from the Oculus Quest are backwards in Unity Integration. Official bug was reported back in August: OK | Oculus

You might be better off discussing this here.

You’re completely right. At the time of posting, I believed this was a physics issue having to do with fixed timestamp. It is now obvious that this is an issue with Oculus Unity Integration.

1 Like

Yes indeed. Sorry if I sounded like I was indicating you should’ve posted there in the first place, wasn’t my intent. Was just thinking that you’d potentially get more info now. Good luck with it!

1 Like

No need to apologize! I appreciated the advice and did exactly what you suggested right after seeing your post :slight_smile:

Thanks for your help, Melv!