antd tooltip里面的图片被遮挡_UE4渲染模块概述(一)---方法论、遮挡剔除、Geometry Rendering...

渲染模块是自己比较薄弱的环节,但这是深入做游戏必备的核心知识,是区别一般软件开发的精髓所在。我也是本着学习的态度来更新此文,所以有理解不对的地方,还望各位同仁指正。做为渲染模块的开篇,我打算总结下我近一周学习的UE官方视频课程(这里用的是截图,因为如果打出网址,知乎会试图解析,进而转变成用户login的URL来):

423eabe3a0c2ad9b5cb095fead012400.png

本中绝大多数图片取自于视频截图,这里大多都是些概念的介绍,比较粗,所以我称之为“概述”,后面还打算出自己更加细致的研究,敬请期待。

渲染方法论

游戏中讨论的都是实时渲染(RealTime Rendering,RTR),也就是随着游戏内相机的移动,要能够尽可能无延迟地展示视口内容,效果不可能做到CG那么好。

RTR流程的本质是管理性能的损耗,以这张图为例:

76c34aba4e9a6ee95cda36071bd5a539.png

X轴表示视觉质量,Y轴表示性能,那么要想获得高质量的渲染,就会带来性能的下降,这个趋势是不会变的。但做的好的优化,是可以降低这种下降的坡度,图中黄色曲线就要好于蓝色曲线。一般地,我们会根据用户体验能接受的角度,来设置一个目标帧率(一般是30帧,帧数表示一秒可以执行多少次主循环),只要能保证在这个帧率之上,就可以尽可能地把渲染视觉效果做好。

19b858ad871f4f91e5dd5e5d69ca6a20.png

图形工程师一直在追求渲染质量、性能、功能这三者的平衡。一个空场景性能必然是最佳的,但这没有意义,另一方面若场景都用最高精度的图片或是堆砌各种功能点,游戏卡得根本玩不了,也是不行的。

在图形优化的路上有很多具体的实现,但都可以归纳成以下六点方法论:

1)流水线:并发多线程,使硬件的利用率达到最高;

2)预计算:能事先计算的就尽量事先做,降低Runtime的计算成本,比如静态光的lightmap;

3)局部化:只在可见的局部区域里做事情,比如屏幕空间反射的计算(SSR);

4)先粗后精:先用消耗低的方法缩小计算范围,再用消耗大的方法执行精确计算,比如八叉树遮挡查询;

5)时空互换:用时间换空间或是空间换时间,比如lightmap就是空间换时间的例子;

6)负担转移:使用stat unit查看如果是CPU的瓶颈,又不可进一步优化了,可以考虑将CPU的计算移至GPU计算,如骨骼动画计算可以移至GPU做。

渲染之前:遮挡查询

渲染有一个看似很简单,但却非常重要的概念:只渲染镜头可见的场景。看不见的场景并不需要浪费性能,直接剔除掉即可,这个过程就是遮挡查询,这部分发生在GPU渲染之前,是在CPU端做的逐Object的遮挡查询。

UE4使用了四种遮挡处理方法,按性能消耗由低到高的排列如下:

1)距离剔除:离镜头太远的物件直接隐去,不去绘制;

2)视锥剔除:镜头能看到的区域是一个锥体,锥体以外的部分可以不去绘制(具体是用八叉树先粗后精筛选进入视锥体的对象);

3)预计算可见性剔除:主要适用于一些室内的场景,比如透过室内的门可以看到哪些区域,这些可以预计算好,不用实时计算了;

4)遮挡剔除:最费性能,需要逐对象查询;

UE会优先使用消耗低的方法去排除掉大部分不用渲染的对象,再用遮挡剔除这种精细的方法进一步计算。

几何渲染

几何渲染可以细分成三部分:

1)GPU端像素级别的prez遮挡查询

2)解析CPU传来的draw primitive绘制指令(draw call)

3)顶点计算(vertex shader)

第一部分是GPU端prepass/prez,防止像素overdraw。举个例子,我们有一张背景图:

f2a69364b8026f5497181f236401ed7c.png

在背景图之前放了一盏茶壶,如下:

1958688446bd9c9a832287f47d28bb16.png

正常情况下我们先绘制背景图,再绘制茶壶,看似没有问题,但茶壶所在位置的像素其实被重复渲染两次了。那么如果先茶壶再是背景图如何呢?还是会遇到如下交错的情况。

7014a768dfa05b0046e0ff8a4b998dd7.png

为了真正解决这个问题,在渲染primitive顶点之前,需要拿到深度信息,这样我们就知道哪个顶点应该被渲,哪个不需要渲了。比如一开始的茶壶场景,渲染背景其实只要这样即可:

cc12145fad1932d31d3175a0b989a7e6.png

第二部分是drawcall。GPU是逐个drawcall渲染的,所谓drawcall,是指CPU向GPU发出的一次渲染指令,让GPU绘制指定的几何体。比如下图:

