Fdcon 2018 分享:淘宝Web 3D应用与游戏开发实战
作者: 发布于:

Fdcon 2018 分享:淘宝Web 3D应用与游戏开发实战

主题:分会场二:全端与全栈专场 - 淘宝Web 3D应用与游戏开发实战

时间:2018年5月19日 15:15

地点:中国 上海

演讲嘉宾:徐乾伟(烧鹅)-淘宝-前端技术专家

PPT地址https://shimo.im/docs/Mq8nWZ3pCyg3AAN5/

寸志:接下来开始下半场。下半场有请淘宝的烧鹅前端技术专家给我们带来“淘宝WEB 3D应用与游戏开发实战”,有请徐乾伟。

徐乾伟:大家下午好!我们今天讲个比较有意思的话题,这个话题在业界被谈及得比较少。大家在座有做过移动端开发的同学吗?请举个手...人还挺多的。那做过3D应用的同学请举个手,有用过Threejs的请举个手。做过游戏的呢..人这么少,那我就放心了,可以大胆讲了(全场笑) 。今天讲的正是移动、3D、游戏三者交叉的话题。

自我介绍一下,我来自淘宝虚拟互动团队,这个团队主攻3D/游戏/VR/AR。其中,我们有一个小团队叫斜杠实验室(),主攻Web方向上的动画和3D技术。为什么我们会在这样交叉领域去发力做一些事情?去年的双十一淘宝去年交易额多少?一千多亿,其中有80%的GMV是来自移动端的,简单地理解就是说我们公司在电商领域80%的钱是通过手机客户端赚取的,而不是PC。这就是为什么在我们要在移动端做3D/VR/AR的应用。

我今天演讲分为三块内容:

  • 第一部分讲述初试Web 3D
  • 第二部分讲使用_WebGL
  • 第三部分讲工作流相关的游戏编辑器

有一句话叫:给我一个支点,我就能撬动地球。很多人都做过2D游戏,3D最大的区别就是多了一根Z轴,而给我一个Z轴我就能创造3D世界。很多做前端的同学对3D这个事情是有误解的,比如说 HTML5中的 Canvas 有两个上下文,大家认为2d Context只能画2D,WebGL context 才能画3D,这是一种误解。

其实3D和2D并不是由绘图引擎来决定的,而是由数学家决定的。假如我们要画这样的曲面会怎么画呢?首先有描述这个面的公式,这个公式根据X、Y入参算出Z的坐标值,假设Z越大颜色越红,Z越小颜色越绿,画出来是这样的。如果X、Y、Z乘以一种神奇的东西叫矩阵(矩阵是数学家发明的),这是3×3的旋转矩阵,把每个点都乘一下,然后画到屏幕上得到的结果就是这样的。大家是不是一脸懵逼呀?这里有一篇MSDN的文章专门讲解了如何用 Canvas _2d 绘制3D曲面。我有一段时间写过CSS3D的库,就是用 glMatrix 数学库做出非常酷炫的效果。

2016年双十一我们做过一个小游戏,这个游戏有玩过的吗?(观众举手)。这个游戏是用Canvas _2d 绘制,就是用的glMatrix 数学库画实现3D效果。当时为什么用Canvas 2d 呢?我们淘宝市场部的同学说我们要做3D,因为人家pokemongo做了一个3D的,但是你这个东西最后要给我搞到iPhone 4上去。大家知道 iPhone 4是不支持WebGL的,而当时开发时间非常紧张,我只能用了Canvas 2d 的方案。

如果点了主场景中的猫,就会进入一个AR捉猫的环境。这个不是web渲染,因为当时移动端的web还不具备获取摄像头数据的能力,我的一个同事正在另外一个分会场讲WebRTC,大家后面有兴趣可以听一下。所以当时AR只能用 Native 的 3D 引擎渲染,叫 T3D,顾名思义Taobao 3D。另外还有一个比较有趣的AR场景,叫“黄金猫”。黄金猫在双十一前后三天会出现在银泰或者苏宁的商场上方,你只要抢到了这只猫至少有一百块钱的红包奖励。

