游戏渲染的挑战
- 一个场景包含成千上万的GO需要的材质、shader、效果都不尽相同,因此
复杂度极高
- 当代各种硬件的适配难度高,硬件架构一直在变化
- 高帧率、高分辨率的要求下,使得绘制算法绘制一帧的时间越来越短,
算法效率要求高
- 绘制系统可以100%的使用显卡,但CPU只能使用一小部分,因为CPU还要处理游戏逻辑、网络、动画、物理、AI等计算
1、光栅化流程
光栅化主要流程
- 顶点属性输入(位置、法线、纹理坐标等)
- MVPV变换、裁剪、透视除法后得到每个顶点在屏幕空间的坐标(范围
(
0
,
0
)
→
(
w
i
d
t
h
,
h
e
i
g
h
t
)
(0,0)\to(width,height)
(0,0)→(width,height)),主要由
顶点着色器
完成 - 光栅化:根据顶点位置采样出三角形所覆盖的像素,交给像素着色器处理
-
像素着色器
中对每个像素进行着色计算(纹理映射、光照计算、后处理等)。 - 输出像素着色器的计算结果
2、一丢丢显卡知识
SIMD:单指令多数据的数学运算,渲染中有大量的向量、矩阵运算,因此SIMD是非常重要的(CPU GPU都可)
SIMT:单指令多线程,一条指令可以在多个核上做同样的运算
SIMD+SIMT可以让计算速度比单指令单数据快很多。如:一个加法指令c = a + b
,在100个核心上同时进行,每个核心又是4个分量同时计算,则速度快400倍
CPU与GPU的数据交换非常的慢,因此衍生出几个原则
- 尽可能单向、批量从CPU向GPU传输数据
- 尽可能不要从GPU中读取数据
Cache的重要性
- 越大的缓存越能减少Cache Miss
- 如果出现Cache Miss,再去内存中取该数据的代价是100多个时钟周期
3、网格绘制组件(Mesh Render Component)
逻辑上的GO是由多个不同的组件组合起来的,其中一个让这个GO变得可见的组件叫 网格绘制组件
。
Mesh包含哪些东西?
- 一个顶点数组(位置、法线、UV坐标)
- 索引缓存(D3D中叫index buffer,opengl中叫EBO)。参考这篇文章EBO部分描述
为什么每个顶点都要定义法线?
- 首先如果不逐顶点定义法线,那么在后面的计算中,需要用到法线时,应该根据该顶点周围的三角面的法线求平均得到,而三角面的法线是通过两个边
叉乘
得出,这样会产生一个问题如下左图所示。面的交接线处的顶点法线是斜着的,这样计算着色就会出问题,但看cube的任何一个表面,表面周围的法线有了梯度
,根据这样插值出来的法线逐像素着色计算完成后,这个边就不硬
!尽管我们的模型是方方正正非常硬的,但他着色后就看起来不硬 -
因此每个顶点定义法线就很重要,右图所示交界处顶点有2、3个法线的是同一个空间位置定义多个顶点的结果。这样有极大的灵活性,想硬就硬,想软也能软,改变顶点的法线即可
4、材质
- Phong Model:Color = Ambient + Diffuse + Specular
- PBR Model:Physically Based Rendering,基于物理的渲染模型
-
Subsurface Material:微表面模型
现代的材质模型中,纹理(Texture)起着非常重要的作用,可以说是决定性作用
比如下面这个生锈的球是怎么表现出来的?
- 高光贴图:生锈部分没有高光,未生锈部分有高光
- 法线贴图:表现物体表面的细节
- 金属度贴图、粗糙度贴图、AO(环境光遮蔽贴图)
纹理/贴图:定义球面上每个点的属性
着色器(Shader)
- 首先 shader是一串代码,但是 在游戏引擎中,shader被当做跟纹理、模型一样的
数据
来使用 - 怎么理解?一个球模型、一堆贴图,再用一段shader,就能形成一个生锈铁球、毛线球、玻璃球等等不一样的球。
如何让一个对象的不同部位表现出不同的材质呢?
- 把模型不同部分应用不同的shader和纹理。一个物体还是对应一个顶点数组,但是我们可以定义不同的偏移量offset,将其分成不同的
子网格subMesh
,对每个submesh应用不同的shader和texture即可 - 总之Mesh要根据材质的不同进行切分,切分成一个个submesh,submesh与材质是一一对应的
课上讲的是 Mesh对应一个大的模型,sub mesh 对应这个模型的不同部位。现代引擎都是这个逻辑但是命名规则可能不同。有些是一整个模型叫Model,而一个Model由不同的Mesh组成。
5、资源池(Resource Pool)
如果游戏中有100个小兵GO,我们难道要为每个小兵都存储一套Mesh(几何模型)
和Material(纹理、shader)
?这样明显太浪费内存,因为所有的小兵Mesh、纹理、shader都是一样共用的,因此提出了 资源池
的概念。即同一个GO的Mesh、shader、Texture都分别用一个Resource Pool来管理,不同的实例(instance)只需要用指针去引用这些资源即可
根据材质来分类Submesh ,在绘制的时候,材质相同的submesh一起绘制,这种方法在工作量上并没有减少,但是速度会更快。因为不用频繁的更改GPU的状态,比如绘制一个小兵就要切换比如5次shader、绑定5次纹理、切换5次submesh几何数据。绘制下一个小兵又要重复这个过程,这样会非常慢。
GPU Batch Rendering
- 一个Draw Call 绘制一大批相同的submesh
- 就是通过将一些渲染状态一致的GO数据,一次提交给gpu进行绘制,这可以显著的节省drawcall,实际上这主要节省了cpu的时间,cpu从提交多次到提交一次,对gpu来说也不用多次切换渲染状态
6、Cluster-Based Mesh Pipeline
一个新的表达模型的管线,主要思想是:将高精度模型分成多个多个mesh块进行渲染。以前只能对单个物体进行可见性裁剪,现在能够对物体的mesh块进行裁剪。
UE5-Nanite系统文章来源:https://www.toymoban.com/news/detail-407622.html
- 在此基础上更往前走一步,走向商业化应用
7、渲染
-
渲染方程:详细介绍可参考计算机图形学【GAMES-101】8、辐射度量学与光线追踪
-
阴影:
- 阴影映射
- 软阴影01(Shadow Mapping、Peter Panning、PCSS原理超详细)
- 软阴影02(VSM、Moment Shadow Mapping、SDF距离场软阴影)
重复的知识就不写了…很多渲染基础知识可以看GAMES101的课程学习,也可以看笔记,甚至可以不用学文章来源地址https://www.toymoban.com/news/detail-407622.html
到了这里,关于【GAMES-104现代游戏引擎】4、引擎渲染基础(渲染基础数据、全局光照、PBR、阴影)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!