在了解了3x3矩阵能够代三维空间的表旋转后,下面介绍4x4矩阵中每行每列所代表三维空间的含义。
在虚拟现实、3D游戏中,仅仅能够三个自由度地旋转是不够的,在通常认识的三维空间中,自由物体总共有六个自由度:沿XYZ三个坐标轴的移动、绕XYZ三轴的旋转。3x3矩阵能够到表空间旋转信息,因此,我们还需要移动位置信息。
通常,位置信息可以使用point代表,因此,理论上,我们可以使用point中的xyz代表物体的空间位置,用3x3的矩阵道标物体的姿态,就能够将物体的空间六自由度完全表述清楚。当然,也可以用四元数和点两部分来表示。
但是,计算相对变得复杂,例如:当我们计算物体绕自己的XYZ中的某个轴旋转时,可以直接使用3x3矩阵或者四元数旋转即可,位置是不会变化的,但当我们需要物体沿着世界坐标的轴、其他定义的轴旋转时,物体在世界中不仅仅姿态会发生变化,位置也会发生变化。
4x4矩阵刚好就能解决这一问题,直接通过4x4矩阵的线性代数运算,就能表达物体的姿态和位置。
在4x4矩阵中,总共时16个浮点数,默认的单位矩阵如下图:
若仅用于空间计算,则只看矩阵的前三行即可,第一列的(1,0,0)代表X轴,第二列的(0,1,0)代表Y轴,第三列的(0,0,1)代表Z轴,第四列的(0,0,0)代表空间位置。此外,第四行永远为(0,0,0,1)。
4x4矩阵的构造函数和析构函数如下:
/// constructor, unit matrix default. matrix4x4(); /// construct from another matrix4x4. matrix4x4(const matrix4x4& mat); /// move constructor. matrix4x4(matrix4x4&& mat) noexcept; /// construct from pointer, there must be sixteen values. matrix4x4(const real* data); /// destructor. virtual ~matrix4x4();其他计算函数:
public: /// print on console. void print() const; /// is real, is available. bool isReal(); /// set rotate form x and y axis, calculate z axis automatically. void rotateFromXYAxis(const vector& vecX, const vector& vecY); /// set rotate from z axis, x and y are random, normalized vector. void rotateFromZAxis(const vector& vecZ); /// set rotate form matrix3x3. void rotateFromMatrix3x3(const matrix3x3& mat); /// set rotate form quaternion. void rotateFromQuaternion(const quaternion& q); /// set position form point. void positionFromPoint(const point& pt); /// set position form data. void positionFromData(const real x, const real y, const real z); /// get rotate from matrix4x4. [[nodiscard]] matrix3x3 getRotate() const; /// get position from matrix4x4. [[nodiscard]] point getPosition(); /// zero all data. void zero(); /// convert to unit matrix. void identity(); /// convert to invert matrix. void invert(); /// convert to transpose matrix. void transpose(); /// *this *= mat, save in this. void multiplied(const matrix4x4& mat); /// mat *= *this, save in this. void preMultiplied(const matrix4x4& mat); /// return *this * mat, non change in *this. [[nodiscard]] matrix4x4 multiply(const matrix4x4& mat) const; /// return mat * *this, non change in *this. [[nodiscard]] matrix4x4 preMultiply(const matrix4x4& mat) const; /// return *this * pt, non change in *this. [[nodiscard]] point multiply(const point& pt) const; /// return *this * vec, non change in *this. [[nodiscard]] vector multiply(const vector& vec) const; /// retuan determinate. real determinate() const; /// rotate around axis void rotateAxis(const real radians, const vector& vec); /// rotate around axis void rotateAxis(const real radians, Axis axis); /// rotate around self axis void rotateSelfAxis(const real radians, Axis axis); /// rotate around self axis void rotateSelfAxis(const real radians, const vector& vec);大部分函数和Matrix3x3基本一样,不做介绍。
运行结果均为默认的单位矩阵,如下图:
对于空间数据的赋值与计算,例如:
qytk::matrix3x3 mat3x3; mat3x3.rotateSelfAxis(PI / 2, qytk::Axis::X); mat4.rotateFromMatrix3x3(mat3x3); mat4.print(); qytk::quaternion q0; q0.rotateAxis(PI / 2, qytk::Axis::Z); mat4.rotateFromQuaternion(q0); mat4.print();mat4的旋转部分来源于mat3x3,可以看出,mat3x3是在世界坐标原点的基础上绕X轴旋转90度得到的,结果如下:
可以看出,矩阵所代表的空间X轴时没有变化的,Y轴与最开始的Z轴重合,Z轴变为与最开始的-Y轴重合了,这符合我们的认知,计算式正确的。从第二部分代码的四元数计算中,可以看出,结果也是完全吻合的。
矩阵的旋转数据除了通过设置3x3矩阵、四元数之外,还能够通过设置XY轴、Z轴实现,如下:
mat5.identity(); mat5.rotateFromZAxis(vec1); mat5.print(); mat5.transpose(); mat5.print(); mat5.identity(); mat5.rotateFromXYAxis(vec0, vec1); mat5.multiplied(mat5); mat5.print();需要特别注意的是,设置XY轴时,需要自己保证XY轴时正确的,相互垂直的,程序会自动计算Z轴。在通过Z轴设置旋转数据时,程序随机生成姿态的XY轴。
4x4的矩阵可用于表示三维空间的姿态、位置等信息,在空间计算中,既可以平移也可以旋转,同时,可以旋转旋转的轴位自身或者其他任何轴。为了更方便地进行空间计算,后续抽象出Transform类专门用于空间六自由度的运算。
qySpace下载地址(github):qySpace
qySpace下载地址(csdn):qySpace
