目录

一:简介

二:属性

eulerAngles-欧拉角

三:方法

1:SetFromToRotation,静态方法FromToRotation

2:SetLookRotation,静态方法LookRotation

3:ToAngleAxis,静态方法AngleAxis

四:静态方法

1:Angle

2:Dot

3:Euler

4:Inverse

5:Lerp LerpUnclamped和Slerp SlerpUnclamped

6:RotateTowards

7:Normalize

五:静态方法

1:四元数*四元数是叠加旋转

2:四元数*向量是旋转向量


一:简介

Quaternion又称四元数,由x,y,z和w这四个分量组成,四元数的乘法不符合交换律

四元数

关于四元数的性质、与旋转的关系、球型线性插值的介绍,请阅读3D游戏与计算机图形学中的数学方法-四元数

在Unity中,用Quaternion来存储和表示对象的旋转角度。

二:属性

eulerAngles-欧拉角

定义

public Vector3 eulerAngles{get;set;}

如何改变一个游戏对象旋的转状态,我们可以通过改变其Transform进行欧拉角的变换次序,例如假设p(x,y,z)是游戏对象上的一个点,绕x轴旋转a角,绕y轴旋转b角,绕z轴旋转c角,这样就可以得到旋转之后的状态p'(x',y',z')。Unity的实现过程是很简单的,一句代码就可以搞定。但是具体的实现过程确实很复杂的,详情请阅读3D游戏与计算机图形学中的数学方法-变换。

下面给出一个例子,演示一下如何使用欧拉角。

using UnityEngine;
using System.Collections;public class EulerAngler_ts : MonoBehaviour {public Transform A, B;Quaternion rotations = Quaternion.identity;Vector3 eulerAngle = Vector3.zero;float speed = 10.0f;float tSpeed = 0.0f;// Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {tSpeed += speed * Time.deltaTime;//第一种方式:将Quaternion实例对象赋值给transform的rotationrotations.eulerAngles = new Vector3(0.0f, tSpeed, 0.0f);A.rotation = rotations;//第二种方式:将三位向量代表的欧拉角直接赋值给transform的eulerAngleB.eulerAngles = new Vector3(0.0f, tSpeed, 0.0f);}
}

三:方法

1:SetFromToRotation,静态方法FromToRotation

public void SetFromToRotion(Vector3 fromDirection,Vector3 toDirection);public static Quaternion FromToRotation (Vector3 fromDirection, Vector3 toDirection); 

示例:

Quaternion q = Quaternion.identity;
q.SetFromToRotation(v1,v2);
transform.rotation = q;

官方文档也有一个示例,有点误导,此函数应该看成将向量fromDirection旋转到向量toDirection

可以将GameObject对象进行如下变换:首先将GameObject对象自身坐标系的x,y,z轴方向和世界坐标系的x,y,z轴方向一致,然后将GameObject对象自身坐标系中向量V1指向的方向旋转到V2方向。

1.2 PS:不可以直接使用transform.rotation.SetFromToRotation(v1,v2)方式进行设置,只能将实例化的Quaternion复制给transform.rotation。

1.3 实例演示

using UnityEngine;
using System.Collections;public class SetFromToDirection_ts : MonoBehaviour {public Transform A, B, C;Quaternion q = Quaternion.identity;// Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {q.SetFromToRotation(A.position, B.position);C.rotation = q;Debug.DrawLine(Vector3.zero, A.position, Color.red);Debug.DrawLine(Vector3.zero, B.position, Color.green);Debug.DrawLine(C.position, C.position + new Vector3(0.0f, 1.0f, 0.0f), Color.black);Debug.DrawLine(C.position, C.TransformPoint(Vector3.up * 1.5f), Color.yellow);}
}

运行结果如下图所示:

2:SetLookRotation,静态方法LookRotation

public void SetLookRotation(Vector3 view);
public void SetLookRotation(Vector3 view,Vector3 up);public static Quaternion LookRotation (Vector3 forward, Vector3 upwards= Vector3.up); 

例如:

Quaternion q = Quaternion.identity;
q.SetLookRotation(v1,v2);
transform.rotation = q;

