private void Update()
    {
        /**
         * Press H to localize FOVE space -> Vive Space -> World Space
         *   The user's current head orientation will now be used as a reference for 0 degree yaw in world space
         *   The position of the user will now be shifted to the origin of world space
         */
        if (Input.GetKeyDown(KeyCode.H))
        {
            // Check that headset vive tracker and controllers are both active
            if ((IsHeadsetPositionTracked() && IsControllersConnected()) == false)
            {
                return;
            }

            // Check that fove is set up correctly
            if ((FoveInterface.IsHardwareConnected() && FoveInterface.IsHardwareReady()) == false)
            {
                return;
            }

            // See how much we should rotate FOVE to get it to its proper Vive space
            Vector3    leftControllerRotation      = leftController.transform.localRotation.eulerAngles;
            Vector3    rightControllerRotation     = rightController.transform.localRotation.eulerAngles;
            Vector3    averageControllerRotation   = (leftControllerRotation + rightControllerRotation) / 2.0f;
            Vector3    foveHmdRotation             = FoveInterface.GetHMDRotation().eulerAngles;
            Quaternion foveToViveRotationTransform = Quaternion.Euler(0.0f, (averageControllerRotation - foveHmdRotation).y, 0.0f);
            Debug.Log("FoveToViveRotationTransform: " + foveToViveRotationTransform + averageControllerRotation);
            yawOrientationOffset = foveToViveRotationTransform.eulerAngles.y;

            // Shift everything back to center
            personSetup.transform.rotation = Quaternion.Euler(0.0f, 0.0f, 0.0f);
            personSetup.transform.position = new Vector3(0.0f, 0.0f, 0.0f);

            // See how much we should rotate the Vive to get it into its proper world space
            FoveViveToWorldSpace           = Quaternion.Euler(0.0f, averageControllerRotation.y * -1.0f, 0.0f);
            personSetup.transform.rotation = FoveViveToWorldSpace;
            Vector3 scenePositionShiftAmount = transform.position * -1.0f;
            personSetup.transform.position = new Vector3(
                scenePositionShiftAmount.x,
                personSetup.transform.position.y,
                scenePositionShiftAmount.z);

            // Log the current FOVE headset and Vive Tracker orientation
            FoveHeadsetTareOrientation = FoveInterface.GetHMDRotation();
            ViveTrackerTareOrientation = currentViveTrackerPose.rot;

            // Everything is done
            isHeadsetCalibrated = true;
            Debug.Log("Finished setting up FOVE localization");
        }

        /**
         * Press P to shift the user's current position to the center of world space
         */
        if (Input.GetKeyDown(KeyCode.P))
        {
            ReCenterUser();
        }

        // Attempt to mitigate FOVE headset's yaw drift
        if (driftCorrection)
        {
            CorrectHeadsetYawDrift();
        }
        else
        {
            yawDriftCorrectionOffset = 0.0f;
        }

        // Update the position and orientation of the headset
        transform.localRotation = Quaternion.Euler(0.0f, yawOrientationOffset + yawDriftCorrectionOffset, 0.0f);
        var eyePositionOffset = transform.localRotation * FoveInterface.GetHMDRotation() * trackerToEyePositionOffset;

        transform.localPosition = currentViveTrackerPose.pos + eyePositionOffset;

        // Rotate person setup to world space + any additional rotate offset specified by user
        Vector3 currentPersonPosition = transform.position;

        personSetup.transform.rotation = Quaternion.Euler(FoveViveToWorldSpace.eulerAngles + new Vector3(0.0f, rotateSetupDegree, 0.0f));
        TeleportUser(currentPersonPosition);
    }