Unity webGL以及HTML與unity通訊
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>