3D游戏引擎笔记

  • 2 评论

1 数学知识

1.1 坐标系

分为左手坐标系和右手坐标系两种,主要区别在于z轴的指向,z轴指向屏幕内的是左手坐标系,z轴指向屏幕外的右手坐标系。UnityDirect3D使用的是左手坐标系,OpenGL使用的右手坐标系。

法线和切线

与椭圆有且仅有一个交点的直线,叫做椭圆的切线。二者公共点,叫做切点。

经过切点且与切线垂直的直线,叫做该椭圆的法线。

1.2 三角学

  • 整个圆周为360度(2\pi弧度),因此180度等于\pi弧度,约57.296度等于1弧度。三角函数sin和cos的参数以弧度为单位,而不是度。
  • 三角形的三个内角之和为180度(\pi弧度)。
  • 正弦 sin(x) = 对边/斜边 = y/r。定义域为 0 <= x <= 2\pi,值域为-1到1。
  • 余弦 cos(x) = 邻边/斜边 = x/r。定义域为 0 <= x <= 2\pi,值域为-1到1。
  • 正切 tan(x) = 对边/邻边 = y/x = 斜率 = M。定义域为 –\pi <= x <= 2\pi,值域为负无穷大到正无穷大。

1.3 向量

向量表示的是一条从一个点到另一个点的有向线段。向量是所有3D引擎算法的基础。

向量长度

是从原点到向量表示的终点的距离,具体来说是各个分量平方和的平方根。公式如下

|u| = sqrt(u_x^2 + u_y^2 + u_z^2)

归一化

归一化(normalize)就是使向量长度为1,同时方向保持不变。计算公式为向量除以其长度,如下

u’ = u / |u|

顶点和向量的区别

顶点和向量都用一个三元组(x, y, z)表示。但顶点表示的是空间中的位置信息,在变换时可以被扩展为齐次坐标(x, y, z, w),这时w通常为1。而向量表示的是一个方向,即从原点到(x, y, z)的方向,没有位置属性,它的齐次坐标(x, y, z, w)中,w为0。

向量加法

向量加法是指两个向量的分量相加。几何学表示为以两个向量的边为平行四边形的长边对角线。在游戏中常用于寻找目标的逻辑,例如,玩家坐标是V0(x_0, y_0, z_0),怪物坐标是V1(x_1, y_1, z_1),为了让玩家自动向怪物移动,首先要确定移动方向,表示为dir=(V0-V1).Normalized,因为方向没有大小,故进行单位化操作。接下来让玩家根据时间移动到怪物位置,表示为V=V0+dir*time。这样就利用两个向量的加法实现了位置移动。

向量减法

向量减法和加法相反,是指两个向量的各个分量相减,几何学表示为以两个向量的边为平行四边形的短边对角线。主要应用在方向的计算,以及判断两个物体间的距离。

向量点积

点积将各个分量分别相乘后相加,得到一个标量,而不是保持向量形式。定义如下

u \cdot v = u_x * v_x + u_y*v_y

点积还有一种表达式:

u \cdot v = |u| * |v| * cos(\theta)

即u和v的点积等于向量u的长度乘上向量v的长度,再乘以它们之间夹角的余弦。上述两个表达式结合在一起,提供了一种计算两个向量之间夹角的方法,进而可推导出一些规律。

  • 如果向量u和v之间的夹角为90度,则u \cdot v = 0
  • 如果向量u和v之间的夹角小于90度(锐角),则u \cdot v > 0
  • 如果向量u和v之间的夹角大于90度(钝角),则u \cdot v<0
  • 如果向量u和v相等,则u \cdot v = |u|^2 = |v|^2

在计算机图形学和游戏编程中,点积的重要用途之一是计算向量在给定方向上的分量(投影)。计算u在v上投影的公式如下

Proj_v u = \displaystyle \frac{(u \cdot v) * v}{|v| * |v|}

向量叉积

假设向量u=<ux, uy, uz>, v=<vx, vy, vz>,则叉积定义为

u \ast v = <uyvz – vyuz, -uxvz + vxuz, uxvy – vxuy>

在三维几何中,向量叉积的结果是法线向量,该向量垂直于向量u和v构成的平面。

叉积有多种应用。

  1. 判断两向量相互之间的顺逆时针关系
  • u \ast v>0,则u在v的顺时针方向;
  • u \ast v<0,则u在v的逆时针方向;
  • u \ast v=0,则u与v共线,但可能同向也可能反向;
  1. 判断是凸多边形还是凹多边形。以两条边作为向量进行叉乘
  • 如果全部大于或等于零,则是凸多边形;
  • 如果全部小于零,则是凹多边形;
  • 如果全为零,则是所有边共线;
  1. 判断点是在线的上方还是下方
  2. 判断点是否在矩形内部

