带玩具逛街时突然按下按钮的故事,丰满的妺妺3伦理播放,新婚人妻不戴套国产精品,大肉大捧一进一出好爽视频百度

真·千人同屏 | 虛擬世界的“煙火氣”

原創 1 收藏 評論
舉報 2023-09-28

1695887643239735.png

我們為什么需要“千人同屏”?

在過去的兩年,各式各樣的虛擬場景層出不窮,有展廳展館、有展覽與音樂會、有景區古跡,但這些場景中多是寥寥數人穿梭其中,附加站在某個角落的NPC,這樣的體驗難免給人一種“單機游戲“的既視感,而千人同屏技術能夠打破這樣的既視感,是帶給擬世界臨場感的基石功能之一!

點擊體驗千人同屏

  靈境大陸-體驗入口  

  音樂空間-體驗入口  


  • 觀看虛擬演出和表演,能感受到不亞于現場音樂節的熱鬧氛圍


(光遇歐若拉演唱會)

  • 體驗虛擬文旅活動,能和更多五湖四海的伙伴同游暢聊,更有現實生活


(逆水寒汴京夜市)

  • 對于線上峰會、發布會等會議,上千人會議現場更有“人聲鼎沸”的熱議氛圍

  • 對于線上社區,大家真實的互動、分享、交流將會直觀視覺化激發用戶的參與感


千人同屏并不是全新的技術,在數年前的游戲中早以可以實現。但是在虛擬空間中,沒有游戲化的APP載體來充分釋放性能,沒有用戶有等待游戲加載的耐心,并且在以網頁為主要實現方式的當下,虛擬空間需要快速載入、兼顧性能,并可實現多端兼容(如不同app/瀏覽器/AR/VR設備...),宛如帶著鐐銬起舞。

雖有如此難度,但“千人同屏”仍被輕易地附加在各類概念化的描述之后,看似可以被輕易地實現。這里想分享下我們理解的“千人同屏”:


用戶可以在各式各樣的虛擬人中無限制地選擇自己喜歡的風格。在千人同屏技術的加持下,整個虛擬世界不再是整齊劃一的虛擬人,而是像聚集了來自五湖四海的各色人兒,呈現千人千面、繽紛多彩的世界。


在真正的千人同屏里,用戶不再是被限制在某個位置坐下或者站立(這樣的千人萬人同屏毫無意義),而是可以自由地操作自己的虛擬形象,去四處漫游,能做各種社交互動,在熱鬧的場域下充分感受真實的人與人之間交流,人與物之間的交流。


在虛擬空間中,能夠認識新朋友遇見老朋友,是在虛擬世界中難忘的經歷,如果此時看上去人山人海,實則只是程序操控下的機器人,那大可不必來到這里享受一個人的狂歡。

當然還有一些文字游戲類的說法,比如“實現千人同屏觀看”這樣以直接偷換了概念的方式硬套千人同屏技術,無不在說明千人同屏技術真實的難度。


為什么要實現“真·千人同屏”這么難?

在網頁端要實現同屏千人流暢的實時互動,不同的環節都有巨大的挑戰:后端對于用戶位置信息的匯總處理、前后端通信細節的優化、前端渲染開銷的控制......

下面具體分享下我們技術處理方案:


說到渲染性能優化,降低 draw call 數往往是最先想到也最有效的做法。一個 draw call 是 CPU 向 GPU 發送一次繪制命令,會產生兩者間的一次通信開銷。一旦 draw call 過多,這些開銷積累起來,便導致渲染性能下降。

在以往的項目架構中,每一個角色人物作為一個單獨的模型,渲染時都需要一次新的draw call,因此當在線人數大量增加時,draw call 數也就線性地猛增。

而實際上角色人物的種類并不多,只有三四個,因此大部分人物都是同一個模型的重復渲染,如果可以把這些重復的模型同時渲染出來,自然就可以大大降低 draw call 了。

說到重復模型,對于3d渲染有所了解的話,自然就會想到實例化繪制(Instanced Drawing), 它可以將同樣的模型以實例化的方式合并成一次 draw call 繪制出來,是 WebGL 提供的能力,正好可以解決我們的問題。

可事情并沒有這么簡單。