这个项目中第一个难点的是建筑模型的制作。我们的设计师是个平面设计师,不会做3D,他当时给我的图是这样的,你看着办吧,我当时花了整整一天时间做模型。第二点难点是地面算法,这个地面是六边型的结构,要把地面从地球坐标系转换成3D世界里的场景,会分几步。我们小时候都看过世界地图,怎样把一个球形的面投射到平面上呢?这种投影叫做墨卡托投影(Mercator projection)。这个投影算法的代码是服务端拷给我的,因为要保持前后端算法一致,我复制了后端的投影算法。相比墨卡托投影,这是简化的算法,因为要求看到周围的猫是在五十米左右,所以精度并不是特别高,简单的算法就能够满足了。

当时的视角是这样的,以用户当前的位置经纬度为中心,辐射一圈就可以看到周围有多少只猫。这里的六边型地面如果用X、Y两个轴的算法去计算其实是比较慢的,我当时看了一篇论文,这是一个斯坦福的同学花了二十年研究六边型的算法,他本质上是以夹角为120度的X、Y、Z三个轴为坐标轴算,相比算X、Y两个轴的算法快很多。上面还有很多基于这个基础算法拓展的算法如寻路等。

好不容易跨过了双十一的坎,我们已经看到 Canvas 2d 的方案在模型输入和绘制性能方面都是非常弱的。如何继续开发 3D 类的游戏呢?可能大家会问,WebGL在PC上都不行,在手机上行不行呀?我跟大家说,现在完全没问题,我们在上亿台同时在线的设备上都试过了,前提是要做一下WebGL能力检测。PC还有一些古董浏览器不支持WebGL,反而手机比PC发展快得太多。

大家之前理解了3D的概念,3D不是绘图引擎的功能,3D是数学的概念。那CPU绘图与GPU绘图有什么区别呢?大家看一个小电影,这是英伟达几个工程师录的视频,CPU这样绘图,GPU是这样绘图。我们可以看到,GPU是并行处理每一个像素的。

我们刚开始尝试WebGL 小心翼翼,因为怕给手淘带来影响,事实上也造成比较大的Crash。2016年的圣诞节,市场部同学说要不在首淘里下一场雪吧,那就下了。后面我会让大家下这场雪的代价。我们还尝试做类似于右边这种模型粒子动画,这是一只天猫的模型。这两个都是粒子系统,因为我们刚开始不知道怎么做复杂的3D渲染,我们只能从最基础的绘制“点”出发去尝试。

我们团队有一种叫 PopLayer 的技术,可以在当前 Native View上面随时弹出一层 Web View,比如说前一阵子搜一下鹿晗出弹幕,还有明星打电话,都是通过 PopLayer 技术实现的。我刚才提到,在淘宝首页的 Poplayer 里 下一场雪导致了大面积的客户端Crash。原因是iOS 下的 UIWebView 使用 webgl 渲染时,WebCore 会调用到 OpenGL ES 进行渲染,而苹果发现有在后台调用 OpenGL ES,就会直接结束 App。大家知道RequestAnimationFrame API吗?解法就是监测当前用户退出后台时或者当前页面不可见的时候,会把RequestAnimationFrame 停止。上午,小倩也提到过Page Visibility方面的API,我们发现安卓是支持这个API的, 但IOS还是需要调 Js Bridge接口来监听App的是否退后台的状态。接着,我把游戏主循环(或者动画主循环)停下来之后还发现一些用户会Crash。最后我发现一件非常神奇的事情,这个代码大家都知道,它是用来获取CanvasWebGL context,这行代码为什么Crash呢?我们翻了 Webkit 的源码发现它有一个reshape 函数,reshape 会通过 GPU 获取当前画布的高宽,所以它还是会Crash。

3D之旅才刚刚开启,我接下来会跟大家分享一下中间很多心情,以及我的思维是如何进化的。2017年的造物节时我们做了真正意义上的3D应用,当时跟英国一家设计公司合作叫FRAMESTORE,这个电影(《奇异博士》)大家知道吧,特效就是他们设计制作的。

