OK,不做引子了,接上篇Unity3D - 详解Quaternion类(一)走起!

四、Quaternion类静态方法

Quaternion中的静态方法有9个即:Angle方法、Dot方法、Euler方法、FromToRotation方法、Inverse方法、Lerp方法、LookRotation方法、RotateToWards方法和Slerp方法。关于静态的方法的使用就是直接用类名调用其静态方法,例如Quaternion.Angle(q1,q2);下面对这些静态方法做下分析。

1、Angle方法

1.1 函数原型

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 initialization
void 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 frame
void Update () { }
}

运行结果

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

2、Dot方法-点乘

2.1 函数原型

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 initialization
void 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 frame
void Update () { }
}

运行输出

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

3、Euler方法

3.1 函数原型

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

该方法用于返回欧拉角Vector3(ex,ey,ez)对应的四元数Quaternion q(qx,qy,qz,qw)。其对应关系如下:

已知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、FromToRotation方法

函数原型

public static Quaternion FromToRotation(Vector3 fromDirection,Vector3 ToDirection);

在前面介绍了SetFromToRotation实例方法,它们的功能都是一样的只不过用法稍有不同。使用FromToRotation类静态方法,需要直接使用类名进行调用,如Quaternion.FromToRotation(v1,v2);

在此就不做演示了!

5、Inverse方法

5.1 函数原型

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°和-z°。由于是在局部坐标系内的变换,最后transform的欧拉角的各个分量值并不一定等于-a、-b或-c。

5.2 实例演示

using UnityEngine;
using System.Collections; public class Invers_ts : MonoBehaviour {
public Transform A, B; // Use this for initialization
void 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 frame
void Update () { }
}

运行截图

6、Lerp和Slerp方法

6.1 函数原型

public static Quaternion Lerp(Quaternion form, Quaternion to,float t);
public static Quaternion Slerp(Quaternion form, Quaternion to,float t);

两种方法的作用都是返回从form到to的插值。当参数t<=0时返回值为from,当参数t>=1时返回值为to。其中Lerp是线性差值,而Slerp是球面插值。

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 initialization
void Start () { } // Update is called once per frame
void 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);
}
}

7、RotateTowards方法

7.1 函数原型

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

该方法也是一个插值方法,即从返回参数from到to的插值,且返回值的最大角度不超过maxDegreesDelta。maxDegreesDelta是角度值,不是插值系数,当maxDegreesDelta < 0时,将进行逆向插值即从to到from的方向进行插值计算。

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 initialization
void Start()
{ } // Update is called once per frame
void 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)); }
}

运行截图

8、LookRotation方法

函数原型

public static Quaternion LookRotation(Vector3 forward);
public static Quaternion LookRotation(Vector3 forward,Vector3 upwards);

参数forward为返回Quaternion实例的forward朝向。该方法和前面讲到的SetLookRotation实例方法的功能是一样的,故不多做阐述了。

五、Quaternion类运算符

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

1、函数原型

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 initialization
void Start () { A.eulerAngles = new Vector3(1.0f, 1.5f, 2.0f);
} // Update is called once per frame
void 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 initialization
void Start () { A.position = Vector3.zero;
A.eulerAngles = new Vector3(0.0f, 45.0f, 0.0f);
} // Update is called once per frame
void 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对象的形式,不可以颠倒顺序。
  • 由于它们都是相对于自身坐标系进行的旋转或移动,所以当自身坐标系的轴向和世界坐标系的轴向不一致时,它们绕着自身坐标系中的某个轴向的变动都会影响到物体在世界坐标系中各个坐标轴的变动。

