《游戏编程算法与技巧》渲染篇
闲话
近日读完了《游戏编程算法与技巧》这本书。更感觉是《游戏引擎架构》的缩略图。先阅读此书会对游戏开发有一个整体的认识与理解。适合需要了解游戏开发的初学者阅读
此书对于我也是梳理游戏开发知识点的概括好书。对于此书会在重点部分做提炼。
渲染基础
此部分只做简单的总结,网上已经有很多的好文章了。而此书作者也没有很详细的写这部分。毕竟这块要是讲细了够学一辈子了
推荐一些好文(有兴趣可以看看我写的软渲染)
双缓冲技术解决渲染撕裂
CRT显示器时代,所谓场消隐期(VBLANK):喷枪从右下角移动到左上角所花费的时间
渲染撕裂:显示器在绘制像素缓冲区中的内容时,游戏输出了新的渲染结果到像素缓冲区,导致渲染撕裂
双缓冲技术:解决屏幕撕裂,用两块像素缓冲区,游戏交替的在这两块缓冲区中绘制
垂直同步:让交换缓冲区的时机在场消隐期进行
三缓冲技术:利用3个缓冲区,让画面更加平滑,但增加输入延迟
画家算法
所有物体按照从后往前的顺序绘制。优点:绘制绝对正确(包括透明物体),缺点:overdraw高,效率慢
3D渲染
为什么用三角形表示面片?
- 仅用3顶点表示的最简单的多边形
- 三角形总在一个面上
- 任何3D对象都可以简单地用细分三角面表示
网格:多个三角面组成
软件光栅化
将3D模型正确渲染到2D颜色缓冲的算法
3D模型经过4个主要坐标系空间转到最终的2D颜色缓冲中
- 模型(局部)坐标系:相对于模型自身的坐标系(角色模型一般为两脚中间)
- 世界坐标系:所有对象都相对于世界原点偏移
- 视角(摄像机)坐标系:将世界坐标系的模型变换到相对于摄像机的位置上
- 投影坐标系:将3D场景平铺到2D平面上得到的坐标系
除了上面的坐标系外,还有一个特殊的坐标系,就是齐次坐标系
将4D坐标系应用在3D空间中,就被称为齐次坐标系。而第四个分量为w分量。如果w=0,则此齐次坐标是3D向量。而w=1,则表示此齐次坐标是3D的点
矩阵变换
将模型在各个坐标系中转换所用的矩阵,就是矩阵变换。
此处和之后所用的都为行向量。(OpenGL为列向量)模型转世界坐标系
平移
将顶点移动一段距离,只作用在点上
$$ T(t_x,t_y,t_z) = \begin{bmatrix} 1 & 0 & 0 & 0 \newline 0 & 1 & 0 & 0 \newline 0 & 0 & 1 & 0 \newline t_x & t_y & t_z & 1 \end{bmatrix} $$
旋转
将顶点或向量相对于某个轴旋转(欧拉角旋转)
旋转矩阵是正交的,就是说转置矩阵就是逆矩阵$$ RotateX(\theta) = \begin{bmatrix} 1 & 0 & 0 & 0 \newline 0 & \cos \theta & - \sin \theta & 0 \newline 0 & \sin \theta & \cos \theta & 0 \newline 0 & 0 & 0 & 1 \end{bmatrix} $$
$$ RotateY(\theta) = \begin{bmatrix} \cos \theta & 0 & \sin \theta & 0 \newline 0 & 1 & 0 & 0 \newline - \sin \theta & 0 & \cos \theta & 0 \newline 0 & 0 & 0 & 1 \end{bmatrix} $$
$$ RotateZ(\theta) = \begin{bmatrix} \cos \theta & - \sin \theta & 0 & 0 \newline \sin \theta & \cos \theta & 0 & 0 \newline 0 & 0 & 1 & 0 \newline 0 & 0 & 0 & 1 \end{bmatrix} $$
缩放
$$ S(s_x,s_y,s_z) = \begin{bmatrix} s_x & 0 & 0 & 0 \newline 0 & s_y & 0 & 0 \newline 0 & 0 & s_z & 0 \newline 0 & 0 & 0 & 1 \end{bmatrix} $$
按行矩阵应用矩阵变换,乘积的顺序应为:$ model2world = scale * rotation * translation $
应先旋转在平移,因为旋转是相对于原点的,先旋转对象可自转。而后旋转则对象就是相对于世界坐标系原点旋转了。观察矩阵(Look-At)
$L$表示左边或x轴,$U$表示上方或y轴,$F$表示前方或z轴,$T$则是摄像机的平移
$$ LookAt = \begin{bmatrix} L_x & U_x & F_x & 0 \newline L_y & U_y & F_y & 0 \newline L_z & U_z & F_z & 0 \newline T_x & T_y & T_z & 1 \end{bmatrix} $$
1Matrix4x4 LookAt(Vector3 eye, Vector3 target, Vector3 Up) {
2 Vector3 F = normalize(target - eye);
3 Vector3 L = normalize(cross(Up, F));
4 Vector3 U = cross(F, L);
5 Vector3 T;
6 T.x = -dot(L, eye);
7 T.y = -dot(U, eye);
8 T.z = -dot(F, eye);
9
10 //创建并返回观察矩阵
11 //...
12}
投影坐标系
正交投影
$$ Orthographic = \begin{bmatrix} \frac{2}{width} & 0 & 0 & 0 \newline 0 & \frac{2}{height} & 0 & 0 \newline 0 & 0 & \frac{1}{far - near} & 0 \newline 0 & 0 & \frac{near}{far - near} & 1 \end{bmatrix} $$
透视投影
$$ Perspective=\begin{bmatrix} \cot \frac{fov}{2} & 0 & 0 & 0 \newline 0 & \frac{height}{width} & 0 & 0 \newline 0 & 0 & \frac{far}{far - near} & 1 \newline 0 & 0 & \frac{-near * far}{far - near} & 0 \end{bmatrix} $$
光照与着色
颜色
RGB颜色空间:将颜色分为红色,绿色和蓝色分量。
色深:每个像素用多少位来存储(大部分每分量都为8位来存储,就是说每位有256种可能,共大约1600万种不同颜色)
不透明度(用A表示,从而组成RGBA,一共32位)
顶点属性
模型顶点上存储的额外信息
- 纹理映射:将2D图片映射到3D的三角形中
- UV坐标:纹理的x坐标为u,y坐标为v
- 顶点法线:产生凹凸感
- 将拥有该顶点的三角形的法线取平均值,用于平滑模型(如圆形)
- 每个顶点存储自己的法线方向,用于棱角清晰的模型(如四边形)
顶点序:顶点的顺序,用于决定叉乘的值向量的朝向,保持全程一致就可。还可用于背面剔除
光照
- 环境光:添加到场景中每一个物体上固定的光
- 方向光:没有位置,只指定光照方向的光
- 点光源:从某个点向四面八方射出的光照
- 聚光灯:将点光源限制在锥体内有光
Phong光照模型公式:
- 漫反射:光源作用于物体表面的主要反射。被所有方向光,点光源和聚光灯影响。
- 高光:物体表面的闪光点
1// N = 物体表面法线
2// eye = 摄像机位置
3// pos = 物体表面位置
4// a = 高光量
5Vector3 V = normalize(eye - pos);
6Vector3 Phong = AmbientColor; // 环境光
7foreach Light light in scene // 循环场景中所有的灯光
8 Vector3 L = normalize(light.pos - pos); // 从物体表面到光源
9 Phong += DiffuseColor * dot(N, L); // 漫反射光照强度
10 Vector3 R = normalize(reflect(-L, N)); // 计算-L关于N的反射
11 Phong += SpecularColor * pow(dot(R, V), a); // 高光强度
着色方式
- 平面着色:每个三角面只用一种颜色
- Gouraud着色:通过顶点颜色插值填充(多边形数量越多越好)
- Phong着色:逐像素光照,针对每个像素单独计算
深度缓冲区
为场景的每个像素存储数据,与颜色缓冲一样,不过存储的是像素到摄像机的距离(深度)
在每一帧渲染前会清空深度缓冲区(让所有像素无限远)。渲染过程中,深度会在像素着色器渲染前计算出来。如果比当前深度小,则绘制并写入新的深度
透明对象的绘制
透明对象不适用于深度缓冲,如果透明物体比不透明物体深度浅,如果先画透明物体,则不透明物体就不会被绘制了
为了解决此问题,应用深度测试先画所有的不透明物体,然后关闭深度测试,渲染所有透明物体。确保不透明物体背后的对象不进行渲染仍需进行深度检查
大多数会采用24位或32位的深度缓冲区
怎么解决像素重绘问题? 先绘制深度pass,然后按照所得的深度缓冲结果计算光照pass
利用剔除或者遮挡算法可消除在某些帧完全看不到的对象。类似的算法有二叉树分区算法(BSP),人口算法和遮挡体积等。
(完)