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