在进行3D编程的时候, 需要知道一些基础的数学知识. 我做了一些整理, 希望对大家有用. 因为只是一些重点的整理, 很多内容不是连续的. 如果希望更进一步的理解, 还是去看相关图形学的书比较好.
1: 3D游戏渲染的原理.
2D游戏的图像很容易理解, 一副副图片以各种方式排列在一起就OK了.
3D游戏的图像稍微复杂一些:
首先需要使用数学方法构建一个世界. 这个世界不是真实存在的, 而且也不是直接可见—因为它们就是一对数字. 然后选取观察点(Camera)和观察窗口(视窗), 根据各种数学方法, 计算出从观察点(camera)应该看到的图像. 然后显示出来.
渲染结果: 从相机这一点看到的图像—当然, 它们不是真实存在的, 而是计算得出.
2: 屏幕坐标系(2D)与3D坐标系
首先是屏幕坐标系. 计算机的显示屏幕是2D的. 不管玩的是2D游戏, 还是3D游戏.
而且需要注意的是, 屏幕坐标系中左上脚为原点(0, 0). 向右, 向下延伸. 在做GUI相关编程时需要注意这一点.
之后是3D坐标系. 首先3D坐标系与2D坐标系有一个重要的不同, 就是有两个3D坐标系: 左手坐标系和右手坐标系.
(而2D坐标系只有一个: 不管将2D坐标系画成什么样子, 总可以根据旋转, 将它们重合. 也就是所有2D坐标系都是等价的. )
可以看到, 左手坐标系不管怎么旋转, 都不可能与右手坐标系重合. 但是左手坐标系之间, 或者右手坐标系之间是等价的. 所以3D的世界中有两种坐标系. 它们之间没有任何优劣之分. DirectX使用左手坐标系, OpenGL和OGRE中使用右手坐标系. 搞错坐标系的话, 会出现位置不对等奇怪现象, 需要注意.
3: 多坐标系
游戏编程中, 最常见的有三种坐标系: 世界坐标系, 物体坐标系, 相机坐标系. (还有一个是惯性坐标系, 游戏中不常用, 就不提了.)
A: 世界坐标系描述的是绝对位置, 也叫作全局坐标系或者宇宙坐标系.
对应Global Position.
B: 物体坐标系是以某个物体的中心为原点的坐标系.
对应Local Position
一般物体自转的话, 一定要在物体坐标系中作.
C: 相机坐标系. 相机坐标系就是以相机为原点的坐标系. 其实它是一个特殊的物体坐标系. (相机也是一个物体)
另外, 左手坐标系中, +Z为观察方向; 右手坐标系中 –Z为观察方向.
在手动计算位置(各种Debug)的时候, 非常重要.
为什么要引入这么多坐标系? 其实就是为了处理简单. 具体原因的话参考相关书籍, 使用中记住有这么三种重要的坐标系就OK了.
4: 向量, 矩阵与变换
向量&矩阵的定义和运算, 请参考线性代数教科书.
这里主要介绍3D引擎中经常出现的4D矩阵.
它的写法是:
其中的R代表旋转部分, T代表平移部分. 旋转的R部分比较复杂,请参考专业书籍; T的换比较简单X,Y,Z分别代表在X轴, Y轴, Z轴上的平移量.
如果在3D引擎中看到一个4*4矩阵, 那么很大的可能是以上形式的矩阵.
3D引擎中的变换主要包括平移, 旋转, 缩放, 投影, 镜像变换等. 其中投影又包括正交投影和透视投影.
5: 方位(Orientation)与角位移
3D引擎中处理最多的, 应该就是平移与旋转了. 上边的4D矩阵定义中也可以发现, 就有2块: 旋转和平移. 平移的话比较简单, 沿着X, Y, Z移动的量构成了这个物体在3D空间中的平移. 旋转的话, 就非常复杂了. ( 至少我这么想-_-)
首先, 需要明确一下概念: 方向(Direction)与方位(Orientation).
一开始可能比较难区分这两个概念…..其实搞清除了也简单, 方位(Orientation)是方向(Direction)加自转.
两架飞机. 它们都沿着同一个方向飞行. 假设是北(N).
它们的方向虽然相同, 但它们的方位不同. 第二架飞机相比第一架飞机, 自转了90度.
方位的概念.
描述物体位置时, 必须指定一个原点, 位置是相对于原点的偏移量.
同样, 描述方位时, 也必须指定一个已知方位(起始方位), 相对已知方位的旋转的量就是这个物体的方位. 这个旋转的量叫做角位移.
(概念上虽然不同, 角位移的值与方位的值时一样的. 类似与偏移量与位置的关系)
3D引擎中有三种方法表示方位: 矩阵, 欧拉角, 四元数.
通常情况下, 用矩阵和四元数表示角位移(用于计算); 用欧拉角表示方位(用于人来查看).
(这部分十分绕, 反正我理解的时候累死了无数脑细胞…大家慢慢琢磨吧)
A: 欧拉角
要想知道一个物体的方位, 那么只要知道它与X, Y, Z轴之间的夹角就可以了.
对人来说, 这是最直观也是最简洁的方式. 相对于各个轴的夹角被命名
为Roll-Pitch-Yaw. (也有一种Heading-Pitch-Bank的命名法, 不过与惯性坐标系相关,
于是忽略掉)
Roll(Bank) 与Z轴的夹角
Pitch 与X轴的夹角
Yaw(类似Heading) 与Y轴的夹角
欧拉角优点是简洁(只有三个数), 便于人理解; 但缺点是不方便计算.
于是有了以下两种表示方法.
B: 矩阵
矩阵数字最多, 3*3一共9个. 概念也比较简单, 直接作乘法就可以了.
但缺点就是需要存储的数字多.
C: 四元数
个人以为这个是最难理解的概念之一… 但是它的优点就是比较简洁(四个数),
而且便于计算, 尤其是插值运算. 四元数的诞生还有一段有趣的小故事,
有兴趣的同学可以趣看看.
一个四元数包括一个标量分量和一个3D向量分量. 一般记为[w, v] = [w, x, y, z].
四元数通过以下方式应用于3D引擎中.
首先是概念基础: 一个旋转序列(也就是很多个旋转)等价于一个单个旋转. -> 也就是
任何角位移都能表示为 绕单一轴的单一旋转. 这个轴叫做旋转轴, 它可以是任意方向.
然后是四元数记法: 设 n 为旋转轴, a 为旋转角, 那么四元数
Q = [ cos(a/2), sin(a/2)*n ] = [ cos(a/2), sin(a/2)*nx, sin(a/2)*ny, sin(a/2)*nz ]
注意, 角的值a与轴的方向x,y,z都没有直接出现. 都经过了三角函数的换算.
(这样作是为了方便插值运算, 不过…嗯, 随便吧, 写一遍都觉得累. 至少知道里边的
值是经过三角函数变换的. 如果直接拿出来当角度值, 那就窘了.)
另外, 只用单位四元数(模为1)来表示方位.
这三种表现方式之间是可以互相转换的. 给一个最简单的: 四元数到欧拉角
Pitch角 = asin(-2(yz + wx))
Yaw角 = atan2(xz – wy, 1/2 – x^2 - y^2) cos(pitch角) != 0
= atan2(xz – wy, 1/2 – y^2 - z^2) cos(pitch角) == 0
Roll角 = atan2(xy – wz, 1/2 – x^2 - z^2) cos(pitch角) != 0
= 0 cos(pitch角) == 0
其他n长的转换公式大家自己找图形学书. 其实看看就行, 知道有这么回事儿就可以. 在图形引擎中已经将这些东西都实现好了. 一般还是会用是最终目标.
----------- Fin -----------