设置Quaternion实例的朝向,view是向量而不是位置,所以view为Vector3.zero时,调用无效

Z 轴将与view对齐,X 轴与 view和 up之间的差乘对齐,Y 轴与 Z 和 X 之间的差乘对齐。

up决定了transform.up的朝向,因为当transform.z和transform.x方向确定后,transform.up的方向总会与up的方向的夹角小于或等于90度。

2.2 PS:同上,不要直接使用transform.rotation.SetLookRotation(v1,v2)的方式来实例化Quaternion对象。

2.3 实例演示

using UnityEngine;
using System.Collections;public class SetLookRotation_ts : MonoBehaviour {public Transform A, B, C;Quaternion q = Quaternion.identity;// Use this for initializationvoid Start(){}// Update is called once per framevoid Update(){q.SetLookRotation(A.position, B.position);C.rotation = q;Debug.DrawLine(Vector3.zero, A.position, Color.red);Debug.DrawLine(Vector3.zero, B.position, Color.green);Debug.DrawLine(C.position, C.TransformPoint(Vector3.right * 1.5f), Color.black);Debug.DrawLine(C.position, C.TransformPoint(Vector3.forward * 1.5f), Color.yellow);Debug.Log("C.right与A的夹角: " + Vector3.Angle(C.right, A.position));Debug.Log("C.right与B的夹角: " + Vector3.Angle(C.right, B.position));Debug.Log("C.up与B的夹角: " + Vector3.Angle(C.up, B.position));}
}

运行结果

    

3:ToAngleAxis,静态方法AngleAxis

public void ToAngleAxis(out float angle,out Vector3 axis);public static Quaternion AngleAxis (float angle, Vector3 axis); 

参数angle为旋转角,参数axis为轴向量。

将一个四元数转换为轴角

3.2 实例演示

using UnityEngine;
using System.Collections;public class ToAngleAxis_ts : MonoBehaviour {public Transform A, B;float angle;Vector3 axis = Vector3.zero;float xSpeed = 0.0f, ySpeed = 0.0f, zSpeed = 0.0f;// Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {xSpeed += 0.5f * Time.deltaTime;ySpeed += 1.0f * Time.deltaTime;zSpeed += 2.5f * Time.deltaTime;A.eulerAngles = new Vector3(xSpeed, ySpeed, zSpeed);//获取A的rotation的旋转轴和角度A.rotation.ToAngleAxis(out angle, out axis);//设置B的rotation,使得B的rotation和A相同B.rotation = Quaternion.AngleAxis(angle, axis);}
}

四:静态方法

Quaternion中的静态方法有9个即:Angle方法、Dot方法、Euler方法、FromToRotation方法、Inverse方法、Lerp方法、LookRotation方法、RotateToWards方法和Slerp方法。

1:Angle

public static float Angle(Quaternion a,Quaternion b);

该方法可以计算两个旋转状态a达到b时需要旋转的最小夹角。

1.2 实例演示

using UnityEngine;
using System.Collections;public class Angle_ts : MonoBehaviour {// Use this for initializationvoid Start () {Quaternion q1 = Quaternion.identity;Quaternion q2 = Quaternion.identity;q1.eulerAngles = new Vector3(30.0f, 40.0f, 50.0f);float a1 = Quaternion.Angle(q1, q2);float a2 = 0.0f;Vector3 v = Vector3.zero;q1.ToAngleAxis(out a2,out v);Debug.Log("a1: " + a1);Debug.Log("a2: " + a2);Debug.Log("q1的欧拉角: " + q1.eulerAngles + " q1的rotation: " + q1);Debug.Log("q2的欧拉角: " + q2.eulerAngles + " q2的rotation: " + q2);}// Update is called once per framevoid Update () {}
}

运行结果

从输出结果可以看出a1和a2的值相等,即Angle的返回值是两个Quaternion实例转换的最小夹角。

2:Dot

public static float Dot(Quaternion a,Quaternion b);

该方法可以根据点乘的结果,判断a和b对应欧拉角的关系。

