12.3D数学-Quaternion四元数-四元数常用方法
12.1 知识点
主要学习内容
单位四元数
identity静态变量 代表单位四元数
identity静态变量代表单位旋转四元数。
//单位旋转(只读)。
print(Quaternion.identity);
testCube.rotation = Quaternion.identity;
//测试立方体无论当前旋转如何 都会恢复成每个轴都不旋转的(0,0,0)
//Object的Instantiate方法有重载 第三个参数可以传入四元数角度
Instantiate(testCube, Vector3.zero, Quaternion.identity);
插值运算
Lerp静态方法 四元数线性插值进行旋转
Lerp静态方法用于在两个四元数之间进行线性插值。
Lerp静态方法是Quaternion结构体提供的一个功能,用于在两个四元数之间进行线性插值。线性插值通常用于在两个值之间以线性方式进行平滑过渡。对于四元数,Lerp方法将在两个四元数之间进行插值,并返回一个介于它们之间的新四元数。此外,该方法还会对结果进行标准化处理,确保返回的四元数仍然代表一个单位旋转。
public static Quaternion Lerp(Quaternion a, Quaternion b, float t);
a
:起始四元数。b
:目标四元数。t
:插值系数,表示在起始和目标之间的插值程度。它的取值范围通常在 [0, 1] 之间。当t
为0时,返回a
;当t
为1时,返回b
。
Quaternion a = Quaternion.Euler(0, 45, 0); // 起始四元数
Quaternion b = Quaternion.Euler(0, 90, 0); // 目标四元数
float t = 0.5f; // 插值系数
Quaternion result = Quaternion.Lerp(a, b, t);
在这个示例中,我们从一个代表绕Y轴旋转45度的四元数 a
,过渡到另一个代表绕Y轴旋转90度的四元数 b
。通过将插值系数 t
设置为0.5,我们在这两个旋转之间进行了平滑的线性插值,并得到了一个新的四元数 result
。
Slerp静态方法 四元数球形插值进行旋转
Slerp静态方法用于在两个四元数之间进行球形插值。
// Update内
// 在四元数 a 与 b 之间按比率 t 进行球形插值。参数 t 限制在范围[0, 1] 内。
// 想让立方体A和立方体B慢慢变成和立方体target相同旋转
// 无限接近,先快后慢
// 传入当前旋转四元数和目标旋转四元数,每帧变化赋值给下一帧旋转四元数
A.transform.rotation = Quaternion.Slerp(A.transform.rotation, target.rotation, Time.deltaTime);
// 匀速变化,time>=1到达目标
// 定死开始旋转四元数和目标旋转四元数,累加事件
time += Time.deltaTime;
// 开始旋转四元数在Start()内 start = B.transform.rotation 赋好值
B.transform.rotation = Quaternion.Slerp(start, target.rotation, time);
向量指向转四元数LookRotation
LookRotation静态方法 获得向量指向转四元数
LookRotation静态方法用于使用指定的forward和upwards方向创建旋转。
// 目标是想让A立即转向看向B
// 先让lookA和lookB位置相减算出lookAB向量,传入LookRotation静态方法中,获得返回的四元数赋值给lookA
Quaternion q = Quaternion.LookRotation(lookB.position - lookA.position);
lookA.rotation = q;
// 资源实现的效果和Transform中的静态方法LookAt方法类似
总结
12.2 知识点代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson12_3D数学_Quaternion四元数_四元数常用方法 : MonoBehaviour
{
//测试立方体
public Transform testCube;
//三个立方体 想让立方体A和立方体B慢慢变成和立方体target相同旋转
public Transform target;
public Transform A;
public Transform B;
private Quaternion start;
private float time;
public Transform lookA;
public Transform lookB;
void Start()
{
#region 知识点一 单位四元数
//identity静态变量 代表单位四元数
//单位旋转(只读)。
print(Quaternion.identity);
testCube.rotation = Quaternion.identity;
//测试立方体无论当前旋转如何 都会恢复成每个轴都不旋转的(0,0,0)
//Object的Instantiate方法有重载 第三个参数可以传入四元数角度
Instantiate(testCube, Vector3.zero, Quaternion.identity);
#endregion
#region 知识点二 插值运算
start = B.transform.rotation;
#endregion
}
void Update()
{
#region 知识点二 插值运算
//Lerp静态方法 四元数线形插值进行旋转
//在 a 和 b 之间插入 newThread,然后对结果进行标准化处理。参数 newThread 被限制在[0, 1] 范围内。
//四元数一般使用球形插值 线性插值的用法和球形插值相同 略
//Slerp静态方法 四元数球形插值进行旋转
//在四元数 a 与 b 之间按比率 newThread 进行球形插值。参数 newThread 限制在范围[0, 1] 内。
//想让立方体A和立方体B慢慢变成和立方体target相同旋转
//无限接近 先快后慢
//传入当前旋转四元数好目标旋转四元数 每帧变化赋值给下一帧旋转四元数
A.transform.rotation = Quaternion.Slerp(A.transform.rotation, target.rotation, Time.deltaTime);
//匀速变化 testNum>=1到达目标
//定死开始旋转四元数和目标旋转四元数 累加事件
time += Time.deltaTime;
//开始旋转四元数在Start()内 start = B.transform.rotation赋好值
B.transform.rotation = Quaternion.Slerp(start, target.rotation, time);
#endregion
#region 知识点三 向量指向转四元数LookRotation
//LookRotation静态方法 获得向量指向转四元数
//使用指定的 forward 和 upwards 方向创建旋转。
//目标是想让A立即转向看向B
//先让lookA和lookB位置相减算出lookAB向量,传入LookRotation静态方法中,获得返回的四元数赋值给lookA
Quaternion q = Quaternion.LookRotation(lookB.position - lookA.position);
lookA.rotation = q;
//资源实现的效果和Transform中的静态方法LookAt方法类似
#endregion
}
}
12.3 练习题
利用四元数的LookRotation方法,实现LookAt的效果
假设Transform类没有LookAt方法,创建Tools脚本,为Transform类提供效果和LookAt方法效果一样的拓展方法
// 自己写的看向目标的方法
public static void MyLookAt(this Transform obj, Transform target)
{
// 算出目标和自己的向量
Vector3 vec = target.position - obj.position;
// 用LookRotation得到转向的四元数赋值给自己
obj.transform.rotation = Quaternion.LookRotation(vec);
}
调用自己写的拓展方法看向B
lookA.MyLookAt(lookB);
将之前摄像机移动的练习题中的LookAt换成LookRotation实现,并且通过Slerp来缓慢看向玩家
摄像机先快后慢旋转看向目标
// 用目标的位置 减去 摄像机的位置 得到新的面朝向向量四元数
targetQ = Quaternion.LookRotation(target.position - this.transform.position);
// 调用球形插值 传入当前摄像机当前旋转四元数、面朝向向量四元数、以及旋转速度 赋值给下一帧摄像机当前旋转
this.transform.rotation = Quaternion.Slerp(this.transform.rotation, targetQ, Time.deltaTime * roundSpeed);
摄像机匀速旋转看向目标
// 当发现目标对象位置改变时
if (targetQ != Quaternion.LookRotation(target.position - this.transform.position))
{
// 重新用目标的位置减去摄像机的位置计算出新的面朝向向量四元数
targetQ = Quaternion.LookRotation(target.position - this.transform.position);
// 清空累加时间 不然时间一直大于1 会一直盯着目标看 不能达到匀速旋转看向目标的效果
roundTime = 0;
// 重置摄像机开始旋转位置
startQ = this.transform.rotation;
}
// 累加时间
roundTime += Time.deltaTime;
// 传入发现目标对象位置改变后定死的摄像机开始旋转位置,目标旋转位置,和累加的时间
this.transform.rotation = Quaternion.Slerp(startQ, targetQ, roundTime * roundSpeed);
12.4 练习题代码
Lesson12_练习题
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//这个脚本将要挂载到摄像机上 实现摄像机跟随
public class Lesson12_练习题 : MonoBehaviour
{
#region 练习题一
//利用四元数的LookRotation方法,实现LookAt的效果
public Transform lookA;
public Transform lookB;
void Update()
{
//调用自己写的拓展方法看向B
lookA.MyLookAt(lookB);
}
#endregion
#region 练习题二
//将之前摄像机移动的练习题中的LookAt换成LookRotation实现,并且通过Slerp来缓慢看向玩家
//目标对象
public Transform target;
//目标旋转角度四元数
private Quaternion targetQ;
//旋转速度
public float roundSpeed;
//旋转累加事件
private float roundTime;
//开始时的旋转四元数
private Quaternion startQ;
private void LateUpdate()
{
//摄像机先快后慢旋转看向目标
////用目标的位置 减去 摄像机的位置 得到新的面朝向向量四元数
//targetQ = Quaternion.LookRotation(target.position - this.transform.position);
////调用球形插值 传入当前摄像机当前旋转四元数、面朝向向量四元数、以及旋转速度 赋值给下一帧摄像机当前旋转
//this.transform.rotation = Quaternion.Slerp(this.transform.rotation, targetQ, Time.deltaTime * roundSpeed);
//摄像机匀速旋转看向目标
////当发现目标对象位置改变时
//if (targetQ != Quaternion.LookRotation(target.position - this.transform.position))
//{
// //重新用目标的位置减去摄像机的位置计算出新的面朝向向量四元数
// targetQ = Quaternion.LookRotation(target.position - this.transform.position);
// //清空累加时间 不然时间一直大于1 会一直盯着目标看 不能达到匀速旋转看向目标的效果
// roundTime = 0;
// //重置摄像机开始旋转位置
// startQ = this.transform.rotation;
//}
////累加时间
//roundTime += Time.deltaTime;
////传入发现目标对象位置改变后定死的摄像机开始旋转位置,目标旋转位置,和累加的时间
//this.transform.rotation = Quaternion.Slerp(startQ, targetQ, roundTime * roundSpeed);
}
#endregion
}
Tools
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class Tools
{
//自己写的看向目标的方法
public static void MyLookAt(this Transform obj, Transform target)
{
//算出目标和自己的向量
Vector3 vec = target.position - obj.position;
//用LookRotation得到转向的四元数赋值给自己
obj.transform.rotation = Quaternion.LookRotation(vec);
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com