VR交互动画短片《拾梦老人》的开发经历

VR交互动画短片《拾梦老人》的开发经历

这是侑虎科技第226篇原创文章,感谢作者张言丰(资深TA,QQ:306566807)供稿。当然,如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:465082844)


笔者去年写了一篇关于如何打造高逼格耀斑效果的文章,很荣幸得到大家的关注。本人平日乐于分享自己工作中的点滴技术心得,欢迎大家联系我进行技术相关的交流学习。

今年笔者在PintaStudio,这是我在中科院的同学创立的一家VR电影工作室,我们希望用游戏引擎实时渲染的方式来表达艺术家的思想。同时,我们制作的VR沉浸式感受也是一种全新的观影体验。接下来,我将简述整个开发的历程。

请输入图片描述
VR交互动画短片《拾梦老人》剧照

一、引擎的选择 (Unity VS UE)

立项阶段,我们遇到了引擎选择上的分歧。我们想做的是重量级大作,所以最初的想法是采用一个重量级引擎。早期做端游时,我们了解得最多的是CRY ENGINE(下称“CE”)和UNREAL ENGINE(下称“UE”)了,这两个引擎就是引擎界的“西门吹雪”和“叶孤城”,长期霸占着国外的大作市场。CE这些年在国内推广不利,所以在最初阶段,更多的小伙伴希望用UE来做我们这个电影。我的加入,给团队带来了新的选择—Unity。相比前两个引擎,Unity可以说是后起之秀,尤其近3年手游的兴起,才把Unity引入大众的视线。我们主要对UE和Unity两个引擎进行了比较:

  1. 在视觉效果上,UE的完成度更高。引擎自带了比较多的效果如Light
    Propagation、各种Volume效果;UE的实时光照用的是经典PBR光照模型,更加接近艺术家们要求的Maya效果;UE的ShaderTree,更是给人一种“屌丝图形码工可以退休”的感觉。反观Unity,自带的效果比较有限(不考虑庞大逆天的AssetStore情况下),而且引擎中增加了一些无端端的优化,造成了一些视觉上的Bug,遭到一些艺术家的诟病。
  2. 性能上,UE没有对所有模块做全部测试,但是Unity经历了90%以上手游的考验,相信可以保证影片的流畅性;同时因为有更多的移动开发案例,所以小胜UE。
  3. 操作上,UE更强大的功能必然会导致编译时间较长;对于喜欢改装引擎的老司机,修改UE代码需要对它所有的模块都熟知;加上是基于C++的开发,程序需要格外小心内存、指针等各种问题。再看Unity,Unity把一些固定代码做了封装,改装引擎最多只能是对某些模块进行重写(当然,这样改装的结果可能导致性能略低,但是对于我们项目而言,不涉及过多硬件交互),不太容易出现问题;Unity是基于C#的开发,程序也相对耐操一些,对于支持VR的PC硬件,内存不是最致命的问题,但怕GC太多。

综上所述,我建议团队采用Unity引擎。尽管后来被几个大坑坑得鼻青脸肿,但是从项目进度以及结果来看,这个引擎基本上达到了我们想要的效果。


二、技术创新

Unity引擎本身的画质相对来说是较为简朴的,但是对于电影来说,艺术家希望能有一些更丰富的画面表现。我之前在公司运营团队写的一篇文章里也简单提过,大家可以参考:
http://www.vrzy.com/vr/60852.html

在这里我们举个简单小例子:
请输入图片描述

如上图这个光影效果,上面窗户衍射效果就有很多种实现方法。先对Depthmap做边缘的blur,然后计算光照是一种办法;直接对Render Target做局部的bloom也是一种方法;OffScreenRenderTarget,渲染一张低分辨率的光照贴图,然后合成回MainTarget,也不失为一种好方法。

对于地上阴影的边缘效果,怎么实现呢?CookieTexture?错误,你没有办法用CookeTexture去解决不规则的阴影衍射,更何况阴影的边缘颜色是艺术家幻想的。那怎么办?其实不难,它是软阴影算法的变种,所以,利用概率采样ShadowMap的方法得到阴影边缘,然后在边缘地区做颜色叠加即可实现。

我们再举一个小例子:
请输入图片描述
这狗的耳朵是不是有点透明?其实这就是个SSS效果,实现方法是:对于一个表面,沿着视线方向做一个延伸,取到次表面的光照,再叠加到前表面的颜色上。仔细看Unity树叶的Shader(Unity内置Terrain里的Shader),有个变量backcontrib,是把树叶背面的颜色叠到前面来,其实也是sss的变种。


三、重重阻碍

我们项目的开发进程充满艰辛,在此列举部分,给可能要入坑的同学提个醒:

1. 普通物件Standard材质
因为进度原因,我们仍然采用了Unity自带Standard里的PBR光照模型,这个光照模型是经典模型的简化版,对于大多数渲染对象来说还是可行的。但Unity自带的StandardShader在支持半透物件时,就会出现瘫痪的情况。如下图:
请输入图片描述
左图为正确效果,右图为UnityStandard的错误效果。这是由于StandardShader里Transparent 没有 Z Buffer 导致。那么有同学又会问“我用cut out不就行了么?”但是cut out是用RenderQueue来解决问题的,我希望上面这个腿和靴子来个半透明效果,它就没办法实现了。比如下图这个淡出效果:
请输入图片描述
此外,Unity还有一个致命的“优化”,就是在OpaqueQueue之后会把ShadowMap给销毁掉。所以半透明物件无法接受阴影。另外,关于点光源,如果光源范围内没有任何物体,Unity会把Lightmap也“优化”掉。类似这样的小细节Bug比较多,但需求不会因为引擎的Bug而减少或者降低标准。一个坑一个坑地填起来,也花费了我们相当大的精力。

2. 特效
如果说普通物件的材质是被Unity坑了一下,那么特效就是被VR的SDK给坑得鼻青脸肿。当时我们用的是HTC VIVE的Steam VR的SDK。研发完成之后才发现,这个SDK对RenderCommand和OffScreenCamera支持极差(OffScreenCamera没有办法左右眼矫正),也就是说所有的特效必须写在固定管线里,比如这种Volumetric Light。我们需要离线烘焙好ShadowMap,然后再前向渲染时,用RayTrace去模拟它的attention。
请输入图片描述
上面两张图中,左图是正确的效果,右图是SteamVR里可能看到的效果(因为OffScreen Camera位置没有经过左右眼矫正,所以位置看上去是偏移的,甚至不在屏幕里)。

3. 其他
在VR的开发中,相机也是个坑。因为传感器会实时地重置相机位置,所以你没有办法去动态改变相机,只能通过反向移动场景的方式来实现相机的动态切换。这也消耗了我们很多的时间来填这个坑。


四、展望

Unity 引擎自带的渲染模块基本都有些许欠缺,但是近年来随着Compute Shader、Render Command这些接口的提出,给我们引擎开发者提供了很大的可扩展空间。正如我多次在UWA技术群(465082844)里呼吁的:引擎是用来帮助开发者减少工作量的,不是用来完全依靠的。没有一款引擎能满足所有项目都通用的需求,所有引擎都需要根据不同的项目来做修改。一个不会造发动机的人,可以开车,甚至简单地维修汽车,但是你没法成为造车场的老司机或者职业赛车手。

附《拾梦老人》1分钟唯美预告片:

文末,再次感谢张言丰的分享,如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:465082844)。

也欢迎大家来积极参与U Sparkle开发者计划,简称"US",代表你和我,代表UWA和开发者在一起!