CG中的几何学——矩阵【4】

来源:互联网 发布:出售淘宝旗舰店id 编辑:程序博客网 时间:2024/05/16 16:01

原文地址:http://www.scratchapixel.com/lessons/mathematics-physics-for-computer-graphics/geometry/matrices

如果在渲染图像的时候,所有的物体都只能够放在场景的原点,那能够制作出来的效果就很有限了。还好,我们可以用矩阵来移动场景中的物体,灯光以及摄像机,这样才能创造出令人影响深刻,匪夷所思的效果。如果您想要写一个自己的3D渲染引擎,那么矩阵是一定要弄明白的。现在,让我们开始来学习这个让人畏惧的存在吧。

矩阵:让我们的变换操作更简单

其实矩阵并不复杂,大家都怕它很有可能是完全了解矩阵代表的是什么或者不知道矩阵是怎么工作的。在3D应用里面,矩阵扮演着非常重要的角色,在代码里面我们会经常看到它们的身影。
在前面的章节中,我们学到如何用线性变换的方式来移动或者旋转一个点。比如,我们可以增加或减少一个点的坐标值来移动这个点。现在,让我们用非正式的数学定义来定义矩阵:矩阵就是融合了各种线性变换(平移,旋转,缩放)的一个结构。通过将这个结构和一个点做乘法,我们可以对这个点进行这个矩阵包含的线性变换。我们可以创建一个让点旋转90度的矩阵,一个缩放点的坐标为之前2倍的矩阵,或者创建一个移动点的坐标(-2,3,1)的矩阵。在没有使用矩阵之前,以上提到的这些操作也是可以完成的,比如像下面这样:
这里写图片描述
虽然完成了这些操作,不过这代码量可不小。现在让我们用矩阵的方式来完成同样的操作:

Matrix M(...);//这个矩阵里包含着所有的线性变换Vec3f p = Vec3f(1,1,1);//待变换的点Vec3f transformed = p*M;//得到变换后的点

用矩阵的话,三行代码就搞定了,我们的生活因此变的更美好,有更多的时间享受快乐时光了。现在您可能会产生一个疑问:矩阵具体是怎么做到这些变换的?请看下文分解。

什么是矩阵

矩阵到底是什么?我们现在不会给出它具体的严格的数学定义,而是给出几个矩阵的例子。然后再由对例子的剖析,反向引申出数学定义,这样理解更深刻一些。如果您已经阅读了一些有关CG的书籍,您会发现在书籍中的很多地方,矩阵通常都是由一个实数构成的二维矩阵表示的。
这里写图片描述
我们用mxn来表示一个二维的数组。其中m和n是两个代表行数和列数的数。比如一个3x5的矩阵:
这里写图片描述
矩阵通常会用一个大写字母来表示,我们通常会使用两个下标来指明矩阵中的具体的某个元素:
这里写图片描述表示矩阵中的第i行第j列的元素。
到现在为止,我们已经剔除了很大一部分矩阵相关的知识,我们只关心矩阵与CG相关的知识。在CG领域中,基本上我们只会用行和列相等的矩阵,也就是方形矩阵。尤其是3x3和4x4的矩阵。
这里写图片描述这里写图片描述
在C++里面我们可以用如下的方式来实现矩阵:

template<typename T>class Matrix44{public:    Matrix44(){}    const T* operator[](uint8_t i)const{        return m[I];    }    T* operator[](uint8_t i){        return m[i];    }    //初始化矩阵为单位矩阵    T m[4][4] = {        {1,0,0,0},        {0,1,0,0},        {0,0,1,0},        {0,0,0,1},        };};typedef Matrix44<float> Matrix44f;

这个矩阵类实现了[]操作符的重载。现在我们如果想要使用矩阵中的某个元素可以这样写:

Matrix44f mat;mat.m[0][3] = 1.f;

也可以这样写:

Matrix44f mat;mat[0][3] = 1.f;

矩阵乘法

我们可以对矩阵执行乘法操作,而这个乘法操作就是完成向量和点线性变换的核心步骤。两个矩阵的乘积是另一个矩阵。
这里写图片描述
我们在本章的开头说过,矩阵是一种定义各种线性变换组合的一种简化形式。如何去得到线性变换的这种矩阵形式呢?我们稍后将为大家揭晓。现在我们只需要知道,我们可以把两个表示线性变换的矩阵通过乘法的方式融合到一个单独的矩阵里。比如M1表示的是一个平移变换,M2表示的是另一个平移变换,通过把它们相乘,得到的矩阵M3同时融合了M1和M2的变换。
这里写图片描述
在上图中,我们有用两种方式将一个点从A移动到点C。第一种方式的路径是A-B-C,第二种方式的路径是A-D-C。将点从A移动到B再从B移动到C需要两个包含平移变换的矩阵M1和M2;将点从A移动到D再移动到C也需要两个包含平移变换的矩阵M4和M5。那么M1*M2和M4*M5都会得到同一个直接将点从A移动到C的矩阵M3。
关于矩阵还有一个规则需要注意,虽然如果我们只使用4x4矩阵的话这条规则并不重要。这条规则就是:如果两个矩阵能做乘法,那么前提条件是第一个矩阵的列数和第二个矩阵的行数需要相等。简而言之,必须满足如下情况的两个矩阵才能做乘法:
这里写图片描述
现在让我们进一步说明要矩阵的乘法具体是个什么过程吧。简而言之,新的矩阵的第i行第j列的元素的值是有第一个矩阵的第i行构成的向量与第二个矩阵第j列构成的向量的点积(i/j为0 表示的是第一列/行)。可以用下图来表示这种计算:
这里写图片描述
我们可以用这种方式把M3的所有元素算出来。

现在用C++的方式来实现这种矩阵的乘法吧。

Matrix44 operator* (const Matrix44& rhs) const{    Matrix44 mult;    for(uint8_t i = 0;i<4;++i){        for(uint8_t j=0;j<4;++j){            mult[i][j] = m[i][0]*rhs[0][j] +                         m[i][1]*rhs[1][j] +                         m[i][2]*rhs[2][j] +                         m[i][3]*rhs[3][j];        }    }    return mult;}

最后,矩阵的乘法顺序是不能交换的,交换运算次序会得到截然不同的结果。

总结

我们并没有说明矩阵是怎样和为什么能够融合各种变换,我们会在下一章里说明。通过本部分的介绍,我们只需记住矩阵其实就是二维数组。我们还需要知道矩阵是如何书写的,矩阵中各个元素可以用何种方法访问,以及矩阵的乘法是如何进行的。

阅读全文
0 0
原创粉丝点击