Unity3d-旋转Quaternion、Matrix4x4、 Euler

来源:互联网 发布:手机屏幕软件 编辑:程序博客网 时间:2024/06/05 09:01

矩阵:Matrix4x4

namespace UnityEngine{public struct Matrix4x4{public float m00;public float m10;public float m20;public float m30;public float m01;public float m11;public float m21;public float m31;public float m02;public float m12;public float m22;public float m32;public float m03;public float m13;public float m23;public float m33;      }}


变换后点的(X’,Y’,Z’)= (x,y,z) *   ( 4*4矩阵)

scale:模型的大小变化,在透视投影中用来产生场景深度效果

public static Matrix4x4 Scale(Vector3 v){return new Matrix4x4{m00 = v.x,m01 = 0f,m02 = 0f,m03 = 0f,m10 = 0f,m11 = v.y,m12 = 0f,m13 = 0f,m20 = 0f,m21 = 0f,m22 = v.z,m23 = 0f,m30 = 0f,m31 = 0f,m32 = 0f,m33 = 1f};}

translate:物体沿着三个坐标轴的任意一个到另一个位置的移动


rotate:顶点的每个坐标值乘上θ角(物体旋转的角度)的sin或cos值就得到了旋转后的坐标

当点P(x,y,z)绕X轴旋转α度时,点P的x坐标值不变,其旋转前后的坐标关系为:

当点P(x,y,z)绕Y轴旋转β度时,点P的y坐标值不变,其旋转前后的坐标关系为:

当点P(x,y,z)绕Z轴旋转γ度时,点P的z坐标值不变,其旋转前后的坐标关系为:

得出的变换矩阵如下

在unity中Matrix4x4没有单独实现translate和rotate的方法,统一使用SetTRS方法来完成

参见另一篇文章:平移、旋转和缩放矩阵


四元数:Quaternion = (xi + yj + zk + w ) = (x,y,z,w).

四元数是最简单的超复数。 复数是由实数加上元素 i 组成,其中i^2 = -1。 相似地,四元数都是由实数加上三个元素 i、j、k 组成,而且它们有如下的关系: i^2 = j^2 = k^2 = -1 , 每个四元数都是 1、i、j 和 k 的线性组合,即是四元数一般可表示为w + xi + yj + zk,其中x、y、z 、w是实数

namespace UnityEngine{public struct Quaternion{public float x;public float y;public float z;public float w;        }}

四元数中的方向由三个旋转轴(x、y、z)和一个旋转角 (w) 确定
q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)

Q.w = cos (angle / 2)

Q.x = axis.x * sin (angle / 2)

Q.y = axis.y * sin (angle / 2)

Q.z = axis.z * sin (angle / 2)
四元数可提供平滑差值,没有Euler旋转的万向锁。


四元数到矩阵

public void SetTRS(Vector3 pos, Quaternion q, Vector3 s)

Quaternion q = Quaternion.LookRotation(new Vector3(0,0.5,1));Matrix4x4 rot = new Matrix4x4();rot.SetTRS(new Vector3(0,0,0),q,new Vector3(1,1,1));

矩阵到四元数

public void SetLookRotation(Vector3 view, [DefaultValue("Vector3.up")] Vector3 up)

Matrix4x4 rot = new Matrix4x4();rot.SetTRS(new Vector3(0,0,0),q,new Vector3(1,1,1));Vector4 vy = rot.GetColumn(1);Vector4 vz = rot.GetColumn(2);Quaternion newQ = Quaternion.LookRotation(new Vector3(vz.x,vz.y,vz.z),new Vector3(vy.x,vy.y,vy.z));//newQ==q

这个函数建立一个旋转使z轴朝向view y轴朝向up

var obj1: Transform;var obj2: Transform;var q:Quaternion;q.SetLookRotation(obj1.position, obj2.position);transform.rotation=q;

然后大家拖动obj1和obj2就可以看到物体永远保持z轴朝向obj1, 并且以obj2的位置来保持y轴的倾斜度。


欧拉角:Euler

欧拉旋转,我们最常用的旋转方法应该是使用yaw, roll和pitch。

yaw是在XZ轴平面上围绕Y轴左右旋转,当开车时使用的是yaw。

pitch在YZ轴平面上围绕X轴上下旋转,喷气机飞行或爬坡时用pitch向上或向下。

roll是在XY轴平面上绕Z轴倾斜旋转,

从字面意思上说,当你驾驶汽车高速急转弯时,你的汽车会出现roll运动,表现一个方向就可以通过三个欧拉角 (α,β,γ) 来定义。



游戏物体的属性视图中调整的角度就是欧拉角



Quaternion q3 = new Quaternion();q3.eulerAngles = new Vector3(10, 30, 20);Quaternion qx3 = Quaternion.AngleAxis(10,Vector3.right);Quaternion qy3 = Quaternion.AngleAxis(30,Vector3.up);//绕y轴旋转30度Quaternion qz3 = Quaternion.AngleAxis(20,Vector3.forward);Quaternion qxyz3 = qz3*qy3*qx3;


上面的代码可以得到q3和qxyz3值一样。从这里可以看出unity中旋转顺序也是按先绕x轴旋转,然后y,最后z。unity中对向量应用旋转量使用的是向量右乘,即如下:

Vector3 newV = qxyz3*v=qz3*qy3*qx3*v;


// A rotation 30 degrees around the y-axis//绕y轴旋转30度var rotation = Quaternion.Euler(0, 30, 0);//返回一个旋转角度,绕z轴旋转z度,绕x轴旋转x度,绕y轴旋转y度(像这样的顺序)。


欧拉角eulerAngles在Unity3D是一个Vector3类的变量,官方约定俗成的层级关系是ZXY,即最里层是Z轴先旋转,中间层是X轴,最外层是Y轴。
unity中的欧拉角有两种方式可以解释:
1,当认为顺序是yxz时(其实就是heading - pitch - bank),是传统的欧拉角变换,也就是以物体自己的坐标系为轴的。
2,当认为顺序是zxy时(roll - pitch - yaw),也是官方文档的顺序时,是以惯性坐标系为轴的。后者比较直观一些,但其实两者的实际效果是一样的,只是理解不一样。

无论以何种方式旋转三个轴,都会有出现万向锁的情况,万向锁主要在动画里面旋转时出现我们不希望见到的旋转路径,所以官方以ZXY顺序来旋转的时候可以最大程度上避免普通情况下会出现的万向锁。


对比:

各方法比较Matrix4x4EulerQuaternion 在坐标系间(物体和惯性)旋转点能不能(必须转换到 矩阵) 不能(必须转换到矩阵)  连接或增量旋转能能,但经常比四元数慢,小心矩阵蠕变的情况不能能,比矩阵快插值基本上不能 能,但可能遭遇万 向锁或其他问题 Slerp提供了平滑插值易用程度难易难在内存或文件中存储9个数3个数4个数 对给定方位的表达方式是否唯一是不是,对同一方位 有无数多种方法不是,有两种方法可能导致非法矩阵蠕变任意三个数都能构成合法的欧拉角可能会出现误差积累,从而产生非法的四元数









0 0