我們的角色人物由用戶操控,會跑、會跳,實際上是帶動作骨骼的蒙皮模型(Skinned Mesh),這些動作互相獨立并受人物當前活動狀態控制。而 現有的移動端3d框架并不支持簡單地將骨骼模型實例化,如果只是簡單將模型實例化的話,只會得到一堆無法表現任何動作的僵硬實例,在世界中平移。顯然這是不可接受的。


(未支持骨骼蒙皮模型時實例化繪制時效果)


(正常帶動作的人物模型)

為了解決這個問題,可以有多種處理方案,其中一種是將動畫烘焙到貼圖材質中,這樣就可以在 GPU 代碼中通過采樣的方式獲取數據完成頂點變形;另一種是將動畫的插值計算放在 CPU 上,再實時將當前動畫數據上傳至 GPU 處理

前一種的優點是性能更優,缺點是需要對動畫的特殊處理,而且 GPU 編程限制更多也更復雜;后一種方案的優點是與現有的邏輯相適配,代碼上也更簡單,缺點是如果想要更加優化性能,還需要做其他特殊處理。

這里,分享下比較簡單的處理方案。

如果我們搞清楚現有框架是如何實現非蒙皮模型的實例化、以及單個蒙皮模型的動作變形,再將這兩種能力組合起來,就可以實現帶動作蒙皮模型的實例化啦!

具體來說,骨骼蒙皮模型能夠渲染出動作動畫,在于它的各個頂點已經綁定了對應哪幾塊骨頭以及它們影響的權重。當骨骼的位置、旋轉、大小變化時(即動作進行中),渲染時便會逐幀去取到最新骨頭的變換矩陣并將其作用到頂點位置上以改變原有的位置,這樣就形成了動畫。


(控制模型動作的骨骼)

要把這些邏輯放入實例化繪制,也需要有同樣的操作。

頂點與骨骼的綁定與單個模型是一致的,只需要復用即可,而不同的地方主要在于之前只需要從一套骨骼中去取骨頭的變換矩陣,而實例化后需要從多套骨骼中去取當前實例對應骨骼的變換矩陣。

因為每一個人物都有自己的動作狀態,因此可以為每一個實例綁定一套骨骼,并由動畫控制器去實現動作的計算。之后再將這些動作數據以數據貼圖(data texture)的形式上傳至 GPU,然后在頂點著色器(vertex shader)代碼中讀取使用即可。

當一個模型有20多塊骨頭時,每塊骨頭需要4個像素來存儲共16個數字的變換矩陣,一套骨骼可用16*16像素的貼圖且還有大量空余。即使實例數量(人物)增加至1000個,貼圖大小也不會超過512*512像素! 

在新的著色器代碼中,我們取到新的骨骼變換矩陣便可完成頂點變形。

完成實例化后,當場景中有1000個角色時,draw call 數也不會像之前增加到1000,而仍然僅為1,在渲染層面大大優化了性能! 


雖然 draw call 已大為降低,但1000個模型仍是1000個模型,頂點數和模型面數都不會減少,仍然是 GPU 計算中不小的開銷。

為了減小大量模型渲染時的面數,我們采用了多細節層級(LOD)的技術方案。

簡單來說,依據人物模型與相機的距離,可以選擇不同細節層級的模型。這是因為當角色距離較遠,其精細細節本就難以分辨,這個時候再去渲染一個精細的模型也沒有必要,完全可以用一個更加粗糙的類似模型來替代。

粗糙的模型頂點數可以減少很多,而且還可以有多個層級,以更細化區分距離,達到既減少面數、又在視覺上無差別的效果。

另外,還可以在角色距離相機一定距離外完全隱藏模型,進一步優化性能。

因為不同的層級對應不同的模型,所以在實例化繪制時,也需要引入新的實例化模型,同時增加幾個 draw call。但這幾個 draw call 仍然遠小于此前每個實例單獨一個 draw call 時的數量,收益遠大于開銷!


雖然用實例化繪制在渲染能力上支持了1000人同時在線,但實際上在場景中不會始終都有1000人,而且因為采用了多細節層級,每個角色也可能會在幾個實例模型間切換,因此就會有實例顯隱的問題 。

因為底層實現的限制,想要控制實例化模型中實例的顯示還是隱藏,無法簡單在各個實例上去控制,而理論上最理想的方式是動態修改 count 屬性值。此時,實例模型中只有前面 count 這么多個實例會進入渲染流程,而后面的實例因為不參與渲染,因此性能上最優。

我們在一開始也是這樣處理的,將場景角色的變換矩陣設定給前n個實例,然后設定好實例化模型的數量,之后當角色退出場景或切換到其他模型時,只需要更新一個實例對應的索引序號、并減小 count 的值即可。這樣就可以保持始終只渲染實際有效的模型。


(理想情況下實例顯隱控制)

但是在實際操作中,在切換數量及同步序號的瞬間,場景中對應的實例偶爾會有閃動。雖然不是非常顯眼,但仍然是不穩定的體驗。

為了解決這個問題,我們在探討權衡后決定不再瞬移實例,而是在 GPU 著色器代碼中處理實例顯隱,并控制計算復雜度。

雖然這樣性能會略微劣化一點,但好處是用戶體驗更為穩定可靠。經過測試,這樣雖然面數相對沒有減少,性能卻有不小的提高。


在處理實例化骨骼蒙皮模型時,我們還遇到了其他一些問題,其中包括模型影子

因為框架只支持非實例化繪制的骨骼模型,在我們實現的實例化模型上,默認的獲取深度映射以渲染影子的著色器代碼無法直接處理。

因此需要再增加自定義的深度材質并綁定自定義的著色器。此時將骨骼動畫的作用應用在頂點位置變形上,即可以得到正確的深度映射啦!


(左:影子沒有跟隨動作變化;右:影子實時跟隨動作變化)

此外,為了陰影性能的考慮,我們也控制了陰影渲染的范圍。不過因為實例化繪制后draw call 數已大大下降,可以有更多角色有自己的影子啦!


(左:只有1個人有影子;右:四周的人都有影子)

不過陰影范圍增加同樣也造成了小問題,即陰影的邊緣過分清晰,整體效果不佳。

為解決這個問題,我們在顯示陰影的著色器代碼中加入了淡出的處理,使得整體效果更為自然。 


(左:影子邊緣過分清晰;右:影子自然淡出)

此外,實例化繪制也并非都是優化。非實例化渲染有一個優點是視錐體剔除(Frustum Culling) 很容易實現,當人物不出現在相機視線中時,也不會再渲染。

而當人物實例化之后,因為整個模型的邊界更難以計算,而且是整體的比較,所以視錐體剔除難以處理,如果想要實現類似單獨模型的剔除結果,就需要手動去控制實例的顯隱并優化著色器代碼來控制開銷


靈境至維團隊一直致力于打造一個既有人間煙火氣,又有無限想象力的虛實共生的世界!而真·千人同屏作為虛擬世界活力的重要基石,技術團隊也不會止步于此,會繼續去優化它。當然要實現團隊愿景,本就需要不斷地去挑戰這個領域里技術、設計、體驗等的眾多高峰。雖然很難,但對于我們,你可以期待更多!


編輯:小蕓、Neeson、久喬、山童、歐陽

技術顧問:久喬、海青


本文系作者授權數英發表,內容為作者獨立觀點,不代表數英立場。
轉載請在文章開頭和結尾顯眼處標注:作者、出處和鏈接。不按規范轉載侵權必究。
本文系作者授權數英發表,內容為作者獨立觀點,不代表數英立場。
未經授權嚴禁轉載,授權事宜請聯系作者本人,侵權必究。
本內容為作者獨立觀點,不代表數英立場。
本文禁止轉載,侵權必究。
本文系數英原創,未經允許不得轉載。
授權事宜請至數英微信公眾號(ID: digitaling) 后臺授權,侵權必究。

    評論

    文明發言,無意義評論將很快被刪除,異常行為可能被禁言
    DIGITALING
    登錄后參與評論

    評論

    文明發言,無意義評論將很快被刪除,異常行為可能被禁言
    800

    推薦評論

    暫無評論哦,快來評論一下吧!

    全部評論(0條)

    主站蜘蛛池模板: 航空| 波密县| 长宁县| 祁门县| 儋州市| 通城县| 巴楚县| 灵宝市| 拉孜县| 仁化县| 崇信县| 黄大仙区| 龙里县| 库尔勒市| 九寨沟县| 昔阳县| 榆林市| 疏勒县| 通州区| 南雄市| 开阳县| 汉阴县| 措勤县| 诸城市| 卢氏县| 九寨沟县| 通辽市| 北宁市| 象山县| 乐平市| 驻马店市| 南木林县| 巫山县| 平定县| 郓城县| 临潭县| 布尔津县| 宾阳县| 隆尧县| 婺源县| 民县|