四元数是在Unity里中用来旋转的,和欧拉旋转相比,四元数使用四个数字即可表示一个选择,且不存在万向节锁,容易插值。但缺点也很明显,不够直观。我们一般使用Quarternion来完成一个旋转过程。
其中,一个只读的静态变量:identity:对应于“无旋转”,让对象与副轴或者世界轴完美对应。
Properties:
- eulerAngles :返回或者设置旋转的欧拉角表示
表示一个绕z轴旋转z度,绕x轴旋转x度,绕y轴旋转y度的旋转。该旋转一定要按照这个顺序。
以下game1和game2的旋转结果相同,
quaternion.eulerAngles = new Vector3(30, 40, 50);
game1.transform.rotation = quaternion;
game2.transform.Rotate(new Vector3(30, 40, 50), Space.World);
但分开写就不行了,不管是绕Space.World与否,原因在于每次欧拉旋转,都是围绕旋转之前的轴,比如旋转(30,40,50),先绕z轴旋转50度,后绕x轴旋转30度,但此时围绕的是z轴旋转前的轴进行转的。但一旦分开写,那么第二次旋转时的轴会发生改变。
game3.transform.Rotate(new Vector3(0, 0, 50));
game3.transform.Rotate(new Vector3(30, 0, 0));
game3.transform.Rotate(new Vector3(0, 40, 0));
- normalized:返回此四元数的单位四元数(只读)
- this[i]:存取x,y,z,w
- 另外还有x,y,z,w四个基本变量
函数只记录个别常用的:
- SetFromToRotation
public void SetFromToRotation(Vector3 fromDirection, Vector3 toDirection);
创建一个从fromDirection转到toDirection的旋转。
从当前位置旋转到鼠标位置
m_MyQuaternion.SetFromToRotation(transform.position, m_MousePosition);
transform.position = Vector3.Lerp(transform.position, m_MousePosition, m_Speed * Time.deltaTime);
transform.rotation = transform.rotation * m_MyQuaternion;
-
FromToRotation
public static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection);
创建一个从fromDirection到toDirection的旋转。以上面的类似,但有返回值,一般
使用这个函数可以使对象的某个轴朝向世界坐标的目标方向。 -
LookRotation
Quaternion LookRotation(Vector3 forward, Vector3 upwards = Vector3.up);
使用指定的向前和向上方向创建旋转。z指向forward方向,X轴与forward和up之间的叉积对齐,Y轴与Z和X之间的叉积对齐。
public Transform target;
void Update()
{
Vector3 relativePos = target.position - transform.position;
Quaternion rotation = Quaternion.LookRotation(relativePos, Vector3.up);
transform.rotation = rotation;
-
SetLookRotation
public void SetLookRotation(Vector3 view, Vector3 up = Vector3.up); -
Angle
float Angle(Quaternion a, Quaternion b);
返回旋转a和旋转b之间的角度,以度为单位 -
Euler
Quaternion Euler(float x, float y, float z);
返回一个旋转,即绕x轴旋转x度,绕y轴旋转y度,绕z轴旋转z度 -
Slerp
Quaternion Slerp(Quaternion a, Quaternion b, float t);
通过t在a和b之间进行球面插值。参数t被钳位到[0,1]范围。
一般使用这个来进行旋转的效果,
这样的旋转是匀速的,
public class Slerf : MonoBehaviour
{
public float speed=1.0f;
Quaternion q1=new Quaternion();
Quaternion q2=new Quaternion();
float time = 0;
// Start is called before the first frame update
void Start()
{
q1 = transform.rotation;
q2.eulerAngles = new Vector3(30, 40, 50);
}
// Update is called once per frame
void Update()
{
transform.rotation = Quaternion.Slerp(q1, q2, time);
time += Time.deltaTime * speed;
}
}
以下这种写法是非匀速的,因为第三个参数不变,而第一个参数一直在改变,所以旋转效果是先慢后快的。
public class Slerf : MonoBehaviour
{
public float speed=1.0f;
Quaternion q1=new Quaternion();
Quaternion q2=new Quaternion();
// Start is called before the first frame update
void Start()
{
q1 = transform.rotation;
q2.eulerAngles = new Vector3(30, 40, 50);
}
// Update is called once per frame
void Update()
{
transform.rotation = Quaternion.Slerp(this.transform.rotation, q2, Time.deltaTime*speed);
}
}
- RotateTowards
public static Quaternion RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta);
以maxDegreeDelta来完成from到to的旋转
如果maxDegreeDelta为负数,则反向旋转直到与目标旋转完全相反的位置。
public class SetLookFro : MonoBehaviour
{
public Transform target;
public float speed=10;
void Update()
{
// The step size is equal to speed times frame time.
var step = speed * Time.deltaTime;
// Rotate our transform a step closer to the target's.
transform.rotation = Quaternion.RotateTowards(transform.rotation, target.rotation, step);
}
}
**最后是 Quaternion.operator * **
public static Quaternion operator *(Quaternion lhs, Quaternion rhs);
将两个旋转结合起来,先进行lhs旋转,后进行rhs旋转,进行rhs旋转时是相对于由lhs旋转产生的参考系的。
在原来的基础上进行新的旋转,见下
transform.rotation *= extraRotation.rotation;