元宇宙探索之路
前言
元宇宙正在如火如荼地發展,大有引領未來潮流之勢。對於我們這麼專業的(web 前端)團隊來說,元宇宙是一個大 (wan) 顯 (quan) 身 (bu) 手 (dong) 的領域,因此團隊在這方面投入了很多人力進行預研和總結,請隨本文一起踏入元宇宙的神祕世界。
元宇宙與 3D
元宇宙,或稱為後設宇宙、形上宇宙、元界、魅他域、超感空間、虛空間,是一個聚焦於社交連結的 3D 虛擬世界之網路。關於元宇宙的討論,主要是探討一個持久化和去中心化的線上三維虛擬環境。此虛擬環境將可以通過虛擬現實眼鏡、增強現實眼鏡、手機、個人電腦和電子遊戲機進入人造的虛擬世界。
以上維基百科對於元宇宙的解釋。
相信大家和我一樣依然看得一頭霧水。或許我們此時還是不明白何為元宇宙,但是由此引出了一個重要的概念—— 3D 虛擬世界。
3D 虛擬世界 這個詞,可以拆分成 3 個單詞來理解:3D、虛擬、世界。3D 即三維,是指在平面二維繫中又加入了一個方向向量構成的空間系;虛擬即使用模型等技術構建的仿實物或偽實物;世界則是由很多虛擬物質構成的事物的總和,即一個個或大或小的虛擬場景。
在元宇宙發展的過程中,涉及到的模型設計製作、場景搭建,都離不開 3D 技術,可以說 3D 技術是元宇宙發展的基石。因此在元宇宙的探索之路上,邁出去的第一步也必然是 3D 技術研究。
3D 技術選型
未入門即勸退的 WebGL
WebGL 是一種 3D 繪圖協議,也是一個 JavaScript API,可在任何相容的 Web 瀏覽器中渲染高效能的互動式 3D 和 2D 圖形,而無需使用外掛。換句話說,WebGL 是在瀏覽器上執行 3D 效果的基礎。
但是 WebGL 的入門門檻足夠勸退大部分開發者。從最基本的著色器開始,還需要我們去學習影象處理、空間處理、矩陣運算、甚至是幾何邏輯等。
我們團隊的小夥伴做過一個 WebGL 分享,其中光是實現一個 WebGL 版本的 Hello World,就超過了四十餘行程式碼,更別說程式碼裡需要涉及的概念:
const canvas = document.querySelector('canvas'); const gl = canvas.getContext('webgl'); const vertex = ` attribute vec2 position; void main() { gl_Position = vec4(position, 1.0, 1.0); } `; const fragment = ` precision mediump float; void main() { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); } `; const vertexShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertexShader, vertex); gl.compileShader(vertexShader); const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragmentShader, fragment); gl.compileShader(fragmentShader); const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); gl.useProgram(program); const points = new Float32Array([ -1, -1, 0, 1, 1, -1, ]); const bufferId = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, bufferId); gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW); const vPosition = gl.getAttribLocation(program, 'position'); gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(vPosition); gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.TRIANGLES, 0, points.length / 2);
所以如果使用 WebGL 從零開始,無疑是非常艱難的挑戰。於是我們把目光投向了 3D 引擎。
抱有幻想的 3D 引擎
我們可以把 3D 引擎看成是一個封裝了 3D API、圖形通用演算法、底層演算法的工具。通常 3D 引擎都搭配有具備視覺化操作介面的編輯器,即便是從零開始,通過建立 3D 型別的節點,甚至只需要拖動編輯器上的 3D 模型,我們就可以快速的搭建一個 3D 場景。相比於晦澀難懂的 WebGL,3D 引擎對於初學者無疑更友好。
Unity 3D
Unity 3D 可以說是市面上使用率最高的 3D 引擎,它具有生態好、功能支援全面、專案優化好等等優點。但是!它可以做到現在的市場規模與地位,隱藏在它背後成功的商業模式功不可沒,遺憾的是,它是收費的,而且價格不菲。在沒有產生經濟效益的預研階段,我們不希望投入太大的經濟成本,因而放棄。
以下是使用 Unity 3D 完成的 Demo 效果:
LayaBox
LayaBox 是一個國產的遊戲引擎品牌,旗下的 LayaAir 支援 JS、TS 等語言,且可以相容使用 Unity 3D 匯出的地形、元件、物理引擎、動畫、攝影機和粒子等元素,因此一個不成熟的想法油然而生,使用 Unity 3D 編輯然後匯出場景,然後使用 LayaAir 繫結互動事件後打包釋出,這樣就可以完美的避開授權費用了?但是很可惜,我們經過嘗試後發現,Layabox 的免費範圍也僅針對 IDE 基礎功能,對於後邊可能用到的 IDE 企業會員專屬功能,也是收費的,且官方要求的在首頁註明「Powered by LayaAir Engine」,這與我們的商業標準不符,所以也告別了商用的可能性。
Egret
Egret 也是一款國產的遊戲引擎,它一開始就專注 h5 開發,在 h5 方面支援較好,但是它原本是專注於 2D 領域的,在 3D 方向起步較晚,很多官方的文件都還不健全,因此上手難度較大,遇到問題只能摸著石頭過河,遂 pass。
Godot
Godot 是一款完全免費的遊戲引擎,它支援跨平臺編輯與釋出,但是在打包釋出到 h5 頁面後,我們發現它打包出來的模型檔案較大,這對於移動端載入體驗來說是比較致命的問題;而且渲染效果也較為粗糙,模型渲染出現了比較明顯的鋸齒現象;H5 匯出格式支援 WebAssembly 和 WebGL,但是 WebGL 尚不支援任何 IOS 的瀏覽器。以上種種都不符合我們對元宇宙的預期,因此也只能無奈放棄。
為方便對比,我們做了以下表格進行總結:
引擎名稱 | 使用價格 | 指令碼語言 | 支援模型格式 |
---|---|---|---|
Unity 3d | 每年1800$(個人) | C# | .fbx、.dae、.3ds、.dxf、.obj |
Egret | 免費 | TypeScript | .obj、.gltf |
Godot | 免費 | GDScript | .obj、.dae、.gltf、.escn、.fbx |
Layabox | 免費 | TS\JS\AS3 | .fbx、.dae、.3ds、.dxf、.obj |
至此,3D 引擎幻想泡滅。
回首擁抱的 BabylonJS
其實除了上述 3D 引擎,我們一開始就想到的還包括 BabylonJs 和 ThreeJs 這兩個主流的 3D 框架。作為市面上比較流行的 3D 框架,它們的文件完善度和學習資源豐富度都沒有問題。而在這兩者的對比上,我們覺得 ThreeJS 與其說是框架,不如說是一個庫,它對 WebGL 進行了封裝,將複雜的介面簡單化,將物件結構資料化,的確是個不錯的選擇;而相較而言,BabylonJS 在模組化層面則更清晰,也更像是一個框架,並且它擁有不亞於 ThreeJS 豐富度的學習資源,最終成為了我們團隊敲定的技術選型。
開展工作
頭腦風暴
作為大促開發團隊,我們希望 3D 預研成果能夠最終落地到我們的活動。因此在作品定向的討論上,我們最終敲定了要實現一個虛擬商場。3D 人物模型可以在一個佈滿各種商品的 3D 商場中行走,它可以運動到心儀的商品前進行預覽,甚至可是實現不同 3D 場館的切換。
素材格式
在明確了作品方向後,我們需要視覺同學提供相關的模型素材。
在眾多的 3D 模型格式中,我們最後選擇了 .gltf 格式。相對於其他模型格式,.gltf 可以減少 3D 格式中與渲染無關的的冗餘資料,從而確保檔案體積更小。目前 3D 素材相對來說都比較大,這對於移動端載入體驗來說,無疑是致命的。因此擁有更小體積的格式,也擁有了更高的優先選擇權。
除此之外,.gltf 是對近二十年來各種 3D 格式的總結,使用最優的資料結構,從而保證最大的相容性以及可伸縮性,在擁有大容量的同時,支援更多的拓展,比如支援多貼圖、多動畫等。
所以 .gltf 成為了我們與視覺約定好的唯一素材格式。
開發痛點
-
模型邊界
- 問題描述:沒有判斷模型邊界,導致模型可以超過合理範圍去放大與縮小。
- 解決方式:從設計規範出發,開發與設計對齊規範,嚴格按照統一尺度輸出模型。
-
碰撞檢測
- 問題描述:沒有做好碰撞檢測,導致人物模型可以穿透場景模型。
- 解決方式:除了輸出常規顯示的模型,還需要輸出不用於顯示的低模,利用低模來實現碰撞檢測,降低碰撞的計算量;新增尋路系統,當運動模型自動行走時,可以自動繞開障礙物模型。
- 優化前:
- 優化後:
-
場景切換
- 問題描述:場景切換時,鏡頭會旋轉。
- 解決方式:切換場景時,需要對不展示的場景關閉控制。需要注意的是,在初始化場景時,通常會伴隨著初始化控制,最好在構建函式的最後關閉控制,在當前場景下再開啟控制,保證場景控制的唯一性。
-
記憶體開支嚴重
- 問題描述:記憶體佔用率大,遊戲執行一段時間後,手機會有發熱和卡頓等現象。
- 解決方式:控制記憶體開銷,切換場景時,清空其他場景,避免無效的記憶體佔用。
- 優化前:
- 優化後:
作品展示
場景切換:
商品材質切換:
歡迎大家檢視連結 預覽連結
小結
元宇宙是一個很龐大的概念,此時只是萌芽階段,正如我們的探索,必然也存在許多不成熟的地方。但我們相信這是未來的一個方向,也相信我們的產品形態會日益豐富與成熟。
讓我們共同期待!
歡迎關注凹凸實驗室部落格: aotu.io
或者關注凹凸實驗室公眾號(AOTULabs),不定時推送文章:
- 執行緒池底層原理詳解與原始碼分析
- 30分鐘掌握 Webpack
- 線性迴歸大結局(嶺(Ridge)、 Lasso迴歸原理、公式推導),你想要的這裡都有
- 【前端必會】webpack loader 到底是什麼
- 中心化決議管理——雲端分析
- HashMap底層原理及jdk1.8原始碼解讀
- 詳解JS中 call 方法的實現
- 列印 Logger 日誌時,需不需要再封裝一下工具類?
- 初識設計模式 - 代理模式
- 密碼學奇妙之旅、01 CFB密文反饋模式、AES標準、Golang程式碼
- Springboot之 Mybatis 多資料來源實現
- CAS核心思想、底層實現
- 面試突擊86:SpringBoot 事務不回滾?怎麼解決?
- 基於electron vue element構建專案模板之【打包篇】
- MiniWord .NET Word模板引擎,藉由Word模板和資料簡單、快速生成檔案。
- 認識執行緒,初始併發
- 1-VSCode搭建GD32開發環境
- 初識設計模式 - 原型模式
- 執行緒安全問題的產生條件、解決方式
- 2>&1到底是什麼意思?