如何提升 VR 渲染的性能?手把手教你 | 干货
渲染那么重要,VR 内容开发者,你们都造怎么做好吗?
全文共计 7072 字,阅读共需 10 分钟
本文您将了解到:
1,VR 渲染面临什么问题?
2,如何做好 VR 的渲染?
3,怎样提升 VR 渲染的性能?
渲染对于 VR 内容的开发来说,是非常重要的议题。
但在现在的 VR 内容开发中,却还没有成熟的解决方案,特别是针对 Unity 开发者。
近期,VR 价值论在 VRCORE 公开课上找到一份 VR 渲染指南。
包括渲染方面的基础知识,以及在 Unity 里面如何去优化渲染的效率。
废话不多说,直接上干货吧,内容较多,建议收藏。
本期(第 44 期)来自 AMD 的 VR 内容开发工程师王文涛在 VRCORE 公开课上的分享:如何做好 VR 渲染以及提升效率?
研究生开始,我一直研究图形学和渲染。
渲染对于游戏开发、以及现在 VR 内容的开发来说是非常重要的议题。
打个比方,你做房地产展示类的应用,那么渲染就很重要,房屋内的光照,日夜之间的切换,这些都需要渲染,做的好的话,将成为让你的应用脱颖而出的杀手锏。
不过,渲染虽然重要,在现在的 VR 内容开发中,却还没有成熟的解决方案,特别是针对 Unity 开发者。
大家都知道,虽然虚幻引擎效果比较好,可以做出电影级别的画质,但很大部分的开发者还是使用 Unity 开发,包括我自己。
Unity 的效果不太完美,不过我们不能因为它渲染效果不好,就去做一个不完美的东西。这样不行,因为你的产品最终是要跟别的引擎做的东西去竞争。
所以,我今天来讲的就是渲染方面的基础知识,和在 Unity 里面怎么去优化它的效率,一些指南性的东西。
这样主要是为了大家在之后使用 Unity 开发的时候能够有一个全局上的了解和判断。
比如说,为什么我的游戏运行的这么慢?
为什么我的帧率这么低?
或者为什么我想要的画面和游戏运行出来的画面差的这么多呢?
到底是我的全局光照出了问题还是说我的抗锯齿有问题?
在开始之前,我想先给大家看一个 Unity 做的电影。(价值论友情提示:视频为演讲者演讲过程,提及的电影也可以从小视频 3 分 40 秒处开始播放哦。)
它和传统电影制作流程不一样,完全是在引擎里实时运行的。
这个也是 Unity 做出来的效果,质量很高,接下来,我们会逐步去分析它。
可以看到的是,首先,这个机器人的材质非常的真实。金属的高光、地板上的反射。
反射在我们生活中很常见,但在游戏引擎里是比较难实现的技术,不管是实时的还是烘培的反射。
但它使用一些特殊的技术去实现反射的技能。这个过道光很自然,你在使用 Unity 开发的时候,打一个普通的面光源或者点光源,很难做到这么自然的光照。
这是因为它在这里面使用了全局光照的技术,或者叫做间接光照。
影片主题其实就是说机器人是人类的造物,或者说人类成为了上帝,这是我自己的理解。
大家看到那个电影很酷炫,有一种电影级的画质。当然我们不考虑显卡因素,因为刚才放的那个电影是用三块 GTX980 去交互渲染的。VR 现在很多的开发者也有 1080 或者我们 AMD 的 FURY X,Fury Nano 这种级别的显卡。
假如你有一块这么好的显卡,你怎么做出一个非常牛逼的画质呢?
怎么理解渲染?
性能
有两点要求需要满足。
- 在某个固定的平台上必须要达到一定的帧率。
就是说,看起来至少每秒得能够有 75 帧,其实必须要达到 90 帧才不会晕眩。
- 必须要满足游戏设计艺术家的要求。
这并不是说特效堆的越多越好,或者说做出来的渲染越真实越好,并不是这样。
比如说,你的游戏可能是水墨风格,可能是美术风格。你用现有的技术把它做的非常漂亮,这是一个很好的渲染系统所必须拥有的特性。
我们想到的现在比较优秀的作品,比如说《使命召唤》或者《战地》。为什么它们能够在 PS4 上跑出这么优秀的效果?
除了美术过硬之外,他们也使过非常多的光照、贴图、建模上的技术去实现效果。
当然,在 VR 里面,这些渲染实现会更加的难。
因为大家都知道,VR 是两只眼睛,通过左右眼的视差去产生立体感。
首先,至少要渲染两个 runnertarget,也就是说两幅图像;
其次,平常我们使用的 PS4 或 PC 上的分辨率 1080p 已经非常高了,现在渲染的分辨率要 2k(HTC 的分辨率是 2k,Oculus 的分辨率也是 2k 以上),两只眼睛,同时帧率还不能说只达到 60FPS,而必须达到 75FPS 或者 90FPS。
在这种情况下,你必须要牺牲掉一些效果。甚至说,你要牺牲掉很多效果去达到基本的性能要求。
在这个情况下,优化就显得非常重要。
锯齿
还有一个比较重要的因素,就是我们在 VR 里,眼睛离屏幕非常近。
同时,我们的眼睛一直在运动的。
那么,我们平常在用电脑玩游戏或者手机玩游戏的时候,一些比较不明显的画质上的差异它就会体现出来,特别明显的就是锯齿。
玩游戏比较多的人知道有个名词叫 “狗牙”。比如说一个非常细的多边形,我看上去会有一段一段一段的 “狗牙”,或者说一块金属反射的高光,我在玩的时候它会不停的闪烁,就会让人感觉画面很不稳定。
而在 VR 里面这种情况更加的严重,也就是我们通常说的抗锯齿会变得更加的重要。
怎样解决性能上的问题?
我先讲一下,怎么解决这些性能上的问题。
减小渲染图像
首先,一个比较自然的想法就是把要渲染的图像变得小一些。
那么怎么变的小一些呢?
一个很明显的优化思想就是,渲染并不是说两幅图都是 2k 的图片,并不是要把这 2k 全部渲染出来,因为现在的头显是有 FOV 的,它在边缘是有畸变的。
也就是说我们完全是可以只渲染中心一部分的图片,而并不是把整个图渲染出来。
用一个遮挡的 Mesh 去把不需要的像素点剔除掉,对你真正的体验来说不会有任何影响。
举一个例子,Valve 公司做的《The Lab》的 Demo。
在这里面就讲到,用一个圆形的 Mesh 去保留所需要的像素。边缘那些黑的在 VR 头显里面,或者说在 HTC Vive 或 Oculus 里面不需要这些像素。它测算出来的结果是,通过这个能够把 17% 的像素去剔除掉。这是一个比较自然的想法。
注视点渲染技术
还有一个类似的想法,像素的着色或者说像素的渲染,是 GPU 里面损耗最大的部分,那我们能不能把这些像素不要再去扔掉呢?
其实最简单的思想是,人在看东西的时候是有一个焦点的。
打个比方说,我现在看到的这块屏幕,我的眼睛会集中在这块屏幕上。我不可能太多的关注周围的窗帘、包括这块广告板。
那是不是说,我们可以把更多的 GPU 的效率提供在这块板(焦点)上而不是我们同样的渲染整个视场中的,包括这边和这边的物体。
这就是一个非常简单或者说非常直白的叫做 Foveated Rendering,就是注视点渲染技术。
传统的渲染流水线中,我们会把三维空间的物体投影到屏幕上,然后每个像素都一个一个地按部就班的去着色。
实际上在 VR 里面,它还真不是这样。因为在 VR 里面我们有注视点,可能说我们只看中间的那一小部分,而并不是说我们对整个的画面中的像素都是一视同仁的。所以说,有一个非常简单的实现技术,固定的注视点渲染,它并不是说我们需要实现眼球跟踪那么复杂的技术。
比方说,我在看的时候,我的眼球会往这边看或者往那边看。
我们做一个最基本的假设,就是说我的眼球总是看着最前方,然后我们通过一个算法把周围像素着色的密度去降低,那就可以提高很多的效率。
这里说的 GameWorks VR,也就是英伟达推出的关于 VR 渲染的技术里面,也用了同样的思想,就是 Multi-resolutionshading。
这个思想其实是一样的,它就是说我也假设我的视点永远是在画面最中心,然后我把画面分成大概 9 个区域,分别按不同的着色密度去渲染。
我看过官方的数据,这个 Multi-resolutionshading 能够提高 15% 或者 20% 的着色效率。
还有一个比较浪费的就是,在 VR 里面你要渲染两遍,左眼和右眼。
其实很多东西是不需要渲染两遍的。
最基本的就是说,和灯光有关的东西,你根本不需要渲染两遍。
- 比如说 Shadow map,也就是阴影。
因为,阴影是跟灯光有关的,和摄像机的位置无关。你的两只眼睛不管距离多大或者是差异性有多大,它都是一样的。
- 还有一个比较值得研究的就是,比如说漫反射。
高光我们可能在两个眼睛里面会有很大的区别,但是漫反射其实区别比较小。
- 再一个就是说,比如说很多的后处理的特效。
比如我们的光晕、HDR 高动态范围,这个特效其实都不需要渲染两遍。
所以我推荐,基本上大家在做 VR 开发的时候能够用 Unity 5.4,虽然现在还 Beta 版,但在 5.4 里已经开始对这些东西做了一些优化。如果你用 5.3 的话,可能效率还是要低一些。
怎样解决锯齿上的问题?
然后我再讲的就是刚才说的锯齿问题。
这个东西在 VR 里面会是一个非常严重的问题。
大家都知道 Unity 里面摄像机可以设 render pass,包括有前向渲染 Forward Rendering 和延迟渲染 Deferred Rendering。
在 VR 里面我们怎么去选择这个呢?
你在做一个小游戏的时候,可能根本不会 care 这个东西。
用前向渲染和用后向渲染,显卡都是能够满足目标的。但是,我在这分析的就是说前向渲染,它有一个天生的好处就是能够在硬件上支持 MSAA。
我们玩游戏的都会知道一个选项,如果你去把《使命召唤》或者这样游戏里的图形选项打开,它有一项就叫 MSAA。
MSAA 实际上是显卡里用硬件算法去支持的。
如果你用前向渲染,它天然就自带了一个 MSAA 的效果,锯齿问题就不是那么严重。
但后向渲染其实就是一个非常尴尬的事情,如果游戏玩的多的可能都知道,现在有抗锯齿的 FXAA,其实是基于一个图像分析,这个图像分析在 VR 里面用处并不是很大,或者说即使加上了对于锯齿的改善并不是很明显。
所以,我向大家推荐 Unity 里面非常强大的插件,就是 VALV 的 Lab Renderer。
其实这是 VALVE 的工程师在做 The Lab 这个 Demo 的时候,想到的这个事情。
如果你听过他们在 GDC 上的演讲,就会明白他们也用 Unity 做开发,那他们为什么不用 Unreal 呢?
VALVE 做的《半条命》、《DOTA2》,是非常高端、特效非常好的游戏。为什么它要用 Unity 呢?他们工程师就说了一句:“我们发现用 Unity 的团队,大部分都是小团队,而这样的小团队里面是不可能有一个人去专门研究图形,专门研究画面效果的,所以我们去专门研究这样一个插件叫做 The LabRenderer 的技术。”
目的就是说能够帮助小团队去实现一个还不错的渲染效果。
这个渲染其实特别容易。
它就是最简单的一个 pass forward renderer 前向渲染器。
能够最大的支持 16 盏动态光源。我想 16 盏动态光源对于绝大多数游戏或者非常复杂的应用来说都是够用的。
它最大的特点就是说 MSAA,能够天然支持 MSAA,锯齿是非常不明显的。它天生就自带了我刚才说的那些注视点渲染、像素剔除这些技术。相比 Unity 默认的渲染,你使用它渲染会有非常好的效率上的提升。
但然,它也有一些限制。
它必须用自己的 Shader。
比如说你在 Unity 用惯了标准材质,或者你自己买的一些 Alloy Shader,贴图就要重画或者重新连接材质的节点。
用这个插件需要你去做一些修改。
当然,如果说项目并不是很大,我非常推荐使用这个东西。去学习一下它的流程,一个是对你自己,对整个团队的图形学知识是个很好的。
另外,它整个代码是 open source,在 asset store 上,搜 The Lab Renderer 就可以下载,不需要掏钱。
再一个就是说,你不用花时间去纠结一些比较基础的东西。
比如 Unity 没有注视点渲染、没有像素剔除的技术。那你看一下用 Unreal 开发的,天生就自带 Gameworks VR,人家做出来为什么这么快。你自己如果要花时间去写,花时间去研究,这就是一个非常大的工程。所以 VALVE 给你搭的这一套东西就节省不少的时间。
然后我讲一下,前向渲染对于我们来说并不是一个非常完整的解决方案。特别是 MSAA 对于比如说高光的锯齿并不是能够解决的很好。
那么我们在 Unity 里面是不是有别的更好的技术去解决它?
我在这里强调的是前向渲染对于多光源并不是非常有效率,包括刚才说的,可能只能支持 16 盏光源,再多它的帧率会下降的非常快。
即使是支持到 16 盏光源,也并不推荐你完全的用满它。
再一个是,比如说,我们很想使用一些特效,比如屏幕空间反射。但这个东西对于前向技术就没有办法实现,因为屏幕空间反射需要用到屏幕的几何信息,那怎么办?那我们是不是有一个更好的方法?
还真有。
大家想一想,我们做电影和做游戏的区别是什么?
做电影其实是一个追求质量的过程,做电影一帧可以渲染 1 个小时、2 个小时。但做游戏,或者说做 VR 内容开发,我们需要的是效率,一帧最多是十几毫秒。如果你超过 20 毫秒,那这一帧基本上完蛋。所以说,电影上的一帧可以一直渲染下去,直到它收敛为止。
那么,渲染在图形学里面其实就是一个不停采样的过程。
而抗锯齿根本的来源就是,一个渲染的图像,它缺少信息,大家如果是工科或理工科出身的,就知道 “奈奎斯特采样定理”。
我的采样频率要高于我最高频率的两倍,我就能完整地恢复出我需要的信息。
在渲染这个领域其实也是一样。
打个比方说,我们大家都知道,最简单的抗锯齿的方法是什么?你渲染一张 2k 的大图,把它缩小到 1k,那这张图肯定锯齿非常少。
为什么?因为这相当于我们对 1k 的图的每一个像素做了四次采样。但是实际上,你真的去渲染一个 2k 的大图,那么 VR 有 2k 我可能就要去渲染 4k,你这样去抗锯齿显然是不行的。
后来就有聪明人说,游戏最大的特点是连续性,那如果我能够找到每帧之间相同的像素,那我就能在时域,也就是说很多帧之间去做个采样。
就实现了个超采样,也就是所谓的 Super Sampling。
有的时候大家在数据信号处理的课里面,提到这个 Super Sampling。这个能够很好的提高画面的质量,最关键的是这个很便宜,或者说并不是很好,当然它的实现难度是有的。
我给大家看一个具体的例子。这个 Demo 挺有名的,使用虚幻引擎做的。这个是没用时域抗锯齿的结果,大家看到最大明显的特点是闪。因为,整个画面高光的东西太多了。如果说你不用抗锯齿,画面会非常不稳定。这个地方会特别的闪。
我们加上了时域抗锯齿的结果,是什么?
最大的特点就是整个画面非常稳定,这样看起来是不是就有电影级别画质的感觉。画面稳定、像素没有任何瑕疵,包括在高光的地方也不会闪,非常的稳定。
我刚才说的 Temporal AA 一样的,在 asset store 上也可以找到一个还不错的实现。我不知道大家知不知道 limbo 这个工作室,可以去搜 limbo 的 taa,能够得到非常不错的 Temporal AA,也是直接在 GitHub 下载就可以了。
我想跟大家建议,要擅于利用包括 GitHub、Asset Store 这样的插件让我们的开发提升效率。
如果你想做很棒的产品,你必须要擅于利用这些前人已有的资源。
怎样解决全局光的问题?
然后,我再讲全局光的问题。
全局光问题历来是游戏里比较头痛的问题,特别是在 VR 里面更麻烦。
什么叫全局光照?
比如一个灯打到一块黑板上或者地板上,它投下来的影子那是直接光照。但如果它在地板上反射出去的光线照亮了其他物体,那这个就是全局光照。
全局光照一般是通过烘焙,也就是离线的方法把全局光照存成某种数据结构,在游戏实时运行时调用去实现的。
但在 VR 里面对于实时的运算是要进行严格的限制,所以我不推荐大家在 VR 里面使用实时的全局光照技术,比如说提速、mpv 这种技术。
我建议大家老老实实用标准的光照贴图,也就说烘焙一张贴图然后贴上去。
但是,Unity 又是一个非常麻烦的问题,Unity 自身所带的 enlighten 的烘焙,不是很好调出非常好的效果。
我想大家可能都看过 Unreal 的一些作品,比如说 Unreal 做的室内装修,为什么室内装修企业,比如说 51VR,他们都会用虚幻引擎去做室内装修呢?
一个最大的原因,室内装修对于全局光照的要求非常高,Unity 是达不到的。如果你是用 Unity 做东西,用 enlighten 去调一个非常好的全局光照,难度很大或者说几乎不可能。
所以,我推荐大家尽量去使用另外的烘焙工具,比如说 vRay。
当然,你把它导进 Unity 里面是需要耗费一定的工作量,但是这个比你去用它自带的烘焙工具要好一些。
我们这边也做过尝试,如果真的去用比较优秀的烘焙工具的话,Unity 做出的室内设计或者室内展示的质量是不会输给 Unreal。
当然,还有屏幕空间的技术,大家都知道屏幕空间的技术关键就是在于快,缺点就是精度不够。
比如 Unity 自带的 SSAO 这个就是一个非常好的实现,但在 asset store 有 HBAO 或者是别的 AO 技术,大家都可以试一下。
我建议大家能用就用,在硬件够、本来全局光很矬的情况下,你没有这些 AO 补偿的话,画面会比较挫。
再一个就是屏幕空间反射,屏幕空间反射现在在 5.4 的 beat 版里面官方已经有了,其实你们只要在相机上加上 imagine facts 里面就会有这个。
当然实现的屏幕空间发射在 Unity 5.4 实现可能不是那么完美,但其实它已经是够用的。
如果场景里有非常多的金属物体,或者说非常多的镜面,使用反射的话会大大增加你视觉上的观感。
打个比方说,我是在一个很空旷的金属竞技场里面,甚至说我只要有空间反射的技术可能不需要 GI,就能给人一种非常好的视觉上的表现力。
说了这么多,我觉得其实优化还是那套方法,大家都知道的,简单说减少 drawcall、减少 DC、batching。
Unity 的 batching 这个东西是一个老生常谈的话题,在百度、谷歌上一搜会有很多相关词条。
怎么去 batching?在场景里怎么去 batching?
在 VR 里面,要求会更高一些。
比方说,我听过一个讲座,《Gunjack》就是在 GearVR 上实现的游戏,它对 drawcall 这个东西限制就非常严,它每只眼睛的 drawcall 不能超过 50。
所以,不管你是开发 HTC 或者是开发什么样的应用,drawcall、batching 这些东西一定要非常的注意。
你不能无限制的堆你所需要的东西,而是说做一段时间,可能就要运行一下,用 Unity 的工具去看一下,我现在这个场帧率是多少?我到底在哪里耗的特别快。
还有一种比较好的方法就是说,实在不行就按艺术家的方法去画。
打个比方说,bloom 光晕特效,这个东西大家都知道 Unity 里面有 shader 自带,但是这个占的时间。
如果你是做移动平台的,你可能知道移动平台后期处理的效果是非常占时间,那怎么办?直接美术画上去,这也是非常行之有效的方法,当然也考验你美术的能力了。
再一个,我推荐多去测你游戏的性能。包括 professional unity 5.4 里也已经是比较完善的一个东西。
多去测性能、多去了解你游戏的瓶颈、bottleneck 在哪里、是 shader 太多了还是说我某个特效真的不该用。不要在编辑器里测,最好是打个光。
对于开发者的建议
最后说一下,渲染有一个自我的评估。
当然我知道现在的很多团队是不会专门有一个程序员、或者专门有技术美术去关注这一块的。
但是我想说的就是,希望大家能够去多考虑一下。
比如说,你所需要的特效的特点是什么?
比方说,如果做的是一个机械的大战,你可能非常需要反射,可能就会去使用一个屏幕空间反射的特效在 Unity 5.4 beta 版里面会有。
再比方说,你做的是一个互动电影,那么对画面的要求会非常高,那么抗锯齿就要做的非常出色,那你只能使用时域的抗锯齿 temporal AA,我刚才说的那种方法。
具体问题具体分析,渲染这个东西,永远不是一成不变的。
它不是像电影渲染一样,只要渲染的够真实或者说只要去模拟每一根光线的运动轨迹,就得到一个非常完美的图像。
关键在游戏里面,根据美术风格去做出妥协,根据性能去做出妥协,所以这是一个永远会谈论下去的话题。
你很难去说,我某个引擎特别牛,任何游戏都能做。即使是效果这么好的虚幻引擎,它也很有可能也有做出来帧率非常低的情况。
如果你不懂,不懂删减特效的话,你最后很有可能遇上非常大的麻烦。Unity 的帧率并不是一个很大的问题,但是它的效果同样是个很大的问题。
如果你不懂得怎么通过各种各样开发,包括 shader 的技巧去加特效的话,也可能很难做出非常优秀的作品。
所以,我希望大家能够多讨论,有问题就提出,甚至能够建立一些自己的 library 或者 open source library,去提高整个 VR 社区开发者的质量。