天天看点

3D数学基础:Matrix4*3类代码清单程序清单:Matrix4×3.h程序清单:Matrix4×3.cpp

Matrix4×3矩阵和RotationMatrix矩阵是《3D数学基础》中的两大矩阵。相比于只能运用于旋转功能的RotationMatrix矩阵,Matrix 4×3矩阵更加一般化,能够支持更加复杂的变换。以下给出代码清单。

程序清单:Matrix4×3.h

/////////////////////////////////////////////////////////////////////////////
//
// 3D数学基础:游戏与图形开发
// 3D Math Primer for Games and Graphics Development
//
// Matrix4x3.h - Matrix4x3类声明
// Matrix4x3.h - Declarations for class Matrix4x3
//

// 更多细节,请看Matrix4x3.cpp
// For more details, see Matrix4x3.cpp
//
/////////////////////////////////////////////////////////////////////////////

#ifndef __MATRIX4X3_H_INCLUDED__
#define __MATRIX4X3_H_INCLUDED__

class Vector3;
class EulerAngles;
class Quaternion;
class RotationMatrix;
//---------------------------------------------------------------------------
// Matrix4x3类
// class Matrix4x3
//
// 实现4x3转化矩阵。这个类可以表现任何仿射变化。
// Implement a 4x3 transformation matrix.  This class can represent
// any 3D affine transformation.

class Matrix4x3 {
public:

// 公有数据
// Public data

    // 这个矩阵的值。上面3x3部分基本上包括了所有线性变换,最后一行是平移部分。
    // 查看Matrix4x3.cpp来获得更多细节。
    // The values of the matrix.  Basically the upper 3x3 portion
    // contains a linear transformation, and the last row is the
    // translation portion.  See the Matrix4x3.cpp for more
    // details.

    float   m11, m12, m13;
    float   m21, m22, m23;
    float   m31, m32, m33;
    float   tx,  ty,  tz;

// 公有操作
// Public operations

    // 设为单位矩阵
    // Set to identity

    void    identity();

    // 直接使用矩阵平移部分
    // Access the translation portion of the matrix directly

    void    zeroTranslation();
    void    setTranslation(const Vector3 &d);
    void    setupTranslation(const Vector3 &d);

    // 构造矩阵来表现一个从父空间到局部空间或相反方向的特定的转换,
    // 假定本地空间是父空间的具体指定位置和朝向。
    // 这个朝向可能是被欧拉角或者旋转矩阵来指定的。
    // Setup the matrix to perform a specific transforms from parent <->
    // local space, assuming the local space is in the specified position
    // and orientation within the parent space.  The orientation may be
    // specified using either Euler angles, or a rotation matrix

    void    setupLocalToParent(const Vector3 &pos, const EulerAngles &orient);
    void    setupLocalToParent(const Vector3 &pos, const RotationMatrix &orient);
    void    setupParentToLocal(const Vector3 &pos, const EulerAngles &orient);
    void    setupParentToLocal(const Vector3 &pos, const RotationMatrix &orient);

    // 构建矩阵执行关于主要轴的旋转
    // Setup the matrix to perform a rotation about a cardinal axis

    void    setupRotate(int axis, float theta);

    // 构建关于任意轴的旋转矩阵。
    // Setup the matrix to perform a rotation about an arbitrary axis

    void    setupRotate(const Vector3 &axis, float theta);

    // 构建矩阵来执行旋转,给定一个四元数形式的角位移。
    // Setup the matrix to perform a rotation, given
    // the angular displacement in quaternion form

    void    fromQuaternion(const Quaternion &q);

    // 构建矩阵来执行每根轴上的缩放。使用向量形式的Vector3(k,k,k)来统一缩放k倍。
    // Setup the matrix to perform scale on each axis

    void    setupScale(const Vector3 &s);

    // 构建矩阵来执行沿着任意轴的缩放。
    // Setup the matrix to perform scale along an arbitrary axis

    void    setupScaleAlongAxis(const Vector3 &axis, float k);

    // 构建矩阵来执行切变
    // Setup the matrix to perform a shear

    void    setupShear(int axis, float s, float t);

    // 构建矩阵来执行投影到一个通过原点的平面。
    // Setup the matrix to perform a projection onto a plane passing
    // through the origin

    void    setupProject(const Vector3 &n);

    // 构建矩阵关于一个平行于基本平面的反射。
    // Setup the matrix to perform a reflection about a plane parallel
    // to a cardinal plane

    void    setupReflect(int axis, float k = f);

    // 设置矩阵执行关于任意通过原点的平面的反射。
    // Setup the matrix to perform a reflection about an arbitrary plane
    // through the origin

    void    setupReflect(const Vector3 &n);
};

// 操作*用来变换点,也用来连接矩阵。
// 从左到右相乘的顺序和变换的顺序是一样的。
// Operator* is used to transforms a point, and also concatonate matrices.
// The order of multiplications from left to right is the same as
// the order of transformations

Vector3     operator*(const Vector3 &p, const Matrix4x3 &m);
Matrix4x3   operator*(const Matrix4x3 &a, const Matrix4x3 &b);

