【译】开始构建三维图形引擎:点、向量和一些基本概念
开始构建三维图形引擎:点、向量和一些基本概念
该系列文章参考链接:Let’s Build a 3D Graphics Software Engine.
当今最大的游戏背后的三维游戏引擎(3D game engines)都源自于惊人的数学和编程工作,而且许多开发者发现,想要完全理解他们是一个非常复杂的任务。如果你缺少一些经验(或者是一些大学课程,例如作者自己),这个任务将变得更加艰巨。在这一系列教程中,我的目标是带你了解三维游戏引擎中基本的图形系统。
具体来讲,在这篇文章中,我们将会讨论点、向量以及它们之间的非常有趣的部分。如果你对代数和计算机科学(面向对象的编程)有一些理解的话,你将会有能力理解该文章的绝大多数内容,但是如果你对于这些概念有疑问的话,请提出问题!因为有一些话题是很难理解的。
1、坐标系基础知识(Basics of Coordinate Systems)
让我们从以下基础知识开始。三维图形需要一个三维空间(three-dimensional space)。最常用的空间我们称之为笛卡尔空间(Cartesian Space),为笛卡尔坐标系(Cartesian coordinates)的使用提供了方便。(基本的(x, y)坐标,以及二维空间图形的知识在大多数高中已经掌握,如下图所示)
三维笛卡尔坐标空间为我们提供了X, Y, Z三个轴向(可以独立的描述水平,垂直和深度方向的位置信息)。在该空间中的任意一点的坐标被表示为一个元组(tuple)(在这里是一个三元元组,因为有三个轴向)。在二维空间中,一个元组可以被描述为(x, y),在三维空间中,被描述为(x, y, z), 三元元组可以表示一个点相对于空间原点(space origin)(典型的原点坐标为(0, 0, 0))的位置。
提示:元组:在计算机和数学学科中,表示元素的一个有序排列(或序列)。(K, y, l, e)是一个4元组,显示了组成我名字的四个字母。
在该空间中,我们将定义一个由三元元组表示的点。如下所示:
除了定义点之外,我们必须定义其它部分。
每一个三元元组的元素叫做一个标量(scalar)(数字),定义了在某一个基向量(basis vector)方向的位置。每一个基向量必须是单位长度的(意思是向量的长度为1),因此,像(1,1,1)和(2,2,2)不能作为基向量。
为该空间定义三个基向量,如下:
2、坐标系(The Coordinate System)
现在来讨论坐标系的数学定义,以及它是如何影响我们的图形系统和相应的计算。
2.1、代数点(Representing Points)
我们坐标系的原点(origin point)可以表示为点O,表示一个三元元组(0,0,0)。这意味着该坐标系的数学表示可以被描述为:
{O; X, Y, Z}
通过上述声明,(x, y, z)可以表示为一个点相对于原点的位置。该定义同样可被描述为:任何点P(a, b, c)都可以表示为:
P = O + aX + bY + cZ
在这里,使用小写字母表示标量,使用大写字母表示向量。因此,a, b, c是标量; X, Y, Z是向量(它们实际上是我们之前定义的基向量)。
这意味着一个由三元元组(2, 3, 4)组成的点可以如下表示:
至此,我们掌握了“点在三维空间”的抽象概念,以及使用四个分离的对象来组合表示。这种类型的定义对于将任何概念转换为代码都是非常重要的。
2.2、互相垂直(Mutually Perpendicular)
我们使用的坐标系具有互相垂直的重要属性。这是说任何两个坐标轴互为90度。
这里使用的坐标系同样被定义为右手坐标系。
可用如下数学公式表示:
X = Y * Z
其中,*表示向量叉乘操作。
假如你不了解什么是叉乘,它可以通过如下公式进行定义(假设给定两个三元元组):
上面的公式看起来是乏味的,但是稍后它将给我们更容易的提供多种不同的计算和变换。幸运的,在构建一个游戏引擎时,你不需要记住所有的这些公式,你可以从这些公式中进行简单的构建,然后在此之上构建稍微复杂的系统。除非你要在你的引擎中编辑一些基本的内容,或者是你要更新引擎的所有。
3、点和向量
在掌握了这些基本的坐标系知识之后,是时候来讨论点和向量了,更重要的是讨论它们之间是如何影响的。要注意的第一个事情是:点和向量是表示不同的东西的。一个点是表示空间中的一个实际位置;一个向量是两个点之间的空间。
要确保不要混淆上述内容,使用大写斜体字表示点,例如P,使用大写粗体字表示向量,例如V。
当使用点和向量时,有两个重要的公里:
公理1:两个点的差表示为一个向量,例如V = P – Q
公理2:点和向量之和为一个点,例如Q = P + V
提示:公理是不需要证明的推论。
4、构建引擎
在上述公理之后,我们有足够的信息来创建三维游戏引擎中重要的基本类:类Point和类Vector。如果想要使用这些信息来构建自己的引擎,会有一些其它重要的步骤要执行(多数情况是优化和处理已有的API函数,译者注:例如使用现有的图形绘制引擎OSG等),但是为了简单起见,我们跳过这些。
下面这些是伪代码,你可以根据这些进行有选择的编程,下面是两个类的概要。
下面是一个示例程序:
5、结论
恭喜你看到文章最后,我们将看起来可怕的数学转化为两个清楚的类。在大多数情况下,你都没必要工作在游戏引擎的这个层级,但是对它有清楚的认识对于你的游戏引擎是很有帮助的。
如果你认为这篇文章是有趣的,那么请查看我的下一篇关于图形系统的基础教程:变换。