实时图形渲染管道

引言

本章由乔晨老师介绍游戏玩法开发,他目前在腾讯魔方工作室。本章内容主要讲解实时图形渲染管道,包括宏观渲染系统以及各个阶段。

宏观渲染系统

在我们之前没有游戏、没有计算机的时候是怎么画一幅画的。当然山水画、国画其实可能没有很多严格的透视规则,所以我们来参考一下西方的绘画。在中世纪的时候,我们发现他们诞生了很多有非常正确透视规则的绘画,这些绘画其实并不是只靠一支笔一张纸完成的,它们是有专门的结构的。

这是 Durer 的一幅画《绘画鲁特琴的人》,这幅画我们可以看到画师会有专门的结构去打点,现在的人也把这个在博物馆里复刻出来。

图形渲染

物体在视网膜产生的颜色主要是靠光线的计算,从二维、三维模型产生图像(Image)使用渲染方程(The Rendering Equation)。渲染方程其实很简单:我们在一点上看到的出射光线等于它本身发射的光线和反射的光线。

在游戏中也有很多复杂的光源,包括环境光、灯光等等。

我们假设每个像素上面的结构由微表面组成,微表面结构表示物体的粗糙或者光滑程度。这样我们可以比较好的实现一些不同粗糙度、不同变化的材质表现。

该模型的主要缺点是不能表现使用高度图表现的材质,例如衣料的绒毛或者一些织物,它的内部结构比较特殊。

传统的电影渲染和离线渲染会使用光线追踪的方式,从观察者的视角发射光线出去,再看打到物体的光照结果。这两年随着 GPU 性能提高和 AI 降噪技术的完善我们逐渐可以实时使用这种方式。

比较陈旧的方式诸如 OpenGL 或 DirectX 则使用光栅化方式,相当于打格子画三角形。

这其实就是光线追踪追出来的结果,它可以很好的表现光的折射、反射等光照效果,也是光栅化方式很难实现的。(顺带一提,这幅图是雪莉光线追踪三部曲小书中的第一本最后的渲染结果,本站也有翻译:Ray Tracing in One Weekend

但光线追踪的问题在于它收敛的比较慢。如果想让渲染质量提高一倍,可能发射的光线数量需要提高四倍,目前的 AI 降噪让实时化变为可能。

画家算法

画家算法就是以前人画油画的方式,首先绘制远山,然后绘制较近的草地,最后绘制场景中最近的树木。但是画家算法无法处理相互重叠的多边形(自遮挡)。

深度缓冲

实时图形管线一般使用带有深度缓冲进行绘制。

不同平台情况

什么是管线/管道

生产流水线/管线是第二次工业革命的标志性发明之一,在游戏的渲染系统中同样有高效的渲染管线。

  1. 应用阶段:找出场景中需要渲染的物体,将这些物体的图元提交到 GPU
  2. 几何阶段:处理和变换几何图元
  3. 光栅阶段:把几何形状光栅化,计算每个像素的输出颜色

应用阶段

应用阶段可以拆分为:

  • 可见性检测
  • 分组和排序
  • 提交图元

场景管理

场景图(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),输入一个顶点的属性计算变换、纹理坐标、顶点光照等内容,输出顶点的裁切空间坐标(必须),纹理坐标(可选)等信息。

几何图元的顶点通常定义于模型空间,经过一连串变换得到屏幕空间的坐标:

  1. 模型空间(model space)
  2. 世界空间(world space)
  3. 观察空间(view space)
  4. 齐次坐标空间(homogeneous clip space)
  5. 屏幕空间(screen space)


朝向剔除

三角形裁剪

裁剪计算

透视除法及视区变换


光栅化阶段

扫描转换

像素是离散的,而我们的计算结果是浮点连续的,所以我们需要把连续的数据映射到离散的数据上去,游戏中的锯齿就是在这个过程中产生。

像素着色

扫描转换之后进行像素着色,决定屏幕每一点的颜色。

输出合并

写入渲染目标


总结

前向管线与延迟管线

作业