// 操作*=使得和C++标准一致
// Operator *= for conformance to C++ standards

Vector3     &operator*=(Vector3 &p, const Matrix4x3 &m);
Matrix4x3   &operator*=(const Matrix4x3 &a, const Matrix4x3 &m);

// 计算3x3矩阵部分的行列式
// Compute the determinant of the 3x3 portion of the matrix

float   determinant(const Matrix4x3 &m);

// 计算矩阵的逆
// Compute the inverse of a matrix

Matrix4x3 inverse(const Matrix4x3 &m);

// 从矩阵中提取平移部分
// Extract the translation portion of the matrix

Vector3 getTranslation(const Matrix4x3 &m);

// 从局部坐标系->父坐标系或父坐标系->局部坐标系提取位置/方位
// Extract the position/orientation from a local->parent matrix,
// or a parent->local matrix

Vector3 getPositionFromParentToLocalMatrix(const Matrix4x3 &m);
Vector3 getPositionFromLocalToParentMatrix(const Matrix4x3 &m);

/////////////////////////////////////////////////////////////////////////////
#endif // #ifndef __ROTATIONMATRIX_H_INCLUDED__
           

程序清单:Matrix4×3.cpp

/////////////////////////////////////////////////////////////////////////////
//
// 《3D数学基础:游戏与图形开发》
// 3D Math Primer for Games and Graphics Development
//
// Matrix4x3.cpp - Matrix4x3实现
// Matrix4x3.cpp - Implementation of class Matrix4x3
//

// 更多细节请看11.5节
// For more details see section 11.5.
//
/////////////////////////////////////////////////////////////////////////////

#include <assert.h>
#include <math.h>

#include "Vector3.h"
#include "EulerAngles.h"
#include "Quaternion.h"
#include "RotationMatrix.h"
#include "Matrix4x3.h"
#include "MathUtil.h"

/////////////////////////////////////////////////////////////////////////////
//
// 注意:
// Notes:
//
// 请看11章获得类设计决策的更多信息。
// See Chapter 11 for more information on class design decisions.
//
//---------------------------------------------------------------------------
//
// 矩阵组织
// MATRIX ORGANIZATION
//
// 这个类的目的是为了用户可能执行转换操作,而不用摆弄加号、减号或者转置矩阵直到输出“看起来是正确的”。
// 不过当然,这个内部表述的详细情况是很重要的。不单是为了这个文件的实现是正确的,
// 而且偶尔直接进入矩阵变量也是必须的,或者有益于优化。因此,这里我们记录我们的矩阵约定。
// The purpose of this class is so that a user might perform transformations
// without fiddling with plus or minus signs or transposing the matrix
// until the output "looks right."  But of course, the specifics of the
// internal representation is important.  Not only for the implementation
// in this file to be correct, but occasionally direct access to the
// matrix variables is necessary, or beneficial for optimization.  Thus,
// we document our matrix conventions here.
//
// 我们使用行向量,所以跟矩阵相乘看起来是这样的:
// We use row vectors, so multiplying by our matrix looks like this:
//
//               | m11 m12 m13 |
//     [ x y z ] | m21 m22 m23 | = [ x' y' z' ]
//               | m31 m32 m33 |
//               | tx  ty  tz  |
// 
// 严格执行线性代数规则规定了这个乘法实际是未定义的。
// 为了绕过这个问题,我们可以假定输入和输出向量有第四个坐标为1。
// 同样,我们不可以根据线性代数规则以学术形式地反转4x3矩阵,我们也会假设
// 最右列是[ 0 0 0 1 ]。它看起来像如下这样的:
// Strict adherance to linear algebra rules dictates that this
// multiplication is actually undefined.  To circumvent this, we can
// consider the input and output vectors as having an assumed fourth
// coordinate of 1.  Also, since we cannot technically invert a 4x3 matrix
// according to linear algebra rules, we will also assume a rightmost
// column of [ 0 0 0 1 ].  This is shown below:
//
//                 | m11 m12 m13 0 |
//     [ x y z 1 ] | m21 m22 m23 0 | = [ x' y' z' 1 ]
//                 | m31 m32 m33 0 |
//                 | tx  ty  tz  1 |
//
// 万一你忘了矩阵乘法的线性代数规则(在第7.1.6和7.1.7节中描述过),查看操作*的扩展计算定义。
// In case you have forgotten your linear algebra rules for multiplying
// matrices (which are described in section 7.1.6 and 7.1.7), see the
// definition of operator* for the expanded computations.
//
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
//
// Matrix4x3类成员
// Matrix4x3 class members
//
/////////////////////////////////////////////////////////////////////////////

//---------------------------------------------------------------------------
// Matrix4x3::identity
//
// 设置矩阵为单位矩阵
// Set the matrix to identity

void    Matrix4x3::identity() {
    m11 = f; m12 = f; m13 = f;
    m21 = f; m22 = f; m23 = f;
    m31 = f; m32 = f; m33 = f;
    tx  = f; ty  = f; tz  = f;
}

