目前版本 Unity 2021.2.7f

疫情的發生讓時間變得好快,於是我就這樣休息了半年。

WebGL 真的必須要說這是我接觸 Unity 五年多以來讓我覺得最靠北的一個東西,不成熟不穩定毛一堆做得我OO叫的,我一定要分享出來讓大家知道拿 Unity 做 WebGL 專案是需要被謹慎評估的。

題外話就是這邊不討論 ECS 跟 Project Tiny 的東西,嗯。

講一些能做到跟不能做到的事情

在硬體規格允許的前提下,確實能 Load 一個不小規模的場景或是高面數模型。

其實只要記憶體跟顯示卡允許,跑場景不會有什麼太大問題。在完全沒有多做設定的狀態下高刷新率螢幕的支援也是沒有問題。(雖然通常會因為效能所以刻意關到 30fps) 唯一我覺得差異比較大的是反鋸齒跟 Shader 算出來的效果真的落差很大,如果是要展示一些擬真效果的物件或場景會顯得比較尷尬。

在 PC 的環境下大多數時候能夠提供一定的效能。

啊你要跑大場景用內顯的話那還真的無解,可能要考慮一下 TA 吧。

大多數狀況下能夠在 Unity 實現的東西都能在 WebGL 被實現。

絕大多數的 Plugin 都能無痛在 WebGL 底下工作,不過由於 WebGL 的環境某種程度上比行動裝置來得嚴苛,所以其實在特效,或是整體的內容規模設計是需要被評估的。

手機沒有被官方支援,所以編出來在手機上跑起來很不理想這件事是可以被預估的。

Unity WebGL 的記憶體管理或是硬體的優化都是針對電腦來實作的,所以在手機端很常會遇到 OO 功能罷工不 work,被瀏覽器 block 掉,記憶體原地爆炸之類的其實都是日常。

Unity WebGL 沒有 WebXR 支援,儘管有人做 plugin 來做相容。

https://github.com/De-Panther/unity-webxr-export 跟本文無關但是題外話,如果要做 WebAR 還是選擇像是 8th Wall 的商業解案要不然就乖乖學 three.js 吧,拿 Unity 做這個光是那個 WebGL build 出來的基本盤大小應該就直接勸退了。

災難

Debug 難度真的很高很高,常常會涉及網頁開發的知識

基本上所有的 WebGL 最佳化的教學都會叫大家把那個印錯誤的功能關掉,所以其實很難一目了然的知道問題在哪。就算開了印出來也是一堆被轉換過的 Javascript 錯誤,我馬系看嘸。而且還有一大堆狀況是我在 Editor 裡面跑就是漂漂亮亮速度很快,一編出來上 Server 或是開裝置一切都毀掉了,所以這邊建議是一定要確實準備好各個平台的裝置跟設備測試,瀏覽器 Edge Chrome Firefox Safari 一定都要有,有開新功能一定要乖乖實測,因為功能通常不會往理想的方向發展,鐵定出毛病的。

由此可知 Debug 跟測試佔了 95% 的時間吧,啊 build 東西又很慢,伺服器不同環境問題也會不太一樣,專案的人力跟時程一定要好好估,嗯。

載入速度 vs 使用體驗 vs 記憶體

三個極端,沒有在全都要的。

載入速度主要是在講整個包的大小,使用者第一次 load 進來就算是空包也要消耗個十秒鐘之類的才有辦法 load 完,更不用說是行動裝置了。所以你可能要絞盡腦汁壓縮各式各樣的東西讓專案越小越好。

使用體驗是在講等待的時間。把專案東西拔光通通改外 load 也未必是好事,可能你今天進場景結果素材都還在 load 所以到處都是 loading 什麼事也沒辦法做,我點開一個影片結果又是幾秒到幾十秒的等待,換個場景也在等待,這樣用起來真的很不舒服。

記憶體,就是在講資源的負載。大量的切換或是沒有適度釋放暫存的東西鐵定會出事的,但是釋放掉重新載入又是會經歷載入的過程,而且也是要等待的,但把東西包在一起也未必是好事。

結論就是可能要拿捏一下到底是什麼重要,什麼其實還好,當然理想上就是不要做手機平台還是比較好啦…

有個 hint 就是 Addressable 是需要實作的,包一起只會讓事情變得更糟而已。

iOS Safari Video Player 無法播放影片

檔檔王 iOS Safari,就你問題最多。

https://issuetracker.unity3d.com/issues/webgl-ios-video-is-not-playing-on-ios

這個問題在去年就遇到了,官方表示是修好了但我實在是沒有辦法正常的使用它,怪怪。(我覺得應該是其他問題)

會發生的原因主要是 iOS Safari 會阻擋一切會發生聲音跟播放影片的內容,如果沒有經由使用者觸碰螢幕而觸發的事件播放影片的話就是吃一記檔掉,然後使用者就會看到一片黑的國防布。

如果懂 HTML 跟 JS 的人可以去寫一個方法就是當 Unity 在按下按鈕播放影片觸發 HTML 端播放影片這樣,但迫於時間壓力跟 JS 白癡的跑去買了 Plugin 來解這個障礙。

https://assetstore.unity.com/packages/tools/video/video-player-webgl-192420

這位老兄在論壇跟 Issue Tracker 宣傳自己做的 100 美「好東西」,居然還真的能用… sort of

問題就在於

  1. 這東西 loading 會有黑螢幕
  2. 一定要使用 Pointer Down 觸發事件
  3. 在 iOS Safari 的環境有很多功能是不會 work 的 (例如自動播放,音量調整等)
  4. 一個場景有 >1 個 VideoPlayerWebGL 可能會導致搶來搶去,或是狀況外發生 (尤其是 iOS Safari,一次只能有一個發聲影片被執行)

