從踩坑到填坑|淘寶Web 3D應(yīng)用與游戲開發(fā)實(shí)戰(zhàn)(淘寶3d網(wǎng)站)
導(dǎo)讀:本文是淘寶前端技術(shù)專家——徐乾偉(燒鵝)分享的淘寶 Web 3D 應(yīng)用與游戲開發(fā)實(shí)戰(zhàn),這個話題在業(yè)界被談及得比較少。今天將會從移動、3D、游戲三種交叉的話題來和大家探討。接下來和小編一起從初試 Web 3D、使用 WebGL、工作流相關(guān)的游戲編輯器三個部分來了解吧~
講師介紹
徐乾偉(燒鵝)-淘寶前端技術(shù)專家,來自淘寶虛擬互動團(tuán)隊(duì),這個團(tuán)隊(duì)主攻 3D /游戲/ VR / AR 。其中,我們有一個小團(tuán)隊(duì)叫斜杠實(shí)驗(yàn)室,主攻 Web 方向上的動畫和 3D 技術(shù)。
為什么我們會在這樣交叉領(lǐng)域去發(fā)力做一些事情?去年的雙十一淘寶去年交易額多少?一千多億,其中有 80% 的 GMV 是來自移動端的,簡單地理解就是說我們公司在電商領(lǐng)域 80% 的錢是通過手機(jī)客戶端賺取的,而不是 PC 。這就是為什么在我們要在移動端做 3D/VR/AR 的應(yīng)用。
初試Web 3D
有一句話叫:給我一個支點(diǎn),我就能撬動地球。
很多人都做過 2D 游戲, 3D 最大的區(qū)別就是多了一根 Z 軸,而給我一個 Z 軸我就能創(chuàng)造 3D 世界。很多做前端的同學(xué)對 3D 這個事情是有誤解的,比如說 HTML5 中的 Canvas 有兩個上下文,大家認(rèn)為 2d Context 只能畫 2D,WebGL context 才能畫 3D ,這是一種誤解。
其實(shí) 3D 和 2D 并不是由繪圖引擎來決定的,而是由數(shù)學(xué)家決定的。假如我們要畫這樣的曲面會怎么畫呢?
首先有描述這個面的公式,這個公式根據(jù) X、Y 入?yún)⑺愠?Z 的坐標(biāo)值,假設(shè) Z 越大顏色越紅,Z 越小顏色越綠,畫出來是這樣的。如果 X、Y、Z 乘以一種神奇的東西叫矩陣(矩陣是數(shù)學(xué)家發(fā)明的),這是 3×3 的旋轉(zhuǎn)矩陣,把每個點(diǎn)都乘一下,然后畫到屏幕上得到的結(jié)果就是這樣的。
大家是不是一臉懵逼呀~
關(guān)于如何用 Canvas 2d 繪制 3D 曲面,以后再詳細(xì)講解,我有一段時間寫過 CSS3D 的庫,就是用 glMatrix 數(shù)學(xué)庫做出非??犰诺男Ч?。
使用 Web GL
2016 年雙十一我們做過一個小游戲,不知道大家有沒有玩過?
這個游戲是用 Canvas 2d 繪制,就是用的 glMatrix 數(shù)學(xué)庫畫實(shí)現(xiàn) 3D 效果。當(dāng)時為什么用 Canvas 2d 呢?我們淘寶市場部的同學(xué)說我們要做 3D ,因?yàn)?pokemongo 做了一個 3D 的,但是你這個東西最后要給我搞到 iPhone 4 上去。大家知道 iPhone 4是不支持 WebGL 的,而當(dāng)時開發(fā)時間非常緊張,我只能用 Canvas 2d 的方案。
如果點(diǎn)了主場景中的貓,就會進(jìn)入一個 AR 捉貓的環(huán)境。這個不是 web 渲染,因?yàn)楫?dāng)時移動端的 web 還不具備獲取攝像頭數(shù)據(jù)的能力,所以當(dāng)時 AR 只能用 Native 的 3D 引擎渲染,叫 T3D,顧名思義 Taobao 3D 。另外還有一個比較有趣的 AR 場景,叫“黃金貓”。黃金貓在雙十一前后三天會出現(xiàn)在銀泰或者蘇寧的商場上方,你只要搶到了這只貓至少有一百塊錢的紅包獎勵。
難點(diǎn)一:建筑模型的制作,我們的設(shè)計師是個平面設(shè)計師,不會做 3D ,他當(dāng)時給我的圖是這樣的,你看著辦吧,我當(dāng)時花了整整一天時間做模型。
**
難點(diǎn)二:地面算法**,這個地面是六邊型的結(jié)構(gòu),要把地面從地球坐標(biāo)系轉(zhuǎn)換成 3D 世界里的場景,會分幾步。我們小時候都看過世界地圖,怎樣把一個球形的面投射到平面上呢?
這種投影叫做墨卡托投影(Mercator projection)。這個投影算法的代碼是服務(wù)端拷給我的,因?yàn)橐3智昂蠖怂惴ㄒ恢?,我?fù)制了后端的投影算法。相比墨卡托投影,這是簡化的算法,因?yàn)橐罂吹街車呢埵窃谖迨鬃笥遥跃炔⒉皇翘貏e高,簡單的算法就能夠滿足了。
當(dāng)時的視角是這樣的,以用戶當(dāng)前的位置經(jīng)緯度為中心,輻射一圈就可以看到周圍有多少只貓。
這里的六邊型地面如果用 X、Y 兩個軸的算法去計算其實(shí)是比較慢的,我當(dāng)時看了一篇論文,這是一個斯坦福的同學(xué)花了二十年研究六邊型的算法,他本質(zhì)上是以夾角為 120 度的 X、Y、Z 三個軸為坐標(biāo)軸算,相比算 X、Y 兩個軸的算法快很多。上面還有很多基于這個基礎(chǔ)算法拓展的算法如尋路等。
好不容易跨過了雙十一的坎,我們已經(jīng)看到 Canvas 2d 的方案在模型輸入和繪制性能方面都是非常弱的。
如何繼續(xù)開發(fā) 3D 類的游戲呢?可能大家會問,WebGL 在 PC 上都不行,在手機(jī)上行不行呀?我跟大家說,現(xiàn)在完全沒問題,我們在上億臺同時在線的設(shè)備上都試過了,前提是要做一下 WebGL 能力檢測。 PC 還有一些古董瀏覽器不支持 WebGL ,反而手機(jī)比 PC 發(fā)展快得太多。
大家之前理解了 3D 的概念, 3D 不是繪圖引擎的功能, 3D 是數(shù)學(xué)的概念。那 CPU 繪圖與 GPU 繪圖有什么區(qū)別呢?GPU 是并行處理每一個像素的。
我們剛開始嘗試 WebGL 小心翼翼,因?yàn)榕陆o手淘帶來影響,事實(shí)上也造成比較大的 Crash 。
2016 年的圣誕節(jié),市場部同學(xué)說要不在手淘里下一場雪吧,那就下了。后面我會和大家介紹下這場雪的代價。我們還嘗試做類似于右邊這種模型粒子動畫,這是一只天貓的模型。這兩個都是粒子系統(tǒng),因?yàn)槲覀儎傞_始不知道怎么做復(fù)雜的 3D 渲染,我們只能從最基礎(chǔ)的繪制“點(diǎn)”出發(fā)去嘗試。
我們團(tuán)隊(duì)有一種叫 PopLayer 的技術(shù),可以在當(dāng)前 Native View 上面隨時彈出一層 Web View。比如之前搜一下鹿晗出彈幕,還有明星打電話,都是通過 PopLayer 技術(shù)實(shí)現(xiàn)的。
上文提到,在淘寶首頁的 Poplayer 里 下一場雪導(dǎo)致了大面積的客戶端Crash 。原因是 iOS 下的 UIWebView 使用 webgl 渲染時,WebCore 會調(diào)用到 OpenGL ES 進(jìn)行渲染,而蘋果發(fā)現(xiàn)有在后臺調(diào)用 OpenGL ES,就會直接結(jié)束 App。
知道 RequestAnimationFrame API 嗎?解法就是監(jiān)測當(dāng)前用戶退出后臺或當(dāng)前頁面不可見時,會把 RequestAnimationFrame 停止。
小倩也提到過 Page Visibility 方面的 API ,我們發(fā)現(xiàn)安卓是支持這個 API 的, 但 IOS 還是需要調(diào) Js Bridge接口來監(jiān)聽 App 的是否退后臺的狀態(tài)。接著,我把游戲主循環(huán)(或者動畫主循環(huán))停下來之后還發(fā)現(xiàn)一些用戶會 Crash 。最后我發(fā)現(xiàn)一件非常神奇的事情~這個代碼大家都知道,它是用來獲取Canvas的WebGL context,這行代碼為什么Crash呢?我們翻了 Webkit 的源碼發(fā)現(xiàn)它有一個 reshape 函數(shù),reshape 會通過 GPU 獲取當(dāng)前畫布的高寬,所以它還是會 Crash 。
接下來將會分享 3D 之旅我們的心情,以及我的思維是如何進(jìn)化的。
2017 年的造物節(jié)時我們做了真正意義上的 3D 應(yīng)用,當(dāng)時跟英國一家設(shè)計公司合作叫 FRAMESTORE ,這個電影(《奇異博士》)大家知道吧,特效就是他們設(shè)計制作的。
FRAMESTORE 當(dāng)時給我的東西是這樣的,俯視圖是這樣的,燈光是這樣打的。雖然他們在影視特效領(lǐng)域非常牛逼,但是他們也沒做過 Web 應(yīng)用。而我當(dāng)時也不知道怎么和設(shè)計團(tuán)隊(duì)合作,還是我的老方法手寫代碼。他們給我的模型,我當(dāng)時也不知道其他高級的格式,只知道 Obj Mtl 。如果發(fā)現(xiàn) WebGL 渲染有問題,我們就去代碼里找原因,模型引用的材質(zhì)對不對,貼圖對不對。我們要翻代碼看一下是不是引用錯了。工作流的問題在這個項(xiàng)目中沒有解決,但是促使我開始尋找問題的解法。
這個項(xiàng)目還有一個性能問題,廣告牌發(fā)光效果,我第一個想到的是后處理(Post Processing),大家不理解的話,可以把它當(dāng)作實(shí)時濾鏡,如果在手機(jī)屏幕這么大的 Bloom 濾鏡是會卡死的。我當(dāng)時的方案是在每塊廣告牌上寫一個獨(dú)立的 Shader ,這樣在iphone6上至少是可以流暢渲染的。
游戲編輯器
上面講了這么多,痛苦和迷茫。其實(shí)我之前做的東西也不能稱之為真正的游戲,只能算是營銷互動類游戲。
我們還是覺得做游戲要向業(yè)界規(guī)范的方案靠攏,所以 游戲編輯器是必須要做的。雖然我今天并沒有做出一款游戲編輯器,我會跟大家分享為什么我要做游戲編輯器(現(xiàn)在已經(jīng)正在做了),這中間的坎坷是今天要講的重點(diǎn)。
和英國團(tuán)隊(duì)合作之后我非常難過,他們的設(shè)計做得那么酷,而我只能實(shí)現(xiàn)成這樣。我在中國環(huán)顧一圈,沒有看到 Web 3D 游戲方面比較好的方案,因?yàn)樵谥袊?WebGL 的都鳳毛麟角。
2017 年我去澳洲參加了 Web 3D 大會,他們當(dāng)時用了 X3dom 像 HTML 一樣用標(biāo)簽地描述 3D 世界。
這是一種非常陳舊的技術(shù),雖然也是基于 WebGL 渲染。這個方案已經(jīng)推了十幾年了,老外也不知道為什么這么執(zhí)著,有幾十個 Paper 都是講這個的。他們講的東西都非常學(xué)術(shù),我覺得對我們的幫助并不是很大。
然后我又去工業(yè)界尋找解決方案。這是前索尼 PlayStation 的一位同學(xué)做的應(yīng)用,他用的技術(shù)大家可能會大吃一驚,他用了Unity。第一次看到 Unity 和 Web 嫁接起來是非常令我震驚的。我當(dāng)時用的是 iphone6 ,運(yùn)行這個 demo 都是 60 fps 滿幀,他是怎么做到的呢?我去查了一下它的代碼,雖然代碼是壓縮過的,但是為了突破這個技術(shù)難關(guān),我閱讀了壓縮后的代碼并且理解了它背后的實(shí)現(xiàn)。
我發(fā)現(xiàn)里面有各種各樣的新穎的技術(shù)。比如,Unity 可以合并 3D 模型的貼圖。
合并貼圖這件事情是很重要的。做前端的同學(xué)都知道雪碧圖,為什么做雪碧圖?大家都知道是為了減少網(wǎng)絡(luò)請求數(shù),但是其實(shí)合并貼圖對運(yùn)行時的性能有很大影響。
GPU 讀一張圖快還是讀十張圖快?計算機(jī)資源是非常寶貴的,圖片要適度合并盡量壓縮。一張 200K 的圖片,可能占用 3-4 倍的顯存。 JS 優(yōu)化半年減少 30K ,圖片批量壓縮減少個幾兆都是有可能的,所以要把時間花在能夠快速見效的事情上面。
下圖的 Texture Baker 就是用來烘培并且合并圖片。這個是 ITween Path 是 Unity 做路徑動畫的插件。
Unity還有一個插件叫 Collada Exporter 。Collada 是標(biāo)準(zhǔn)的 3D 模型格式,看到這里我們已經(jīng)拋棄了之前 Obj Mtl 的老方案。而Runtime根據(jù)我之前的開發(fā)經(jīng)驗(yàn)封裝了一套 MVC 的方案。
基于這套工作流,我們做了 2017 年雙十一切紅包項(xiàng)目。我們經(jīng)常調(diào)侃:騰訊做游戲和阿里做有戲有什么區(qū)別?騰訊做游戲是收錢,我們做游戲是發(fā)錢。用 Unity 帶來的好處是能夠直接導(dǎo)入設(shè)計師給的源文件,如 Maya 源文件、 Photoshop 源文件。這里我們看到,紅包模型是預(yù)先切開的,大家知道切水果也是這樣做的,即使你豎著切菠蘿它還是橫著裂開的。
至于紅包的特效,我會經(jīng)常逛一些國外的網(wǎng)站,這是某個游戲開發(fā)者寫的 Shader 特效,我就照著他的思路來寫了一個類似的。
大家看到一個紅包在天上飛,上面有光在流動,其實(shí)整個場景中一盞燈都沒有打。光照計算,特別是點(diǎn)光源的計算是非常耗性能的。所以大家做 3D 應(yīng)用的時候盡量要少放光源。這種效果其實(shí)只要在像素著色器中寫一行代碼就解決了。
紅包是怎么切中的呢?Picking 這個話題對沒有開發(fā)過游戲的人也許比較陌生,切紅包的游戲里我當(dāng)時做了兩種方案:一種叫做 CPU Picker ,另一種是 GPU Picker 。
CPU Picker:在每個紅包上面套上一個包圍盒,計算射線有沒有擊中這個包圍盒,因?yàn)?CPU Picker 的計算成本和場景的復(fù)雜度正相關(guān), 用包圍盒會比較快;
GPU Picker:通過拾取離屏畫布上面的顏色值就行了。
雖然感覺 GPU Picker 性能會特別好,但在移動端性能表現(xiàn)卻不佳,因?yàn)槭叭☆伾倪^程實(shí)際上是 CPU 和 GPU 通信的過程,這個過程會比較慢。所以,CPU Picker 性能會更好一點(diǎn)。
還有一點(diǎn)就是 Dom 操作,在 Web 游戲開發(fā)中,Dom 操作就是魔鬼。我抓了比較慢的一幀花了 25 毫秒(約 40 幀)。
游戲邏輯加上 Web GL 渲染就花了那么幾毫秒,而 DOM 操作卻耗掉很長的時間,而且還引發(fā)了重繪(紫色部分)。
所以 Dom在游戲里是不合適的,GUI 部分需要用 2D 的 Canvas 或者 Web GL 渲染去解決。
最后講一下音效,我個人非常喜歡游戲中聲音給我?guī)淼莫剟?。我做切紅包的時候注意到了上面幾點(diǎn),這也是我上周去北京 Unity 大會上聽到關(guān)于 CRIWare 的聲音中間件的內(nèi)容:
- 背景音樂要有漸有漸出,這樣用戶體驗(yàn)比較好;
- 用戶做一些操作或者比較重要操作的時候,當(dāng)前聲音要強(qiáng)調(diào)一下,背景音樂減弱一下;
- 聲音要有變化,比如說很多射擊的游戲,如果槍聲都一樣,用戶聽覺會疲勞的,我們切紅包時左切和右切都是不一樣的。
這個軟件叫 bfxr,是一款制作游戲音效的小軟件,在線和客戶端版本都有,人人都可以設(shè)計音效。
講了那么多技術(shù)點(diǎn),我們總要看一下業(yè)界真正做游戲的人是怎么做的。我大概探索了一兩年,發(fā)現(xiàn) Playcanvas 引擎是 Web 世界上最健全的游戲引擎。它的引擎代碼是開源的,但是編輯器不開源。我分析了一下它的引擎源碼,大概有幾部分組成:
- ECS 的架構(gòu),Unity 也是采用這樣的設(shè)計模式。
- PBR,基于物理的渲染模型,看起來更像真實(shí)世界的渲染。物理引擎也是很重要的,還有輸入設(shè)備,比如說你的游戲手柄、手機(jī)都是輸入設(shè)備。
Playcanvas 和 Threejs 有什么區(qū)別?
Threejs 只是一個 3D 渲染庫。游戲還有一個非常重要的東西叫編輯器,這是 Playcanvas 在線的編輯器,我看了這個游戲之后就覺得一定要做編輯器,因?yàn)榫庉嬈魇且娴妮d體。如果沒有編輯器,我們每次開發(fā)游戲要注意的工程和技術(shù)問題太多。
編輯器架構(gòu)
最后講一下我們團(tuán)隊(duì)思考的編輯器的架構(gòu),現(xiàn)在只是一張工程架構(gòu)圖。
游戲最后發(fā)布的內(nèi)容是什么?就是一堆資源,圖片、模型、音頻、腳本,在 Web 開發(fā)環(huán)境中最后都要發(fā)上 CDN 。
游戲里的大部分資源如音頻、全景圖、模型這些都是第三方軟件輸入的,模型資源的序列化、減面、合并、烘培等操作我們暫時可能不會去做(還是交給 Unity 做),中間 GUI 部分就是編輯器的面板操作,最后 Script 組件和 Shader 可以通過 Vscode 來編輯。這張圖是我一兩年的心得,大家可以留言區(qū)交流~
作者:徐乾偉(燒鵝)