使用 Babylon.js 構建跨平台 WebGL 遊戲
已發表: 2022-03-10這對您來說是一個挑戰:週末製作一個 3D 遊戲怎麼樣? Babylon.js 是一個 JavaScript 框架,用於使用 HTML5、WebGL 和 Web Audio 構建 3D 遊戲,由您和 Babylon.js 團隊構建。 為了慶祝庫的新版本 2.3,我們決定構建一個名為“Sponza”的新演示,以突出在當今構建出色遊戲時可以使用 WebGL 引擎和 HTML5 做什麼。
這個想法是在所有支持 WebGL 的平台上創建一致、相似(如果不相同)的體驗,並嘗試達到原生應用程序的功能。 在本文中,我將解釋這一切如何協同工作,以及我們面臨的各種挑戰以及我們在構建它時學到的教訓。
關於 SmashingMag 的進一步閱讀:
- 使用 Babylon.js 構建著色器
- 在 Web 遊戲中使用 Gamepad API
- 多邊形建模和 Three.js 簡介
- 如何創建響應式 8 位鼓機
為了實現這一目標,Sponza 使用了許多 HTML5 功能,如 WebGL、Web 音頻以及指針事件(現在由於 jQuery PEP polyfill 而得到廣泛支持)、Gamepad API、IndexedDB、HTML5 AppCache、CSS3 過渡/動畫、flexbox 和全屏API。 您可以在台式機、移動設備或 Xbox One 上測試 Sponza 演示。

發現演示
首先,您將從自動動畫序列開始,將功勞歸於構建場景的人。 團隊的大部分成員都來自演示現場。 您會發現這是 3D 開發人員文化的重要組成部分。 在我這邊,我在 Atari 上,而 David Catuhe 在 Amiga 上,這仍然是我們之間經常發生衝突的根源,信不信由你。 我正在編寫一些代碼,但主要是在我的演示組中創作音樂。 我是 Future Crew 的忠實粉絲,尤其是 Purple Motion,我最喜歡的演示場景作曲家。 但是,我們不要偏離主題。
對於 Sponza,以下是貢獻者:
- Michel Rousseau aka “Mitch”作為 3D 藝術家完成了出色的視覺動畫和渲染優化。 它採用了 Crytek 在其網站上免費提供的 Sponza 模型,並使用 3DS Max 導出器來生成您所看到的。
- David Catuhe又名“deltakosh”,我已經完成了 Babylon.js 引擎的核心部分以及演示的所有代碼(自定義加載器、使用淡入黑後期處理的演示模式的特殊效果等)以及一種名為“ UniversalCamera ”的新型相機以通用方式處理所有類型的輸入。
- 我使用 Renoise 和 EastWest Symphonic Orchestra 音色庫創作了音樂。 如果您有興趣,我已經在使用 Renoise 跟踪器和東西方 VST 插件為 World Monger Windows 8 遊戲創作音樂的文章中分享了我的工作流程和過程
- Julien Moreau-Mathis幫助我們構建了一個新工具來幫助 3D 藝術家完成建模工具(3DS Max、Blender)和最終結果之間的工作。 例如,米歇爾用它來測試和調整各種動畫攝像機,並將粒子注入場景。
如果您等到自動序列結束直到“史詩般的完成”,您將自動切換到交互模式。 如果您想繞過演示模式,只需單擊相機圖標或按遊戲手柄上的A
在交互模式下,如果您使用的是 Mac 或 PC,您將能夠像 FPS 遊戲一樣使用鍵盤/鼠標在場景中移動。 如果您使用的是智能手機,您將能夠通過一次觸摸(以及2
旋轉相機)來移動。 最後,在 Xbox One 上,您可以使用遊戲手柄(或桌面,如果您將游戲手柄插入其中)。 有趣的事實:在 Windows 觸控 PC 上,您可以同時使用 3 種類型的輸入。
互動模式的氣氛不同。 您在 3D 環境中隨機放置了三個風暴音頻源,每個角落都有風和火裂紋。 在支持的瀏覽器(Chrome、Firefox、Opera 和 Safari)上,您甚至可以通過單擊專用圖標在普通揚聲器模式和耳機模式之間切換。 然後,它將使用 Web Audio 的雙耳音頻渲染來進行更逼真的音頻模擬 - 如果您通過耳機收聽。
為了獲得完整的類似應用程序的體驗,我們為所有平台生成了圖標和磁貼。 這意味著,例如,在 Windows 8 ⁄ 10上,您可以將 Web 應用程序固定到“開始”菜單中。 我們甚至有多種尺寸可供選擇:


