【译】开始构建三维图形引擎:线性变换
开始构建三维图形引擎:线性变换
该系列文章参考链接:Let’s Build a 3D Graphics Software Engine.
欢迎来到三维图形引擎系列的第二部分!本文我们将讨论线性变换(linear transformations),可以对向量进行旋转、缩放等操作,以及如何将它们应用于我们已经定义好的类中。
如果你没有读过该系列的第一部分the first part of this series,我建议你现在阅读一下第一部分。为了防止你忘记之前的内容,下面是一个上节内容的快速回顾。
上面两个类将会是我们整个图形引擎的基础,第一个类表示一个点(空间中的一个实际位置),第二个类表示一个向量(两个点之间的空间)。
为了讨论线性变换,你需要在类Point中做一些小的变动:不同于之前将数据输出到一个控制台中的方法,而是使用你喜欢的图形API函数,使用对应的函数将当前的点绘制在屏幕中。(译者注:即将计算的点绘制在屏幕中)
1、线性变换基础
一个小提示:线性变换公式看起来要比实际情况更糟糕。其中将会涉及到一些三角函数,但是实际上你并不需要知道如何进行三角变换,我将会解释每一个函数分别包含哪些输入和输出数据,对于中间处理过程,你可以使用任何计算或数学的第三方库来完成。
提示:如果你想要更深入的了解这些公式,请观看如下视频(video),和PDF文档(PDF)。
所有的线性变换都可以表示为如下形式:
B = F(A)
上面公式是说,如果有一个线性变换函数F()和一个输入向量A,那么将会得到一个输出向量B。
上面提到的内容——两个向量和一个函数,都可以被表示为一个矩阵。向量A和B是1x3的矩阵,线性变换F是一个3x3的矩阵(称之为变换矩阵(transformation matrix))。
这意味着,当你表达上述公式时,它看起来是下面的样子:
如果你之前学过三角函数或者是线性代数,你可能会想到噩梦般的矩阵数学。幸运的是,有一种简单的方法来写下上述公式。它看起来如下:
然而,这些公式需要通过两个输入来计算,例如在旋转操作中,需要同时指定一个向量和旋转量。让我们看一下旋转矩阵是如果工作的。
2、旋转矩阵
按照定义,旋转是围绕一个点进行旋转的圆周运动。我们空间的旋转点可以是以下三种情况之一:XY平面、XZ平面和YZ平面(每一个平面是由两个我们之前定义的基向量组成的)。
定义的三个旋转点意味着有三个分离的旋转矩阵,如下所示:
XY旋转矩阵:
XZ旋转矩阵:
YZ旋转矩阵:
因此,将一个点A绕着XY平面旋转90角度(pi/2弧度,大多数数学库具有弧度和角度互相转换的函数),你可以进行如下操作:
因此,如果初始点是A(3, 4, 5),那么输出点会是B(-4, 3, 5)。
练习:旋转函数
作为一个练习,尝试为类Vector创建三个新的函数。一个绕着XY平面旋转,一个绕着YZ平面旋转,一个绕着XZ平面旋转。函数应当将旋转的角度作为输入参数,然后将旋转之后的向量作为输出。
该函数的基本流程如下所示:
- 创建输出向量。
- 将输入的角度转换为弧度形式。
- 通过使用上面的公式计算输出向量。
- 返回输出向量。
为了使输入向量A(a0, a1, a2)沿着X轴方向放大两倍(使用缩放三元组 S = (2, 1, 1)),数学公式如下:
因此,如果给定输入向量A = (3, 4, 0),那么输出向量B将会是(6, 4, 0)。
练习:缩放函数
另外一个练习,为类vector增加一个新的函数。该函数接收一个三元元组,返回一个输出向量。
该函数的基本流程如下所示:
根据上面公式计算输出向量(可以简化为y0 = x0 * s0; y1 = x1 * s1; y2 = x2 * s2)。
返回输出向量。
下面是该程序的一些快速的描述:
程序使用一个包含100个点的数组。
按下按键D,程序清除屏幕,绘制点。
按下按键A,程序对所有的点执行0.5缩放。
按下按键S,程序对所有的点执行2.0缩放。
按下按键R,程序对所有点绕着XY平面旋转15度。
ESC按下,程序退出。
当前的两个类如下所示:
示例程序代码如下:
现在你有一个很酷的小程序来展示你的新技术。可以查看示例demo。
5、结论
尽管我们没有涉及所有可能的线性变换,但是我们小引擎已经开始成形了。
同样的,为了简化引擎,有一些剩余内容(错切变换等)。如果你想要得到更多的线性变换的内容,你可以查看维基百科。
该系列的下一个部分,我们将会处理不同的观察空间以及如果对目标进行拣选。