1.4 矩阵

单位矩阵

单位矩阵的定义是:主对角线上所有元素都为1,其他元素为0。例如

\left[ \begin{matrix} 1&0&0\\0&1&0\\0&0&1 \end{matrix} \right]

单位矩阵必须是方形的,即维数为m*m,其中m>=1。

零矩阵

是一个m*n矩阵,所有元素都为0。

矩阵加法和减法

唯一规则是:两个矩阵必须有相同的维数。

矩阵乘法

要将两个矩阵相乘,它们的内维数必须相等。例如A为m*n矩阵,则B必须为n*r矩阵,其中m和r可以相等,也可以不相等。

矩阵乘法不满足交换律,即(AB) \neq (BA)。

逆矩阵

如果矩阵A*A^{-1}=I,其中I是单位矩阵,则称矩阵A可逆,且A^{-1}为矩阵A的逆矩阵。

单位矩阵的逆矩阵是它自身。

平移矩阵

M_t=\left[ \begin{matrix} 1&0&0&0\\0&1&0&0\\0&0&1&0\\dx&dy&dz&1 \end{matrix} \right]

缩放矩阵

M_s=\left[ \begin{matrix} sx&0&0&0\\0&sy&0&0\\0&0&sz&0\\0&0&0&1 \end{matrix} \right]

旋转矩阵

绕z轴旋转

M_z=\left[ \begin{matrix} cos\theta&sin\theta&0&0\\-sin\theta&cos\theta&0&0\\0&0&1&0\\0&0&0&1 \end{matrix} \right]

绕x轴旋转

M_x=\left[ \begin{matrix} 1&0&0&0\\0&cos\theta&sin\theta&0\\0&-sin\theta&cos\theta&0\\0&0&0&1 \end{matrix} \right]

绕y轴旋转

M_y=\left[ \begin{matrix} cos\theta&0&-sin\theta&0\\0&1&0&0\\sin\theta&0&cos\theta&0\\0&0&0&1 \end{matrix} \right]

2 固定流水线

简单来说,固定流水线就是将3D图形转换成屏幕上的2D图像显示的过程。

标准化设备坐标,是指x,y,z的值都在(-1, 1)的范围内。

2.1 局部坐标到世界坐标的变换

不同的3D模型需要放到同一个世界坐标系展示,这个过程就称为局部坐标到世界坐标的变换,也就是将每个物体的中心平移到世界空间中所需的位置。算法很简单,把模型的所有顶点乘以平移矩阵,结果即是世界坐标。

2.2 世界坐标到相机坐标的变换

3D游戏总是围绕着3D相机进行,要观察某个物体,就需要将物体放到相机视口里。不管是将相机靠近物体,还是将物体移动到相机里,都需要把物体从世界坐标系变换到以相机为原点的相机坐标系,这个过程称为世界坐标到相机坐标的变换。

主要包含旋转和平移两个步骤。

2.3 物体剔除和裁剪

在世界坐标到相机坐标的变换中,还要把不在视角内的物体剔除掉(从性能效率上考虑也必须这样做),以免错误地渲染它们,或者说避免进行相机变换。

首先剔除物体,然后对余下的可见物体,剔除其背面。

2.3.1 背面消除

即背对相机的物体背面不参与绘制,直接裁剪掉,以排除尽可能多的多边形。

2.3.2 包围球测试

创建一个将物体包围起来的球体,判断该球体是否在相机内,如果整个不在,则直接丢弃。如果部分在,则后续做进一步的测试。

2.4 相机坐标到透视坐标的变换

每个相机对应着一个视景体,视景体分为三部分:视平面、近裁剪面、远裁剪面,只有位于近裁剪面和远裁剪面之间的物体才是可见的,3D物体投射到视平面上,这个过程称为相机坐标到透视坐标的变换。

2.5 透视坐标到屏幕坐标的变换

视平面上的物体最终都要展现在屏幕上,不管是PC端还是移动端,实际屏幕坐标和虚拟的视平面坐标都是不一样的,所以需要执行平移、缩放、反转等操作,这个过程称为透视坐标到屏幕坐标的变换。

2.6 光栅化

光栅化就是对物体上色,最终以可见图像的方式在屏幕上显示出来。

欢迎关注微信公众号“楚游香”,获取更多文章和交流。

标签:

《3D游戏引擎笔记》有2个想法

  1. 最后一条对光栅化的理解跟我自己的理解有点出入。光栅化不是上色,是将矢量化的几何数据像素化,在屏幕中显示出来。

发表回复

您的电子邮箱地址不会被公开。