//---------------------------------------------------------------------------
// Matrix4x3::zeroTranslation
//
// 将矩阵的第四行都置为0,该行包含了平移部分
// Zero the 4th row of the matrix, which contains the translation portion.

void    Matrix4x3::zeroTranslation() {
    tx = ty = tz = f;
}

//---------------------------------------------------------------------------
// Matrix4x3::setTranslation
//
// 用向量形式设置矩阵的平移部分
// Sets the translation portion of the matrix in vector form

void    Matrix4x3::setTranslation(const Vector3 &d) {
    tx = d.x; ty = d.y; tz = d.z;
}

//---------------------------------------------------------------------------
// Matrix4x3::setupTranslation
//
// 用向量形式设置矩阵的平移部分,并设置线性变换部分为单位矩阵
// Sets the translation portion of the matrix in vector form

void    Matrix4x3::setupTranslation(const Vector3 &d) {

    // 设置线性变换部分为单位矩阵
    // Set the linear transformation portion to identity

    m11 = f; m12 = f; m13 = f;
    m21 = f; m22 = f; m23 = f;
    m31 = f; m32 = f; m33 = f;

    // 设置平移部分
    // Set the translation portion

    tx = d.x; ty = d.y; tz = d.z;
}

//---------------------------------------------------------------------------
// Matrix4x3::setupLocalToParent
// 
// 给定一个父参考帧中的局部参考帧的位置和朝向,构造矩阵来执行从局部空间->父空间的转换。
// Setup the matrix to perform a local -> parent transformation, given
// the position and orientation of the local reference frame within the
// parent reference frame.
//
// 一个非常常见的用法是构造从物体->世界矩阵。
// 作为一个示例,这种情况的转换是很直接的。
// 我们首先从物体坐标系到惯性坐标系的转换,然后平移到世界空间。
// A very common use of this will be to construct a object -> world matrix.
// As an example, the transformation in this case is straightforward.  We
// first rotate from object space into inertial space, then we translate
// into world space.
//
// 我们允许通过欧拉角或者旋转矩阵来指定方位。
// We allow the orientation to be specified using either euler angles,
// or a RotationMatrix

void    Matrix4x3::setupLocalToParent(const Vector3 &pos, const EulerAngles &orient) {

    // 创建旋转矩阵
    // Create a rotation matrix.

    RotationMatrix orientMatrix;
    orientMatrix.setup(orient);

    // 构造4x3矩阵。注意:如果我们真的关心速度,我们可以直接创建这个矩阵到各个变量,
    // 而不用使用临时的旋转矩阵。这会节约函数调用和一些的拷贝操作开销。
    // Setup the 4x3 matrix.  Note: if we were really concerned with
    // speed, we could create the matrix directly into these variables,
    // without using the temporary RotationMatrix object.  This would
    // save us a function call and a few copy operations.

    setupLocalToParent(pos, orientMatrix);
}

void    Matrix4x3::setupLocalToParent(const Vector3 &pos, const RotationMatrix &orient) {

    // 复制矩阵的旋转部分。根据RotationMatrix.cpp的注释,这个旋转矩阵通常是惯性坐标系->物体坐标系的矩阵,
    // 也就是从父空间->局部空间。我们想要局部空间->父空间旋转,复制的时候必须要转置。
    // Copy the rotation portion of the matrix.  According to
    // the comments in RotationMatrix.cpp, the rotation matrix
    // is "normally" an inertial->object matrix, which is
    // parent->local.  We want a local->parent rotation, so we
    // must transpose while copying

    m11 = orient.m11; m12 = orient.m21; m13 = orient.m31;
    m21 = orient.m12; m22 = orient.m22; m23 = orient.m32;
    m31 = orient.m13; m32 = orient.m23; m33 = orient.m33;

    // 现在设置平移部分。平移发生在3x3部分之后,所以我们可以简单直接地复制位置。
    // Now set the translation portion.  Translation happens "after"
    // the 3x3 portion, so we can simply copy the position
    // field directly

    tx = pos.x; ty = pos.y; tz = pos.z;
}

//---------------------------------------------------------------------------
// Matrix4x3::setupParentToLocal
// 
// 给定在父空间参考帧下的局部坐标的位置和方向参考帧,构造矩阵来执行父空间->局部空间。
// Setup the matrix to perform a parent -> local transformation, given
// the position and orientation of the local reference frame within the
// parent reference frame.
// 
// 它的一个非常常见的用法就是从世界坐标系->物体坐标系。
// 为了执行这个转换,我们通常首先会从世界坐标系到惯性坐标系的转换,然后从惯性坐标系到物体坐标系的旋转。
// 然而4x3矩阵可以完成后一个转换。所以我们可以创建两个矩阵T和R,然后连接M = TR。
// A very common use of this will be to construct a world -> object matrix.
// To perform this transformation, we would normally FIRST transform
// from world to inertial space, and then rotate from inertial space into
// object space.  However, out 4x3 matrix always translates last.  So
// we think about creating two matrices T and R, and then concatonating
// M = TR.
//
// 我们允许使用欧拉角或者旋转矩阵来指定朝向。
// We allow the orientation to be specified using either euler angles,
// or a RotationMatrix

