Unity学习笔记10——旋转(四元数和欧拉角)

Unity学习笔记10——旋转(四元数和欧拉角)

2016年05月01日 19:41:59 阅读数:9034更多

个人分类: Unity3D游戏开发

所属专栏: Unity学习笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/linshuhe1/article/details/51206377

        在Unity中,所有物体即使是空物体,也至少绑定Transform这个组件,这个组件有三个属性:position、rotation、scale,它们分别用于控制物体的平移、旋转和缩放三种变化,而其中最为复杂的一种就是旋转,它就对应于transform组件中的rotation属性,这个属性的类型其实就是四元数。

引言:

        常用的控制旋转的方法有:矩阵旋转和欧拉旋转,还有本篇要介绍的重点四元数,它也是实现旋转的方式之一。下面简单介绍一下前面的两种实现方式:

1.矩阵旋转:使用一个4*4的矩阵来表示绕任意轴旋转时的变换矩阵,这个矩阵具有的特点:乘以一个向量的时候只改变向量的方向而不会改变向量的大小;

优点:旋转轴可以是任意向量;

缺点:进行旋转其实我们只需要知道一个向量和一个角度,4个值的信息,而旋转变换矩阵使用了4*4=16个元素;

            变换过程增加乘法运算量,耗时;

2.欧拉旋转:在旋转时,按照一定的顺序(例如:x、y、z,Unity中的顺序是z、x、y)每个轴旋转一定的角度,来变换坐标或者是向量,实际上欧拉旋转也可以理解为:一系列坐标旋转的组合;

优点:只需使用3个值,即三个坐标轴的旋转角度;

缺点:必须严格按照顺序进行旋转(顺序不同结果就不同);

           容易造成“万向节锁”现象,造成这个现象的原因是因为欧拉旋转是按顺序先后旋转坐标轴的,并非同时旋转,所以当旋转中某些坐标重合就会发生万向节锁,这时就会丢失一个方向上的选择能力,除非打破原来的旋转顺序或者三个坐标轴同时旋转;

           由于万向节锁的存在,欧拉旋转无法实现球面平滑插值;

一、四元数:

        根据前面所述,我们知道了四元数是用于表示旋转的一种方式,而且transform中的rotation属性的数据类型就是四元数,那么四元数该如何表示呢?从本质上来讲,四元数就是一个高阶复数,也就是一个四维空间。

        普通的低阶复数形式一般是:x = a + bi,其中a、b为实数,而i则是虚数单位,而且存在i^2 = -1这样的运算规律,用坐标表示时其实就是由实轴和虚轴构成的二维空间。

        说四元数是高阶复数,是因为它一般表示为:x = a + bi + cj + dk,其中i、j、k都是虚数单位,所以也都满足:i2=j2=k2=−1。此外,这三个虚数单位还有以下特点:ij = k,jk = i,ki = j

关于四元数的优缺点:

优点:避免万向节锁现象;

           可绕任意过原点的向量旋转;

           可提供球面平滑插值;

缺点:比欧拉旋转复杂,多了一个维度;

           不够直观;

二、四元数与欧拉角:

        根据上述,我们可以这样表示一个四元数:q = w + xi + yj + zk,为了与三维旋转联系起来,可以简化表示为:q = ((x,y,z),w) = (v,w),其中v是一个向量,而w是个实数。此外,向量可以看做实部为0的四元数,而实数亦可以看做虚部为0的四元数。

        四元数基本运算法则:(证明:http://www.cnblogs.com/yiyezhai/p/3176725.html

        

        假设我们想让点P绕单元向量u = (x,y,z)表示的旋转轴转θ角度,具体步骤:

1.将点P坐标转换到四元数空间:P = (P,0);

2.使用q=((x,y,z)sinθ2,cosθ2)    来执行这个旋转;

3.旋转后的结果p'的坐标为:p′=qpq−1;

三、实际应用:

        上述讲解的是四元数的原理,但是在实际的使用中并没有那么复杂,我们只要调用Unity为我们提供的接口来修改旋转角度即可,例如为对象直接设置一个旋转值:

 
  1. float speed = 100.0f;

  2. float x;

  3. float z;

  4.  
  5. void Update () {

  6.   if(Input.GetMouseButton(0)){//鼠标按着左键移动

  7.     y = Input.GetAxis("Mouse X") * Time.deltaTime * speed;

  8.     x = Input.GetAxis("Mouse Y") * Time.deltaTime * speed;

  9.   }else{

  10.     x = y = 0 ;

  11.   }

  12.   

  13.   //旋转角度(增加)

  14.   transform.Rotate(new Vector3(x,y,0));

  15.   /**---------------其它旋转方式----------------**/

  16.   //transform.Rotate(Vector3.up *Time.deltaTime * speed);//绕Y轴 旋转

  17.  
  18.   //用于平滑旋转至自定义目标

  19.   pinghuaxuanzhuan();

  20.  
  21.  
  22. //平滑旋转至自定义角度

  23.  
  24. void OnGUI(){

  25.   if(GUI.Button(Rect(Screen.width - 110,10,100,50),"set Rotation")){

  26.     //自定义角度

  27.  
  28.     targetRotation = Quaternion.Euler(45.0f,45.0f,45.0f);

  29.     // 直接设置旋转角度

  30.     //transform.rotation = targetRotation;

  31.  
  32.     // 平滑旋转至目标角度

  33.     iszhuan = true;

  34.   }

  35. }

  36.  
  37. bool iszhuan= false;

  38. Quaternion targetRotation;

  39.  
  40. void pinghuaxuanzhuan(){

  41.   if(iszhuan){

  42.     transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 3);

  43.   }

  44. }

        就像上述的代码中,在实际应用中我们只需通过Quaternion.Euler和Quaternion.Slerp来完成Rolation的赋值操作。

猜你喜欢

转载自blog.csdn.net/linuxheik/article/details/82353317