# ​如何提升 VR 渲染的性能？手把手教你 \| 干货

- 作者：VR 价值论
- 发布时间：2017-01-20 17:44
- 分类：新创
- 原文：https://www.ifanr.com/778900

![yofrankie004](https://s3.ifanr.com/wp-content/uploads/2017/01/Yofrankie004.jpg)

> 渲染那么重要，VR 内容开发者，你们都造怎么做好吗？

![640-1](https://s3.ifanr.com/wp-content/uploads/2017/01/640-1-13.jpeg)

全文共计 7072 字，阅读共需 10 分钟

本文您将了解到：

> 1，VR 渲染面临什么问题？
> 
> 2，如何做好 VR 的渲染？
> 
> 3，怎样提升 VR 渲染的性能？

渲染对于 VR 内容的开发来说，是非常重要的议题。

但在现在的 VR 内容开发中，却还没有成熟的解决方案，特别是针对 Unity 开发者。

近期，VR 价值论在 VRCORE 公开课上找到一份 VR 渲染指南。

包括渲染方面的基础知识，以及在 Unity 里面如何去优化渲染的效率。

废话不多说，直接上干货吧，内容较多，建议收藏。

本期（第 44 期）来自 AMD 的 VR 内容开发工程师王文涛在 VRCORE 公开课上的分享：**如何做好 VR 渲染以及提升效率？**

![640](https://s3.ifanr.com/wp-content/uploads/2017/01/640-5.png)

研究生开始，我一直研究图形学和渲染。

**渲染对于游戏开发、以及现在 VR 内容的开发来说是非常重要的议题。**

打个比方，你做房地产展示类的应用，那么渲染就很重要，房屋内的光照，日夜之间的切换，这些都需要渲染，做的好的话，将成为让你的应用脱颖而出的杀手锏。

**不过，渲染虽然重要，在现在的 VR 内容开发中，却还没有成熟的解决方案，特别是针对 Unity 开发者。**

大家都知道，虽然虚幻引擎效果比较好，可以做出电影级别的画质，但很大部分的开发者还是使用 Unity 开发，包括我自己。

Unity 的效果不太完美，不过我们不能因为它渲染效果不好，就去做一个不完美的东西。这样不行，因为你的产品最终是要跟别的引擎做的东西去竞争。

所以，我今天来讲的就是**渲染方面的基础知识**，和在 Unity 里面**怎么去优化它的效率，**一些**指南性的东西**。

这样主要是为了大家在之后使用 Unity 开发的时候能够有一个全局上的了解和判断。

比如说，为什么我的游戏运行的这么慢？

为什么我的帧率这么低？

或者为什么我想要的画面和游戏运行出来的画面差的这么多呢？

到底是我的全局光照出了问题还是说我的抗锯齿有问题？

在开始之前，我想先给大家看一个 Unity 做的[电影](https://v.qq.com/iframe/player.html?vid=o0353zjdh0a&width=670&height=502.5&auto=0)。（价值论友情提示：视频为演讲者演讲过程，提及的电影也可以从小视频 3 分 40 秒处开始播放哦。）

[嵌入内容](https://v.qq.com/iframe/player.html?vid=o0353zjdh0a&tiny=0&auto=0)

它和传统电影制作流程不一样，完全是在引擎里实时运行的。

这个也是 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 里面用处并不是很大，或者说即使加上了对于锯齿的改善并不是很明显。

[嵌入内容](https://v.qq.com/iframe/player.html?vid=q0353bmgoqm&tiny=0&auto=0)

所以，我向大家推荐 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 挺有名的，使用虚幻引擎做的。这个是没用时域抗锯齿的结果，大家看到最大明显的特点是闪。因为，整个画面高光的东西太多了。如果说你不用抗锯齿，画面会非常不稳定。这个地方会特别的闪。

[嵌入内容](https://v.qq.com/iframe/player.html?vid=n1312upzgc4&tiny=0&auto=0)

我们加上了时域抗锯齿的结果，是什么？

最大的特点就是整个画面非常稳定，这样看起来是不是就有电影级别画质的感觉。画面稳定、像素没有任何瑕疵，包括在高光的地方也不会闪，非常的稳定。

我刚才说的 **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 社区开发者的质量。