先下線!
演示完全加載後,您可以將手機切換到飛行模式以切斷連接並單擊 Sponza 圖標。 該網絡應用程序仍將提供完整的 WebGL 渲染、3D 網絡音頻和触控支持體驗。 將其切換到全屏,您實際上將無法感受到演示和原生應用體驗之間的區別。
為此,我們在 Babylon.js 中使用本機可用的 IndexedDB 層。 場景(JSON 格式)和資源(JPG/PNG 紋理以及用於音樂和聲音的 MP3)存儲在 IDB 中。 IDB 層與 HTML5 應用程序緩存相結合,然後提供離線體驗。 要了解有關這部分的更多信息以及如何配置您的遊戲以獲得類似的結果,您可以閱讀有關使用 IndexedDB 處理您的 3D WebGL 資產的文章:分享 Babylon.JS 的反饋和提示以及在 Babylon.js 中的 IndexedDB 中的緩存資源
Xbox One 很喜歡這個節目
最後但並非最不重要的一點是,同樣的演示在您的 Xbox One 上的 MS Edge 中完美運行:

按A
切換到交互模式。 Xbox One 將通知您現在可以使用遊戲手柄在 3D 場景中移動:

所以,讓我們簡要回顧一下。
相同的代碼庫適用於 Mac、Linux、MS Edge 上的 Windows、Chrome、Firefox、Opera 和 Safari、iPhone/iPad、帶有 Chrome 或 Firefox 的 Android 設備、Firefox OS 和 Xbox One! 這不是很酷嗎? 能夠直接從您的 Web 服務器定位到如此多的具有完全成熟的原生體驗的設備嗎?
我已經在前一篇關於網絡的文章中分享了我對該技術潛力的興奮:下一個遊戲前沿?
使用調試層破解場景
如果您想了解 Michel 如何掌握 3D 建模的魔力,您可以使用 Babylon.js調試層工具破解場景。 要在帶有鍵盤的機器上啟用它,請按CMD/CTRL + SHIFT + D
,如果您在 PC 或 Xbox 上使用遊戲手柄,請按Y
請注意,由於渲染引擎需要執行合成作業,顯示調試層會消耗一些性能。 所以顯示的 FPS 比沒有顯示調試層的真實 FPS 重要一點。
例如,讓我們在 PC 上對其進行測試。
靠近獅子的頭部,從我們的著色器管道中切掉凹凸通道:

您應該看到頭部現在不那麼逼真了。 與其他頻道一起播放以檢查發生了什麼。
您還可以切斷動態閃電引擎或禁用碰撞引擎以飛行或穿過牆壁。 例如,禁用“碰撞”複選框並飛到一樓。 將相機放在紅旗前。 你可以看到它們在輕微移動。 Michel 使用 Babylon.js 的骨骼/骨架支持來移動它們。 現在,禁用“骨架”選項,它們應該停止移動:

最後,您可以在右上角顯示網格樹。 您可以啟用或禁用它們以完全破壞 Michel 所做的工作:

移除幾何圖形、著色器通道或引擎的某些選項可以幫助您對特定設備的性能進行故障排除,以了解當前成本過高的情況。 您還可以檢查您是否受 CPU 限製或 GPU 限制,儘管在大多數情況下,由於 JavaScript 的單線程特性,您在 WebGL 中會受到 CPU 限制。 最後,該工具對於幫助您了解 3D 藝術家如何構建場景也非常有用。
順便說一句,它在 Xbox One 上也能很好地工作:

挑戰
在此過程中,我們在構建演示時遇到了許多問題和挑戰。 讓我們詳細研究其中的一些。
WebGL 性能和跨平台兼容性
編程方面可能是最容易解決的,因為它完全由 Babylon.js 引擎本身處理。 我們正在使用自定義著色器的架構,該架構通過嘗試使用各種後備方法找到可用於當前瀏覽器/GPU 的最佳著色器來適應平台。 這個想法是降低渲染引擎的質量和復雜性,直到我們設法在屏幕上顯示一些有意義的東西。

