我想将我的相机从一个四元数 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.Lerp
或 Quaternion.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));
我想实现将相机从原始四元数旋转到目标四元数。
然后我使用了下面的代码:
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.Lerp
或 Quaternion.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));