1;什么是Unity webGL
webGL 的编译选项允许unity发布像使用了HTML5和webGL渲染API技术来使unity程序可以跑在浏览器中的javascript 程序。想要编译和测试WebGL程序,只需要在Build Playersetting里选择WebGL编译平台即可。
2:unity是怎么样发布为webGl程序的
为了运行webgl,需要我们的所有代码都是采用JavaScript编写,unity使用emscripten编译器工具链交叉编译unity运行时的代码(C和C++)为asm.js JavaScript,asm.js 是一个高度优化的JavaScript子集,并且可以采用javascript 的AOT编译引擎将asm.js代码变为高性能的代码。 如果代码采用C#编译,那么unity将使用Il2CPP技术将C#代码转换为相应的的C++源文件,然后编译器使用emscripten来使C++再转为JavaScript代码。当然,这里会存在兼容性的问题。unity的webGL 程序目前在大多数的桌面浏览器中都能支持,但是移动端的目前还无法支持。
1:,Unity并不是所有的功能都能在webGl中支持,
首先;由于JavaScript不支持多线程,所以多线程只适用在unity内部线程对程序的加速和一些托管DLL以及使用一些线程脚本代码 ,基本上System.Threading命名空间里的东西是不支持的。
2:webGL还无法在VS和MonoDevelop里调试
3:由于安全问题浏览器不能直接访问IP套接字。
4:WebGL图形API相当于OpenGL ES 2,这具有一定的局限性。
5:WebGL生成使用自定义后台音频,基于Web Audio API。这只支持基本的音频功能
6:WebGL是一个AOT(静态编译)平台,所以它不允许动态生成的代码中使用system.reflection.emit。这是对所有其他il2cpp平台,如iOS,和大多数控制台是相同的。
3:浏览器的兼容情况
桌面浏览器兼容情况
Mozilla Firefox 42 Google Chrome 46 Apple Safari 9.0 MS Internet Explorer 11 MS Edge 13
对运行unity的webGL内容的支持能力 X (1) X (1) X (Safari 8 and higher) X (IE 11 and higher) X
Web Audio unity WebGL中的音频需要调用Web Audio API来播放 X X X - X
全屏支持 X X - (2) X X
鼠标锁定支持 X X - - - (3)
Gamepad support X X - - X
IndexedDB Required for local storage as used by the Data Caching feature, the PlayerPrefs class, and WWW.LoadFromCacheOrDownload. X (4) X X (4) X X
WebSockets Required for Networking. X X X X X
WebRTC Required by the WebCamTexture class. X X - - X
WebGL 2.0 - (5) - - - -
asm.js AOT compilation asm.js is a susbset of JavaScript for which a browser can specifically optimize. Browsers which implement asm.js support may be able to run Unity WebGL content faster, as Unity uses asm.js. X - - - X
Notes (6) (7)
注释:
1:WebGL可能不支持特定的老显卡。
2:Safari浏览器支持HTML5全屏API,但全屏模式时没有键盘输入,所以unity在Safari中运行时将禁止全屏功能。
3:Edge不支持鼠标锁定,Edge13可能会支持。
4:Firefox和Safari上42版本不支持在一个iframe中运行的内容IndexedDB。火狐43或更高版本将修复问题。、
5:Firefox 支持WebGL2.0,但它默认是禁用的,需要启用:配置。
6:Chrome可能需要大量的内存来解析生成的JavaScript代码,当在32位版本浏览器中加载webgl内容时可能会导致内存错误或崩溃。
7:IE浏览器不支持音频并且还太慢对于加载unity的webGL内容,出于这个原因,
unity将在使用Internet Explorer打开内容时显示使用不支持的浏览器的警告
4:webGl的发布工作
编译一个webGL 项目时,unity将会创建一些文件
*一个index.html文件,这个文件可以直接使用浏览器打开,但是出于考虑,chrome限制用户从本地打开这种文件。
*一个Development和 Release 文件夹, 这些是生成的输出文件,一个用于继续开发,一个是可以用于直接发布。
*一个TemplateData文件夹,一些资源文件。
发布时当勾选Development Build复选框时,unity将生成一个Development Build(带有分析器支持和错误控制台);
此外,Development Build是非压缩的,所以生成的JavaScript是可读的并且保留了函数名(以便于你得到有用的错误堆栈跟踪)但是非常分散。
使用Use pre-built Engine选项可用于加快开发迭代时间在开发过程中。启用此选项时,只有托管代码将被重建,然后与预构建Unity引擎动态链接,因此工程重新生成的速度会提升30%到40%。但是注意,这种编译只适合开的目的,因为这样会产生多余的引擎代码。此外,由于动态链接开销,这种编译的性能有点慢于正常编译。
当你想配置你的unity webGL内容时必须勾选Autoconnect Profiler复选框,虽然在webGL上连接分析器使用WebSockets ,但是浏览器只允许从内容向外的连接,所以在WebGL使用Profiler的唯一方法是选中“自动连接分析器”有内容连接到编辑。
5:webGl Graphics
WebGL是一个浏览器的图形渲染引擎API,目前是基于OpenGL ES 2.0 图形库。Unity webGL目前只支持烘焙GL不支持实时GL,而且,仅仅支持非定向lightmaps,webGL在运行时也不支持过程化材质,过程化材质在编译时将被烘焙为普通材质。webGL 也不支持使用Movie Texture播放视频,但是你可以通过使用HTML元素在WebGL里高效的播放视频。
6:WebGL的网络通信
由于安全性的影响,JavaScript代码没有直接访问IP套接字来实现网络连接。因此,该.NET网络类(System.Net命名空间中的一切,特别是System.Net.Sockets)在WebGL中不能工作。UnityEngine.Network* 类也是这样,编译WebGL时将找不到这些类。如果你需要在WebGL使用网络通信,你现在可以选择使用unity的WWW 或UnityWebRequest 类或则支持webGL的新的Unity 网络通信特性。或在JavaScript中使用WebSockets或WebRTC实现你自己的网络通信。
7:WWW 或WebRequest类的使用
WebGl支持WWW和unitywebrequest类。他们在JavaScript里使用XMLHttpRequest类实现,使用浏览器来处理网络请求。这对访问跨域资源施加了一些安全限制。基本上对于服务器的任何WWW请求不同于托管服务器的是WebGL内容需要通过你试图访问的服务器授权。在WebGL的跨域访问WWW资源,您试图访问的服务器需要使用CORS授权。如果你使用WWW或unitywebreqest试图访问内容,但是远程服务器没有CORS系统设置或没有正确配置,你会在浏览器控制台看到类似这样的错误:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://myserver.com/. This can be fixed by moving the resource to the same domain or enabling CORS.
CORS表示跨域资源共享。基本上,服务器需要向它发送的HTTP响应里添加一些访问控制头,这将告诉浏览器允许它访问服务器上的内容。这是一个控制头设置的例子,将允许unity WebGL访问来源于任何Web服务器资源,通过常见的请求头和使用HTTP GET,POST或OPTIONS方法:
“Access-Control-Allow-Credentials”: “true”,
“Access-Control-Allow-Headers”: “Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time”,
“Access-Control-Allow-Methods”: “GET, POST, OPTIONS”,
“Access-Control-Allow-Origin”: “*”,
注意,www.responseheaders限于实际响应标头的一个子集,根据7.1.1的CORS规范。还要注意XMLHttpRequest不允许使用数据流,因此WebGL的WWW类只会处理下载完成的数据(所以assestbundles不能像其他平台上那样解压和加载)。
8:为什么需要通信
当为web构建内容时,您可能需要与web页上的其他元素进行通信。或者您可能希望使用Unity当前不默认的Unity API来实现功能。在这两种情况下,您都需要直接与浏览器的JavaScript引擎对接。unity的WebGL提供不同的方法来实现这些。
9:从Unity里调用JavaScript里的方法。
你可以使用下面的代码从浏览器的JavaScript里调用unity里的方法:
SendMessage (‘MyGameObject’, ‘MyFunction’, ‘foobar’);
MyGameObject是场景内物体名称,MyFunction方法名,foobar是参数
下面是个例子:
<!--传值方法-->
<script type="text/javascript">
//按钮点击事件id为test()
function test() {
//获取ID名为storeID的Value的值,赋值给sparm
var sparm= document.getElementById("storeID").value;
//传参到U3D场景内GoName挂载脚本的MyFunc函数,参数为一个字符串
SendMessage("GoName", "MyFunc", sparm);
}
</script>
unity端实例
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Test : MonoBehaviour {
public Text WebText;
public void MyFunc(string abc)
{
WebText.text = abc; //在U3D的ugui的WebText上显示传值进来的字符串
}
}
10:如何通过SendMessage传递多个参数
我们知道unity的SendMessage只接受一个字符串参数,但是我们的项目经常会用到多参数,这样就很尴尬了,关于这个,目前我还没找到好的方式,只是看到大家都在使用连接多个string参数为一个字符串的形式,当然,这样也只是能传递个string参数。
<!--传值方法-->
<script type="text/javascript">
function test() {
var Parm_1= "Parm_1";
var Parm_2= "Parm_2";
var Parm_3= "Parm_3";
//传参到U3D场景内GoName挂载脚本的MyFunc函数,参数为一个字符串
SendMessage("GoName","MyFunc",Parm_1+'-'+Parm_2+'-'+Parm_3);
}
</script>
unity里的方法为:
void MyFunc(string indata)
{
string[] words = indata.Split('-');
data1 = words[0];
moredata2 = words[1];
anotherpiece3 = words[2];
}
11:从Unity里调用网页里的方法
你可以使用Application.ExternalCall()和 Application.ExternalEval()函数调用嵌入网页的名为functionName的JavaScript函数,并传递给定的参数。支持原始的数据类型(string, int, float, char)和这些类型的数字。如何其他的对象被转化为字符串(使用ToString方法)并作为字符串传递。这个函数调用时不会被阻塞,即ExternalCall立即返回的功能而不必等待被完成。传递的参数数量是可变的。
// 调用网页上的MyFunction1并不使用参数。
Application.ExternalCall ("MyFunction1");
//调用网页上的MyFunction2并使用字符串参数。
Application.ExternalCall ("MyFunction2", "Hello World!");
//调用网页上的MyFunction3并使用几个不同类型的参数。
Application.ExternalCall ("MyFunction3", "str", 3, 5.0);
被调用的在HTML中的函数只需要使用标准的语法即可,例如:
<script type="text/javascript">
// 响应Unity的调用并接受"Hello World!" 做为参数
function MyFunction2( arg )
{
alert( arg );
}
</script>