Babylon.js 主要基於 WebGL 1.0,以保證基於它構建的 3D 體驗幾乎可以在任何地方運行。 它的構建考慮了 Web 理念,因此我們正在逐步增強著色器編譯過程。 這對於大部分時間不想處理這些複雜性的 3D 藝術家來說是完全透明的。
儘管如此,3D 美術師在性能優化方面仍扮演著非常重要的角色。 她必須了解她的目標平台、支持的功能和限制。 您不能獲取來自為高端 GPU 和 DirectX 12 製作的 AAA 遊戲的資產,然後將它們集成到在 WebGL 引擎上運行的遊戲中。 我認為,今天以 WebGL 為目標與您為優化移動設備體驗而必須做的工作非常相似,只是需要一些額外的 JavaScript,這些 JavaScript 必須是高度單線程的。
Mitch 非常擅長:優化貼圖,預先計算閃電將其烘焙到貼圖中,盡可能減少繪製調用的次數等等。他身後有多年的經驗,看到了各代的3D 硬件和引擎(從 PowerVR/3DFX 到今天的 GPU)確實有助於實現演示。
他已經在他關於 Real Time 3D 的文章中分享了一些基礎知識:為 WebGL 目的製作演示 - 基礎知識,並且已經多次證明您可以在小型集成 GPU 上以高性能在 Web 上創建非常引人入勝的視覺體驗,例如在Mansion、Hill Valley 或 Espilit 演示場景。 如果您有興趣,請花時間觀看他在 NGF2014 上的演講——為移動世界和網絡創建 3D 資產,一位 3D 設計師分享他的經驗以及他如何設法優化 Hill Valley 場景的觀點小於 1 fps 到 60 fps。
Sponza 的最初目標是構建兩個場景。 一種用於台式機,另一種用於移動設備,具有較低的複雜性、較小的紋理和更簡單的網格和幾何形狀。 但在我們的測試中,我們終於發現桌面版本在移動設備上運行也相當不錯,因為它可以在 iPhone 6s 或 Android OnePlus 2 上運行高達 60fps。然後我們決定不再繼續開發更簡單的移動版本。
但同樣,在 Sponza 上採用乾淨的移動優先方法可能會更好,以在許多移動設備上達到 30fps+,然後增強高端移動和桌面的場景。 儘管如此,到目前為止,我們在 Twitter 上收到的大部分反饋似乎都表明最終結果在大多數設備上運行良好。 誠然,Sponza 已在 HD4000 GPU(集成 Intel Core i5)上進行了優化,它或多或少等同於實際高端手機的 GPU。
我們對我們取得的成績感到非常滿意。 Sponza 使用我們的著色器,啟用了環境、漫反射、凹凸、鏡面反射和反射。 我們有一些粒子來模擬每個角落的小火、紅旗的動畫骨骼、3D 定位的聲音和使用交互模式移動時的碰撞。
從技術上講,我們在場景中使用了 98 個網格,生成多達 377781 個頂點,16 個活動骨骼,60 多個粒子,可以生成多達 36 個繪製調用。 我們學到了什麼? 可以肯定的一件事:減少繪製調用是優化性能的關鍵,在網絡上更是如此。
裝載機
對於 Sponza,我們想創建一個新的加載器,與我們在 BabylonJS 網站上使用的默認加載器不同,以擁有一個乾淨和優美的 web 應用程序。 然後我請 Michel 提出一些新的建議。
他首先將以下屏幕發送給我:

確實,當您第一次看到它時,屏幕看起來非常漂亮。 但隨後您可能開始想知道如何以真正響應的方式使其在所有設備上運行? 讓我們弄清楚。
先說一下背景吧。 Michel 創建的模糊效果很好,但在所有窗口大小和分辨率下都不能很好地產生一些波紋。 然後,我將其替換為場景的“經典”屏幕截圖。 但是,我希望背景完全填滿屏幕,沒有黑條,也不會拉伸圖像來破壞比例。
解決方案主要來自CSS background-size: cover
+ centering image on X and Y軸。 結果,無論使用什麼屏幕比例,我們都會獲得我想要的體驗:

