Unity3D官方教程:WebGL

开始WebGL开发

什么是 Unity WebGL?**

WebGL工程选项允许Unity以JavaScript程序形式发布使用HTMl5技术和WebGL渲染API、在网页浏览器中运行的Unity内容。为了构建和测试WebGL内容,在“Build Player”窗口中选择WebGL构建目标,并且点击“Build & Run ”。

技术概览

为了在WebGL中运行,所有代码需要是JavaScript。我们使用 emscripten 编译器工具链来交叉编译Unity运行时代码(用C和C++编写)到asm.js的JavaScript代码。asm.js是一个非常理想的JavaScript子集,允许JavaScript引擎 预编译asm.js代码为极具性能的原生代码。
为了转换.NET 游戏代码(C#和UnityScript脚本)至JavaScript,我们使用了一个称为IL2CPP的技术。IL2CPP获取.NET字节代码并将它转换为对应的C++源文件,然后通过使用emscripten,这些源文件被编译,最终将用户的脚本转换为JavaScript。

平台支持

Unity WebGL内容在当前大部分桌面主流浏览器都支持,然而不同的浏览器,提供的支持程度仍有所差别。移动设备并不被Unity WebGL支持。
不是所有Unity特性在WebGL工程中都可用,大部分是因为平台限制的关系,例如:

  • 多线程不被支持,因为JavaScript没有线程支持技术。这对Unity使用多线程来提升执行速度,以及脚本代码和管理dll,都产生了影响。实际上,所有在System.Threading命名空间中的都不被支持。
  • WebGL工程无法在MonoDevelop或Visal Studio中进行调试。详细请看“Debugging and trouble shooting WebGL builds”(暂未译出)。
  • 浏览器不允许联网进行IP套接字的直接存取,出于安全方面得考虑。详细请看“WebGL Networking”(暂未译出)。
  • WebGl图形API等同于OpenGL ES 2.0,有一些限制,详细请看:“ WebGL Graphics”(暂未译出)。
  • WebGL工程使用一个自定义、基于Web Audio API的后端,用于音效。这仅支持基本的音频功能。详细请看“Using Audio in WebGL”(暂未译出)。
  • WebGL是一个预编译平台,所以它不允许使用System.Reflection.Emit的代码动态生成。这在所有其它IL2CPP平台,iOS,以及大部分控制台都一样。

WebGL 浏览器兼容性

Unity WebGL在一定程度上支持所有的桌面主流浏览器。然而,不同的浏览器之间,支持程度、预期性能并不一样。请通过以下的表格,对Unity WebGL特性,以及哪些浏览器支持它们做一个整体查看。
注意,Unity WebGL 内容目前在移动设备上不支持。它或许在高档设备仍可以工作,但许多现有的设备并不足够强大,且没有足够的内存空间来很好地支持Unity WebGL内容。出于这个原因,当尝试在移动设备的浏览器上加载内容时,Unity WebGL会显示一个警告信息(如果需要,此功能可以被关闭)。
注意到,这个兼容表针对浏览器特定版本才有意义。更高版本会继续支持,但先前的版本可能会不稳定。

Mozilla Firefox 42Google Chrome 46Apple Safari 9.0MS Internet Explorer 11MS Edge 13
WebGL支持是。GPU黑名单可用。WebGL可能不被一些特定的老显卡所支持。是。GPU黑名单可用。WebGL可能不被一些特定的老显卡所支持。是。需要Safari8以及更高版本。是。需要IE11及更高版本。
网页音效。网页音效API被用于在Unity WebGL内容中播放声音。
全屏否。Safari supports the HTML5 full-screen API, but no keyboard input when in full-screen mode, so Unity will disable full-screen functionality when running in Safari.Safari支持HTML5全屏API,但在全屏模式下没有键盘输入。所以在Safari中运行时,Unity将关闭全屏功能。
游标锁定是。需要Edge13及更高版本。
手柄
本地索引数据库是。火狐直到42版、以及Safari不支持用于在一个iFrame中运行内容的索引数据库。火狐43及以后的版本会修复此支持。是。火狐直到42版、以及Safari不支持用于在一个iFrame中运行内容的索引数据库。火狐43及以后的版本会修复此支持。
网络套接字
网络实时通信
WebGL2.0否。火狐支持WebGL2.0,但默认不可用,并且需要在about:config中开启。否。Chrome支持WebGL2.0,但默认不可用,并且需要在chrome://flags中开启。
asm.js预编译。asm.js是浏览器可以针对性优化的JavaScript子集。由于Unity使用asm.js,所以实现了asm.js支持的浏览器能够更快地运行Unity WebGL。
注意

Chrome可能需要大量的内存来解析生成的JavaScript代码,可能在32位浏览器重加载内容时,引起内存溢出或崩溃错误。查看“Memory Considerations”(暂未译出)获得更多关于内存使用的信息。
Internet Explorer 不支持音效,并且太缓慢而无法像样地支持大部分Unity WebGL内容。出于这个原因,当在IE中打开内容时,我们将展示一个关于使用不支持的浏览器的警告信息。在表格中列举IE只是为了完整性;应当建议IE使用者升级到微软新的Edge浏览器。

构建并运行一个WebGL项目

当你构建一个WebGL项目时,Unity用以下文件创建了一个文件夹:

  • 一个index.html文件,浏览器可以使用它导航读取到你的内容。
  • 一个开发或发行文件夹装有你生成的工程输出文件(是哪个文件夹,依赖于你是否进行开发)
  • 一个模板数据文件夹(至少在使用默认模板时会有),装有加载条和其它模板资源。查看“WebGL 模板”(暂未译出)的用户手册页面,来获取更多信息。

开发/发行 文件夹包含了以下文件(“MyProject”文件名称代表你项目的名称)。(注意,如果你生成一个发行版工程,这个文件夹里的文件会诶压缩并有一个.gz的后缀。查看下面分发尺寸的注释。)

  • MyProject.js这个JavaScript 文件包含了你播放器的代码。
  • MyProject.mem文件包含了一个初始化你播放器堆内存的二进制图像。
  • MyProject.data文件包含了资源数据和场景。
  • UnityLoader.js文件包含了需要用于在网页中加载Unity内容的代码。

你可以通过用大部分浏览器打开index.html文件,直接查看你的WebGL 播放器。然而,出于安全的原因,Chrome在从本地文件URL中打开的脚本上做了限制,所以这个技术在Chrome中无法使用。为了绕过Chrome的限制,使用Unity的Build&Run命令(File->Build&Run);这个文件就暂时在一个本地网页服务器中,并且是从一个本地宿主URL中打开。或者,可以用 –disable-web-security 命令行选项来运行Chrome,这允许Chrome从本地文件的URL加载内容。
在一些服务器上,用户需要生成可读取的.mem和.data文件,因为服务器需要提供这些文件给用户。

构建播放器选项

(菜单:File->Build Settings…)进入WebGL选项对话框。在对话框中,从平台列表中选择WebGL,然后选择播放器选项…
平台选择对话框

开发工程

当你选中Development Build 勾选框,Unity生成一个开发工程,有事件探查器支持喝一个开发控制台来查看错误。另外,开发工程不压缩内容(即,内容不是最小化的);维持在在可以人工阅读的JavaScript形式,保留了函数名,这样用户得到有用的错误追踪栈。注意,这意味着开发工程会非常大,太大而无法发布。

使用预构建引擎

这个选项仅在用户勾选了开发工程时出现。在工程选项对话框中使用“Use pre-build Engine”选项来在开发期间加速构建迭代时间。当此选项被启用时,Unity仅重构建”manager code”,动态链接到预编译Unity引擎,这样项目的重构建大概会快30%至40%。注意,这种构建类型仅适合于开发目的,因为总是产生”unstripped”引擎代码。此外,由于动态链接,这种工程的类型比普通类型的执行上更慢。

自动连接探查器

此选项仅当用户勾选了开发工程时可用。勾选自动连接探查器选项,让用户探查Unity WebGL内容。对于WebGL,它不可能连接到事件探查器来运行工程像在其它平台上那样,所以用户需要使用这个选项来连接内容到编辑器。这是因为事件探查器连接通过使用WebGL的WebSockets被掌控,单一个网页浏览器仅允许内容的向外连接。

播放器设置

WebGL在播放器设置的检视器窗口(菜单:Edit->Project Settings ->Player)中,有一些另外的选项。

其它选项 Other Settings

其它选项

精简引擎代码

打开 Other Settings 来选择 Strip Engine Code选项。这个选项默认被选中,来允许代码为WebGL所精简。随着这个选项被选中,Unity不包括任何你不使用的类的代码。例如,如果你不使用任何物理组件或功能,那么整个物理引擎会被从你的工程中移除。查看下方的精简区来获得更多细节。

发布选项

发布选项

WebGL内存大小

打开Publishing Settings进入WebGL 内存大小区域。这里,你可以指定内容应为它的堆分配多少内存(以MB为单位)。如果这个值太低,用户会收到“内存溢出”错误。这意味着要加载的内容喝场景无法完整放入可用的内存中。然而如果这个值太高,内容可能无法加载到一些浏览器或一些机器里,因为浏览器可能没有足够的可用内存来分配要求的堆尺寸。这个值被写到在生成的 .html 文件里一个名为TOTAL_MEMORY的变量中,所以如果用户希望尝试这个值,可以编辑 .html 文件来避免重构你的项目。查看在 WebGL memory usage 中的 User Manual 页面来获取更多细节。

启用异常

打开发布设置来进入 Enable Exceptions(启用异常) 。启用异常允许用户指定在运行时意外的代码行为(通常被认为是错误)如何被处理。这里有三个选项:

  • None 无:选择这个如果你不需要任何异常支持。这提供了最佳的性能和最小的构建。使用这个选项,任何异常的抛出都引起你内容停止。
  • Explicitly Thrown Exceptions Only 仅抛出明确异常(默认):选择此项来捕获,在用户脚本中抛出状态明确指定的异常。此选项也会让脚本中最终的阻塞产生作用。注意,选择此选项,会让从用户脚本所生成的JavaScript代码变得更大及更缓慢,但,除非脚本是你项目主要的瓶颈,这并不是大问题。
  • Full 完整:选择这个选项来捕获:
    • 在用户脚本中抛出状态明确指定的异常
    • 空引用
    • 数组越界读写
    • 托管栈跟踪

Unity通过在代码中嵌入检查,为它们生成这些异常;因此这些选项增大了代码尺寸并且降低了性能。仅在需要调试时,在代码中使用这个模式,因为它构建了非常庞大且非常缓慢的工程。
选择Publishing Settings(发布设置)来进入Data Caching(数据缓存)。选择此项来开启播放器数据的自动本地缓存。这个选项设置资源在浏览器的索引型数据库中,作为本地的缓存而存储;这样在内容的后续运行时,资源不会被再次下载。注意,不同的浏览器在允许索引型数据库存储时,有不同的规则;浏览器可能询问用户来允许存储数据,并且工程可能超出被浏览器定义的尺寸限制。

发行大小

当向WebGL平台发布时,保证工程的大小尽可能低,让用户在内容开始前,只经历可忍受的下载时长。关于降低资源尺寸的通用技巧,请阅读Reducing the file size of the build

对于WebGL的专有提示
  • 对在纹理导入器中所有压缩的纹理,指定Crunch纹理压缩格式。
  • 不要部署开发工程;这些未被压缩,或不是最小化,所以有很大的文件尺寸。
  • 到播放器设置中(菜单:Edit->Project Settings ->Player),打开Publishing Settings并设置Enable ExceptionsNone,如果你不需要在工程中抛出异常。
  • 到播放器设置中(菜单:Edit->Project Settings ->Player),打开Other Settings 并且启用Strip Engine Code来保证产生高效的工程。
  • 当使用第三方dlls时要小心,因为它们可能包含大量的依赖,并且因此明显增大了生成代码的大小。

如果要生成一个发行版工程,Unity根据在WebGL PlayerSetings->Publishing Settings窗口中选择的Compression Format(压缩格式),来压缩工程输出文件。
这里写图片描述
查看Deploying compressed builds中的文档,来获取更多这些选项的信息,以及如何用这些选项来发布工程。

资源包

因为所有资源数据需要在内容之前预先下载,所以你应当考虑从你的主数据文件中移除资源,放入资源包中。用这种方式,你可以为你的内容创建一个能迅速读取的,小的加载场景。资源包也有助于资源数据内存管理:你可以通过调用AssetBundle.Unload,从内存中卸载你不再需要的资源数据。
一些在WebGL平台上使用资源包时需要考虑的事情:
当你在资源包中使用在你主工程中没用到的类类型,Unity会对这些类从工程中精简掉这些代码。当尝试从资源包中加载资源时,这可能引发错误。查看在下方 Stripping 中的部分,来学习如何修复这个问题。
WebGL不支持多线程,但http下载仅在它们结束下载时可用。由于这个原因,当下载完成时,Unity WebGL工程需要在主线程中解压资源数据,阻塞了主线程。为了避免这一中断,对于在WebGL上的资源包,LZMA AssetBundle compression是不可用的。资源包换成用LZ4来压缩,在解压缩时非常迅速。如果你需要比LZ4更小的压缩尺寸,你可以配置你的网页服务器对你的资源包使用gzip或者Brotli压缩(比LZ4压缩更小)。查看Deploying compressed builds中的文档来获取如何进行压缩的更多信息。
通过使用浏览器的索引型数据库API,来实现:在WebGL中使用 WWW.LoadFromCacheOrDownload 以支持资源包在用户的电脑上缓存。注意,索引型数据库可能在某些浏览器上支持有限,且这些浏览器可能要求用户提供在磁盘上存储数据的权限。查看 WebGL browser compatibility 中的文档来获取更多信息。

Stripping 精简

Unity 默认会从你的工程中移除所有不被使用的代码。可以通过播放器设定检视器窗口来改变设置。(菜单:Edit->Project Settings->Player):选择Other Settings 进入Strip Engine Code 精简代码选项。开启精简选项会更好。
选择精简,Unity对你的项目中任何被使用的UnityObject派生类进行检查(无论是被脚本代码引用,或是在你场景序列化数据中)。然后,从工程中移除没有任何类被使用的Unity子系统。这让你的工程代码更少,需要下载与解析的量都更少(所以代码运行更快,使用更少的内存)。

**代码精简带来的问题**Issues with code stripping

如果精简了实际上必须保留的代码,可能导致你的项目出问题。当你在运行时,要加载的资源包中原本包含不在主工程中、并已被精简了的类,就会产生问题。当这发生时,浏览器的JavaScript控制台会出现错误信息(并可能伴随着更多错误)。例如:
无法生成编号为XXX的类
为了排除这些从无,在类编号引用中查找,以查看是哪个类在尝试创建实例。在这种情况下,你可以强制要求Unity在工程中为这个类包含代码,要么通过在你的脚本或场景中添加一个对该类的引用,或者对你的项目增加一个link.xml文件。
下面是一个确保碰撞器类(以及物理模块)在项目中得以保留的例子。向名为link.xml的文件中添加这些XML代码,并将此文件放到你的资源文件夹中。
<linker>
<assembly fullname="UnityEngine">
<type fullname="UnityEngine.Collider" preserve="all"/>
</assembly>
</linker>

如果你怀疑,精简引起你工程的问题,你也可以尝试在测试期间关闭精简引擎代码选项。
Unity不提供查看哪些模块和类在工程中包含的方便途径,这途径可以让你最优化地精简项目。然而,为了得到所包含类及模块的概览,你在生成一个工程后,可以查看生成的文件Temp/StagingArea/Data/il2cppOutput/UnityClassRegistration.cpp
注意,精简引擎代码选项只影响Unity引擎代码。IL2CPP总是从你管理的dll和脚本精简字节代码。当你需要在你的代码中,通过反射动态地引用管理的类、而不是通过静态引用,这会引起问题。如果你需要通过反射存取类型,你也需要设置一个link.xml文件来保留这些类。查看iOS Build size optimization 的文档来获取更多link.xml文件的信息。

移动工程输出文件

如果你希望改变你输出文件相对于index.html文件的位置,可以通过编辑dataUrl
,codeUrl,以及memUrl区,以及在index.html文件中的UnityLoader.js脚本标签来实现。你可以为这些内容指定在外部服务器的URL,如果你希望将文件在一个内容分布式网络(CDN)上主办,但你需要确保,宿主服务器已经启用 跨域资源共享(Cross Origin Resource Sharing, CORS)。查看 WebGL networking 页面的指南来获取更多关于CORS的信息。

增量工程

你的项目通过IL2CPP生成的C++代码时增量编译的;即,在最新工程中改变的C++代码会被再次编译。没有改变的源代码复用为之前工程生成的相同目标文件。用于增量C++工程的对象文件存储在你的Unity项目 Library/il2cpp_cache目录中。
为了得到一个干净的,从零开始都没有使用增量编译所生成C++代码的工程,删除 你Unity项目目录中 Library/il2cpp_cache目录。注意,如果Unity编辑器版本不同于用于之前WebGL工程的编辑器,Unity会自动生成一个干净的,从零开始的工程。

Logo

分享前沿Unity技术干货和开发经验,精彩的Unity活动和社区相关信息

更多推荐