void    Matrix4x3::setupParentToLocal(const Vector3 &pos, const EulerAngles &orient) {

    // 创建一个旋转矩阵。
    // Create a rotation matrix.

    RotationMatrix orientMatrix;
    orientMatrix.setup(orient);

    // 构造4x3矩阵。
    // Setup the 4x3 matrix.

    setupParentToLocal(pos, orientMatrix);
}

void    Matrix4x3::setupParentToLocal(const Vector3 &pos, const RotationMatrix &orient) {

    // 复制矩阵的旋转部分。我们根据RotationMatrix.cpp注释中的布局,可以直接复制元素(不用转置)
    // Copy the rotation portion of the matrix.  We can copy the
    // elements directly (without transposing) according
    // to the layout as commented in RotationMatrix.cpp

    m11 = orient.m11; m12 = orient.m12; m13 = orient.m13;
    m21 = orient.m21; m22 = orient.m22; m23 = orient.m23;
    m31 = orient.m31; m32 = orient.m32; m33 = orient.m33;

    // 现在设置平移部分。通常地,我们通过取位置的负号来实现从世界到惯性坐标系。
    // 然而,我们必须修正这个事实——旋转是先发生的。所以必须先旋转平移部分。
    // 这和创建一个平移矩阵T来平移-pos,和旋转矩阵R,并且创建一个连接矩阵TR是一样的。
    // Now set the translation portion.  Normally, we would
    // translate by the negative of the position to translate
    // from world to inertial space.  However, we must correct
    // for the fact that the rotation occurs "first."  So we
    // must rotate the translation portion.  This is the same
    // as create a translation matrix T to translate by -pos,
    // and a rotation matrix R, and then creating the matrix
    // as the concatenation of TR

    tx = -(pos.x*m11 + pos.y*m21 + pos.z*m31);
    ty = -(pos.x*m12 + pos.y*m22 + pos.z*m32);
    tz = -(pos.x*m13 + pos.y*m23 + pos.z*m33);
}

//---------------------------------------------------------------------------
// Matrix4x3::setupRotate
//
// 构建矩阵执行关于主要轴的旋转
// Setup the matrix to perform a rotation about a cardinal axis
//
// 使用基于1的索引指定旋转轴
// The axis of rotation is specified using a 1-based index:
//
//  1 => 关于x轴旋转
//  2 => 关于y轴旋转
//  3 => 关于z轴旋转
//  1 => rotate about the x-axis
//  2 => rotate about the y-axis
//  3 => rotate about the z-axis
//
// theta是以弧度计的旋转量。使用左手法则定义正方向的旋转。
// theta is the amount of rotation, in radians.  The left-hand rule is
// used to define "positive" rotation.
// 
// 平移部分被重设。
// The translation portion is reset.
//
// 参见8.2.2获得更多信息。
// See 8.2.2 for more info.

void    Matrix4x3::setupRotate(int axis, float theta) {

    // 获得旋转角的sin和cos值
    // Get sin and cosine of rotation angle

    float   s, c;
    sinCos(&s, &c, theta);

    // 检查关于哪根轴旋转
    // Check which axis they are rotating about

    switch (axis) {

                // 关于x轴旋转
        case : // Rotate about the x-axis

            m11 = f; m12 = f; m13 = f;
            m21 = f; m22 = c;    m23 = s;
            m31 = f; m32 = -s;   m33 = c;
            break;

                // 关于y轴旋转
        case : // Rotate about the y-axis

            m11 = c;    m12 = f; m13 = -s;
            m21 = f; m22 = f; m23 = f;
            m31 = s;    m32 = f; m33 = c;
            break;

                // 关于z轴旋转
        case : // Rotate about the z-axis

            m11 = c;    m12 = s;    m13 = f;
            m21 = -s;   m22 = c;    m23 = f;
            m31 = f; m32 = f; m33 = f;
            break;

        default:

            // 不存在的轴索引
            // bogus axis index

            assert(false);
    }

    // 重设平移部分
    // Reset the translation portion

    tx = ty = tz = f;
}

//---------------------------------------------------------------------------
// Matrix4x3::setupRotate
//
// 构建关于任意轴的旋转矩阵。
// 该轴必须通过原点。
// Setup the matrix to perform a rotation about an arbitrary axis.
// The axis of rotation must pass through the origin.
//
// axis定义了哪根旋转轴,并且必须是单位向量。
// axis defines the axis of rotation, and must be a unit vector.
//
// theta是旋转量,以弧度计。左手法则定义了旋转的正方向。
// theta is the amount of rotation, in radians.  The left-hand rule is
// used to define "positive" rotation.
//
// 平移部分会被重置。
// The translation portion is reset.
//
// 查看8.2.3来获得更多信息。
// See 8.2.3 for more info.

