【问题标题】:I want to lerp my camera from one quaternion to another我想把我的相机从一个四元数移到另一个
【发布时间】:2019-07-25 01:34:12
【问题描述】:

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

然后我使用了以下代码:

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

但是,相机根本没有旋转,不知道为什么

【问题讨论】:

    标签: c# unity3d rotation quaternions


    【解决方案1】:

    作为Ruzihm's answer 的替代方案,我想在这里留下一个实际使用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));
    

    【讨论】:

    • 谢谢~你的详细解答,轮流学习了很多?
    • 很好的答案!如果你想使用不同的缓动,你会改变什么?这将是对var smoothedLerpFactor 行的更改,对吗?
    • 没错!结帐this post。您可以使用许多其他的缓动数学示例
    【解决方案2】:

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

    【讨论】:

    • 是的,我检查了它仍然无法工作。我正在考虑我的 targetRotation 是正确的值。这是我从检查员那里检查的 (x,y,z) 值,对吗?
    • x,y,z 是四元数的欧拉表示,但不能直接将这些值用作四元数 x,y,z,w
    • @ChenJi 尽量使用public Vector3 targetRotation(更容易调整欧拉角),而在RotateTowards 中使用Quaternion.Euler(targetRotation)。或者在循环开始之前更有效地存储这个值一次;)
    猜你喜欢
    • 2012-02-05
    • 2016-07-27
    • 2019-03-15
    • 2014-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多