unity常用变换计算

unity变换计算

系统库介绍

  • 核心库

    • GeometryUtility
  • 插件库

    • Unity.Mathematics
      这里面包含了很多变换计算,可以参考 matrix.cs 中的 float4x4
      float4x4 可以跟 Matrix4x4 隐式转换,参考 math_unity_conversion.cs

向量

Vector3.up 是 y 轴正向 , Vector3.right 是 x 轴正向,Vector3.forward 是 z 轴正向

  • 点积(Dot)
    Vector3.Dot(a,b) = |a||b|cosθ
    可用来检测2个向量是否同方向

    • Vector3.Dot(a,b) == 0 表示a跟b垂直
    • Vector3.Dot(a,b) > 0 表示a跟b同方向,也就是夹角小于90
    • Vector3.Dot(a,b) < 0 表示a跟b反方向,也就是夹角大于90
  • 叉积(Cross)
    |Vector3.Cross(a,b)| = |a||b|sinθ 0 表示 a 平行 b
    叉积得到的向量与原来2个向量构成的平面垂直,并且遵循左手法则
    即手掌从a转向b(要取角度最小的方向转)握紧,大拇指方向就是叉积的方向
    可用来获取平面的法向量

    • Vector3 normal = Vector3.Cross(a,b).Normalized();
      可用来判断向量平行
    • Vector3.Cross(a,b).magnitude == 0 说明向量平行
      可用来判断向量的位置关系,假设 a,b 位于平面p上,p的法线量是n(代表平面上方向)
    • var d = Vector3.Dot(Vector3.Cross(a,b),n);
    • d == 0 表示 a 跟 b 平行
    • d > 0 表示 a 在 b 左侧
    • d < 0 表示 a 在 b 右侧
  • 计算2个向量的夹角

	// 获得夹角
	float angle = Vector3.Angle(fromVector, toVector);
	// 获得法线向量
	Vector3 normal = Vector3.Cross(fromVector, toVector);
	//	获得夹角的正负值
	angle *= Mathf.Sign(Vector3.Dot(normal, upVector));

四元数操作

  • 欧拉角转换
    在unity中欧拉角是按照 yxz 的顺序进行旋转的
    绕y轴旋转 degree 度
    Quaternion rot = Quaternion.Euler(0, degree, 0);
    等价于
    Quaternion q = Quaternion.AngleAxis(degree, Vector3.up);

  • 旋转叠加
    q=qa*qb; // 顺序是有影响的,先旋转qb再旋转qa

  • 相乘顺序
    q=qa * qb * qc=( qa * qb ) * qc=qa * ( qb * qc )

  • 相乘求反
    ( qa * qb ).inverse = qb.inverse * qa.inverse;

  • *=的运算顺序
    a *= b * c; // 等价于 a = a * ( b * c );

  • 向量旋转
    通过 rotation 获得当前向上向量,本质上就是把向上向量旋转 rotation
    Vector3 newUp = rotation * Vector3.up;
    其它方向也是一样的
    可以直接参考 Transform.up

  • 绕轴旋转
    Quaternion q = Quaternion.AngleAxis(angle,axis)
    表示的意义是左手法则: 左手大拇指跟旋转轴同向,则握拳的方向就是旋转的方向

  • 旋转到向量
    比如向上旋转到 newUp ,刚好是上面向量旋转的逆操作,则旋转角度为
    Quaternion q = Quaternion.FromToRotation(Vector3.up, newUp);

  • 通过2个方向获得当前旋转
    比如 通过 forward 和 upwards 确定方向

        //	这里 forward 和 upward 不要求垂直,这里保证计算出的方向 forward 对齐 
        //	因为实际上是 left = upward*forward,用 forward 和 left 来计算旋转
        //	Z 轴将与forward对齐,X 轴与 forward 和 upwards 的差积对齐
        Quaternion rotation = Quaternion.LookRotation(forward, upward);
        
        //	如果要保证 upward 对齐,有3种方法(摘自 QuaternionUtil)
        //      1. 把要精准对齐的当成 forward,另一个当成 upward,用 Quaternion.LookRotation 算出方向后,再把坐标轴还原
        public static Quaternion LookRotationYZ(Vector3 up, Vector3 forward)
        {
         
          
          
            return Quaternion.LookRotation(up, -forward) * Quaternion.AngleAxis(90, Vector3.right);
        }
        //      2. 用叉积计算出精准的 forward, 再用 Quaternion.LookRotation 计算出方向
        public static Quaternion LookRotationYZ2(Vector3 up, Vector3 forward)
        {
         
          
          
            Vector3 left = Vector3.Cross(up, forward);
            Vector3 forwardNew = Vector3.Cross(left, up);       //	重新计算出 forward
            return Quaternion.LookRotation(forwardNew, up);
        }
        //      3. 用平面投影计算出精准的 forward, 再用 Quaternion.LookRotation 计算出方向,参考 LookRotationYZ3
        public static Quaternion LookRotationYZ3(Vector3 up, Vector3 forward)
        {
         
          
          
            Plane plane = new Plane(up, Vector3.zero);
            Vector3 forwardNew = plane.ClosestPointOnPlane(forward);	//  forward 在 up 为法线的平面上的投影
            return Quaternion.LookRotation(forwardNew, up);
        }
    
        //	应用举例,比如 场景确定好坐标和向上方向后,要朝向相机
        void AdjustSceneTransform(Transform sceneTransfrom, Vector3 pos, Vector3 upword, Vector3 cameraPos )
        {
         
          
          
            Vector3 forward = pos - cameraPos;
            Vector3 left = Vector3.Cross(upword, forward);
            forward = Vector3.Cross(left, upword);
            Quaternion rotation = Quaternion.LookRotation(forward, upword);
            sceneTransfrom.position = pos;
            sceneTransfrom.rotation = rotation;
        }
    

