霍比特人体验:通过移动 WebGL 将中土世界带入生活
从历史上看,为手机和平板电脑带来基于 Web 的交互式多媒体体验一直是一项挑战。 主要限制是性能、API 可用性、设备上 HTML5 音频的限制以及缺乏无缝内联视频播放。
今年早些时候,我们与谷歌和华纳兄弟的朋友启动了一个项目,为新的霍比特人电影 《霍比特人:史矛革之战》 打造移动优先的网络体验。 构建多媒体密集型移动 Chrome Experiment 是一项非常鼓舞人心且具有挑战性的任务。
在我们现在可以访问 WebGL 和 Web Audio 的新 Nexus 设备上,该体验针对 Android 版 Chrome 进行了优化。 然而,由于硬件加速合成和 CSS 动画,大部分体验也可以在非 WebGL 设备和浏览器上访问。
整个体验基于中土世界地图以及霍比特人电影中的地点和角色。 使用 WebGL 使我们能够戏剧化和探索霍比特人三部曲的丰富世界,并让用户控制体验。
WebGL 在移动设备上的挑战
首先,术语移动设备非常宽泛。 设备的规格差异很大。 因此,作为开发人员,您需要决定是要支持更多的设备但体验不那么复杂,还是像我们在本例中所做的那样,将支持的设备限制为能够显示更逼真的 3D 世界的设备。 对于“中土世界之旅”,我们专注于 Nexus 设备和五款流行的 Android 智能手机。
在实验中,我们使用 了 three.js ,就像我们为之前的一些 WebGL 项目所做的那样。 的初始版本来开始实施 的Trollshaw 游戏 我们通过构建可以在 Nexus 10 平板电脑上良好运行 。 在对设备进行一些初步测试后,我们想到了一个优化列表,看起来很像我们通常用于低规格笔记本电脑的列表:
使用低多边形模型
使用低分辨率纹理
尽可能减少 drawcall 的数量 通过合并几何体
简化材料和照明
删除后期效果并关闭抗锯齿
优化 Javascript 性能
以一半大小渲染 WebGL 画布并使用 CSS 放大
在将这些优化应用到我们的第一个游戏粗略版本后,我们获得了稳定的 30FPS 帧率,这让我们很满意。 当时我们的目标是在不对帧速率产生负面影响的情况下改善视觉效果。 我们尝试了很多技巧:有些确实对性能产生了影响; 一些没有像我们希望的那样产生很大的影响。
使用低多边形模型
让我们从模型开始。 使用低多边形模型当然有助于减少下载时间,以及初始化场景所需的时间。 我们发现我们可以在不影响性能的情况下大大增加复杂性。 我们在这个游戏中使用的巨魔模型大约有 5000 张面孔,场景大约有 40000 张面孔,效果很好。
Trollshaw 森林的巨魔之一
对于体验中的另一个(尚未发布)位置,我们看到减少多边形对性能的影响更大。 在那种情况下,我们为移动设备加载的多边形对象低于为桌面加载的对象。 创建不同的 3D 模型集需要一些额外的工作,但并非总是如此。 这实际上取决于您的模型开始时的复杂程度。
在处理包含大量对象的大场景时,我们试图在如何划分几何体方面具有战略意义。 这使我们能够快速打开和关闭不太重要的网格,找到适用于所有移动设备的设置。 然后,我们可以选择在运行时合并 JavaScript 中的几何图形以进行动态优化,或者在预生产中合并它以节省请求。
使用低分辨率纹理
为了减少移动设备上的加载时间,我们选择加载大小为桌面纹理一半的不同纹理。 事实证明,所有设备都可以 纹理尺寸 处理最大 2048x2048px 的 ,大多数可以处理 4096x4096px。 一旦将它们上传到 GPU,对单个纹理的纹理查找似乎就不是问题了。 纹理的总大小必须适合 GPU 内存,以避免不断地上传和下载纹理,但这对于大多数网络体验来说可能不是一个大问题。 然而,将纹理组合到尽可能少的 spritesheet 中对于减少 drawcall 的数量很重要——这对移动设备的性能有很大影响。
Trollshaw 森林巨魔之一的纹理(原始尺寸 512x512px)
简化材料和照明
材料的选择也会极大地影响性能,必须在移动设备上进行明智的管理。 使用 MeshLambertMaterial
(每个顶点光计算)在 three.js 中而不是 MeshPhongMaterial
(每个纹素光计算)是我们用来优化性能的一件事。 基本上我们尝试使用尽可能少的光照计算的简单着色器。
要查看您使用的材质如何影响场景的性能,您可以使用 MeshBasicMaterial
. 这会给你一个很好的比较。
scene.overrideMaterial = new THREE.MeshBasicMaterial({color:0x333333, wireframe:true});
优化 JavaScript 性能
在为手机开发游戏时,GPU 并不总是最大的障碍。 大量时间花在 CPU 上,尤其是物理和骨骼动画。 根据模拟,有时会有帮助的一个技巧是仅每隔一帧运行这些昂贵的计算。 当涉及对象池、 垃圾收集和对象创建 时,您还可以使用可用的 JavaScript 优化技术。
在循环中更新预先分配的对象而不是创建新对象是避免游戏过程中垃圾收集“打嗝”的重要步骤。
例如,考虑这样的代码:
var currentPos = new THREE.Vector3(); function gameLoop() { currentPos = new THREE.Vector3(0+offsetX,100,0); }
此循环的改进版本避免创建必须被垃圾收集的新对象:
var originPos = new THREE.Vector3(0,100,0); var currentPos = new THREE.Vector3(); function gameLoop() { currentPos.copy(originPos).x += offsetX; //or currentPos.set(originPos.x+offsetX,originPos.y,originPos.z); }
事件处理程序应尽可能只更新属性,并让 requestAnimationFrame
渲染循环句柄更新舞台。
另一个技巧是优化和/或预先计算光线投射操作。 例如,如果您需要在静态路径移动期间将对象附加到网格,您可以在一个循环中“记录”位置,然后从该数据中读取,而不是对网格进行光线投射。 或者就像我们在 Rivendell 体验 中所做的那样,光线投射以寻找与更简单的低多边形不可见网格的鼠标交互。 在高多边形网格上搜索碰撞非常缓慢,通常应避免在游戏循环中进行。
以一半大小渲染 WebGL 画布并使用 CSS 放大
WebGL 画布的大小可能是您可以调整以优化性能的最有效的参数。 用于绘制 3D 场景的画布越大,每一帧上必须绘制的像素就越多。 这当然会影响性能。具有高密度 2560x1600 像素显示屏的 Nexus 10 必须推动 4 倍于低密度平板电脑的像素数。 为了针对移动设备优化这一点,我们使用了一个 技巧 ,将画布设置为一半大小 (50%),然后使用硬件加速 CSS 3D 转换将其放大到预期大小 (100%)。 这样做的缺点是像素化图像,其中细线可能会成为问题,但在高分辨率屏幕上效果还不错。 额外的性能绝对值得。
同一场景在 Nexus 10 上没有画布缩放 (16FPS) 并缩放到 50% (33FPS)。
对象作为积木
为了能够创建 Dol Guldur 城堡的大迷宫和永无止境的 Rivendell 山谷,我们制作了一组可重复使用的积木 3D 模型。 重用对象让我们确保对象在体验开始时被实例化和上传,而不是在体验中间。
Dol Guldur 迷宫中使用的 3D 对象构建块。
在 Rivendell 中,我们有许多地面部分,随着用户旅程的进行,我们不断地在 Z 深度上重新定位。 当用户通过路段时,这些路段会在远处重新定位。
对于 Dol Guldur 城堡,我们希望每场比赛都能重新生成迷宫。 为此,我们创建了一个重新生成迷宫的脚本。
从一开始就将整个结构合并成一个大网格会导致场景非常大且性能不佳。 为了解决这个问题,我们决定根据构建块是否在视图中来隐藏和显示它们。 从一开始,我们就有了使用 2D raycaster 脚本的想法,但最终我们使用了 内置的 three.js frustrum culling 。 我们重新使用了 raycaster 脚本来放大玩家面临的“危险”。
下一件要处理的大事是用户交互。 在桌面上,您有鼠标和键盘输入; 在移动设备上,您的用户通过触摸、滑动、捏合、设备方向等进行交互。
在移动网络体验中使用触摸交互
添加触摸支持并不困难。 有 很多关于该主题的文章 可供阅读。 但是有些小事情会使它变得更加复杂。
您可以 同时使用 触摸和鼠标。 Chromebook Pixel 和其他触控笔记本电脑同时支持鼠标和触控。 一个常见的错误是检查设备是否支持触摸,然后只添加触摸事件侦听器而没有为鼠标添加触摸事件侦听器。
不要更新事件侦听器中的呈现。 将触摸事件保存到变量中,并在 requestAnimationFrame 渲染循环中对它们做出反应。 这可以提高性能并合并冲突事件。 确保在事件侦听器中重复使用对象而不是创建新对象。
请记住它是多点触控:event.touches 是所有触摸的数组。 在某些情况下,更有趣的是查看 event.targetTouches 或 event.changedTouches 而不是只对您感兴趣的触摸做出反应。为了将点击与滑动分开,我们在检查触摸是否已移动(滑动)或是否已移动之前使用延迟它仍然是(点击)。 为了得到一个捏,我们测量了两个初始触摸之间的距离以及它如何随时间变化。
在 3D 世界中,您必须决定相机对鼠标和滑动操作的反应。 添加相机移动的一种常见方法是跟随鼠标移动。 这可以通过使用鼠标位置的直接控制或增量移动(位置更改)来完成。 您并不总是希望移动设备上的行为与桌面浏览器相同。 我们进行了广泛的测试,以确定适合每个版本的内容。
在处理较小的屏幕和触摸屏时,您会发现用户的手指和 UI 交互图形通常会挡住您想要显示的内容。 这是我们在设计本机应用程序时习惯的事情,但在使用 Web 体验之前并没有真正考虑过。 这对设计师和 UX 设计师来说是一个真正的挑战。
概括
我们从这个项目中得到的总体经验是,WebGL 在移动设备上运行得非常好,尤其是在较新的高端设备上。 在性能方面,多边形数量和纹理大小似乎主要影响下载和初始化时间,而材质、着色器和 WebGL 画布的大小是优化移动性能的最重要部分。 但是,影响性能的是各个部分的总和,因此您可以采取的一切优化措施都很重要。
以移动设备为目标还意味着您必须习惯于考虑触摸交互,这不仅与像素大小有关——它还与屏幕的物理尺寸有关。 在某些情况下,我们必须将 3D 摄像机移近一些才能真正看到发生了什么。
实验已经启动,这是一段奇妙的旅程。 希望你喜欢它!
想尝试一下吗? 开启您自己 的中土之旅 。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: 移动端跨设备同步运行测试
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论