热门
Unity 2018.2正式支持WebAssembly
2015年我们宣布计划将Unity WebGL构建目标的导出文件改为WebAssembly,即Wasm。现在Unity 2018.2已经支持这项改动。本篇文章我们将介绍它是如何实现,以及对使用Unity制作交互式Web内容的开发者的意义所在。
Wasm的发展
我们在Unity 5.6中曾对WebAssembly支持作为实验性功能发布,WebAssembly刚开始就得到四大主流桌面端浏览器的支持。从此时起,Unity和浏览器就开始加入不少相关的改进内容和错误修复。
从此WebAssembly的用户使用量也在增长,我们得到了许多积极的反馈。所以下一步计划是正式支持它:Unity 2018.1标志着对WebAssembly支持的实验阶段结束,同时我们也实现了制作Wasm-only版本的可能。
在Unity 2018.2,Wasm最终取代了asm.js,成为了默认链接目标(Linker Target)。这意味着,当开发者发布Unity WebGL构建目标时,Unity 2018 LTS将默认使用Wasm。
这是一个非常重要的里程碑,我们一直在为实现这个目标而努力。我们的要求是:确保Unity的实现和浏览器支持是稳定的,并且需要覆盖Wasm的内部测试,这其中包括升级Emscripten和修复代码中的一些问题。
如今我们拥有了所有测试套件的Wasm变体,任何将要合并到程序主线的改动都会针对WebAssembly进行测试。
请注意:我们仍然维护和运行asm.js套件,但现在所有要合并到主线的改动都是针对Wasm进行测试。
WebAssembly与asm.js
下面详细介绍一下WebAssembly,并探讨与asm.js之间的区别。
Wasm比asm.js速度更快、容量更小且内存使用率更高,这些都是Unity WebGL导出的痛点。Wasm也许不能解决所有的问题,但它能改善所有领域的平台。需要注意,性能可能会因浏览器实现而异。但所有浏览器厂商都将致力于支持和改进WebAssembly。
打开Wasm文件时,你会立即注意到它是一个二进制文件,而asm.js是个文本文件。这种发布代码的方法比较紧凑,但是也造成开发者无法在调试的时候而阅读或修改代码。
Wasm有自己的指令集,而asm.js则是“高度可优化”的Javascript子集。在开发构建中,WebAssembly给算术运算加入了更为精确的错误检测功能,它能在特定情况抛出异常,例如:除以零、将大浮点数舍为整数等。在非开发版本中,这类算术错误的检测将被屏蔽,所以不会影响用户体验。
1、代码大小
为了生成WebAssembly,我们有一套基于IL2CPP、emscripten和binaryen复杂的工具链,它会将C/C++和C#代码转换为WebAssembly。这会产生二进制文件<build name>.wasm.code.Unityweb,从而实现比asm.js更小的版本。
此外,WebAssembly开发版本的代码大小要比asm.js小数十MB,而非开发版本的大小会小几百KB。为了让你了解衡量基线,WebAssembly空项目的代码大小约比asm.js的小12%,如果包含3D物理则会小18%。
请注意:上图的测试结果在测量时不包含任何非必要资源包,也不包含内置着色器,使用Brotli作为压缩格式。对于任意改进内容,例如:性能、内存、载入时间,得到的改进效果会根据项目而异。
2、内存
限定Unity堆的大小是asm.js的限制之一,即Unity堆的大小必须在构建时指定,后面无法进行更改。WebAssembly能让Unity堆的大小在运行时增长,从而使Unity内容的内存使用超过启动时指定的初始堆大小。
这意味着开发者可以让内容从例如32MB这样的小型堆开始,并让它根据需要增长,这在之前是无法实现的。
将Memory Size值视为内容一开始的初始大小,这是Unity 2018.2中的功能,所以可以立即使用此功能。但是如果构建目标是asm.js,则无法使用此方法,因为无法调整堆的大小。
如果堆增长得过多,浏览器可能会耗尽内存,是否过多取决于浏览器。为了使各浏览器获得一致的行为,请设置Unity堆的最大值。你可以通过在编辑器脚本中设置emscripten参数 “-s WASM_MEM_MAX=<value>” 来实现。
例如:PlayerSettings.WebGL.emscriptenArgs = "-s WASM_MEM_MAX=512MB";
请注意:内存最大值为2032,任何大于此数值都将导致浏览器中的运行时错误。
Wasm在载入时能更高效地使用内存。因此它能减少用户在使用asm.js时遇到的内存不足问题,尤其是在32位浏览器上。更多关于Unity WebGL中的内存处理方式,请阅读:Unity WebGL内存详解。
3、性能
Wasm和asm.js之间的性能差异取决于浏览器。Wasm作为二进制文件拥有比解析为JavaScript文本文件的asm.js更快的载入速度。已经被编译的Wasm代码模块会存储在IndexedDB缓存中,从而在重载相同内容时实现快速的启动过程。为了利用Wasm缓存功能,只要确保启用Data Caching选项即可。
启动后,在针对asm.js代码样式优化其JavaScript引擎的浏览器中,Assembly的执行速度将和asm.js旗鼓相当。如果在之前无法识别asm.js的浏览器上运行Wasm,那么Wasm的速度明显会更快。
根据代码的不同,一些指令在Wasm的速度会更快,例如:64位整数算术,它在asm.js没有相应的特定指令。
4、多线程
WebAssembly多线程支持或许是最受期待的功能,也是最能提高性能的功能。该功能本来应该于今年早些时候在浏览器中推出,但是由于Spectre和Meltdown的安全问题,必须禁用SharedArrayBuffer支持,而这是实现该功能的重要组成部分。
好消息是,在最近多个浏览器加入了很多安全措施,以便重新启用SharedArrayBuffer,我们也已经看到多个迹象表明这些浏览器将要在即将推出的版本中发布该功能。
在Unity方面,我们打算为该功能的发布做好准备,所以我们正积极地开发Wasm多线程支持,它将在接下来数月作为实验功能发布,该支持仅限于本地内部线程,例如:目前没有C#线程。这里的内部指的是用于蒙皮,动画,剔除,AI寻路和其它子系统的作业线程。一开始它们可能不会被全部启用,但我们的长期目标是尽可能利用多线程功能。
调试
调试对asm.js来说一直是个挑战。但是WebAssembly中的调试还没有变得更好。虽然浏览器开始在开发套件中提供WebAssembly调试,但是这些调试工具尚未很好地扩展到Unity3D的内容大小。
Wasm的设计初衷是“开放和可调试”,所以可以期待浏览器在未来将提供实现该目标的更好的工具。与此同时,开发者可以使用其它调试方法:
通常Unity WebGL版本中的问题出现在已构建游戏与浏览器API交互层中。该交互层位于UnityLoader.js和<build name>.asm/wasm.framework.Unityweb中,它包含易于读取的JavaScript代码,便于通过浏览器内置开发工具进行调试。
对于调试C#代码,Debug.Log()通常是唯一选项,因此建议尽可能在其它平台上进行调试。
对于高级调试功能,请尝试导出为asm.js,从而能够使用console.log().来注释所生成的asm.js内容。
值得一提的是,Unity 2018.2中加入了IL2CPP的托管代码调试支持,在实现WebAssembly多线程支持后,我们会立即开始做调试实验。
未来展望
各浏览器厂商会致力继续改进WebAssembly支持,他们一直在开发新功能和优化内容,用于改进启动时间和性能。
例如:
▶异步Wasm实例化功能(在Unity中得到支持)
▶Wasm结构化克隆功能,允许编译后的Wasm在浏览器中缓存(在Unity中得到支持)
▶基线和分层编译,以加速实例化过程(在运行Unity内容时会自动支持)
▶流式实例化功能,能够实现在下载时编译Wasm代码(正考虑是否在Unity加入支持)
▶多线程功能(正在开发该功能在Unity中的支持)
▶上述的一些功能已经实现,具体取决于浏览器。
我们坚信WebAssembly的未来,也鼓励开发人员默认使用它来进行开发。如有需要,可以将asm.js保留为旧版浏览器的运行时回退。该功能可以通过在WebGL Player Settings中选取WebGLLinkerTarget.Both实现。
我们计划在Unity 2018.3中弃用asm.js。这意味着在将来,asm.js将不会获得任何针对Wasm的改进内容,例如:多线程功能、SIMD等。但asm.js还会在Unity 2018 LTS发布后的二年时间里面得到支持。
电话:010-50951355 传真:010-50951352 邮箱:sales@souvr.com ;点击查看区域负责人电话
手机:13811546370 / 13720091697 / 13720096040 / 13811548270 /
13811981522 / 18600440988 /13810279720 /13581546145