void    Matrix4x3::setupRotate(const Vector3 &axis, float theta) {

    // 快速清楚检查确保axis是单位向量
    // Quick sanity check to make sure they passed in a unit vector
    // to specify the axis

    assert(fabs(axis*axis - f) < f);

    // 获得旋转角的sin和cos值
    // Get sin and cosine of rotation angle

    float   s, c;
    sinCos(&s, &c, theta);

    // 计算1 - cos(theta) 和一些公共的子表达式
    // Compute 1 - cos(theta) and some common subexpressions

    float   a = f - c;
    float   ax = a * axis.x;
    float   ay = a * axis.y;
    float   az = a * axis.z;

    // 设置矩阵元素。这里仍然有一些机会去优化,出于许多公共的子表达式。
    // 我们会让编译器来处理它..
    // Set the matrix elements.  There is still a little more
    // opportunity for optimization due to the many common
    // subexpressions.  We'll let the compiler handle that...

    m11 = ax*axis.x + c;
    m12 = ax*axis.y + axis.z*s;
    m13 = ax*axis.z - axis.y*s;

    m21 = ay*axis.x - axis.z*s;
    m22 = ay*axis.y + c;
    m23 = ay*axis.z + axis.x*s;

    m31 = az*axis.x + axis.y*s;
    m32 = az*axis.y - axis.x*s;
    m33 = az*axis.z + c;

    // 重置平移部分
    // Reset the translation portion

    tx = ty = tz = f;
}

//---------------------------------------------------------------------------
// Matrix4x3::fromQuaternion
//
// 构建矩阵来执行旋转,给定一个四元数形式的角位移。
// Setup the matrix to perform a rotation, given the angular displacement
// in quaternion form.
//
// 平抑部分会被重置。
// The translation portion is reset.
//
// 查看10.6.3来获得更多信息。
// See 10.6.3 for more info.

void    Matrix4x3::fromQuaternion(const Quaternion &q) {

    // 计算一些值来优化公共子表达式
    // Compute a few values to optimize common subexpressions

    float   ww = f * q.w;
    float   xx = f * q.x;
    float   yy = f * q.y;
    float   zz = f * q.z;

    // 设置矩阵元素。这里仍然有一些机会去优化,出于许多公共的子表达式。
    // 我们会让编译器来处理它..
    // Set the matrix elements.  There is still a little more
    // opportunity for optimization due to the many common
    // subexpressions.  We'll let the compiler handle that...

    m11 = f - yy*q.y - zz*q.z;
    m12 = xx*q.y + ww*q.z;
    m13 = xx*q.z - ww*q.x;

    m21 = xx*q.y - ww*q.z;
    m22 = f - xx*q.x - zz*q.z;
    m23 = yy*q.z + ww*q.x;

    m31 = xx*q.z + ww*q.y;
    m32 = yy*q.z - ww*q.x;
    m33 = f - xx*q.x - yy*q.y;

    // 重置平移部分。
    // Reset the translation portion

    tx = ty = tz = f;
}

//---------------------------------------------------------------------------
// Matrix4x3::setupScale
// 
// 构建矩阵来执行每根轴上的缩放。使用向量形式的Vector3(k,k,k)来统一缩放k倍。
// Setup the matrix to perform scale on each axis.  For uniform scale by k,
// use a vector of the form Vector3(k,k,k)
//
// 这个平移部分会被重置。
// The translation portion is reset.
//
// 查看8.3.1来获得更多信息。
// See 8.3.1 for more info.

void    Matrix4x3::setupScale(const Vector3 &s) {

    // 设置矩阵元素。相当直接
    // Set the matrix elements.  Pretty straightforward

    m11 = s.x;  m12 = f; m13 = f;
    m21 = f; m22 = s.y;  m23 = f;
    m31 = f; m32 = f; m33 = s.z;

    // 重置平移部分。
    // Reset the translation portion

    tx = ty = tz = f;
}

//---------------------------------------------------------------------------
// Matrix4x3::setupScaleAlongAxis
//
// 构建矩阵来执行沿着任意轴的缩放。
// Setup the matrix to perform scale along an arbitrary axis.
//
// 这根轴被单位向量指定。
// The axis is specified using a unit vector.
//
// 平移部分会被重置。
// The translation portion is reset.
//
// 查看8.3.2节来获得更多信息。
// See 8.3.2 for more info.

void    Matrix4x3::setupScaleAlongAxis(const Vector3 &axis, float k) {

    // 快速清楚检查确保axis是单位向量
    // Quick sanity check to make sure they passed in a unit vector
    // to specify the axis

    assert(fabs(axis*axis - f) < f);

    // 计算k-1和一些公共子表达式
    // Compute k-1 and some common subexpressions

    float   a = k - f;
    float   ax = a * axis.x;
    float   ay = a * axis.y;
    float   az = a * axis.z;

    // 填充矩阵元素。我们会完成我们的公共子表达式的优化,因为对角相应的矩阵元素是相等的
    // Fill in the matrix elements.  We'll do the common
    // subexpression optimization ourselves here, since diagonally
    // opposite matrix elements are equal

    m11 = ax*axis.x + f;
    m22 = ay*axis.y + f;
    m32 = az*axis.z + f;

    m12 = m21 = ax*axis.y;
    m13 = m31 = ax*axis.z;
    m23 = m32 = ay*axis.z;

    // 重设平移部分
    // Reset the translation portion

    tx = ty = tz = f;
}