所以如果要用這個 Plugin 終究還是要針對要解決的問題量身訂製一個控制器來符合自己的需要,並且要一直誘導使用者碰螢幕,大概是這樣。

iOS Safari 外開連結

檔檔王 iOS Safari,就你問題最多 part 2。

OpenURL 居然會被 Safari 檔掉。 其實好像是因為透過這個觸發的開視窗事件會被瀏覽器當成彈出式視窗,所以直接被 block 掉。

類似的作法如 ExternalEval 或是另外寫 JS 的做法我都試過了,結果還是檔好檔滿。

還有一個重點就是我實在是沒有辦法選擇開在同一個分頁,這其實有點不太符合我的需求。

因此我又踏上了解決問題之路。

https://assetstore.unity.com/packages/tools/integration/launchurlwebgl-185980

又是你 wwwwww 不過這次是免費的所以就算了 w

基本上重點就在於事件一定要透過 Pointer Down 觸發,然後搭配它寫的 JS 觸發到底是要開同一個分頁還是開新分頁,這真的非常非常非常重要。

無時無刻都在 Memory Leak

這個必須要拿出來講就是 Memory Leak 顧名思義就是記憶體炸掉了。但並不是因為資源太多硬體跑不動的那種炸掉,而是「任何的程式錯誤都有可能導致溢位」。

一方面第一個就是寫 code 要確實 Handle 掉可能會吐出 null 的狀況,盡可能針對會用到的新功能常常 build 出來測試會不會報錯,最後就是資源能省則省,電腦看似可以用到 1 2GB 的記憶體但手機千萬不要,能壓在 128MB 內最理想。

啊你可能查資料會看到什麼可以改 Memory Heap Size 之類的調整記憶大小的做法,那個東東早就在 Unity 換成 wasm 之後就被拋棄了,wasm 本身就會對瀏覽器請求真正被需要的記憶體大小,根據需求要求更多。

最後就是每個瀏覽器會爆炸的點都不盡相同,像 Android Chrome 在請求更多記憶體會很容易炸掉,iOS 在功能錯誤或是 block 東西很容易炸掉,所以就是多測吧。

貼圖壓縮

基本上 build 出執行檔一定要再回去看看 Build Report,那個每個 MB 都是黃金非常的重要,決定了使用者載入的速度以及之後記憶體消耗的量。

而久了就會發現最佔空間不外乎就是貼圖、音檔跟字體。

TextMeshPro 的字形是必要之惡那就算了,音檔要記得壓縮,爛爛的能聽就好,貼圖的話一定要乖乖設解析度上限,一定要用破壞性壓縮為佳 (Crunched),盡可能維持 Power of 2 的原則 (Unity 有內建轉檔功能,有這個對壓縮率跟記憶體使用的效率幫助很大)

最後最後就是那個預設的 DXT 格式貼圖在行動裝置上沒辦法用 R,手機就會在那邊解壓縮貼圖然後記憶體就吃三倍的量就爆炸惹。

解決辦法就是整個專案的貼圖要轉換成手機能硬解的貼圖格式像是 PVRTC 或是 ETC。最後我因為想要雙平台通吃所以建議走 ASTC,但是等級要自己拿捏了,UI 我用 6x6 其他的就爛爛 8x8 就好。啊剩下沒硬解的行動裝置估計都是一堆垃圾機或是太老的東西直接 drop support 就好。桌機的部分雖然沒硬解但是解壓縮之後看起來對於記憶體消耗不知道為什麼沒有太多改變,還 OK 啦這個就請各位自己慢慢測了。

我學了什麼?

  1. Less is more
    相較於原生開發,Unity 低的學習跟開發成本,在 WebGL 可能會要付出更高的代價才能把事情做完。

  2. 認真思考要不要來經營套件生意
    欸它那個套件一個 100 美,我都開始懷疑是不是內部的人放著不修出來賣套件了,我還真的第一次覺得其實賣套件來修官方的 bug 加上一些獨到的功能真的很猛,反正就算基本功能要到位大家還不是買爆。

  3. 怎麼最佳化專案在這邊真的是顯學
    以前在大學作專題為了讓我的肥肥打字遊戲能在 Android 跑那時候研究了好一陣子這下子在這裡派上用場了,結果這裡比想像的還要嚴苛。其實與其花那麼多時間做最佳化,有一部分也是打從一開始在企劃階段就針對這樣貧弱的環境來做規劃確實比較合適,也可以少走很多冤枉路。

  4. 程式基本功啊
    對 Unity code 的熟悉度真的會大幅影響效能,像是那個 GameObject.Find 之類的玩意真的少用啊!!! (至於為什麼要拿出來講就是另一個故事了,徹底理解資工出身的程式看到我寫的東西結屎面的感覺)

應該還有很多東西沒講啦,以後有想到再說。 啊有錯誤的理解需要更正就再從某個地方跟我講一聲吧,雖然這個是日記性質的閒聊但也不希望誤導其他人啦 w

後記

欸最近一打開 YouTube 就是各種罵 Unity 跳 Unreal 或是 Godot 的影片,久而久之真心覺得 Unity 最尷尬的點就是要漂亮也沒到位,要輕量也不輕量,真的會有想要跳槽去研究其他引擎的念頭。

不過如果 Godot 在 WebGL 環境運作的表現還不錯的話,那我是真心覺得也許有一學的價值。但我更看好經過 Facebook 投資的他們,日後在 OpenXR 環境的相容性,或是 WebVR WebAR 的支援達到了比較成熟的階段,那我覺得 Unity 這塊真的可以收一收了。