我想将我的相机从一个四元数 lerp 到另一个

I want to lerp my camera from one quaternion to another

我想实现将相机从原始四元数旋转到目标四元数。

然后我使用了下面的代码:

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;
        }
    }
}

然而,相机根本没有旋转,我知道为什么

使用Quaternion.RotateTowards

Quaternion.LerpQuaternion.Slerp 当您总是有一个距离您想要旋转的起点的百分比时,将被使用。但是,您有一个当前旋转、一个目标旋转和一个速度。这更适合使用 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;
    }
}

作为 的替代方案,我想在这里留下一个实际使用 Lerp 的解决方案。

这样做的巨大优势是您可以额外添加缓入和缓出,例如使用 Mathf.SmoothStep 甚至使用其他数学计算来更改旋转动画。

它还允许您精确控制旋转需要多长时间,而与必须旋转多少度无关。在下面的示例中,我再次使用以每秒度数为单位的速度值来计算持续时间,但您也可以简单地例如传递一个固定的持续时间,例如 1 或 2 秒。

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;
    }
}

有关轻松数学结帐的更多精彩示例this post

例如因为我们有缓入和缓出:

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

例如仅缓出

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

例如仅缓入

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

例如

呈指数增长
var lerpFactor = passedTime / duration;
smoothedLerpFactor = lerpFactor * lerpFactor;

您还可以多次使用它们来增加平滑效果,例如超级流畅的步骤;)

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