//---------------------------------------------------------------------------
// Matrix4x3::setupShear
// 
// 构建矩阵来执行切变
// Setup the matrix to perform a shear
//
// 切变类型被基于1的轴索引指定。通过一个矩阵变换一个点的效果如下面的伪代码所示:
// The type of shear is specified by the 1-based "axis" index.  The effect
// of transforming a point by the matrix is described by the pseudocode
// below:
//
//  axis == 1  =>  y += s*x, z += t*x
//  axis == 2  =>  x += s*y, z += t*y
//  axis == 3  =>  x += s*z, y += t*z
//
// 平移部分会被重置。
// The translation portion is reset.
//
// 查看8.6来获得更多信息。
// See 8.6 for more info.

void    Matrix4x3::setupShear(int axis, float s, float t) {

    // 检查它们想要那种切变类型
    // Check which type of shear they want

    switch (axis) {

                // 使用x切变y和z
        case : // Shear y and z using x

            m11 = f; m12 = s;    m13 = t;
            m21 = f; m22 = f; m23 = f;
            m31 = f; m32 = f; m33 = f;
            break;

                //使用y切变x和z
        case : // Shear x and z using y

            m11 = f; m12 = f; m13 = f;
            m21 = s;    m22 = f; m23 = t;
            m31 = f; m32 = f; m33 = f;
            break;

                // 使用z来切变x和y
        case : // Shear x and y using z

            m11 = f; m12 = f; m13 = f;
            m21 = f; m22 = f; m23 = f;
            m31 = s;    m32 = t;    m33 = f;
            break;

        default:

            // 不存在的轴索引
            // bogus axis index

            assert(false);
    }

    // 重设平移部分
    // Reset the translation portion

    tx = ty = tz = f;
}

//---------------------------------------------------------------------------
// Matrix4x3::setupProject
//
// 构建矩阵来执行投影到一个通过原点的平面。这个平面垂直于单位向量n。
// Setup the matrix to perform a projection onto a plane passing
// through the origin.  The plane is perpendicular to the
// unit vector n.
//
// 查看8.4.2来获得更多的信息。
// See 8.4.2 for more info.

void    Matrix4x3::setupProject(const Vector3 &n) {

    // 快速清楚检查确保axis是单位向量
    // Quick sanity check to make sure they passed in a unit vector
    // to specify the axis

    assert(fabs(n*n - f) < f);

    // 填充矩阵元素。我们会完成我们的公共子表达式的优化,因为对角相应的矩阵元素是相等的
    // Fill in the matrix elements.  We'll do the common
    // subexpression optimization ourselves here, since diagonally
    // opposite matrix elements are equal

    m11 = f - n.x*n.x;
    m22 = f - n.y*n.y;
    m33 = f - n.z*n.z;

    m12 = m21 = -n.x*n.y;
    m13 = m31 = -n.x*n.z;
    m23 = m32 = -n.y*n.z;

    // 重置平移部分
    // Reset the translation portion

    tx = ty = tz = f;
}

//---------------------------------------------------------------------------
// Matrix4x3::setupReflect
//
// 构建矩阵关于一个平行于基本平面的反射。
// Setup the matrix to perform a reflection about a plane parallel
// to a cardinal plane.
//
// axis轴是基于1的索引,指定了关于哪个平面的投影:
// axis is a 1-based index which specifies the plane to project about:
//
//  1 => 关于平面 x=k 的反射
//  2 => 关于平面 y=k 的反射
//  3 => 关于平面 z=k 的反射
//  1 => reflect about the plane x=k
//  2 => reflect about the plane y=k
//  3 => reflect about the plane z=k
//
// 平移部分会被恰当地设置,因为如果k!=0的时候平移必须会发生。
// The translation is set appropriately, since translation must occur if
// k != 0
//
// See 8.5 for more info.

void    Matrix4x3::setupReflect(int axis, float k) {

    // 检查关于哪个平面的反射
    // Check which plane they want to reflect about

    switch (axis) {

                // 关于平面x=k平面的反射
        case : // Reflect about the plane x=k

            m11 = -f; m12 =  f; m13 =  f;
            m21 =  f; m22 =  f; m23 =  f;
            m31 =  f; m32 =  f; m33 =  f;

            tx = f * k;
            ty = f;
            tz = f;

            break;

                // 关于y=k平面的反射
        case : // Reflect about the plane y=k

            m11 =  f; m12 =  f; m13 =  f;
            m21 =  f; m22 = -f; m23 =  f;
            m31 =  f; m32 =  f; m33 =  f;

            tx = f;
            ty = f * k;
            tz = f;

            break;

                // 关于z=k平面的反射
        case : // Reflect about the plane z=k

            m11 =  f; m12 =  f; m13 =  f;
            m21 =  f; m22 =  f; m23 =  f;
            m31 =  f; m32 =  f; m33 = -f;

            tx = f;
            ty = f;
            tz = f * k;

            break;

        default:

            // 不存在的轴索引
            // bogus axis index

            assert(false);
    }

}

