简体   繁体   中英

I want to lerp my camera from one quaternion to another

I want to achieve rotate the camera from original Quaternion to the target one.

Then i used the following code:

public class CameraMove : MonoBehaviour 
{
    public static bool start = false; 
    public Vector3 targetPosition;
    public Quaternion targetRotation;
    public float speed = 0.1f;

    void Start()
    {
        StartCoroutine(cameraRotate());
    }

    IEnumerator cameraRotate()
    {
        // Trigger cameraMove until clicking the sphere
        yield return new WaitUntil(() => start == true);
        while (transform.localRotation!=targetRotation)
        {
            transform.localRotation = Quaternion.Lerp(transform.localRotation, targetRotation, speed * Time.deltaTime);
            yield return null;
        }
    }
}

However, the camera didn't rotate at all, idk why

Use Quaternion.RotateTowards

Quaternion.Lerp or Quaternion.Slerp are to be used when you always have a percentage of how far from the start you want to rotate. However, you have a current rotation and a goal rotation and a speed. This is better suited to using Quaternion.RotateTowards :

IEnumerator cameraRotate()
{
    // Trigger cameraMove until clicking the sphere
    yield return new WaitUntil(() => start);
    while (transform.localRotation != targetRotation)
    {
        transform.localRotation = Quaternion.RotateTowards(transform.localRotation, 
                targetRotation, speed * Time.deltaTime);
        yield return null;
    }
}

As alternative to Ruzihm's answer I wanted to leave a solution here actually using Lerp .

The huge advantage of this is that you can additionally add ease-in and ease-out eg using Mathf.SmoothStep or even use other maths calculations in order to change the animation of the rotation.

It also allows you to control exactly how long the rotation will take independend how many degrees have to be rotated. In the example below I again calculated the duration by using your speed value in degrees per second but you could also simply eg pass a fixed duration like 1 or 2 seconds.

public class CameraMove : MonoBehaviour 
{
    public static bool start = false; 
    public Vector3 targetPosition;
    // it's easier to adjust euler angles instead
    public Vector3 targetRotation;

    // here now set the rotation speed in degrees / second
    public float speed = 90f;

    void Start()
    {
        StartCoroutine(cameraRotate());
    }

    private IEnumerator cameraRotate()
    {
        // Trigger cameraMove until clicking the sphere
        yield return new WaitUntil(() => start == true);

        var startRotation = transform.localRotation;
        var finalRotation = Quaternion.Euler(targetRotation);

        // angle difference / angle per second => duration in seconds
        var duration = Quaternion.Angle(startRotation, finalRotation) / speed;

        var timePassed = 0f;

        while (timPassed < duration)
        {
            // with this factor you get a linear rotation like using Quaternion.RotateTowards ...
            var lerpFactor = timPassed / duration;

            // ... Huge advantage: You can now add ease-in and ease-out to the rotation!
            var smoothedLerpFactor = Mathf.SmoothStep(0, 1, lerpFactor);

            transform.localRotation = Quaternion.Lerp(startRotation, finalRotation, smoothedLerpFactor);

            // add to the timePassed avoiding overshooting
            timaPassed += Mathf.Min(duration - timePassed, Time.deltaTime);
            yield return null;
        }

        // to be sure set the rotation fixed when done
        transform.localRotation = finalRotation;
    }
}

For more awesome examples for the easing maths checkout this post

eg as we had ease-in and ease-out:

var lerpFactor = passedTime / duration;
smoothedLerpFactor = Mathf.SmoothStep(0, 1, lerpFactor);

eg only ease-out

var lerpFactor = passedTime / duration;
smoothedLerpFactor = Mathf.Sin(lerpFactor * Mathf.PI * 0.5f);

eg only ease-in

var lerpFactor = passedTime / duration;
smoothedLerpFactor = 1f - Mathf.Cos(lerpFactor * Mathf.PI * 0.5f);

eg exponential ease in

var lerpFactor = passedTime / duration;
smoothedLerpFactor = lerpFactor * lerpFactor;

and you can also use them multiple times to even increase the smoothing effects like eg super smooth step ;)

var lerpFactor = passedTime / duration;
smoothedLerpFactor = Mathf.SmoothStep(0, 1, Mathf.SmoothStep(0, 1, lerpFactor));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM