真·千人同屏 | 虛擬世界的“煙火氣”
我們?yōu)槭裁葱枰扒送痢保?/strong>
在過去的兩年,各式各樣的虛擬場(chǎng)景層出不窮,有展廳展館、有展覽與音樂會(huì)、有景區(qū)古跡,但這些場(chǎng)景中多是寥寥數(shù)人穿梭其中,附加站在某個(gè)角落的NPC,這樣的體驗(yàn)難免給人一種“單機(jī)游戲“的既視感,而千人同屏技術(shù)能夠打破這樣的既視感,是帶給擬世界臨場(chǎng)感的基石功能之一!
點(diǎn)擊體驗(yàn)千人同屏
觀看虛擬演出和表演,能感受到不亞于現(xiàn)場(chǎng)音樂節(jié)的熱鬧氛圍
(光遇歐若拉演唱會(huì))
體驗(yàn)虛擬文旅活動(dòng),能和更多五湖四海的伙伴同游暢聊,更有現(xiàn)實(shí)生活
(逆水寒汴京夜市)
對(duì)于線上峰會(huì)、發(fā)布會(huì)等會(huì)議,上千人會(huì)議現(xiàn)場(chǎng)更有“人聲鼎沸”的熱議氛圍
對(duì)于線上社區(qū),大家真實(shí)的互動(dòng)、分享、交流將會(huì)直觀視覺化激發(fā)用戶的參與感
千人同屏并不是全新的技術(shù),在數(shù)年前的游戲中早以可以實(shí)現(xiàn)。但是在虛擬空間中,沒有游戲化的APP載體來充分釋放性能,沒有用戶有等待游戲加載的耐心,并且在以網(wǎng)頁為主要實(shí)現(xiàn)方式的當(dāng)下,虛擬空間需要快速載入、兼顧性能,并可實(shí)現(xiàn)多端兼容(如不同app/瀏覽器/AR/VR設(shè)備...),宛如帶著鐐銬起舞。
雖有如此難度,但“千人同屏”仍被輕易地附加在各類概念化的描述之后,看似可以被輕易地實(shí)現(xiàn)。這里想分享下我們理解的“千人同屏”:
用戶可以在各式各樣的虛擬人中無限制地選擇自己喜歡的風(fēng)格。在千人同屏技術(shù)的加持下,整個(gè)虛擬世界不再是整齊劃一的虛擬人,而是像聚集了來自五湖四海的各色人兒,呈現(xiàn)千人千面、繽紛多彩的世界。
在真正的千人同屏里,用戶不再是被限制在某個(gè)位置坐下或者站立(這樣的千人萬人同屏毫無意義),而是可以自由地操作自己的虛擬形象,去四處漫游,能做各種社交互動(dòng),在熱鬧的場(chǎng)域下充分感受真實(shí)的人與人之間交流,人與物之間的交流。
在虛擬空間中,能夠認(rèn)識(shí)新朋友遇見老朋友,是在虛擬世界中難忘的經(jīng)歷,如果此時(shí)看上去人山人海,實(shí)則只是程序操控下的機(jī)器人,那大可不必來到這里享受一個(gè)人的狂歡。
當(dāng)然還有一些文字游戲類的說法,比如“實(shí)現(xiàn)千人同屏觀看”這樣以直接偷換了概念的方式硬套千人同屏技術(shù),無不在說明千人同屏技術(shù)真實(shí)的難度。
為什么要實(shí)現(xiàn)“真·千人同屏”這么難?
在網(wǎng)頁端要實(shí)現(xiàn)同屏千人流暢的實(shí)時(shí)互動(dòng),不同的環(huán)節(jié)都有巨大的挑戰(zhàn):后端對(duì)于用戶位置信息的匯總處理、前后端通信細(xì)節(jié)的優(yōu)化、前端渲染開銷的控制......
下面具體分享下我們技術(shù)處理方案:
說到渲染性能優(yōu)化,降低 draw call 數(shù)往往是最先想到也最有效的做法。一個(gè) draw call 是 CPU 向 GPU 發(fā)送一次繪制命令,會(huì)產(chǎn)生兩者間的一次通信開銷。一旦 draw call 過多,這些開銷積累起來,便導(dǎo)致渲染性能下降。
在以往的項(xiàng)目架構(gòu)中,每一個(gè)角色人物作為一個(gè)單獨(dú)的模型,渲染時(shí)都需要一次新的draw call,因此當(dāng)在線人數(shù)大量增加時(shí),draw call 數(shù)也就線性地猛增。
而實(shí)際上角色人物的種類并不多,只有三四個(gè),因此大部分人物都是同一個(gè)模型的重復(fù)渲染,如果可以把這些重復(fù)的模型同時(shí)渲染出來,自然就可以大大降低 draw call 了。
說到重復(fù)模型,對(duì)于3d渲染有所了解的話,自然就會(huì)想到實(shí)例化繪制(Instanced Drawing), 它可以將同樣的模型以實(shí)例化的方式合并成一次 draw call 繪制出來,是 WebGL 提供的能力,正好可以解決我們的問題。
可事情并沒有這么簡(jiǎn)單。
我們的角色人物由用戶操控,會(huì)跑、會(huì)跳,實(shí)際上是帶動(dòng)作骨骼的蒙皮模型(Skinned Mesh),這些動(dòng)作互相獨(dú)立并受人物當(dāng)前活動(dòng)狀態(tài)控制。而 現(xiàn)有的移動(dòng)端3d框架并不支持簡(jiǎn)單地將骨骼模型實(shí)例化,如果只是簡(jiǎn)單將模型實(shí)例化的話,只會(huì)得到一堆無法表現(xiàn)任何動(dòng)作的僵硬實(shí)例,在世界中平移。顯然這是不可接受的。
(未支持骨骼蒙皮模型時(shí)實(shí)例化繪制時(shí)效果)
(正常帶動(dòng)作的人物模型)
為了解決這個(gè)問題,可以有多種處理方案,其中一種是將動(dòng)畫烘焙到貼圖材質(zhì)中,這樣就可以在 GPU 代碼中通過采樣的方式獲取數(shù)據(jù)完成頂點(diǎn)變形;另一種是將動(dòng)畫的插值計(jì)算放在 CPU 上,再實(shí)時(shí)將當(dāng)前動(dòng)畫數(shù)據(jù)上傳至 GPU 處理。
前一種的優(yōu)點(diǎn)是性能更優(yōu),缺點(diǎn)是需要對(duì)動(dòng)畫的特殊處理,而且 GPU 編程限制更多也更復(fù)雜;后一種方案的優(yōu)點(diǎn)是與現(xiàn)有的邏輯相適配,代碼上也更簡(jiǎn)單,缺點(diǎn)是如果想要更加優(yōu)化性能,還需要做其他特殊處理。
這里,分享下比較簡(jiǎn)單的處理方案。
如果我們搞清楚現(xiàn)有框架是如何實(shí)現(xiàn)非蒙皮模型的實(shí)例化、以及單個(gè)蒙皮模型的動(dòng)作變形,再將這兩種能力組合起來,就可以實(shí)現(xiàn)帶動(dòng)作蒙皮模型的實(shí)例化啦!
具體來說,骨骼蒙皮模型能夠渲染出動(dòng)作動(dòng)畫,在于它的各個(gè)頂點(diǎn)已經(jīng)綁定了對(duì)應(yīng)哪幾塊骨頭以及它們影響的權(quán)重。當(dāng)骨骼的位置、旋轉(zhuǎn)、大小變化時(shí)(即動(dòng)作進(jìn)行中),渲染時(shí)便會(huì)逐幀去取到最新骨頭的變換矩陣并將其作用到頂點(diǎn)位置上以改變?cè)械奈恢茫@樣就形成了動(dòng)畫。
(控制模型動(dòng)作的骨骼)
要把這些邏輯放入實(shí)例化繪制,也需要有同樣的操作。
頂點(diǎn)與骨骼的綁定與單個(gè)模型是一致的,只需要復(fù)用即可,而不同的地方主要在于之前只需要從一套骨骼中去取骨頭的變換矩陣,而實(shí)例化后需要從多套骨骼中去取當(dāng)前實(shí)例對(duì)應(yīng)骨骼的變換矩陣。
因?yàn)槊恳粋€(gè)人物都有自己的動(dòng)作狀態(tài),因此可以為每一個(gè)實(shí)例綁定一套骨骼,并由動(dòng)畫控制器去實(shí)現(xiàn)動(dòng)作的計(jì)算。之后再將這些動(dòng)作數(shù)據(jù)以數(shù)據(jù)貼圖(data texture)的形式上傳至 GPU,然后在頂點(diǎn)著色器(vertex shader)代碼中讀取使用即可。
當(dāng)一個(gè)模型有20多塊骨頭時(shí),每塊骨頭需要4個(gè)像素來存儲(chǔ)共16個(gè)數(shù)字的變換矩陣,一套骨骼可用16*16像素的貼圖且還有大量空余。即使實(shí)例數(shù)量(人物)增加至1000個(gè),貼圖大小也不會(huì)超過512*512像素!
在新的著色器代碼中,我們?nèi)〉叫碌墓趋雷儞Q矩陣便可完成頂點(diǎn)變形。
完成實(shí)例化后,當(dāng)場(chǎng)景中有1000個(gè)角色時(shí),draw call 數(shù)也不會(huì)像之前增加到1000,而仍然僅為1,在渲染層面大大優(yōu)化了性能!
雖然 draw call 已大為降低,但1000個(gè)模型仍是1000個(gè)模型,頂點(diǎn)數(shù)和模型面數(shù)都不會(huì)減少,仍然是 GPU 計(jì)算中不小的開銷。
為了減小大量模型渲染時(shí)的面數(shù),我們采用了多細(xì)節(jié)層級(jí)(LOD)的技術(shù)方案。
簡(jiǎn)單來說,依據(jù)人物模型與相機(jī)的距離,可以選擇不同細(xì)節(jié)層級(jí)的模型。這是因?yàn)楫?dāng)角色距離較遠(yuǎn),其精細(xì)細(xì)節(jié)本就難以分辨,這個(gè)時(shí)候再去渲染一個(gè)精細(xì)的模型也沒有必要,完全可以用一個(gè)更加粗糙的類似模型來替代。
粗糙的模型頂點(diǎn)數(shù)可以減少很多,而且還可以有多個(gè)層級(jí),以更細(xì)化區(qū)分距離,達(dá)到既減少面數(shù)、又在視覺上無差別的效果。
另外,還可以在角色距離相機(jī)一定距離外完全隱藏模型,進(jìn)一步優(yōu)化性能。
因?yàn)椴煌膶蛹?jí)對(duì)應(yīng)不同的模型,所以在實(shí)例化繪制時(shí),也需要引入新的實(shí)例化模型,同時(shí)增加幾個(gè) draw call。但這幾個(gè) draw call 仍然遠(yuǎn)小于此前每個(gè)實(shí)例單獨(dú)一個(gè) draw call 時(shí)的數(shù)量,收益遠(yuǎn)大于開銷!
雖然用實(shí)例化繪制在渲染能力上支持了1000人同時(shí)在線,但實(shí)際上在場(chǎng)景中不會(huì)始終都有1000人,而且因?yàn)椴捎昧硕嗉?xì)節(jié)層級(jí),每個(gè)角色也可能會(huì)在幾個(gè)實(shí)例模型間切換,因此就會(huì)有實(shí)例顯隱的問題 。
因?yàn)榈讓訉?shí)現(xiàn)的限制,想要控制實(shí)例化模型中實(shí)例的顯示還是隱藏,無法簡(jiǎn)單在各個(gè)實(shí)例上去控制,而理論上最理想的方式是動(dòng)態(tài)修改 count 屬性值。此時(shí),實(shí)例模型中只有前面 count 這么多個(gè)實(shí)例會(huì)進(jìn)入渲染流程,而后面的實(shí)例因?yàn)椴粎⑴c渲染,因此性能上最優(yōu)。
我們?cè)谝婚_始也是這樣處理的,將場(chǎng)景角色的變換矩陣設(shè)定給前n個(gè)實(shí)例,然后設(shè)定好實(shí)例化模型的數(shù)量,之后當(dāng)角色退出場(chǎng)景或切換到其他模型時(shí),只需要更新一個(gè)實(shí)例對(duì)應(yīng)的索引序號(hào)、并減小 count 的值即可。這樣就可以保持始終只渲染實(shí)際有效的模型。
(理想情況下實(shí)例顯隱控制)
但是在實(shí)際操作中,在切換數(shù)量及同步序號(hào)的瞬間,場(chǎng)景中對(duì)應(yīng)的實(shí)例偶爾會(huì)有閃動(dòng)。雖然不是非常顯眼,但仍然是不穩(wěn)定的體驗(yàn)。
為了解決這個(gè)問題,我們在探討權(quán)衡后決定不再瞬移實(shí)例,而是在 GPU 著色器代碼中處理實(shí)例顯隱,并控制計(jì)算復(fù)雜度。
雖然這樣性能會(huì)略微劣化一點(diǎn),但好處是用戶體驗(yàn)更為穩(wěn)定可靠。經(jīng)過測(cè)試,這樣雖然面數(shù)相對(duì)沒有減少,性能卻有不小的提高。
在處理實(shí)例化骨骼蒙皮模型時(shí),我們還遇到了其他一些問題,其中包括模型影子。
因?yàn)榭蚣苤恢С址菍?shí)例化繪制的骨骼模型,在我們實(shí)現(xiàn)的實(shí)例化模型上,默認(rèn)的獲取深度映射以渲染影子的著色器代碼無法直接處理。
因此需要再增加自定義的深度材質(zhì)并綁定自定義的著色器。此時(shí)將骨骼動(dòng)畫的作用應(yīng)用在頂點(diǎn)位置變形上,即可以得到正確的深度映射啦!
(左:影子沒有跟隨動(dòng)作變化;右:影子實(shí)時(shí)跟隨動(dòng)作變化)
此外,為了陰影性能的考慮,我們也控制了陰影渲染的范圍。不過因?yàn)閷?shí)例化繪制后draw call 數(shù)已大大下降,可以有更多角色有自己的影子啦!
(左:只有1個(gè)人有影子;右:四周的人都有影子)
不過陰影范圍增加同樣也造成了小問題,即陰影的邊緣過分清晰,整體效果不佳。
為解決這個(gè)問題,我們?cè)?strong>顯示陰影的著色器代碼中加入了淡出的處理,使得整體效果更為自然。
(左:影子邊緣過分清晰;右:影子自然淡出)
此外,實(shí)例化繪制也并非都是優(yōu)化。非實(shí)例化渲染有一個(gè)優(yōu)點(diǎn)是視錐體剔除(Frustum Culling) 很容易實(shí)現(xiàn),當(dāng)人物不出現(xiàn)在相機(jī)視線中時(shí),也不會(huì)再渲染。
而當(dāng)人物實(shí)例化之后,因?yàn)檎麄€(gè)模型的邊界更難以計(jì)算,而且是整體的比較,所以視錐體剔除難以處理,如果想要實(shí)現(xiàn)類似單獨(dú)模型的剔除結(jié)果,就需要手動(dòng)去控制實(shí)例的顯隱并優(yōu)化著色器代碼來控制開銷。
靈境至維團(tuán)隊(duì)一直致力于打造一個(gè)既有人間煙火氣,又有無限想象力的虛實(shí)共生的世界!而真·千人同屏作為虛擬世界活力的重要基石,技術(shù)團(tuán)隊(duì)也不會(huì)止步于此,會(huì)繼續(xù)去優(yōu)化它。當(dāng)然要實(shí)現(xiàn)團(tuán)隊(duì)愿景,本就需要不斷地去挑戰(zhàn)這個(gè)領(lǐng)域里技術(shù)、設(shè)計(jì)、體驗(yàn)等的眾多高峰。雖然很難,但對(duì)于我們,你可以期待更多!
編輯:小蕓、Neeson、久喬、山童、歐陽
技術(shù)顧問:久喬、海青
轉(zhuǎn)載請(qǐng)?jiān)谖恼麻_頭和結(jié)尾顯眼處標(biāo)注:作者、出處和鏈接。不按規(guī)范轉(zhuǎn)載侵權(quán)必究。
未經(jīng)授權(quán)嚴(yán)禁轉(zhuǎn)載,授權(quán)事宜請(qǐng)聯(lián)系作者本人,侵權(quán)必究。
本文禁止轉(zhuǎn)載,侵權(quán)必究。
授權(quán)事宜請(qǐng)至數(shù)英微信公眾號(hào)(ID: digitaling) 后臺(tái)授權(quán),侵權(quán)必究。
評(píng)論
評(píng)論
推薦評(píng)論
暫無評(píng)論哦,快來評(píng)論一下吧!
全部評(píng)論(0條)