引言
本章由乔晨老师介绍游戏玩法开发,他目前在腾讯魔方工作室。本章内容主要讲解实时图形渲染管道,包括宏观渲染系统以及各个阶段。
宏观渲染系统
在我们之前没有游戏、没有计算机的时候是怎么画一幅画的。当然山水画、国画其实可能没有很多严格的透视规则,所以我们来参考一下西方的绘画。在中世纪的时候,我们发现他们诞生了很多有非常正确透视规则的绘画,这些绘画其实并不是只靠一支笔一张纸完成的,它们是有专门的结构的。
这是 Durer 的一幅画《绘画鲁特琴的人》,这幅画我们可以看到画师会有专门的结构去打点,现在的人也把这个在博物馆里复刻出来。
图形渲染
物体在视网膜产生的颜色主要是靠光线的计算,从二维、三维模型产生图像(Image)使用渲染方程(The Rendering Equation)。渲染方程其实很简单:我们在一点上看到的出射光线等于它本身发射的光线和反射的光线。
在游戏中也有很多复杂的光源,包括环境光、灯光等等。
我们假设每个像素上面的结构由微表面组成,微表面结构表示物体的粗糙或者光滑程度。这样我们可以比较好的实现一些不同粗糙度、不同变化的材质表现。
该模型的主要缺点是不能表现使用高度图表现的材质,例如衣料的绒毛或者一些织物,它的内部结构比较特殊。
传统的电影渲染和离线渲染会使用光线追踪的方式,从观察者的视角发射光线出去,再看打到物体的光照结果。这两年随着 GPU 性能提高和 AI 降噪技术的完善我们逐渐可以实时使用这种方式。
比较陈旧的方式诸如 OpenGL 或 DirectX 则使用光栅化方式,相当于打格子画三角形。
这其实就是光线追踪追出来的结果,它可以很好的表现光的折射、反射等光照效果,也是光栅化方式很难实现的。(顺带一提,这幅图是雪莉光线追踪三部曲小书中的第一本最后的渲染结果,本站也有翻译:Ray Tracing in One Weekend)
但光线追踪的问题在于它收敛的比较慢。如果想让渲染质量提高一倍,可能发射的光线数量需要提高四倍,目前的 AI 降噪让实时化变为可能。
画家算法
画家算法就是以前人画油画的方式,首先绘制远山,然后绘制较近的草地,最后绘制场景中最近的树木。但是画家算法无法处理相互重叠的多边形(自遮挡)。
深度缓冲
实时图形管线一般使用带有深度缓冲进行绘制。
不同平台情况
什么是管线/管道
生产流水线/管线是第二次工业革命的标志性发明之一,在游戏的渲染系统中同样有高效的渲染管线。
- 应用阶段:找出场景中需要渲染的物体,将这些物体的图元提交到 GPU
- 几何阶段:处理和变换几何图元
- 光栅阶段:把几何形状光栅化,计算每个像素的输出颜色
应用阶段
应用阶段可以拆分为:
- 可见性检测
- 分组和排序
- 提交图元
场景管理
场景图(Scene Graph)组织场景中的物体如:摄像机、光源、网络、骨骼等等。
我们需要空间分割技术来逐级切分找到场景中需要更新的物体。这种加速的场景查询需要一些数据结构来帮助:
- 二元空间分割(binary space partition,BSP)
- 八叉树(octree)
- 入口(portal)/反入口(anti-portal)
可见性检测
场景节点下挂载一些逻辑节点,通过这种方式来组织场景,但这种场景未必对渲染友善。
可见性检测(visibility determination)找出摄像机可看的渲染物体:
- 平截头体剔除(view frustum culling)
- 遮挡剔除(occlusion culling)
- 细节层次剔除(level-of-detail/LOD culling)
对于投影阴影的光源,也需要从光源角度找出可见的阴影投射物体。
平截头体只渲染摄像机视角范围内的物体,不考虑视角外的物体。在此过程中还需要剔除被遮挡的物体,即遮挡剔除。
LOD 就是对细节有不同的等级,实际制作中会根据距离灵活选择细节等级。
一般情况下我们需要按照渲染层进行分组,对于不透明物体由近及远绘制;对半透明物体用画家算法由后往前绘制。
但是两个物体不一定有全序关系,仅仅排序是不够的,需要使用次序无关透明技术。(Order Independent Transparency, OIT)
提交图元(primitive)就是所谓的 drawcall,由应用阶段输出数据给接下来的阶段,提交前需要设置图元数据和渲染状态。
图元数据定义了将要绘制的物体由哪些顶点组成,这些顶点的位置、法相、UV、相对索引关系等等。
几何阶段
输入装配
输入装配(input assembler)根据图元的拓扑类型及顶点格式读取 VB、IB 生成三角形的顶点数据。
顶点着色
顶点着色对每一个顶点执行顶点着色器(vertex shader),输入一个顶点的属性计算变换、纹理坐标、顶点光照等内容,输出顶点的裁切空间坐标(必须),纹理坐标(可选)等信息。
几何图元的顶点通常定义于模型空间,经过一连串变换得到屏幕空间的坐标:
- 模型空间(model space)
- 世界空间(world space)
- 观察空间(view space)
- 齐次坐标空间(homogeneous clip space)
- 屏幕空间(screen space)
朝向剔除
三角形裁剪
裁剪计算
透视除法及视区变换
光栅化阶段
扫描转换
像素是离散的,而我们的计算结果是浮点连续的,所以我们需要把连续的数据映射到离散的数据上去,游戏中的锯齿就是在这个过程中产生。
像素着色
扫描转换之后进行像素着色,决定屏幕每一点的颜色。