矩阵操作

  • M行N列矩阵的存储(展开成一维数组)有2种方式:

    1. 行优先: 先存储第一行,再存储第二行,依次类推,i行j列元素=i*N+j
    2. 列优先: 先存储第一列,再存储第二列,依次类推,i行j列元素=j*M+i
      2种存储方式互为转置关系: M行优先=M列优先.transpose
  • unity 采用的是方案2,也就是列优先,这点在 Matrix4x4 文档中有说明
    0 => m00, 1 => m10, 2 => m20, 3 => m30, 4 => m01, 5 => m11, …
    平移存储在最后一列,也就是 m.GetColumn(3) ,也就是 m03, m13, m23,也就是 [12] [13] [14]
    因此跟 Vector4 相乘时是 M*V ,也就是M在前,V在后,V写成4行1列

  • 相乘
    m = a * b; // 先进行 a 变换再进行 b 变换

  • 相乘求逆
    (a * b)-1 = b-1 * a-1

  • TRS
    m = Matrix4x4.TRS(t,r,s) = Matrix4x4.Translate§ * Matrix4x4.Rotate® * Matrix4x4.Scale(s);
    也就是先平移再旋转最后缩放

  • 从矩阵获得旋转
    直接获取 Quaternion q = m.rotation;
    参考 OpenCVForUnity\org\opencv\unity\ARUtils.cs

        Vector3 forward = new Vector3(m.02,m.12,m.22);
        Vector3 upwards = new Vector3(m.01,m.11,m.21);
        Quaternion q = Quaternion.LookRotation(forward, upwards);
    
  • 矩阵和Pose的互转

        Matrix4x4 m = Matrix4x4.TRS(pose.position,pose.rotation, Vector3.one);	//	pose转矩阵
        pose.position = new Vector3(m.03, m.13, m.23);
        pose.rotation = m.rotation;
    
  • 变换坐标点

        //	对坐标进行变换,等价于 matrix * new Vector4(pos.x,pos.y,pos.z,1)
        //	只能用于普通的 TRS 矩阵,也就是最后一行是 0,0,0,1 , 不能用于投影矩阵
    	pos1 = matrix.MultiplyPoint3x4(pos

猜你喜欢

转载自blog.csdn.net/qmladm/article/details/128884598#comments_25317838