FRAMESTORE 当时给我的东西是这样的,俯视图是这样的,灯光是这样打的。虽然他们在影视特效领域非常牛逼,但是他们也没做过Web应用。而我当时也不知道怎么和设计团队合作,还是我的老方法手写代码。他们给我的模型,我当时也不知道其他高级的格式,只知道Obj + Mtl。如果发现WebGL渲染有问题,我们就去代码里找原因,模型引用的材质对不对,贴图对不对。我们要翻代码看一下是不是引用错了。工作流的问题在这个项目中没有解决,但是促使我开始寻找问题的解法。

这个项目还有一个性能问题,广告牌发光效果,我第一个想到的是后处理(Post Processing),大家不理解的话,可以把它当作实时滤镜,如果在手机屏幕这么大的Bloom滤镜是会卡死的。我当时的方案是在每块广告牌上写一个独立的Shader,这样在iphone6上至少是可以流畅渲染的。

我刚才讲了这么多,痛苦和迷茫。其实我之前做的东西也不能称之为真正的游戏,只能算是营销互动类游戏。我们还是觉得做游戏要向业界规范的方案靠拢,所以游戏编辑器是必须要做的。虽然我今天并没有做出一款游戏编辑器,我会跟大家分享为什么我要做游戏编辑器(现在已经正在做了),这中间的坎坷是今天要讲的重点。

跟英国团队合作之后我非常难过,他们的设计做得那么酷,而我只能实现成这样。我在中国环顾一圈,没有看到Web 3D游戏方面比较好的方案,因为在中国做WebGL的都凤毛麟角。然后2017年我去澳洲参加了Web3D大会,他们当时用了X3dom,像 HTML 一样用标签地描述3D世界。这是一种非常陈旧的技术,虽然也是基于WebGL 渲染。这个方案已经推了十几年了,老外也不知道为什么这么执着,有几十个Paper都是讲这个的。他们讲的东西都非常学术,我觉得对我们的帮助并不是很大。然后我又去工业界寻找解决方案。这是前索尼 PlayStation 的一位同学做的应用,他用的技术大家可能会大吃一惊,他用了Unity。第一次看到 Unity 和 Web 嫁接起来是非常令我震惊的。我当时用的是iphone6,运行这个demo都是 60 fps 满帧,他是怎么做到的呢?我去查了一下它的代码,虽然代码是压缩过的,但是为了突破这个技术难关,我阅读了压缩后的代码并且理解了它背后的实现。

我发现里面有各种各样的新颖的技术。比如,Unity可以合并3D模型的贴图。合并贴图这件事情是很重要的。做前端都知道雪碧图吧,为什么做雪碧图?大家都知道是为了减少网络请求数,但是其实合并贴图对运行时的性能有很大影响。GPU读一张图快还是读十张图快?计算机资源是非常宝贵的,图片要适度合并尽量压缩。一张200K的图片,可能占用3-4倍的显存。JS优化半年减少30K,图片批量压缩减少个几兆都是有可能的,所以要把时间花在能够快速见效的事情上面。

这张图中的 Texture Baker 就是用来烘培并且合并图片。然后,这个是 ITween Path是Unity做路径动画的插件。 Unity还有一个插件叫Collada Exporter 。Collada 是标准的3D模型格式,看到这里我们已经抛弃了之前 Obj+Mtl 的老方案。而Runtime根据我之前的开发经验封装了一套MVC的方案。基于这套工作流,我们做了2017年双十一切红包项目。我们经常调侃:腾讯做游戏和阿里做有戏有什么区别?腾讯做游戏是收钱,我们做游戏是发钱(全场笑)。用Unity带来的好处是能够直接导入设计师给的源文件,如Maya源文件、Photoshop源文件。这里我们看到,红包模型是预先切开的,大家知道切水果也是这样做的,即使你竖着切菠萝它还是横着裂开的(全场笑)。

至于红包的特效,我会经常逛一些国外的网站,这是某个游戏开发者写的Shader特效,我就照着他的思路来写了一个类似的。大家看到一个红包在天上飞,上面有光在流动,其实整个场景中一盏灯都没有打。光照计算,特别是点光源的计算是非常耗性能的。所以大家做3D应用的时候尽量要少放光源。这种效果其实只要在像素着色器中写一行代码就解决了。