--------------------------------------------------------------------------------------------------------至此完结!-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Unity3D - 详解Quaternion类(二)的更多相关文章

  1. Unity3D - 详解Quaternion类(一)

    一.简介 Quaternion又称四元数,由x,y,z和w这四个分量组成,是由爱尔兰数学家威廉·卢云·哈密顿在1843年发现的数学概念.四元数的乘法不符合交换律.从明确地角度而言,四元数是复数的不可交 ...

  2. unity3D游戏开发之详解Animation类和Animator类

    详解Animator类和Animation类 链接: http://wenku.baidu.com/link?url=SiaUYcdrNYjOYrWVDJSKGAYdJOntMTOhsVJtyBk2i ...

  3. 【python进阶】详解元类及其应用1

    前言 元类在python中是很重要的一部分,我将分两次去讲解元类及其应用,此篇为详解元类及其应用第一篇,下面开始今天的说明~~~ 1. 类也是对象 在⼤多数编程语⾔中,类就是⼀组⽤来描述如何⽣成⼀个对 ...

  4. 【python进阶】详解元类及其应用2

    前言 在上一篇文章[python进阶]详解元类及其应用1中,我们提到了关于元类的一些前置知识,介绍了类对象,动态创建类,使用type创建类,这一节我们将继续接着上文来讲~~~ 5.使⽤type创建带有 ...

  5. Android开发:文本控件详解——TextView(二)文字跑马灯效果实现

    一.需要使用的属性: 1.android:ellipsize 作用:若文字过长,控制该控件如何显示. 对于同样的文字“Android开发:文本控件详解——TextView(二)文字跑马灯效果实现”,不 ...

  6. Kotlin——最详解的类(class)的使用

    在任何一门面向对象编程的语言里,类(class)是非常基础.但也是非常重要的一项组成,通俗的说就是万般皆对象,而所说的对象就是我们生成的类.Kotlin也是如此,下面详细为大家介绍Kotlin中的类的 ...

  7. 【Java入门提高篇】Day30 Java容器类详解(十二)TreeMap详解

    今天来看看Map家族的另一名大将——TreeMap.前面已经介绍过Map家族的两名大将,分别是HashMap,LinkedHashMap.HashMap可以高效查找和存储元素,LinkedHashMa ...

  8. MySQL存储过程详解 mysql 存储过程(二)

    mysql存储过程详解 1.      存储过程简介 我们常用的操作数据库语言SQL语句在执行的时候需要要先编译,然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL ...

  9. JDBC详解系列(二)之加载驱动

    ---[来自我的CSDN博客](http://blog.csdn.net/weixin_37139197/article/details/78838091)---   在JDBC详解系列(一)之流程中 ...

随机推荐

  1. 安装composer slim(php web api micro services)

    1. 安装php7 2. 下载 https://getcomposer.org/composer.phar 3. 开启ssh, 在 php.ini中.extension=C:\Program File ...

  2. 微服务架构的进程间通信(IPC)

    先抛出几个问题: 微服务架构的交互模式有哪些? 微服务常用的进程间通信技术有哪些? 如何处理部分请求失败? API的定义需要注意的事项有哪些 微服务的通信机制与SOA的通信机制之间的关系与区别 微服务 ...

  3. Windows Store Apps 开发转载

    懒得写了,就直接记录转载一下文章地址吧. 如何为应用定义全局默认字体:http://blogs.msdn.com/b/gautamdh/archive/2014/03/16/how-to-change ...

  4. 向Oracle数据库插入一条数据

    这几天搞了一下Oracle数据库.可能用sql server习惯了,感觉好不方便.PL的界面友好度比sql server差远了 .既然都收购了PL了 为什么不给它做好一点呢?各种不便.郁闷 向Orac ...

  5. Spring Boot干货系列:(八)数据存储篇-SQL关系型数据库之JdbcTemplate的使用

    Spring Boot干货系列:(八)数据存储篇-SQL关系型数据库之JdbcTemplate的使用 原创 2017-04-13 嘟嘟MD 嘟爷java超神学堂 前言 前面几章介绍了一些基础,但都是静 ...

  6. python 高阶函数 map lambda filter等

    map 描述 map() 会根据提供的函数对指定序列做映射. 第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表. ...

  7. sqlserver 关于子查询的优化操作

    在对条件需要用到子查询的时候,通常可以通过连接来代替子查询来完成操作,更加高效 SELECT t1.id,t2.columnName,t2.columnType,t1.rownum,t1.cellVa ...

  8. 基于jQuery商品分类选择提交表单代码

    分享一款基于jQuery商品分类选择提交表单代码.这是一款基于jQuery实现的商品信息选择列表表单提交代码. 在线预览   源码下载 实现的代码: <div class="yList ...

  9. jQuery 选择器大全总结

    jQuery基础语法中规定的选择器有三种,分别是类选择器.ID选择器.标签选择器.如:$(“.aa”).$(“#id”).$(“div”),但中实际的应用中,DOM机构非常复杂,层级非常多.如和应对这 ...

  10. buildroot 搭建ftpd 服务器记录

    vsftpd 搭建失败,应该是buildroot 文件系统还有操作没有理解透,还需要不断的学习. 所以用轻量级的 ftpd 进行替代, 步骤如下: // ---> make busybox-me ...