Asm.js 和 WebGL 在 Unity 和 Unreal Engine 中的应用





5.00/5 (4投票s)
随着 WebGL 和 asm.js 的出现,开发者现在可以从浏览器内部充分利用其计算设备的强大功能,并进入以前无法进入的市场。
Unity 和 Epic 的虚幻引擎(游戏开发者经常使用的流行中间件工具)不仅限于创建作为可执行文件运行的编译应用程序。Unity 之前有一个 网页播放器,它是一个使用 ActiveX 的可下载插件。Chrome 停止支持 NPAP (Netscape Plugin API),但 一年多前就宣布了。
在四月份,随着 Chrome 42 稳定版的发布,他们终于将其砍掉了。原因有很多,但最值得注意的是他们提到“挂起、崩溃、安全事件和代码复杂性。Google 建议使用 Web 标准,例如 WebGL,我将在下面解释。”
微软也在效仿,废弃了 ActiveX、VBScript、attachEvent 和其他遗留技术,转而支持 Web 标准。HTML5 时代的功能大大减少了对 ActiveX 控件的需求,这也可以在不同浏览器之间生成可互操作的代码。
随着 WebGL 和 asm.js 的出现,开发者现在可以从浏览器内部充分利用其计算设备的强大功能,并进入以前无法进入的市场。在本教程中,我将向您展示“如何”的一小部分。
为什么要编译成 JavaScript?
JavaScript 是唯一在所有 Web 浏览器中都可用的语言。尽管只有 JavaScript 才能在浏览器中运行,但您仍然可以用其他语言编写代码并将其编译成 JavaScript,从而使其也能在浏览器中运行。这通过一项名为 emscripten 的技术得以实现。
Emscripten 是一个基于 LLVM 的项目,它将 C 和 C++ 编译成 asm.js 格式的高性能 JavaScript。简而言之:在浏览器内部使用 C 和 C++,达到接近原生的速度。更好的是,emscripten 将 OpenGL(一个桌面图形 API)转换为 WebGL(该 API 的 Web 版本)。
这段代码是如何转换为 WebGL 的?
Unity 最近也对其在 WebGL 上运行的软件进行了一些性能基准测试。
然而,代码进行交叉编译(通常也称为“转译”)并非没有缺陷。静态类型语言中常见的性能增强技术,例如多线程(JS 是单线程的)和 SIMD(单指令多数据)尚不可用。
尽管如此,Mozilla 与其他几家领先的科技公司一直在研究 SIMD.js,因此性能提升和功耗降低可能在不久的将来实现。在此处阅读更多相关信息。Unity 没有采用上述性能优化,而是依赖于其新的脚本运行时 IL2CPP (In Line 2 C++)。这是一个不同帖子中的故事,但 Unity 每隔几周都会发布一个精彩的网络系列,以说明 IL2CPP 的工作原理。
IL2CPP 有两个不同的部分
- 预编译(AOT)编译器
- 支持虚拟机(VM)的运行时库
.NET 编译器中的中间语言 (IL) 通过 AOT 编译器编译为 C++ 源代码。运行时库提供的一些好处包括平台无关的线程和文件访问以及垃圾回收器等服务和抽象。
这样看
当您在 Windows 机器上运行 .exe 文件时,它实际上不是字节码(0 和 1)。它仍然是虚拟机在运行时读取的二进制文件,然后转换为字节码。Windows 机器上的 DotNet CLI 是一个可以读取此二进制文件的虚拟机的示例。CPU 无法理解除二进制之外的任何内容,因此需要额外的步骤。
仍然感到困惑?这篇文章解释了更多关于机器代码、字节码和虚拟机之间的区别。
asm.js 如何发挥作用?
Asm.js,即 Assembly JavaScript 的缩写,是 JavaScript 的一个子集。无论是在现有 JavaScript 引擎中运行,还是在识别并优化 asm.js 的预编译 (AOT) 引擎中运行,asm.js 程序都将表现出相同的行为——当然,速度除外!
在速度方面,很难精确衡量它与原生代码的对比,但将 C 程序编译为 asm.js 的初步基准测试通常比使用 Clang(C、C++ 和 Obj-C 编程语言的编译器前端)进行原生编译慢大约 2 倍。需要注意的是,这对于单线程程序来说是“最佳”情况。有关 JavaScript 语言这一限制的更多信息,请参阅下文。
在后端,Clang 使用 LLVM,它是一个用于构建、优化和生成中间和/或二进制机器代码(又是那些 0 和 1)的库。LLVM 可以用作编译器框架,您提供“前端”(解析器和词法分析器,如 Clang)和“后端”(将 LLVM 表示转换为实际机器代码的代码)。
延伸阅读:Mozilla 的 Alon Zakai 有一个精彩的幻灯片演示,其中详细介绍了这一切是如何运作的。
那么 asm.js 有多酷呢?它甚至有自己的 Twitter 账号:@asmjs。虽然 asm 网站有些简陋,但它确实涵盖了 W3C 规范,并且有详细的常见问题解答。更棒的是,Mozilla 在 2014 年协调了 Humble Mozilla Bundle,让你可以购买大量利用 asm.js 的游戏。
为什么不直接将 JavaScript 代码转换为 asm.js?
JavaScript 由于其动态特性,无法真正编译成 asm.js 并提供太多好处。这与尝试将其编译成 C 语言,甚至是 原生代码 时遇到的问题相同——需要一个虚拟机来处理那些非静态方面。然而,您可以手动编写 asm.js。
如果已经能够以完全静态的方式翻译标准 JavaScript,那么就没有必要使用 _asm.js_。Asm.js 的存在是为了实现 JavaScript 在开发者无需任何努力的情况下变得更快。对于 JIT 来说,理解动态语言和静态编译器一样困难。
为了更好地理解这一点,重要的是要理解 asm.js 为什么能提供性能优势;或者为什么静态类型语言比动态类型语言性能更好。一个原因是“运行时类型检查需要时间”,而更周全的答案会包括优化静态类型代码的可行性增强。从 C 等静态类型语言转换的最后一个好处是,编译器在编译时知道每个对象的类型。
Asm.js 是 JavaScript 的一个受限子集,可以很容易地转换为字节码。为了获得这个优势,第一步需要将 JS 的所有高级功能分解为该子集,这有点复杂。但是 JavaScript 引擎经过优化和设计,可以直接将所有这些高级功能转换为字节码——因此像 asm.js 这样的中间步骤并没有带来太多优势。
WebGL 在做什么?
WebGL(Web 图形库)是一个 JavaScript API,用于在任何兼容的 Web 浏览器中渲染交互式 3D 计算机图形和 2D 图形,无需使用插件。WebGL 具有三个显著优势:
- 任务:绘制反射材料或复杂光照会产生大量开销,鉴于 JavaScript 是单线程且受 CPU 限制,为什么不将其中一些任务卸载到设备中的 GPU 上,让它来完成繁重的工作呢?
- 性能:利用硬件加速(设备中内置的 GPU),WebGL 非常适合游戏或复杂的视觉效果。
- 着色器:可以通过称为“着色器”的小程序生成复杂的视觉效果。这可能像生成棕褐色着色效果一样简单,或者像水或火焰等更复杂的模拟。访问Shadertoy 以查看一些真正突出此功能的示例。
当您构建一个 WebGL 项目时,Unity 会创建一个包含以下文件的文件夹
- 一个 `index.html` 文件,将您的内容嵌入到网页中。
- 一个包含播放器代码的 JavaScript 文件。
- 一个 .mem 文件,包含用于初始化播放器堆内存的二进制图像。
- 一个 .data 文件,包含资产数据和场景。
- 一些支持 JavaScript 文件,用于初始化和加载播放器。
您还可以自定义页面样式以更好地适应您的游戏,尽管建议利用全屏 API 以获得更沉浸式的体验。
有兴趣学习 WebGL 吗?请查看 WebGL Academy,那里有完整的课程。
WebGL 缺少什么?
WebGL 是 OpenGL ES 规范的一个子集。这是您经常在移动设备上看到的图形 API,例如 Android 和 iOS 设备。ES(嵌入式系统)规范实际上是 OpenGL 的一个子集,OpenGL 是台式机和游戏机(例如 PlayStation 和 Wii)可用的图形 API。由于 WebGL 与 OpenGL 不是直接的一一对应关系,因此会缺少一些功能。
以下是 Unity 游戏 WebGL 版本目前缺少的一些功能列表。预计此列表会随着时间而改变。
- Substance 纹理的运行时生成
- 电影纹理
- 除了 WWW 类之外的网络(可提供 WebSockets 插件)
- 支持网络摄像头和麦克风访问
- 硬件光标支持
- 大多数非基本音频功能
- 脚本调试
- 线程
- 任何需要动态代码生成的 .NET 功能
浏览器支持情况如何?
这才是事情变得疯狂的地方。您可以在这里尝试他们的两个 WebGL 演示。您需要使用支持 asm.js 的浏览器。截至撰写本文时(2015 年 7 月),asm.js 的支持情况如下:
- Firefox
- Chrome
- Edge
- Safari
值得注意的是,asm.js 规范在所有浏览器中并未完全实现,因此结果会有所不同。遗憾的是,asm.js 未列在流行的功能检查网站 CanIUse.com 上,因此很难清楚地了解它在每个浏览器中的支持情况。这在移动浏览器上不起作用,因为它们目前不支持 asm.js,尽管有几个支持 WebGL。我曾在 2014 年 11 月写过一篇关于 WebGL 在移动设备上当前状态 的文章。
性能如何?
您可以在浏览器中尝试 Unity 的基准测试套件,看看其 C# 到 JavaScript 的转换性能如何。这涵盖了从 Mandelbrot GPU 测试到 2D 物理和粒子等所有内容。Unity 在 2014 年 10 月发布的这篇帖子,在微软 Edge 浏览器宣布之前,也强调了一些有趣的发现:
- 在几乎所有基准测试中,使用 asm.js 的 Firefox 都比 Chrome 和 Safari 快,并且目前是运行 Unity WebGL 内容的最佳浏览器。
- 当您主要受 GPU 限制时,可以预期 WebGL 的性能与原生代码非常相似。
- 在某些领域,WebGL 实际上会显著超越原生代码。对于那些高度依赖脚本性能的测试(Mandelbrot 和 CryptoHash,它们都用 C# 实现了算法),IL2Cpp 可以生成更优化的代码(更多信息请参阅此帖子)。
- 对于大量优化以使用多线程和/或 SIMD 的领域,例如 3D 物理测试(Unity 5.0 中的 PhysX 3.3 现在完全多线程),原生代码仍然比 WebGL 快几倍。相比之下,当比较 Firefox 与原生时,2D 物理非常接近(Box2D 不是多线程)。我们希望未来 JavaScript 将带来 SIMD 和多线程扩展,届时这种情况可能会改变。
那么,这对您,作为开发者,意味着什么呢?自然,在某些领域,WebGL 明显慢于原生代码,例如利用多线程的领域,但 WebGL 性能尚可,而且每天都在进步。事实上,致力于开发网络标准的国际社区 W3C 刚刚宣布了 WebAssembly,这是一种用于网络安全代码的新中间表示。“Wasm”是低级安全代码的新二进制语法,目前将与 asm.js 并行运行。这将进一步提高在浏览器中运行的 JavaScript 应用程序的性能。
Alon Zakai 在三月份发表了一篇文章,概述了过去一年中 asm 和 JavaScript 的整体速度在各大浏览器中是如何提升的。
为什么会有人想做这个?
这是一个相当常见的问题。但我听到最多的问题是“谁会想下载一个 60MB 的网站?”你说的没错——一个网站有 60MB 确实很大!但我想,每天从 YouTube 和 Netflix 下载数 GB 视频内容的人就是那些人。如果你把它看作一个网站,那么当然,它很大。但如果你把它看作一个游戏,60MB 就很小了!下面的案例研究很好地说明了这一点。
此外,作为开发者,您现在可以绕过应用商店的限制。想要更新您的应用程序?没问题,将新版本推送到您的网站。不想等待 iOS 应用商店一周的审批流程(也就是说,如果它获得批准的话)?完美,推送到您自己的网站。
当然,您也可以通过付费墙出售它;或者要求某种授权才能玩该游戏。此外,您不需要支付应用商店的年度许可费,也不需要为他们的商店准备图片,为他们的桌面准备图标等。现在事情开始变得有吸引力了,而我们才刚刚触及表面。
看看 Illyriad games 团队在他们的太空战斗游戏 Age of Ascent 中做了什么。他们最初只传输一小部分数据,刚好够你开始,然后才向你发送额外的数据。我相信我们上次对话时,它开始于 50MB。您可以在我与他们一起做的播客中了解更多信息:在这里。用户可以立即加入并玩游戏。无需下载庞大的客户端,并立即降低了进入门槛。在我玩 Everquest 的那些年里,十几岁的我一定会喜欢这个。
相比之下,传统游戏在你可以开始玩之前会一次性将所有内容发送给你。当然,游戏机刚刚开始使用“分块”技术,它将游戏分成更小的部分,并立即开始下载你需要玩的部分。
Jonas Echterhoff 指出,在 Unity 中,通过使用 AssetBundles 已经可以流式传输资产。或者,您可以尝试这个 Asset Store 包,它重新打包了 WebGL 构建数据,以便您的构建中的场景被拆分成多个文件,并且您的内容可以在第一个场景加载后开始。
https://www.assetstore.unity3d.com/en/#!/content/38368
为了与太空模拟主题保持一致,我研究了《星际公民》,该游戏预计将达到 100GB 左右。你真的相信你能体验到这 100GB 的所有内容吗?
离线体验
仅仅因为您指向一个 HTML5 网站,并不意味着您不能拥有离线体验。不相信我?看看 Syd Lawrence(Snowbuddy 的创作者之一)的这段视频。Syd 运营着 We Make Awesome Sh,在他的演讲中,他展示了一些用 PhoneGap 制作的令人难以置信的应用程序,以及他在 PhoneGap Day EU 2015 上制作高性能 PhoneGap 应用程序的 7 大技巧,但特别强调了如何创建离线体验。
明智的做法是为您的应用程序混合使用本地和远程内容。IndexedDB、localStorage 和 AppCache 等技术(Microsoft Edge 支持)允许这样做。可以在您的应用程序包中保留一个本地页面,该页面仍然可以提供基本的离线体验。
案例研究:Owlchemy Labs 的 Aaaaa! 从 Unity 转换为 asm.js
Owlchemy Labs 团队在 2014 年转换了他们的游戏《Aaaaa!》,并发表了一篇关于该过程的精彩事后分析文章。去年六月,他们使用 WebGL 导出器预阿尔法版本,将所有 C# 代码转换为一个 JavaScript 文件,该文件有超过一百万行代码!
《Aaaaa!》拥有超过 200 个关卡,超过 300 个可在运行时生成的游戏资产,以及 38 首完整歌曲。在 PC/mac 上,他们使用的是 388MB 的未压缩文件,因此可以想象,每次有人想玩游戏时都必须下载所有这些内容会有点麻烦。
他们最大的节省空间的方法之一是Unity 的 AudioClip 流媒体解决方案,它可以在运行时按需流媒体播放音乐。完成后,他们最终压缩后的 WebGL 构建大小(包括所有已加载的资产和 Unity 引擎本身)最终为 68.8 MB。而压缩后的独立 PC 构建则几乎是其三倍,达到 192 MB。
当然,需要进行一些用户体验的更改,包括重新绑定 Esc 键,在许多游戏中,它会显示暂停菜单,但在浏览器中,它会退出全屏模式并释放鼠标锁定。此外,由于浏览器的安全模型强制这些游戏沙盒化,将大量数据保存到磁盘或从用户的硬盘加载自定义音频可能会带来问题。
最后,考虑某种云同步功能也很重要,因为玩家通常不会只在一台机器上玩基于网络的游戏。对于消费者来说,从任何机器加载到他们的个人资料中并让他们的设置/保存内容立即出现会方便得多。
还有其他中间件工具利用此技术吗?
Epic 的虚幻引擎 4 也可以导出到 WebGL 并利用 asm.js。您可以在此处找到分步说明。他们的流程与 Unity 的流程几乎相同,只是缺少第一个 C# 步骤,因为您在虚幻引擎中编写的代码已经是 C++。
Epic 目前的展示作品是 Tappy Chicken,一个类似 Tappy Bird 的游戏,也适用于 iOS 和 Android。他们于 2014 年 GDC 首次展示了 UE 4 在 Firefox 中运行。
在那之前的一年,在 GDC 上,Mozilla 和 Epic 在他们的一次演讲中震惊了所有人,他们透露 UDK (Unreal Engine 3) 在与 Epic Citadel 演示合作一周后,就可以在浏览器中运行了。
NomNom Games 的 Monster Madness 是第一款使用 asm.js 在 Web 上发布的商业虚幻引擎 3 游戏。
未来会怎样?
WebGL 不仅限于游戏。应用程序也可以轻松利用这项技术。
抢先体验虚幻巴黎 1.2 演示,用户可以在其中漫步于精心设计的公寓。(下载链接)
想象一下,您是一名建筑师或设计师,正试图向客户推销这个。您可以即时在浏览器中运行它。更好的是,用户无需下载整个应用程序。
看看像 Age of Ascent 这样的东西。下载 54MB,您就可以开始玩这个应用程序,因为它只流式传输您**当时**需要的内容,并且可以使用 IndexedDB 等技术将其缓存到本地,因此您无需再次下载。用户可以在几秒钟内启动并运行。我在 12 月采访了 Ilyriad games 的团队,以更好地了解他们是如何将他们的技术组合在一起的。
另一方面,我们有 《星际公民》,它起步大小为 70GB。这对许多人来说是一个巨大的入门门槛,尤其是在他们可能没有快速宽带的地方。
对于那些可能不想使用 C 或 C++ 编写应用程序的开发者,您仍然可以使用 WebGL 框架并全部用 JavaScript 编写。例如,BabylonJS 就是一个例子,它包含一个用于 2D 和 3D 应用程序的物理引擎,以及 handJS,它将所有输入类型(点击、触摸、笔)都汇集到指针事件中。
还有其他替代方案吗?
当然!PlayCanvas 是一个出色的基于 WebGL 的框架,它使用 asm.js 进行物理计算。更棒的是,它拥有出色的文档和教程,还有一个基于浏览器的编辑器。
对于这样的工具,您需要使用某种包装器(例如 Cordova 或 PhoneGap)将其移植到应用商店,例如 Google Play、App Store 或 Windows Marketplace。ManifoldJS。
ManifoldJS 旨在通过利用 Web App Manifests,让移动开发者的生活比以往任何时候都更容易,它允许网站声明类似应用程序的属性。ManifoldJS 将该标准用于支持它的平台,但对于不支持它的平台则退回到 Cordova。Cordova 很棒,但 W3C 也考虑了 Mozilla(Firefox Open Web Apps)、Google(Chrome Hosted Apps)和微软(Windows 8 有本地 Web 应用程序,Windows 10 扩展到托管 Web 应用程序)所做的工作。有了这个,我们现在可以封装网站并创建混合应用程序,这些应用程序可以部署在各种应用商店中,同时仍然利用每个设备的许多原生特性(联系人、日历、文件存储、陀螺仪、GPS 等)。
当我们把两者结合起来,我们就可以创建以原生速度运行的应用程序,这些应用程序可以部署在多个应用商店中,并且主要使用一个代码库。移动开发没有银弹,但这无疑让过程变得更容易。
结论
Unity 在其文档中概述了将您的游戏导出到 WebGL 播放器的过程。WebGL 和 asm.js 的浏览器支持正在不断改进,Firefox 甚至在今年早些时候在旧金山举行的游戏开发者大会上展示了 WebGL 2.0 的功能。WebGL 2.0 带来了一系列改进,包括一次渲染最多 32 个纹理的能力,而不是当前的 8 个标准,此外还为开发者提供了抗锯齿和多个渲染目标的访问权限。
将 Unity 游戏移植到 WebGL 有许多优点
- 通过非精选应用商店分发
- 通常包体更小
- 轻松演示或分享项目
开发者已经证明了这种模式是可行的,正如《Aaaaa!》案例研究和 Mozilla Humble Bundle 所展示的那样,所以现在是利用浏览器最终能提供的一切并让您的作品获得更多曝光的绝佳时机。
更多关于 JavaScript 的实践
本文是微软技术布道师关于实用 JavaScript 学习、开源项目和互操作性最佳实践的 Web 开发系列文章的一部分,其中包括 Microsoft Edge 浏览器和新的 EdgeHTML 渲染引擎。
我们鼓励您使用 dev.modern.IE 上的免费工具,在包括 Microsoft Edge(Windows 10 的默认浏览器)在内的各种浏览器和设备上进行测试。
- 扫描您的网站是否存在过时库、布局问题和可访问性问题
- 将虚拟机用于 Mac、Linux 和 Windows
- 在您自己的设备上远程测试 Microsoft Edge
- GitHub 上的编程实验室:跨浏览器测试和最佳实践
来自我们工程师和布道者的 Microsoft Edge 和 Web 平台深度技术学习
- Microsoft Edge Web Summit 2015(新浏览器有什么值得期待的,新的支持的 Web 平台标准,以及 JavaScript 社区的特邀演讲者)
- 哇,我可以在 Mac 和 Linux 上测试 Edge 和 IE!(来自 Rey Bango)
- 在不破坏 Web 的情况下推进 JavaScript(来自 Christian Heilmann)
- 让 Web 正常工作的 Edge 渲染引擎(来自 Jacob Rossi)
- 利用 WebGL 释放 3D 渲染(来自 David Catuhe,包括 vorlon.JS 和 babylonJS 项目)
- 托管 Web 应用程序和 Web 平台创新(来自 Kevin Hill 和 Kiril Seksenov,包括 manifold.JS 项目)
更多免费的跨平台工具和网络平台资源