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 42

Google Chrome 46

Apple Safari 9.0

MS Internet Explorer 11

MS 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,然后选择播放器选项…

js和unity交互 unity javascript教程_unity3d

开发工程

当你选中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

js和unity交互 unity javascript教程_Chrome_02

精简引擎代码

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

发布选项

js和unity交互 unity javascript教程_加载_03

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(压缩格式),来压缩工程输出文件。

js和unity交互 unity javascript教程_Chrome_04


查看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会自动生成一个干净的,从零开始的工程。