1ad43810ae0a10c5ceda798cd07d4acf.png

CPU会提交五次drawcall,一次天空,一次地面,三个柱子各一次(因为是三个独立的模型)

而下面这个图:

b006c87fed9eb432f8a34532cc9a062d.png

因为最右侧柱子上下两部分采用了不同的材质,所以需要提交两次渲染信息,这样就多一次drawcall,共计6次drawcall。

924dae42770c42deffc17e8b3e81807d.png

这张图展示了渲染的顺序,蓝色的是地面,因为事先做了prez,所以为地图上原来柱子的区域留空了没去绘制。

从左到右依次是:渲染地面,渲染右侧柱子的下半截,渲染中间柱子,渲染左侧柱子,渲染右侧柱子的上半截,渲染天空。

渲染顺序也就侧面反映了提交drawcall的次序,其实对于图形工程师而言,不必特别注意drawcall提交次序,只要最终结果是对的就行。不过这里也可以发现一个问题,那就是为啥没有完整地渲染完右侧的柱子,再去渲染中间的呢?那是因为渲染器会把相同材质的对象放到相邻drawcall中处理,这样可以节省让硬件切换渲染状态的耗时。可以注意到这里右侧柱子下半截的材质与其他柱子材质是一样的,所以会放到连续的drawcall中处理,而右侧柱子上半截材质不同,被放到了所有相同材质柱子渲染完成后才进行绘制。

UE4看drawcall数量的命令是stat RHI,在命令行敲入后可见:

2ce9691657c68e9e6c7a7b3824d32710.png

draw primitivec calls的数量就是drawcall的数量,一般来说移动端在1000个drawcall左右比较好,PC在2000~3000左右为宜,而超过5000就有可能出性能问题了。这时需要check下出问题的区域。Triangles drawn就是这个视口中三角形面数的总量。

drawcall涉及到CPU向GPU数据的传递,这个传递的代价一般远大于三角形本身的绘制成本,可以举个对应例子,你觉得是拷贝一个1GB的文件快,还是拷贝一百万个1KB的文件快?

降低drawcall的通用处理方案是进行模型的合并,将空间邻近、相同材质、相同渲染状态的小模型合并成一个大模型,这样就只需要提交一次drawcall就可以完成绘制了。特别注意这与组件化的设计概念是不同的,不要认为将物件作为component挂在同一个Actor上就可以自动合并成同一个drawcall了,这些component仍会分开渲染。

模型合并后,虽然drawcall数量降低,但也要考虑它的副作用:

1)遮挡剔除力度减弱,哪怕是镜头锥体内只出现合并模型的一个面片,也会去渲染整个合并模型;

2)lightmap占用更多空间,这个是跟模型走的;

3)碰撞计算变得困难;

4)模型占用内存更大,传统摆一个建筑的方式是将一些局部小模型拼凑,相同的小模型在内存中只要一份就行了,但如果合并,多个相同模型顶点信息都要被完整保存下来。

所以还是推荐美术同学先使用小模型按乐高积木的方式拼接,等接近终版时再按实际性能需要进行合并(可以用3d美术工具或者UE4自带的MeregeActorTools)。

虽然面数相对于drawcall来说,影响不是那么大,但我们仍然要控制面数,可以减少后续光照计算与pixel shader的复杂度。减面的方法常用的就是LOD(Level Of Detail),它可以按镜头与物体的距离来替换不同精度的模型,比如离得很近的话用1000面的模型,离得很远的话就用100面的模型,因为离得远在屏幕上绘制的像素个数也比较少,就看不出来模型的细节了。

HLOD相对于LOD来说可以进一步优化面数和drawcall,它的原理是近处正常显示,比如4个模型就绘制成四个单独的模型,但在远距离上就用合并成一个低精度模型来替换这一组对象。

第三部分是顶点的处理,CPU传过来的顶点是三维的,但屏幕上能显示的是二维数据,因此需要降维投影,这个算法过程被称为vertex shader。shader可以理解成一种程序,它接受输入数据,再经过某种算法,给出输出。vertex shader就是将三维的顶点数据输出成屏幕空间的二维顶点,这其中要经历模型空间到世界空间,世界空间到视口空间,视口空间到屏幕空间的矩阵变换。

vertex shader的一个形象例子就是在shader里面给输入顶点一定偏移量,如下图所示:

080e3eb353474e9dc63d9745fae23628.png

这种看似无聊的效果,其实可以用于水流的波动,草随风摆的效果等。不过要注意的是此时只是GPU端改变了顶点显示的位置,它的实际碰撞信息(CPU端控制的)是没有变化的,也就是你不能试图蹲着从中间那个柱子经过。

本来想一口气写完概述的,内容太多还是分开写吧,下一部分介绍Pixel shader相关的内容,详见:

Jerry:UE4渲染模块概述(二)---光栅化与纹理​zhuanlan.zhihu.com
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值