//---------------------------------------------------------------------------
// Matrix4x3::setupReflect
// 
// 设置矩阵执行关于任意通过原点的平面的反射。这个单位向量n垂直于平面。
// Setup the matrix to perform a reflection about an arbitrary plane
// through the origin.  The unit vector n is perpendicular to the plane.
// 
// 平移部分会被重置。
// The translation portion is reset.
//
// 查看8.5节来获得更多的信息。
// See 8.5 for more info.

void    Matrix4x3::setupReflect(const Vector3 &n) {

    // 快速清楚检查确保axis是单位向量
    // Quick sanity check to make sure they passed in a unit vector
    // to specify the axis

    assert(fabs(n*n - f) < f);

    // 计算公共子表达式
    // Compute common subexpressions

    float   ax = -f * n.x;
    float   ay = -f * n.y;
    float   az = -f * n.z;

    // 填充矩阵元素。我们会完成我们的公共子表达式的优化,因为对角相应的矩阵元素是相等的
    // Fill in the matrix elements.  We'll do the common
    // subexpression optimization ourselves here, since diagonally
    // opposite matrix elements are equal

    m11 = f + ax*n.x;
    m22 = f + ay*n.y;
    m32 = f + az*n.z;

    m12 = m21 = ax*n.y;
    m13 = m31 = ax*n.z;
    m23 = m32 = ay*n.z;

    // 重置平移部分。
    // Reset the translation portion

    tx = ty = tz = f;
}

//---------------------------------------------------------------------------
// Vector * Matrix4x3
//
// 变换顶点。这会使得向量类看起来和线性代数纸上记号是一致的。
// Transform the point.  This makes using the vector class look like it
// does with linear algebra notation on paper.
//
// 我们也会提供*=操作,作为C语言的习惯约定。
// We also provide a *= operator, as per C convention.
//
// 参见7.1.7节
// See 7.1.7


Vector3 operator*(const Vector3 &p, const Matrix4x3 &m) {

    // 通过线性代数磨合
    // Grind through the linear algebra.

    return Vector3(
        p.x*m.m11 + p.y*m.m21 + p.z*m.m31 + m.tx,
        p.x*m.m12 + p.y*m.m22 + p.z*m.m32 + m.ty,
        p.x*m.m13 + p.y*m.m23 + p.z*m.m33 + m.tz
    );
}

Vector3 &operator*=(Vector3 &p, const Matrix4x3 &m) {
    p = p * m;
    return p;
}

//---------------------------------------------------------------------------
// Matrix4x3 * Matrix4x3
//
// 矩阵连接。这会使得矩阵类看起来和线性代数纸上记号是一致的。
// Matrix concatenation.  This makes using the vector class look like it
// does with linear algebra notation on paper.
//
// 我们也会提供*=操作,作为C语言的习惯约定。
// We also provide a *= operator, as per C convention.
//
// 参见7.1.6节
// See 7.1.6

Matrix4x3 operator*(const Matrix4x3 &a, const Matrix4x3 &b) {

    Matrix4x3 r;

    // 计算上面3x3(线性变换)部分
    // Compute the upper 3x3 (linear transformation) portion

    r.m11 = a.m11*b.m11 + a.m12*b.m21 + a.m13*b.m31;
    r.m12 = a.m11*b.m12 + a.m12*b.m22 + a.m13*b.m32;
    r.m13 = a.m11*b.m13 + a.m12*b.m23 + a.m13*b.m33;

    r.m21 = a.m21*b.m11 + a.m22*b.m21 + a.m23*b.m31;
    r.m22 = a.m21*b.m12 + a.m22*b.m22 + a.m23*b.m32;
    r.m23 = a.m21*b.m13 + a.m22*b.m23 + a.m23*b.m33;

    r.m31 = a.m31*b.m11 + a.m32*b.m21 + a.m33*b.m31;
    r.m32 = a.m31*b.m12 + a.m32*b.m22 + a.m33*b.m32;
    r.m33 = a.m31*b.m13 + a.m32*b.m23 + a.m33*b.m33;

    // 计算平移部分
    // Compute the translation portion

    r.tx = a.tx*b.m11 + a.ty*b.m21 + a.tz*b.m31 + b.tx;
    r.ty = a.tx*b.m12 + a.ty*b.m22 + a.tz*b.m32 + b.ty;
    r.tz = a.tx*b.m13 + a.ty*b.m23 + a.tz*b.m33 + b.tz;

    // 返回它。哎呀 - 会调用了构造函数。如果速度是至关重要的,我们可能需要
    // 一个不同的函数在我们想要的地方放置它...
    // Return it.  Ouch - involves a copy constructor call.  If speed
    // is critical, we may need a seperate function which places the
    // result where we want it...

    return r;
}

Matrix4x3 &operator*=(Matrix4x3 &a, const Matrix4x3 &b) {
    a = a * b;
    return a;
}

//---------------------------------------------------------------------------
// determinant
//
// 计算3x3部分的矩阵行列式
// Compute the determinant of the 3x3 portion of the matrix.
//
// 参见9.1.1节获得更多信息。
// See 9.1.1 for more info.