例如有两个Quaternion实例q1(x1,y1,z1,w1)和q2(x2,y2,z2,w2),则float f = Quaternion.Dot(q1,q2);即f = x1*x2+y1*y2+z1*z2+w1*w2,结果值f的范围为[-1,1]。

当f=+(-)1时,q1和q2对应的欧拉角是相等的,即旋转状态是一致的。特别地,当f = -1时,说明其中一个rotation比另外一个rotation多旋转了360°。

2.2 实例演示

using UnityEngine;
using System.Collections;public class Dot_ts : MonoBehaviour {public Transform A, B;Quaternion q1 = Quaternion.identity;Quaternion q2 = Quaternion.identity;// Use this for initializationvoid Start () {A.eulerAngles = new Vector3(0.0f, 40.0f, 0.0f);B.eulerAngles = new Vector3(0.0f, 360.0f + 40.0f, 0.0f);q1 = A.rotation;q2 = B.rotation;float f = Quaternion.Dot(q1, q2);Debug.Log("q1的欧拉角: " + q1.eulerAngles + " q1的rotation: " + q1);Debug.Log("q2的欧拉角: " + q2.eulerAngles + " q2的rotation: " + q2);Debug.Log("Dot(q1,q2): " + f);}// Update is called once per framevoid Update () {}
}

运行输出

从输出结果可以证明q1和q2的欧拉角相等,但是rotation值却是相反的,也说明当Dot的返回值为-1时,两个参数的角度相差360°。

3:Euler

public static Quaternion Euler(Vector3 euler);
public static Quaternion Euler(float x,float y,float z);

欧拉角转换为四元数。

其对应关系如下:

已知PIover180 = 3.141592/180 = 0.0174532925f是计算机图形学中的一个常亮,其变换过程如下:

ex = ex * PIover180 / 2.0f;
ey = ey * PIover180 / 2.0f;
ez = ez * PIover180 / 2.0f;qx = Mathf.Sin(ex) * Mathf.Cos(ey) * Mathf.Cos(ez) + Mathf.Cos(ex) * Mathf.Sin(ey) * Mathf.Sin(ez);
qy = Mathf.Cos(ex) * Mathf.Sin(ey) * Mathf.Cos(ez) - Mathf.Sin(ex) * Mathf.Cos(ey) * Mathf.Sin(ez);
qz = Mathf.Cos(ex) * Mathf.Cos(ey) * Mathf.Sin(ez) - Mathf.Sin(ex) * Mathf.Sin(ey) * Mathf.Cos(ez);
qw = Mathf.Cos(ex) * Mathf.Cos(ey) * Mathf.Cos(ez) + Mathf.Sin(ex) * Mathf.Sin(ey) * Mathf.Sin(ez);

3.2 验证变换过程