其他部分正在使用良好的基於百分比的 CSS 定位。 好的,排序後,我們如何處理排版 - 字體大小應該基於視口的大小。 顯然,我們可以為此使用視口單位。 vw
和vh
(其中 1vw 是視口寬度的 1%,而 1vh 是視口高度的 1%)在瀏覽器中得到了很好的支持,尤其是在所有兼容 WebGL 的瀏覽器中。 (在 Smashing Magazine 上還有一篇關於 Viewport Sized Typography 的文章,我強烈建議您閱讀。)
最後,我們正在使用背景圖像的opacity
屬性,根據當前下載過程從 0 移動到 100%,將其從0
移動到1
。
哦,順便說一下,文本動畫是簡單地使用 CSS 過渡或動畫結合 flexbox 佈局來實現的,以一種簡單但有效的方式顯示在中心或每個角落。
以透明的方式處理所有輸入
我們的 WebGL 引擎正在渲染端完成所有工作,以在所有平台上正確顯示視覺效果。 但是,無論使用何種輸入類型,我們如何保證用戶能夠在場景中移動呢?
在以前的 Babylon.js 版本中,我們支持所有類型的輸入和用戶交互:鍵盤/鼠標、觸摸、虛擬觸摸操縱桿、遊戲手柄、設備方向 VR(用於 Card Board)和 WebVR,每個都通過專用的攝像頭。 您可以閱讀我們的文檔以了解更多關於它們的信息。
通過 jQuery PEP polyfill(在需要時為應用程序生成觸摸事件)傳播到所有平台的指針事件規範對觸摸進行了普遍管理。 要了解有關指針事件的更多信息,您可以閱讀統一觸摸和鼠標:指針事件如何使跨瀏覽器觸摸支持變得容易
然後回到演示。 Sponza 的想法是擁有一個獨特的相機,同時處理所有用戶的場景:桌面、移動和控制台。
我們最終創建了UniversalCamera 。 老實說,創建它是如此明顯和簡單,以至於我仍然不知道為什麼我們以前沒有這樣做。 UniversalCamera 或多或少是一個擴展了TouchCamera的遊戲手柄相機,它擴展了FreeCamera 。
FreeCamera 提供鍵盤/鼠標邏輯; TouchCamera 提供觸摸邏輯,最終擴展提供遊戲手柄邏輯。
現在,Babylon.js 默認使用 UniversalCamera。 如果您正在瀏覽演示,您可以在所有場景中使用鼠標、觸摸和遊戲手柄在場景中移動。 同樣,您可以研究代碼以了解它是如何完成的。
將過渡與音樂同步
現在,這部分是我們問自己最多問題的地方。 您可能已經註意到介紹序列與音樂播放曲目的特定區域同步。 當一些鼓聲響起時會顯示第一行,最後的結束序列是在我們使用的喇叭樂器的每個音符上從一個攝像機快速切換到另一個攝像機。
將音頻與 WebGL 渲染循環同步並不容易。 同樣,這是 JavaScript 的單線程特性導致了這種複雜性。 關於 HTML5 Web Workers 簡介:JavaScript 多線程方法的文章分享了這背後的一些見解。 了解問題對於了解我們面臨的全球性問題非常重要,但此處詳細介紹超出了本文的範圍。
通常,在演示場景(和視頻遊戲)中,如果您想將視覺效果與聲音/音樂同步,您將受到音頻堆棧的驅動。 經常使用兩種方法:
- 生成將注入音頻文件的元數據,然後當您到達它的特定部分時可以“調用”一些事件,
- 通過 FFT 或類似技術對音頻流進行實時分析,以檢測有趣的峰值或 BPM 變化,這些變化將再次為視覺引擎生成事件。
這些方法在 C++ 等多線程環境中效果特別好。 但是在 JavaScript 中,使用 Web Audio,我們遇到了兩個問題:
- JavaScript,它是單線程的,不幸的是,大多數時候網絡工作者不會真正幫助我們,
- 即使瀏覽器在單獨的線程上處理 Web 音頻,Web 音頻也沒有任何可以發送回 UI 線程的事件。
Web Audio 的計時器比 JavaScript 精確得多。 如果能夠在單獨的線程上使用這個單獨的計時器將事件驅動回 UI 線程,那就太棒了。 但是今天,你不能這樣做(還沒有?)。
另一方面,我們使用 WebGL 和requestAnimationFrame
方法渲染場景。 這意味著,在“最佳情況”下,我們有 16 毫秒的窗口時間範圍。 如果您錯過了一個,您將不得不等待最多 16 毫秒才能對下一幀採取行動以反映聲音同步(例如啟動“淡入淡出”效果)。
然後我正在考慮將同步邏輯註入到requestAnimationFrame
循環中。 我研究了自序列開始以來所花費的時間,並研究了調整視覺以對音頻事件做出反應的選項。 好消息是,無論主 UI 線程中發生什麼,Web 音頻都會呈現聲音。 例如,您可以確定音樂的 12 秒時間戳將在音樂開始播放後的 12 秒後準確到達,即使 GPU 很難渲染場景。
最後,我們最終選擇了可能是有史以來最簡單的解決方案:使用setTimeout()
調用! 是的,我知道。 如果您查看那裡的大多數文章,包括我在上面鏈接的那篇,您會發現它非常不可靠。 但在我們的例子中,一旦準備好渲染場景,我們就知道我們已經下載了所有資源(紋理和聲音)並編譯了著色器。 我們不應該對使 UI 線程飽和的意外事件感到太惱火。 GC 可能是個問題,但我們也花了很多時間在引擎中與它作鬥爭:通過使用 Internet Explorer 11 的 F12 開發人員欄來減少垃圾收集器的壓力。
儘管如此,我們知道這個解決方案遠非理想。 切換到另一個選項卡或鎖定手機並在幾秒鐘後解鎖可能會在演示的同步部分產生一些問題。 我們可以通過使用 Page Visibility API 來解決這些問題,例如暫停渲染循環、各種聲音並重新計算setTimeout()
調用的下一個時間幀。
但也許我們錯過了一些東西; 也許,甚至可能,有更好的方法來處理這個問題。 如果您認為有更好的方法來解決相同的問題,我們很樂意在評論部分聽到您的想法和建議。
在 iOS 上處理網絡音頻
我想與您分享的最後一個挑戰是 iOS 在 iPhone 和 iPad 上處理 Web Audio 的方式。 如果您正在尋找有關“網絡音頻 + iOS”的文章,您會發現很多人很難在 iOS 上播放聲音。 現在,那裡發生了什麼事?
iOS 對 Web Audio 的支持非常出色——甚至是雙耳音頻模式。 但是蘋果已經決定,如果沒有特定用戶的交互,網頁默認不能播放任何聲音。 做出這個決定可能是為了避免廣告或其他任何通過播放不請自來的聲音來打擾用戶的東西。
這對 Web 開發人員意味著什麼? 好吧,您首先需要在用戶觸摸後解鎖 iOS 的網絡音頻上下文——在嘗試播放任何聲音之前。 否則,您的 Web 應用程序將保持極度靜音。
不幸的是,我發現這樣做的唯一方法是通過用戶平台嗅探方法來檢查,因為我沒有找到一種特徵檢測方法來做到這一點。 這簡直就是一種可怕的,而不是防彈的技術,但我找不到任何其他可以解決這個問題的解決方案。 代碼? 幹得好!
如果您不在 iPad/iPhone/iPod 上,則可以立即使用音頻上下文。 否則,我們將通過在touchend事件上播放代碼生成的空聲音來解鎖 iOS 的音頻上下文。 如果您想在啟動遊戲之前等待它,您可以註冊onAudioUnlocked事件。 因此,如果您在 iPhone/iPad 上啟動 Sponza,您將在加載序列結束時看到這個最終屏幕:

觸摸屏幕上的任意位置將解鎖 iOS 的音頻堆棧並啟動“顯示”。
所以我們開始吧! 我希望您對演示開發背後的一些見解有所了解。 要了解更多信息,請在我們的 GitHub 上閱讀此演示的完整源代碼。 顯然,一切都是開源的,你可以在 GitHub 上找到主要文件:index.js 和 babylon.demo.ts。
最後,我真的希望您現在更加確信網絡絕對是一個很棒的遊戲平台! 請繼續關注,因為我們目前正在開發新的演示,希望它們也能令人印象深刻。
本文是 Microsoft 技術傳播者和工程師關於實用 JavaScript 學習、開源項目和互操作性最佳實踐(包括 Microsoft Edge 瀏覽器)的 Web 開發系列的一部分。我們鼓勵您使用 dev.microsoftedge.com 上的免費工具(包括 F12 開發人員工具)跨瀏覽器和設備進行測試,包括 Microsoft Edge(Windows 10 的默認瀏覽器)——七種不同的、完整記錄的工具,可幫助您調試、測試和加快您的網頁速度。 此外,請訪問 Edge 博客以隨時了解 Microsoft 開發人員和專家的最新信息。