Moving camera around player with Vector3.Slerp - Jittery

ssslerp

I am trying to move and rotate camera around player if you press a button. I achieved it with Quaternion.Lerp and Vector3.Slerp. However - as you can see in the gif, it isnt very smooth and the camera moves closer to the player on rotation. I want my camera to rotate perfectly so that player is always at the same spot in the screen. Here is my code (Its inside FixedUpdate):

if (_isLerping)
{
    if (_elapsedTime < _transitionTime)
    {
        _newPos = Vector3.Slerp(_newPos, _endingPos, (_elapsedTime / _transitionTime));
        _newPos.y = 8f;
        transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(35f, GameManager.instance.cameraDegrees, 0f).normalized, (_elapsedTime / _transitionTime));
        _elapsedTime += Time.fixedDeltaTime;
    }
    else
    {
        _newPos = _endingPos;
        transform.rotation = Quaternion.Euler(35f, GameManager.instance.cameraDegrees, 0f).normalized;
        _isLerping = false;
    }
}

transform.position = _playerTransform.position + _newPos;

2 Answers

2

I think there are two changes you need to make. First, you are changing _newPos on every FixedUpdate, so you are constantly moving the start point of the Slerp. You should use the original starting point as the first parameter to Slerp.

Second, Slerp is supposed to be used with directions, not absolute positions, so I think you will want to do something like this:

//I'm assuming there is a "_startPos" vector which is the world-space location prior to the move.
//I'm also assuming _endPos is in world-space.
Vector3 startVector = _startPos - _playerTransform.position;
Vector3 endVector = _endPos - _playerTransform.position;
Vector3 currentPosition = Vector3.Slerp(startVector, endVector, (_elapsedTime / _transitionTime));
currentPosition += _playerTransform.position;
transform.position = currentPosition;

I modeled this after the example given in the documentation:

I tried it, but it didnt work. I decided to use Transform.RotateAround to do everything for me instead. It works pretty well, although there is sometimes a slight inaccuracy (nothing huge, like 0.05-0.015 in world position that I adjust after rotation is done)

    private void LateUpdate()
    {
        if (_isLerping)
        {
            if (_elapsedTime < GameManager.instance.cameraTransitionTime)
            {
                _elapsedTime += Time.deltaTime;
                // rotation angle divided by transition time as rotation angle is rotated once every second
                transform.position = _newPos + _playerTransform.position;
                transform.RotateAround(_playerTransform.position, Vector3.up, (_rotationDegrees / GameManager.instance.cameraTransitionTime) * Time.deltaTime);
                _newPos = transform.position - _playerTransform.position;
            }
            else
            {
                _newPos = _endingPos;
                transform.rotation = Quaternion.Euler(transform.rotation.eulerAngles.x, GameManager.instance.cameraRotationY, 0f).normalized;
                _isLerping = false;
            }
        }
        else
        {
            transform.position = _newPos + _playerTransform.position;
        }
    }