Quaternion(四元数)
四元数用来表示旋转。他们紧凑,不受万向锁的困扰,而且容易插值。Unity内部使用四元数来表示所有的旋转。它们是基于复数的,不容易直观理解。你几乎从未访问或修改过单个四元数组件(x,y,z,w);通常情况下,你只需要使用现有的rotations来构造新的旋转(例如在两个旋转之间平滑的插值)。你99%的时间使用的四元数函数是:
Quaternion.LookRotation,Quaternion.Angle,Quaternion.Euler,Quaternion.Slerp,Quaternion.FromToRotation 以及Quaternion.identity.(其他功能仅用于特殊用途)。
你可以使用Quaternion.operator *将一个旋转转换到另一个,或者通过一个旋转,旋转一个向量。
注意:Unity期望四元数被标准化
Static Properties
identity:同一性旋转(只读)。该四元数,相当于无旋转,这个物体完全对齐于世界或父轴。
函数定义:public static Quaternion identity;
代码示例:
using UnityEngine;
public class rotateTest:MonoBehaviour
{
void Start()
{
//此时transform的坐标轴与世界坐标轴一致
transform.rotate = Quaternion.identity;
}
}
Properties
eulerAngles:返回旋转的欧拉角表示(2017.4.3f已弃用),围绕z轴旋转euler.z度,围绕x轴旋转euler.x度,围绕y轴旋转euler.y度(按照此顺序).可以为四元数设置或读取euler.
函数定义:public Vector3 eulerAngles;
代码示例:
using UnityEngine;
public class rotateTest : MonoBehaviour {
private Quaternion quaternion;
private GameObject cube;
private float timeCount = 0.0f;
private void Awake()
{
quaternion = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
cube = CreateCube();
}
private void Update()
{
if(timeCount > 2.0f)
{
quaternion = Random.rotation;
cube.transform.rotation = quaternion;
timeCount = 0.0f;
}
timeCount = timeCount + Time.deltaTime;
}
private void OnGUI()
{
GUIStyle style = new GUIStyle();
style.fontSize = 24;
Vector3 angles = quaternion.eulerAngles;
GUI.Label(new Rect(10, 10, 0, 0), angles.ToString("F3"), style);
//GUI.Label(new Rect(10, 90, 250, 50), cube.transform.localEulerAngles.ToString("F3"));
}
private GameObject CreateCube()
{
GameObject newCube = new GameObject("Cube");
GameObject minusZ = GameObject.CreatePrimitive(PrimitiveType.Quad);
minusZ.transform.position = new Vector3(0.0f, 0.0f, -0.5f);
minusZ.GetComponent<Renderer>().material.color = Color.gray;
minusZ.transform.parent = newCube.transform;
GameObject plusZ = GameObject.CreatePrimitive(PrimitiveType.Quad);
plusZ.transform.position = new Vector3(0.0f, 0.0f, 0.5f);
plusZ.transform.Rotate(new Vector3(0.0f, 180.0f, 0.0f));
plusZ.GetComponent<Renderer>().material.color = Color.magenta;
plusZ.transform.parent = newCube.transform;
GameObject minusX = GameObject.CreatePrimitive(PrimitiveType.Quad);
minusX.transform.position = new Vector3(0.5f, 0.0f, 0.0f);
minusX.transform.Rotate(new Vector3(0.0f, 270.0f, 0.0f));
minusX.GetComponent<Renderer>().material.color = Color.yellow;
minusX.transform.parent = newCube.transform;
GameObject plusX = GameObject.CreatePrimitive(PrimitiveType.Quad);
plusX.transform.position = new Vector3(-0.5f, 0.0f, 0.0f);
plusX.transform.Rotate(new Vector3(0.0f, 90.0f, 0.0f));
plusX.GetComponent<Renderer>().material.color = Color.blue;
plusX.transform.parent = newCube.transform;
GameObject minusY = GameObject.CreatePrimitive(PrimitiveType.Quad);
minusY.transform.position = new Vector3(0.0f, -0.5f, 0.0f);
minusY.transform.Rotate(new Vector3(270.0f, 0.0f, 0.0f));
minusY.GetComponent<Renderer>().material.color = Color.green;
minusY.transform.parent = newCube.transform;
GameObject plusY = GameObject.CreatePrimitive(PrimitiveType.Quad);
plusY.transform.position = new Vector3(0.0f, 0.5f, 0.0f);
plusY.transform.Rotate(new Vector3(90.0f, 0.0f, 0.0f));
plusY.GetComponent<Renderer>().material.color = Color.red;
plusY.transform.parent = newCube.transform;
return newCube;
}
}
normalized:返回模为1的四元数(只读)。归一化时,四元数保持相同的方向,但其大小为1.0。注意:当前四元数未更改,并返回新的归一化的四元数。如果想要归一化原始的四元数,改用Normalize方法。如果四元数太小,以至于无法归一化,则将返回Quaternion.identity。
函数定义:
public Quaternion normalized;
this[int]:分别使用[0],[1],[2],[3]访问x,y,z,w分量
函数定义:
public float this[int]
代码示例:
using UnityEngine;
public class rotateTest : MonoBehaviour {
private void Start()
{
Quaternion p = new Quaternion();
Debug.Log(p);
p[3] = 0.5f; //等价于p.w = 0.5f
Debug.Log(p);
}
}
输出为:
(0.0,0.0,0.0,0.0)
(0.0,0.0,0.0,0.5)
w:四元数的w分量,不要直接修改它,除非你完全了解四元数
函数定义:public float w;
w:四元数的w分量,不要直接修改它,除非你完全了解四元数.四元数可以表示3D旋转,并由4个实数定义。x,y,z表示一个向量。w是一个标量用于存储绕向量的旋转角度(cos(θ/2))
函数定义:public float w;
代码示例:
using UnityEngine;
public class rotateTest : MonoBehaviour {
private float timeDelay = 0.0f;
private Quaternion q;
private string label = "";
private void Awake()
{
GameObject line = GameObject.CreatePrimitive(PrimitiveType.Cube);
line.transform.localScale = new Vector3(0.05f, 1.5f, 0.05f);
line.transform.parent = gameObject.transform;
}
private void Update()
{
if(timeDelay > 1.0f)
{
Vector3 v;
v.x = Random.Range(0.0f, 360.0f);
v.y = Random.Range(0.0f, 360.0f);
v.z = Random.Range(0.0f, 360.0f);
q = Quaternion.Euler(v);
transform.rotation = q;
label = q.ToString("f3");
timeDelay = 0.0f;
}
timeDelay += Time.deltaTime;
}
private void OnGUI()
{
GUI.skin.label.fixedHeight = 40;
GUI.skin.label.fontSize = 24;
GUI.Label(new Rect(10, 10, 400, 30), label);
}
}
设旋转轴为v,旋转角为a则x = sin(a/2)v.x,y = sin(a/2)v.y,z = sin(a/2)v.z
x:四元数的x分量,不要直接修改它,除非你完全了解四元数
y:四元数的y分量,不要直接修改它,除非你完全了解四元数
z:四元数的z分量,不要直接修改它,除非你完全了解四元数
函数定义:
public float x;
public float y;
public float z;
代码示例:
using UnityEngine;
using UnityEngine.UI;
public class rotateTest : MonoBehaviour {
float m_MyX, m_MyY, m_MyZ;
public Slider m_SlidersX, m_SliderY, m_SliderZ;
public Text m_TextX, m_TextY, m_TextZ;
private void Start()
{
m_MyX = 0;
m_MyY = 0;
m_MyZ = 0;
m_SlidersX.maxValue = 1;
m_SliderY.maxValue = 1;
m_SliderZ.maxValue = 1;
m_SlidersX.minValue = -1;
m_SliderY.minValue = -1;
m_SliderZ.minValue = -1;
}
private static Quaternion Change(float x, float y,float z)
{
return new Quaternion(x, y, z, 1);
}
private void Update()
{
m_MyX = m_SlidersX.value;
m_MyY = m_SliderY.value;
m_MyZ = m_SliderZ.value;
m_TextX.text = " X : " + m_MyX;
m_TextY.text = " Y : " + m_MyY;
m_TextZ.text = " Z : " + m_MyZ;
transform.rotation = Change(m_MyX, m_MyY, m_MyZ);
}
}
Constructors
Quaternion:用给定的x,y,z,w分量构造新的四元数
函数定义:public Quaternion(float x,float y,float z,float w)
Public Methods
Set:设置现有四元数的x,y,z和w分量
函数定义:
public void Set(float newX,float newY,float newZ,float newW);
SetFromToRotation:创建一个从一个方向旋转到另一个方向的旋转。使用此选项创建一个从第一个向量开始并旋转到第二个向量的旋转。
函数定义:
public void SetFromToRotation(Vector3 fromDirection,Vector3 toDirection)
代码示例1:
using UnityEngine;
public class rotateTest : MonoBehaviour {
public Transform m_NextPoint;
Quaternion m_MyQuaternion;
float m_Speed = 1.0f;
private void Start()
{
m_MyQuaternion = new Quaternion();
}
private void Update()
{
Debug.DrawLine(Vector3.zero, transform.position, Color.red);
Debug.DrawLine(Vector3.zero, m_NextPoint.position, Color.green);
Vector3 crossVector = Vector3.Cross(transform.position, m_NextPoint.position);
Debug.DrawLine(Vector3.zero, crossVector,Color.black);
Debug.DrawLine(transform.position, transform.position + crossVector, Color.cyan);
//绕原点指向transform.position的向量A以及原点指向m_NextPoint.position的向量B组成的平面的垂直线旋转A到B的夹角
m_MyQuaternion.SetFromToRotation(transform.position, m_NextPoint.position);
transform.position = Vector3.Lerp(transform.position, m_NextPoint.position, m_Speed * Time.deltaTime);
//从世界坐标轴旋转至transform位置,然后在旋转到m_NextPoint的位置
transform.rotation = m_MyQuaternion * transform.rotation;
}
}
代码示例2:
using UnityEngine;
public class rotateTest : MonoBehaviour {
Quaternion m_MyQuaternion;
float m_Speed = 1.0f;
Vector3 m_MousePosition;
private void Start()
{
m_MyQuaternion = new Quaternion();
}
private void Update()
{
m_MousePosition = Input.mousePosition;
m_MousePosition.z = 50.0f;
m_MousePosition = Camera.main.ScreenToWorldPoint(m_MousePosition);
m_MyQuaternion.SetFromToRotation(transform.position, m_MousePosition);
transform.position = Vector3.Lerp(transform.position, m_MousePosition, m_Speed * Time.deltaTime);
transform.rotation = m_MyQuaternion * transform.rotation;
}
}
SetLookRotation:创建一个旋转,沿着forward(z轴)并且头部沿着up(y轴)的约束注视。也就是建立一个旋转,使z轴朝向view,y轴朝向up)。如果forward方向是0,记录一个错误。
函数定义:public void SetLookRotation(Vector3 view,Vector3 up = Vector3.up);
函数参数:
1.view:朝向的方向
2.up:定义up方向
ToAngleAxis:将旋转转换为角轴表示(角度单位)
函数参数:public void ToAngleAxis(out float angle,out Vector3 axis)
代码示例1:
using UnityEngine;
public class rotateTest : MonoBehaviour
{
private void Start()
{
float angle = 0.0f;
Vector3 axis = Vector3.zero;
//绕世界坐标轴Y轴顺时针(左手坐标系)旋转90度:则旋转轴(0,1,0),a = 90;即四元数为(sin(a/2) * 0,sin(a/2) * 1,sin(a/2) * 0,con(a/2));
Quaternion A = new Quaternion(0, 0.525f, 0, 0.525f);
//绕世界坐标轴X轴顺时针(左手坐标系)旋转90:则旋转轴为(1,0,0),a = 90
Quaternion B = new Quaternion(0.525f, 0, 0, 0.525f);
//transform绕世界坐标轴Y轴顺时针旋转90度,然后绕世界坐标轴X轴顺时针旋转90度
//由于transform绕世界坐标轴Y轴顺时针旋转90度后transform的模型坐标轴:X轴对应世界坐标轴-Z轴,Z轴对应世界坐标轴X轴,Y轴对应世界坐标轴Y轴
//则绕世界坐标轴X轴顺时针旋转90度相当于绕模型坐标轴Z轴旋转90.
transform.rotation = B * A;
transform.rotation.ToAngleAxis(out angle, out axis);
Debug.Log(angle + ":" + axis);
float halfRadians = Mathf.Acos(transform.rotation.w);
float halfSin = Mathf.Sin(halfRadians);
Debug.Log(halfRadians * Mathf.Rad2Deg * 2 + ":" + transform.rotation.x / halfSin + ":" + transform.rotation.y / halfSin + ":" + transform.rotation.y / halfSin);
Debug.Log(transform.eulerAngles);
}
}
代码示例2:
using UnityEngine;
public class RotateTest : MonoBehaviour
{
public Transform target1;
public Transform target2;
float angle;
void Start()
{
}
private void Update()
{
//万向锁
//在Inspector面板的Transfomr组件中输入R:X = 90, Y = 0, Z = 0;然后随意修改Y值和Z值可以发现无论修改Y值还是Z值,
//模型都只能绕着模型坐标轴的Z轴或-Z轴进行旋转,无法再通过修改Y值或者Z值来达到绕着Y轴旋转的目的,这就是万向锁问题
//这是由于Unity的旋转顺序是Y-X-Z,设此时绕Y轴的选择为QY,绕X轴的旋转为QX,绕Z轴的旋转为QZ则此时的旋转变化为
//transform.rotation = QZ * QX * QY,则物体绕世界坐标轴Y轴进行旋转变化QY,然后在进行QY旋转变化后的坐标轴进行变化QX
//由于此时的QX变化导致了模型坐标轴Z轴与世界坐标轴-Y轴重叠
//从而导致改变Y值与改变Z值,模型都只能绕着模型坐标轴的Z轴或-Z轴进行旋转。
target1.localRotation = Quaternion.identity;
target1.Rotate(new Vector3(0, angle, 0), Space.Self);
target1.Rotate(new Vector3(90, 0, 0), Space.Self);
target2.localRotation = Quaternion.identity;
target2.Rotate(new Vector3(90, 0, 0), Space.Self);
target2.Rotate(new Vector3(0, 0, angle), Space.Self);
angle = angle + 1;
if (angle > 360)
angle = 0;
}
}
ToString:返回一个格式良好的四元数字符串
函数定义:
public string ToSTring();
public string ToString(string format);
代码示例:
using UnityEngine;
public class rotateTest : MonoBehaviour {
private void Start()
{
print(Quaternion.identity);
}
}
Static Methods
Angle:返回两个旋转a和b之间的角度
函数定义:
public static float Angle(Quaternion a,Quaternion b);
代码示例:
using UnityEngine;
public class rotateTest : MonoBehaviour {
public Transform target;
private void Start()
{
//想象两个游戏对象(A和B)围绕第三个GameObject(C)移动。
//从C到A和C到B的线创建一个可以随时间变化的三角形.CA和CB之间的角度是Quaternion.Angle提供的值
//public static float Dot(Quaternion a, Quaternion b)
//{
//return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
//}
//public static float Angle(Quaternion a, Quaternion b)
//{
//float dot = Dot(a, b);
//return IsEqualUsingDot(dot) ? 0.0f : Mathf.Acos(Mathf.Min(Mathf.Abs(dot), 1.0F)) * 2.0F * Mathf.Rad2Deg;
//}
float angle = Quaternion.Angle(transform.rotation, target.rotation);
float dot = transform.rotation.x * target.rotation.x + transform.rotation.y * target.rotation.y + transform.rotation.z * target.rotation.z
+ transform.rotation.w * target.rotation.w;
Debug.Log(angle + ":" + dot);
}
}
AngleAxis:创建一个围绕轴旋转某个角度的旋转
函数定义:
public static Quaternion AngleAxis(flaot angle,Vector3 axis);
代码示例:
using UnityEngine;
public class rotateTest : MonoBehaviour {
private void Start()
{
//绕世界坐标轴y轴顺时针旋转30度
transform.rotation = Quaternion.AngleAxis(30, Vector3.up);
}
}
Dot:两个旋转之间的点积
函数定义:
public static float Dot(Quaternion a,Quaternion b);
代码示例:
using UnityEngine;
public class rotateTest : MonoBehaviour {
private void Start()
{
float dot1 = Quaternion.Dot(transform.rotation, Quaternion.identity);
float dot2 = transform.rotation.x * Quaternion.identity.x + transform.rotation.y * Quaternion.identity.y + transform.rotation.z * Quaternion.identity.z
+ transform.rotation.w * transform.rotation.w;
Debug.Log(Quaternion.identity + ":" + dot1 + ":" + dot2);
}
Euler:返回绕z轴旋转z度,绕x轴旋转x度,绕y轴旋转y度的旋转
函数定义:
1.public static Quaternion Euler(float x, float y, float z)
2.public static Quaternion Euler(Vector3 euler);
代码示例1:
using UnityEngine;
public class rotateTest : MonoBehaviour {
private void Start()
{
//绕世界坐标轴Y轴顺时针旋转30度
Quaternion rotation = Quaternion.Euler(0, 30, 0);
transform.rotation = rotation;
}
}
代码示例2:
using UnityEngine;
public class rotateTest : MonoBehaviour {
private void Start()
{
//绕世界坐标轴Y轴顺时针旋转30度
Vector3 rotationVector = new Vector3(0, 30, 0);
Quaternion rotation = Quaternion.Euler(rotationVector);
transform.rotation = rotation;
}
}
FromToRotation:创建一个从一个方向旋转到另一个方向的旋转,见SetFromToRotation
函数定义:
public static Quaternion FromToRation(Vector3 fromDirection,Vector3 toDirection);
代码示例:
using UnityEngine;
public class rotateTest : MonoBehaviour {
private void Start()
{
Debug.DrawLine(transform.position, transform.position + Vector3.up, Color.cyan,1000);
Debug.DrawLine(transform.position, transform.position + transform.forward, Color.black,1000);
Vector3 cross = Vector3.Cross(Vector3.up, transform.forward);
Debug.DrawLine(transform.position, transform.position + cross, Color.white, 1000);
transform.rotation = Quaternion.FromToRotation(Vector3.up, transform.forward);
}
}
Inverse:返回旋转的逆
函数定义:
public static Quaternion Inverse(Quaternion rotation)
代码示例:
using UnityEngine;
public class rotateTest : MonoBehaviour
{
private void Update()
{
//绕世界坐标轴Y轴顺时针旋转90度
Quaternion q = new Quaternion(0, 0.525f, 0, 0.525f);
//绕世界坐标轴Y轴逆时针旋转90度
transform.rotation = Quaternion.Inverse(q);
Debug.Log(q + ":" + Quaternion.Inverse(q) + ":" + Quaternion.Inverse(q).normalized + ":" + transform.rotation);
}
}
//由于四元数:q = [cos(θ/2) (sin(θ/2)n(x) sin(θ/2)n(y) sin(θ/2)n(z))] = [w (x y z)]
//四元数q的逆:表示沿q的相反方向旋转相同的角度 = [w (-x -y -z)]或表示沿q的方向旋转负的旋转角=[-w (x y z)]
//注意是与归一化后的值相等
输出结果:(0.0, 1.0, 0.0, 1.0):(0.0, -1.0, 0.0, 1.0):(0.0, -0.7, 0.0, 0.7):(0.0, -0.7, 0.0, 0.7)
Lerp:在a和b之间用t插值,然后将结果归一化。将参数t固定到范围[0,1].运算效率比Slerp快,但如果旋转相距很远,看起来效果则不太好。
函数定义:public static Quaternion Lerp(Quaternion a,Quaternion b,float t);
using UnityEngine;
public class rotateTest : MonoBehaviour {
private void Update()
{
Quaternion Q1 = new Quaternion(0, 0.525f, 0, 0.525f);
Quaternion Q2 = new Quaternion(0.525f, 0, 0, 0.525f);
Debug.DrawLine(transform.position, transform.position + Vector3.up, Color.green);
Debug.DrawLine(transform.position, transform.position + Vector3.right, Color.red);
//从transform绕世界坐标轴Y轴旋转90度时的位置,Lerp到transform绕世界坐标轴X轴旋转90度的位置
//即从transform.rotaion = Q1 到 transform.rotation = Q2
transform.rotation = Quaternion.Lerp(Q1, Q2, Time.time * 0.1f);
}
}
LerpUnclamped:在a和b之间用t插值,然后将结果归一化。参数t不需要固定范围.a和b之间用t插值,然后将结果归一化。参数t没有被限制在[0,1]之间。这比Slerp快,但如果旋转相距很远,则看起来效果不太好。
函数定义:
public static Quaternion LerpUnclamped(Quaternion a,Quaternion b,float);
LookRotation:创建具有指定的向前和向上方向的旋转。Z轴将对其forward方向,X轴与forward和upwards的叉积对其,Y轴与Z轴和X轴的叉积对齐。返回identity如果forward或者upward的长度为0,返回identity如果forward和upwards共线。
函数定义:public static Quaternion LookRotation(Vector3 forward,Vector3 upwards = Vector3.up);
函数参数:
1.forward:朝向的方向
2.upwards:定义方向up
代码示例:
using UnityEngine;
public class rotateTest : MonoBehaviour
{
public Transform target;
private void Update()
{
Vector3 relativePos = target.position - transform.position;
Quaternion rotation = Quaternion.LookRotation(relativePos, Vector3.up);
transform.rotation = rotation;
}
}
Normalize:将这个四元数转换为方向相同但模为1的四元数。归一化时,四元数保持相同的方向,但其模为1。注意,此方法会改变当前的四元数,如果要保持当前四元数不变,请改用normalized属性。如果此四元数太小而无法规范化,则将其设置为Quaternion.identity.
函数定义:public static Quaternion Normalize(Quaternion q);
代码示例:
using UnityEngine;
public class rotateTest : MonoBehaviour
{
private void Start()
{
Quaternion q = new Quaternion(0, 0.525f, 0, 0.525f);
Debug.Log(q + ":" + q.normalized + ":" + q + ":" + Quaternion.Normalize(q) + ":" +q);
}
}
输出结果:(0.0, 0.5, 0.0, 0.5):(0.0, 0.7, 0.0, 0.7):(0.0, 0.5, 0.0, 0.5):(0.0, 0.7, 0.0, 0.7):(0.0, 0.5, 0.0, 0.5)
RotateTowards:从from旋转到to.from四元数通过maxDegreesDelta的角度步长向前旋转(注意:旋转不会超过to的值)。负的maxDegreesDelta将远离to方向,直到旋转到完全相反的方向。
函数定义:public static Quaternion RotateTowards(Quaternion from,Quaternion to,float maxDegreesDelta);
代码示例:
using UnityEngine;
public class rotateTest : MonoBehaviour
{
public Transform target;
public float speed;
private void Update()
{
var step = speed * Time.deltaTime;
transform.rotation = Quaternion.RotateTowards(transform.rotation, target.rotation, step);
}
}
Slerp:在a和b之间用t进行球面插值,将参数t固定在范围[0,1]
函数定义:public static Quaternion Slerp(Quaternion a,Quaternion b,float t)
using UnityEngine;
public class rotateTest : MonoBehaviour
{
public Transform from;
public Transform to;
private float timeCount = 0.0f;
private void Update()
{
transform.rotation = Quaternion.Slerp(from.rotation, to.rotation, timeCount);
timeCount = timeCount + Time.deltaTime;
}
}
SlerpUnClamped:在a和b之间用t进行球面插值,参数t不需要固定范围
函数定义:public static Quaternion SlerpUnclamped(Quaternion a,Quaternion b,float t);
Operators
operator *:第一个函数表示:结合旋转lhs和rhs。通过乘积与lhs*rhs旋转与按顺序应用两个旋转相同:先是lhs,然后在进行lhs旋转后的坐标系下进行rhs旋转。请注意,这意味着旋转时不可交换的,因此lhs * rhs不等于 rhs * lhs。第二个函数表示:根据rotation旋转point.
函数定义:
1.public static Quaternion operator*(Quaternion lhs,Quaternion rhs);
2.public static Vector3 operator*(Quaternion rotation,Vector3 point);
函数参数:
1.lhs:左边的四元数
2.rhs:右边的四元数
代码示例1:
using UnityEngine;
public class rotateTest : MonoBehaviour
{
public Transform extraRotation;
void Update()
{
transform.rotation *= extraRotation.rotation;
}
}
代码示例2:
using UnityEngine;
public class rotateTest : MonoBehaviour
{
public Vector3 relativeDirection = Vector3.forward;
private void Update()
{
Debug.DrawLine(Vector3.zero, Vector3.zero + relativeDirection, Color.red);
Vector3 absoluteDirection = transform.rotation * relativeDirection;
Debug.DrawLine(Vector3.zero, Vector3.zero + absoluteDirection, Color.yellow);
transform.position += absoluteDirection * Time.deltaTime;
}
}
operator ==:判断两个四元数是否相等.这个函数测试两个四元数的点积是否接近1.0.注意,因为四元数可以表示最多连个完整旋转(720)的旋转,所以即使结果旋转看起来相同,此比较也可能返回false.
函数定义:public static bool operator==(Quaternion lhs,Quaternion rhs);
物体A存在以下关系:
A.transform.up = A.transform.rotation * Vector3.up;
A.transform.right = A.transform.rotation * Vector3.right;
A.transform.forward = A.transform.rotation * Vector3.forward;
//transform.forward向量旋转至mouseWorldPos向量
Quaternion lookAtRotate = Quaternion.FromToRotation(A.transform.forward, mouseWorldPos);
//下面两句是等价的:transform.forward向量旋转至mouseWorldPos关于transform.up对称的向量
lookAtRotate = new Quaternion(-lookAtRotate.x, -lookAtRotate.y, -lookAtRotate.z, lookAtRotate.w);
lookAtRotate = new Quaternion(lookAtRotate.x, lookAtRotate.y, lookAtRotate.z, -lookAtRotate.w);
Quaternion origin = A.rotation;
A.rotation = lookAtRotate,此时
A.transform.forward = lookAtRotate * (Quaternion origin * Vector3.forward);
Quaternion quat = Quaternion.AngleAxis(Time.time * 180,A.transform.forward);
A.rotation = quat
此时:
A.transform.up = quat * Vector3.up,也就是Vector3.up绕A.transform.forward旋转Time.time * 180
若换成:
A.rotation = quat * A.rotation,也就是Vector3.up旋转到当前A的位置,然后绕A.transform.forward旋转Time.time * 180
A.rotation = A.parent.rotation * A.localRotation
Unity旋转顺序:
using UnityEngine;
public class RotateTest : MonoBehaviour
{
public Transform target1;
public Transform target2;
public Transform target3;
void Start()
{
//Transform.Rotate的实现
// public void Rotate(Vector3 eulers, [UnityEngine.Internal.DefaultValue("Space.Self")] Space relativeTo)
//{
// Quaternion eulerRot = Quaternion.Euler(eulers.x, eulers.y, eulers.z);
// if (relativeTo == Space.Self)
// localRotation = localRotation * eulerRot;
// else
// {
// rotation = rotation * (Quaternion.Inverse(rotation) * eulerRot * rotation);
// }
//}
//以下三种方式所得结果一致
// target1.Rotate(new Vector3(30, 40, 50), Space.World);
// target2.Rotate(new Vector3(0, 0, 50), Space.World);
// target2.Rotate(new Vector3(30, 0, 0), Space.World);
// target2.Rotate(new Vector3(0, 40, 0), Space.World);
// Quaternion x = Quaternion.AngleAxis(30, Vector3.right);
// Quaternion y = Quaternion.AngleAxis(40, Vector3.up);
// Quaternion z = Quaternion.AngleAxis(50, Vector3.forward);
// target3.rotation = y * x * z;
//以下三种方式所得结果一致
target1.Rotate(new Vector3(30, 40, 50), Space.Self);
target2.Rotate(new Vector3(0, 40, 0), Space.Self);
target2.Rotate(new Vector3(30, 0, 0), Space.Self);
target2.Rotate(new Vector3(0, 0, 50), Space.Self);
Quaternion x = Quaternion.AngleAxis(30, Vector3.right);
Quaternion y = Quaternion.AngleAxis(40, Vector3.up);
Quaternion z = Quaternion.AngleAxis(50, Vector3.forward);
target3.rotation = y * x * z;
}
}
参考资料:
1.https://docs.unity3d.com/ScriptReference/Quaternion.html
2.https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Quaternion.cs
3.https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Vector3.cs
4.【重要:必看】【复数与四元数】https://krasjet.github.io/quaternion/quaternion.pdf
5.【正交投影矩阵】https://zhuanlan.zhihu.com/p/28379857
6.【Transform】https://github.com/Unity-Technologies/UnityCsReference/tree/master/Runtime/Transform/ScriptBindings