float   determinant(const Matrix4x3 &m) {
    return
          m.m11 * (m.m22*m.m33 - m.m23*m.m32)
        + m.m12 * (m.m23*m.m31 - m.m21*m.m33)
        + m.m13 * (m.m21*m.m32 - m.m22*m.m31);
}

//---------------------------------------------------------------------------
// inverse
//
// 计算矩阵的逆。我们使用传统的用伴随矩阵除以行列式来的方法计算。
// Compute the inverse of a matrix.  We use the classical adjoint divided
// by the determinant method.
//
// 参见9.2.1来获得更多信息。
// See 9.2.1 for more info.

Matrix4x3 inverse(const Matrix4x3 &m) {

    // 计算行列式
    // Compute the determinant

    float   det = determinant(m);

    // 如果是奇异矩阵,行列式是零,并且没有逆矩阵
    // If we're singular, then the determinant is zero and there's
    // no inverse

    assert(fabs(det) > f);

    // 计算一除以行列式,所以我们只需要除一次,然后乘去每一个元素。
    // Compute one over the determinant, so we divide once and
    // can *multiply* per element

    float   oneOverDet = f / det;

    // 计算3x3部分的逆矩阵,通过伴随矩阵除以行列式。
    // Compute the 3x3 portion of the inverse, by
    // dividing the adjoint by the determinant

    Matrix4x3   r;

    r.m11 = (m.m22*m.m33 - m.m23*m.m32) * oneOverDet;
    r.m12 = (m.m13*m.m32 - m.m12*m.m33) * oneOverDet;
    r.m13 = (m.m12*m.m23 - m.m13*m.m22) * oneOverDet;

    r.m21 = (m.m23*m.m31 - m.m21*m.m33) * oneOverDet;
    r.m22 = (m.m11*m.m33 - m.m13*m.m31) * oneOverDet;
    r.m23 = (m.m13*m.m21 - m.m11*m.m23) * oneOverDet;

    r.m31 = (m.m21*m.m32 - m.m22*m.m31) * oneOverDet;
    r.m32 = (m.m12*m.m31 - m.m11*m.m32) * oneOverDet;
    r.m33 = (m.m11*m.m22 - m.m12*m.m21) * oneOverDet;

    // 计算逆矩阵的平移部分
    // Compute the translation portion of the inverse

    r.tx = -(m.tx*r.m11 + m.ty*r.m21 + m.tz*r.m31);
    r.ty = -(m.tx*r.m12 + m.ty*r.m22 + m.tz*r.m32);
    r.tz = -(m.tx*r.m13 + m.ty*r.m23 + m.tz*r.m33);

    // 返回它。哎呀 - 会调用了构造函数。如果速度是至关重要的,我们可能需要
    // 一个不同的函数在我们想要的地方放置它...
    // Return it.  Ouch - involves a copy constructor call.  If speed
    // is critical, we may need a seperate function which places the
    // result where we want it...

    return r;
}

//---------------------------------------------------------------------------
// getTranslation
//
// 以向量形式返回矩阵的平移部分
// Return the translation row of the matrix in vector form

Vector3 getTranslation(const Matrix4x3 &m) {
    return Vector3(m.tx, m.ty, m.tz);
}

//---------------------------------------------------------------------------
// getPositionFromParentToLocalMatrix
//
// 提取从父空间->局部空间变换矩阵的平移部分(就像世界坐标系->物体坐标系矩阵)
// Extract the position of an object given a parent -> local transformation
// matrix (such as a world -> object matrix)
//
// 我们假定矩阵呈现的是坚固的变换。(没有缩放、倾斜、或者镜像)
// We assume that the matrix represents a rigid transformation.  (No scale,
// skew, or mirroring)

Vector3 getPositionFromParentToLocalMatrix(const Matrix4x3 &m) {

    // 通过转置3x3部分乘以负平移值。通过矩阵的转置,我们假定矩阵是正交的。(这个函数对于非坚固变换的变换是没有意义的)
    // Multiply negative translation value by the
    // transpose of the 3x3 portion.  By using the transpose,
    // we assume that the matrix is orthogonal.  (This function
    // doesn't really make sense for non-rigid transformations...)

    return Vector3(
        -(m.tx*m.m11 + m.ty*m.m12 + m.tz*m.m13),
        -(m.tx*m.m21 + m.ty*m.m22 + m.tz*m.m23),
        -(m.tx*m.m31 + m.ty*m.m32 + m.tz*m.m33)
    );
}

//---------------------------------------------------------------------------
// getPositionFromLocalToParentMatrix
//
// 提取给定局部坐标系->父坐标系的位置变换矩阵(例如物体坐标系->世界坐标系矩阵)
// Extract the position of an object given a local -> parent transformation
// matrix (such as an object -> world matrix)

Vector3 getPositionFromLocalToParentMatrix(const Matrix4x3 &m) {

    // 位置简明地是平移部分
    // Position is simply the translation portion

    return Vector3(m.tx, m.ty, m.tz);
}
           

继续阅读