红包是怎么切中的呢?Picking这个话题对没有开发过游戏的人也许比较陌生,切红包的游戏里我当时做了两种方案:一种叫做CPUPicker,另一种是GPUPicker。所谓 CPU Picker 在每个红包上面套上一个包围盒,计算射线有没有击中这个包围盒,因为 CPU Picker 的计算成本和场景的复杂度正相关, 用包围盒会比较快;还有一种方案是GPUPicker,通过拾取离屏画布上面的颜色值就行了。虽然感觉GPUPicker性能会特别好,但在移动端性能表现却不佳,因为拾取颜色的过程实际上是CPU和GPU通信的过程,这个过程会比较慢。所以,CPUPicker性能会更好一点。

还有一点就是Dom操作,在Web游戏开发中,Dom操作就是魔鬼。我抓了比较慢的一帧花了25毫秒(约40帧)。游戏逻辑加上WebGL渲染就花了那么几毫秒,而DOM操作却耗掉很长的时间,而且还引发了重绘(紫色部分)。所以 Dom在游戏里是不合适的,GUI 部分需要用2D的Canvas或者WebGL渲染去解决。

最后讲一下音效,我个人非常喜欢游戏中声音给我带来的奖励。我做切红包的时候注意到了上面几点,这也是我上周去北京Unity大会上听到关于CRIWare的声音中间件的内容:

1. 背景音乐要有渐有渐出,这样用户体验比较好;

2.用户做一些操作或者比较重要操作的时候,当前声音要强调一下,背景音乐减弱一下;

3.声音要有变化,比如说很多射击的游戏,如果枪声都一样,用户听觉会疲劳的,我们切红包时左切和右切都是不一样的。

这个软件叫 bfxr,是一款制作游戏音效的小软件,在线和客户端版本都有,人人都可以设计音效。

讲了那么多技术点,我们总要看一下业界真正做游戏的人是怎么做的。我大概探索了一两年,发现 Playcanvas 引擎是Web世界上最健全的游戏引擎。它的引擎代码是开源的,但是编辑器不开源。我分析了一下它的引擎源码,大概有几部分组成:ECS的架构,Unity 也是采用这样的设计模式。第二个是PBR,基于物理的渲染模型,看起来更像真实世界的渲染。物理引擎也是很重要的,还有输入设备,比如说你的游戏手柄、手机都是输入设备。Playcanvas 和 Threejs 有什么区别?Threejs只是一个3D渲染库。游戏还有一个非常重要的东西叫编辑器,这是 Playcanvas在线的编辑器,我看了这个游戏之后就觉得一定要做编辑器,因为编辑器是引擎的载体。如果没有编辑器,我们每次开发游戏要注意的工程和技术问题太多。

最后讲一下我们团队思考的编辑器的架构,现在只是一张工程架构图。游戏最后发布的内容是什么?就是一堆资源,图片、模型、音频、脚本,在Web开发环境中最后都要发上CDN。游戏里的大部分资源如音频、全景图、模型这些都是第三方软件输入的,模型资源的序列化、减面、合并、烘培等操作我们暂时可能不会去做(还是交给Unity做),中间GUI部分就是编辑器的面板操作,最后 Script 组件和 Shader 可以通过 Vscode 来编辑。这张图是我一两年的心得,里面有一些细节时间问题这里就不展开了。OK,我讲完了,大家有什么问题。

问1:开发游戏是不是要先学习数学知识?

徐乾伟:这些都是骗人的,游戏引擎都封装了数学库。游戏开发中,边做边学很重要。我举个我上周在Unity Beijing听到的例子,开发青蛙旅行的人在他们公司是个助理工程师,一群前辈都把活给都扔给了他,然后他就开发出来了。关于游戏和图形的数学方面的书,你只要搜一下游戏数学的关键词,就会出来非常多的结果。

问2:老师您好,我们这边我们的团队都是Web开发的,对游戏开发不是很清楚,以限有的Web开发为基础,我们的同学应该学习那些知识?

徐乾伟:前端转型到游戏开发者,可以先试着做一款游戏,或者说别人做了一款比较好玩的游戏,你不看源代码的情况下,你用自己具备的技术知识克隆出来,你在做的过程中自然而然会接触到游戏开发中的各种概念和知识体系。