Ejemplo n.º 1
0
 /// <summary>
 /// Utility function for checking whether the algorithm wants to apply the opposite type of rotation gain.
 /// If so, smoothing is activated to improve the transition.
 /// </summary>
 /// <param name="newGain">The new type of rotation gain we want to apply this frame.</param>
 /// <param name="rotationProposed">The proposed camera angle injection</param>
 /// <param name="deltaDir">Just a straight copy of redirectionManager's deltaDir</param>
 private void CheckForGainDifference(RotationGainTypes newGain, float rotationProposed, float deltaDir)
 {
     // The approximately check is used to make sure that we dont transition between gains if they have been set to 0
     if (newGain != RotationGainTypes.none && newGain != _previousRotationGainType && !Mathf.Approximately(rotationProposed, deltaDir))
     {
         _transitioningBetweenGains = true;
         _lerpTimer = 0f;
     }
 }
Ejemplo n.º 2
0
    /// <summary>
    /// Main function for calculating and applying camera injection angle.
    /// </summary>
    public override void ApplyRedirection()
    {
        // If the SteamVR menu is entered or tracking somehow is lost, it will break the
        // smoothing algorithm and turn _smoothedRotation and _lastRotationApplied into NaNs.
        // This has to be reset if so.
        if (float.IsNaN(_smoothedRotation) || float.IsNaN(_lastRotationApplied))
        {
            _smoothedRotation    = 0;
            _lastRotationApplied = 0;
        }

        if (_transitioningBetweenGains && _lerpTimer >= 1f)
        {
            _transitioningBetweenGains = false;
        }

        var deltaDir = redirectionManager.deltaDir;

        _rotationFromRotationGain = 0;

        // The steering direction is used to determine whether rotations are clockwise or counter clockwise.
        // In this case it can be considered the desired way we want to shift the physical space.
        var desiredSteeringDirection = (-1) * (int)Mathf.Sign(Utilities.GetSignedAngle(_redirectionManagerER._centreToHead, _redirectionManagerER._futureVirtualWalkingDirection));

        var currentGainType = RotationGainTypes.none;

        // If user is rotating above the threshold
        if (Mathf.Abs(deltaDir) / Time.deltaTime >= _rotationThreshold)
        {
            // Calculate gains
            var againstGain = deltaDir * redirectionManager.MIN_ROT_GAIN;
            var withGain    = deltaDir * redirectionManager.MAX_ROT_GAIN;

            // The resulting dot products from applying gains to the vector from the centre of the physical space to the user head
            var dotFromAgainst = Vector3.Dot(Quaternion.AngleAxis(againstGain, Vector3.up) * _redirectionManagerER._centreToHead, _redirectionManagerER._futureVirtualWalkingDirection);
            var dotFromWith    = Vector3.Dot(Quaternion.AngleAxis(withGain, Vector3.up) * _redirectionManagerER._centreToHead, _redirectionManagerER._futureVirtualWalkingDirection);

            // The the gain that provides the closest dot product to the target is chosen.
            // The target in this case is aligning the future virtual direction with a vector from the tracking centre to the user's head.
            if (dotFromAgainst < dotFromWith)
            {
                _rotationFromRotationGain = Mathf.Min(Mathf.Abs(deltaDir * redirectionManager.MIN_ROT_GAIN), _ROTATION_GAIN_CAP_DEGREES_PER_SECOND * redirectionManager.GetDeltaTime());
                currentGainType           = RotationGainTypes.against;
            }
            else
            {
                _rotationFromRotationGain = Mathf.Min(Mathf.Abs(deltaDir * redirectionManager.MAX_ROT_GAIN), _ROTATION_GAIN_CAP_DEGREES_PER_SECOND * redirectionManager.GetDeltaTime());
                currentGainType           = RotationGainTypes.with;
            }
        }
        // If the head movement is below the threshold for applying gains, the smoothing function will move back towards natural head rotation.
        // This helps with one particular edge case:
        // After a body rotation is finished, the user's head will slightly bob in the opposite direction,
        // This small bob is usually below the threshold for applying gains which can result in a somewhat
        // jarring difference between just having used gains to not using them.
        // By allowing the smoothing function to smooth back to natural head rotation we avoid this issue.

        var rotationProposed = desiredSteeringDirection * _rotationFromRotationGain;

        CheckForGainDifference(currentGainType, rotationProposed, deltaDir);

        if (_superSmoothingEnabled && _transitioningBetweenGains)
        {
            _lerpTimer += Time.deltaTime;

            // Whenever the gain type changes, we smoothly interpolate from the injected rotation at the time of changing towards the current one.
            // As such, we are essentially interpolating from a positive to negative rotation gain or vice versa.
            _smoothedRotation = SuperSmoothLerp(_smoothedRotation, _lastRotationApplied, rotationProposed, _lerpTimer, _superSmoothSpeed);
            //Debug.Log(_smoothedRotation);
        }
        else
        {
            // Azmandian et al.'s smoothing method
            _smoothedRotation = (1.0f - SMOOTHING_FACTOR) * _lastRotationApplied + SMOOTHING_FACTOR * rotationProposed;
        }

        _lastRotationApplied      = _smoothedRotation;
        _previousRotationGainType = currentGainType;
        InjectRotation(_smoothedRotation);

        _currentlyAppliedGainType = _isAligned ? RecordedGainTypes.none : (RecordedGainTypes)currentGainType;
    }
Ejemplo n.º 3
0
 /// <summary>
 /// Called as a initialisation function whenever this redirector is activated again.
 /// </summary>
 public void OnRedirectionMethodSwitch()
 {
     _previousRotationGainType = RotationGainTypes.none;
     _isAligned = false;
 }