using UnityEngine;
using System.Collections;public class Euler_ts : MonoBehaviour {public float ex, ey, ez;float qx, qy, qz,qw;float PIover180 = 0.0174532925f;Quaternion q = Quaternion.identity;Vector3 euler;void OnGUI(){if(GUI.Button(new Rect(10.0f,10.0f,100.0f,45.0f),"计算")){euler = new Vector3(ex,ey,ez);Debug.Log("欧拉角Euler(ex,ey,ez): " + euler);q = Quaternion.Euler(ex, ey, ez);Debug.Log("对应的四元数为: " + q);Debug.Log("q.x: " + q.x + " q.y: " + q.y + " q.z: " + q.z + " q.w: " + q.w);//验证算法ex = ex * PIover180 / 2.0f;ey = ey * PIover180 / 2.0f;ez = ez * PIover180 / 2.0f;qx = Mathf.Sin(ex) * Mathf.Cos(ey) * Mathf.Cos(ez) + Mathf.Cos(ex) * Mathf.Sin(ey) * Mathf.Sin(ez);qy = Mathf.Cos(ex) * Mathf.Sin(ey) * Mathf.Cos(ez) - Mathf.Sin(ex) * Mathf.Cos(ey) * Mathf.Sin(ez);qz = Mathf.Cos(ex) * Mathf.Cos(ey) * Mathf.Sin(ez) - Mathf.Sin(ex) * Mathf.Sin(ey) * Mathf.Cos(ez);qw = Mathf.Cos(ex) * Mathf.Cos(ey) * Mathf.Cos(ez) + Mathf.Sin(ex) * Mathf.Sin(ey) * Mathf.Sin(ez);Debug.Log("qx: " + qx + " qy: " + qy + " qz: " + qz + " qw: " + qw);}}
}

运行结果

从输出结果可以证明该公式是正确,另外转换后的四元数直接输出的话,如下:

 q = Quaternion.Euler(ex, ey, ez);Debug.Log("对应的四元数为: " + q);

输出值是做了四舍五入处理的。

4:Inverse

public static Quaternion Inverse(Quaternion rotation);

该方法可以返回参数rotation的逆向Quaternion值。

例如rotation(x,y,z,w),那么Quaternion.Inverse(rotation) = (-x,-y,-z,w)。假设rotation的欧拉角为(a,b,c),则transform.rotation = Quaternion.Inverse(rotation)相当于transform依次绕自身坐标系的z轴、x轴和y轴分别旋转-c°、-a°和-b°。由于是在局部坐标系内的变换,最后transform的欧拉角的各个分量值并不一定等于-a、-b或-c。

5.2 实例演示

using UnityEngine;
using System.Collections;public class Invers_ts : MonoBehaviour {public Transform A, B;// Use this for initializationvoid Start () {Quaternion q1 = Quaternion.identity;Quaternion q2 = Quaternion.identity;q1.eulerAngles = new Vector3(30.0f,40.0f,50.0f);q2 = Quaternion.Inverse(q1);A.rotation = q1;B.rotation = q2;Debug.Log("q1的欧拉角: " + q1.eulerAngles + "q1的rotation: " + q1);Debug.Log("q2的欧拉角: " + q2.eulerAngles + "q2的rotation: " + q2);}// Update is called once per framevoid Update () {}
}

运行截图

5:Lerp LerpUnclamped和Slerp SlerpUnclamped

public static Quaternion Lerp(Quaternion form, Quaternion to,float t);
public static Quaternion LerpUnclamped (Quaternion a, Quaternion b, float t); public static Quaternion Slerp(Quaternion form, Quaternion to,float t);
public static Quaternion SlerpUnclamped (Quaternion a, Quaternion b, float t); 

Lerp是线性插值,Slerp是球面插值

都是返回从form到to的插值

Lerp和Slerp当参数t<=0时返回值为from,当参数t>=1时返回值为to。

LerpUnclamped和SlerpUnclamped不作限定

6.2 实例演示

using UnityEngine;
using System.Collections;public class LerpAndSlerp_ts : MonoBehaviour
{public Transform A, B, C,D;float speed = 0.2f;float total = 0.0f;// Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {total += Time.deltaTime * speed;if(total >= 1.0f)total = 1.0f;C.rotation = Quaternion.Lerp(A.rotation, B.rotation, total);D.rotation = Quaternion.Lerp(A.rotation, B.rotation, total);//C.rotation = Quaternion.Lerp(A.rotation, B.rotation, Time.deltaTime * speed);//D.rotation = Quaternion.Lerp(A.rotation, B.rotation, Time.deltaTime * speed);}
}

6:RotateTowards

public static Quaternion RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta);

期望将from旋转到to,先旋转maxDegreesDelta度,超过会返回不旋转,maxDegreesDelta为负则反方向旋转直到180度停止. 一般用于匀速插值

7.2 实例演示

using UnityEngine;
using System.Collections;public class RotateToWards_ts : MonoBehaviour {public Transform A, B, C;float speed = 10.0f;float total = 0.0f;// Use this for initializationvoid Start(){}// Update is called once per framevoid Update(){total += Time.deltaTime * speed;if (total >= 1.0f)total = 1.0f;C.rotation = Quaternion.RotateTowards(A.rotation, B.rotation, Time.time * speed - 40.0f);Debug.Log("C与A的欧拉角的插值: " + (C.eulerAngles - A.eulerAngles) + "maxDegreesDelta: " + (Time.time * speed - 40.0f));}
}

运行截图

7:Normalize

public static Quaternion Normalize (Quaternion q); 

将此四元数转换为 1,方向相同,但量值为 1。

如果该四元数太小而无法归一化,则将其设置为 Quaternion.identity

五:静态方法

1:四元数*四元数是叠加旋转

2:四元数*向量是旋转向量

以下为转载,个人不用看了

五、Quaternion类运算符

Quaternion类涉及到两个Quaternion对象相乘和Quaternion对象与Vector3对象相乘,那么就必须重载"*"运算符。

四元数*四元数是叠加旋转

四元数*向量是旋转向量

public static Quaternion operator *(Quaternion lhs, Quaternion rhs);
public static Vector3 operator *(Quaternion rotation, Vector3 point);

2、两个Quaternion对象相乘

对于两个Quaternion对象相乘主要用于自身旋转变换,例如:

B.rotation *= A.rotation;
  • B会绕着B的局部坐标系的z、x、y轴按照先绕z轴再绕x轴最后绕y轴的旋转次序,分别旋转A.eulerAngles.z度、A.eulerAngles.x度、和A.eulerAngles.y度。由于是绕着局部坐标系进行旋转,所以当绕着其中一个轴进行旋转时,可能会影响其余两个坐标轴方向的欧拉角(除非其余两轴的欧拉角都为0才不会受到影响)。
  • 假如A的欧拉角为aEuler(ax,ay,az),则沿着B的初始局部坐标系的aEuler方向向下看B在绕着aEuler顺时针旋转。B的旋转状况还受到其初始状态的影响。

2.1 实例演示

using UnityEngine;
using System.Collections;public class Multiply1_ts : MonoBehaviour {public Transform A, B;// Use this for initializationvoid Start () {A.eulerAngles = new Vector3(1.0f, 1.5f, 2.0f);}// Update is called once per framevoid Update () {B.rotation *= A.rotation;Debug.Log(B.eulerAngles);}
}

运行截图

2.2 分析

B绕着其自身坐标系的Vector3(1.0f,1.5f,2.0f)方向旋转。虽然每次都绕着这个轴向旋转的角度相同,但角度的旋转在3个坐标轴的值都不为零,三个轴的旋转会相互影响,所以B的欧拉角的各个分量的每次递增是不固定的。

3、Quaternion对象与Vector3对象

对于Quaternion对象与Vector3对象相乘主要用于自身移动变换,例如

transform.position += tansform.rotation * A;

其中A为Vector3的对象。transform对应的对象会沿着自身坐标系中向量A的方向移动A的模长的距离。transform.rotation与A相乘可以确定移动的方向和距离。

3.1 实例演示

using UnityEngine;
using System.Collections;public class Multiply2_ts : MonoBehaviour {public Transform A;float speed = 0.1f;// Use this for initializationvoid Start () {A.position = Vector3.zero;A.eulerAngles = new Vector3(0.0f, 45.0f, 0.0f);}// Update is called once per framevoid Update () {A.position += A.rotation * (Vector3.forward * speed);Debug.Log(A.position);}
}

运行截图

4、两个Quaternion对象相乘与Quaternion对象与Vector3对象相乘的异同

  • 设A为两个两个Quaternion对象相乘的结果。B为Quaternion对象与Vector3对象相乘的结果。其中A为Quaternion类型,B为Vector3类型。
  • A与B的相同之处是它们都通过自身坐标系的“相乘”方式来实现在世界坐标系中的变换。
  • A主要用来实现transform绕自身坐标系的某个轴旋转,B主要用来实现transform沿着自身坐标系的某个方向移动。
  • 必须遵守Quaternion对象*Vector3对象的形式,不可以颠倒顺序。
  • 由于它们都是相对于自身坐标系进行的旋转或移动,所以当自身坐标系的轴向和世界坐标系的轴向不一致时,它们绕着自身坐标系中的某个轴向的变动都会影响到物体在世界坐标系中各个坐标轴的变动。

Quaternion相关推荐

  1. Quaternion.identity是什么意思?

    Quaternion.identity就是指Quaternion(0,0,0,0),

  2. unity3d 的Quaternion.identity和transform.rotation区别是什么

    Quaternion.identity就是指Quaternion(0,0,0,0),就是每旋转前的初始角度,是一个确切的值,而transform.rotation是指本物体的角度,值是不确定的,比如可 ...

  3. C语言quaternion(四元数)(附完整源码)

    quaternion四元数 quaternion四元数类型定义 geometry_datatypes.h 四元数有关的几个接口 quaternion(四元数)有关的功能的完整源码(定义,实现,main ...

  4. QML基础类型之quaternion

    四元数类型具有标量,x,y和z属性. 四元数类型具有标量,x,y和z属性. 要创建四元数值,请将其指定为" scalar,x,y,z"字符串,或单独定义组件,或使用Qt.quate ...

  5. 【Unity】6.8 Quaternion类(四元数)

    分类:Unity.C#.VS2015 创建日期:2016-04-20 一.四元数的概念 四元数包含一个标量分量和-个三维向量分量,四元数Q可以记作: Q=[w,(x,y,z)] 在3D数学中使用单位四 ...

  6. Unity中Quaternion的含义及其使用

    官网API文档: file:///Applications/Unity/Unity.app/Contents/Documentation/html/en/ScriptReference/Quatern ...

  7. Unity3D_(API)Quaternion四元数中的Quaternion.LookRotation()

    四元数百度百科: 传送门 四元数官方文档: 传送门 欧拉旋转.四元数.矩阵旋转之间的差异: 传送门 四元数转换为欧拉角eulerAngles 官方文档: 传送门 欧拉角转换为四元数Euler 官方文档 ...

  8. About The Quaternion 有关四元数

    About The Quaternion 有关四元数 I took many days to try to understand anything about Quaternion but got n ...

  9. 学习和研究下unity3d的四元数 Quaternion

    学习和研究下unity3d的四元数 Quaternion 今天准备学习和研究下unity3d的四元数 Quaternion 四元数在电脑图形学中用于表示物体的旋转,在unity中由x,y,z,w 表示 ...

  10. Unity3D 中 用quaternion 来对一个坐标点进行旋转的初步体会

    在unity3d中,用四元数来表示旋转,四元数英文名叫quaternion . 比如 transform.rotation 就是一个四元数,其由四个部分组成 Quaternion = (xi + yj ...

最新文章

  1. linux常用命令汇总
  2. 机器学习和计算机视觉有关的数学
  3. 解决ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
  4. 精读《javascript高级程序设计》笔记二——变量、作用域、内存以及引用类型
  5. 盘点PHP编程常见失误
  6. netcore 内存限制_.NET Core 和 Serverless 构建飞速发展的架构
  7. 利用Java针对MySql封装的jdbc框架类 JdbcUtils 完整实现(包含增删改查、JavaBean反射原理,附源码)...
  8. linux vim命令跳到67行,Linux学习之Vim/Vi使用(十三)
  9. Qt实践录:TCP网络调试助手
  10. cocos2dx 回调函数
  11. mongodb 的进库操作
  12. 【POJ 3666】Making the Grade【线性DP】
  13. java电力巡检系统 项目讲解_苏河湾1号街坊项目电力监控系统的设计与应用
  14. Hexo博客优化之Next主题美化
  15. Webstorm—Webstorm汉化(图文详解)
  16. python游戏自动化实战--游戏辅助软件冰山后的秘密
  17. 工控领域组态软件开发感触
  18. 12-Solidity8.0-view和pure区别
  19. EC2实例挂载使用EFS操作步骤
  20. 软件开发需要学习什么?

热门文章

  1. 【系统】ntoskrnl.exe导致Win10蓝屏的解决方案
  2. Clickhouse 查询表的列名
  3. 实验4 图的应用问题 给定n个村庄之间的交通图,现计划在n个村庄中选定一个村庄建造一所医院,请设计方案解决问题
  4. Escaping Closures
  5. 《小木工》华硕中国业务群总经理石文宏
  6. 常见信号质量问题、危害及其解决方法
  7. 实现类知乎android客户端关注和取消关注的按钮点击效果
  8. 有关2009年春晚的几个文章,另网站被百度收录,自己庆祝一下!
  9. Netcat 介绍及使用
  10. 通过源码发现nltk.Text.similar相似度衡量标准