Expo
如果您對於在一個Fusion應用程式中整合XR互動工具組上需要協助,請聯絡在Circle Discord上的VR團隊
概述
Fusion Expo範例展示了一個方法,以開發一個在Fusion的最多達100名玩家的社交應用程式。
各個玩家由一個虛擬人偶所代表,並且如果玩家們位於相同的聊天氣泡中,則可以利用Photon Voice SDK與其他玩家交談。
這個範例的一些聚焦點有:
- 首先,玩家在選擇虛擬人偶畫面來客製化其虛擬人偶,
- 然後,他們可以加入Expo場景。如果玩家在PC或MAC上啟動範例,它可以選擇桌面模式(使用鍵盤及滑鼠)或VR模式(Meta Quest頭戴式裝置)。
- 如果玩家們位於相同的靜態聊天氣泡中,玩家可以與彼此交談。在各個靜態聊天氣泡中,可用一個鎖定按鈕以預防新的玩家進入。
- 同時,如果兩個玩家彼此很接近,將以較慢的速度在玩家周圍建立一個動態聊天氣泡。
- 某些3D筆可用於建立3D繪畫。可使用錨點來移動各個3D繪畫。
- 同時,可用一個傳統的白板。可使用錨點來移動各個繪畫。
- 玩家可以移動到一個新的位置(新的場景載入)。
在程式碼評論中直接提供更多技術細節。
技術資訊
- 這個範例使用共享模式拓撲,但是核心是與共享及主機端模式拓撲相容,
- 組建可用於PC、Mac及Meta Quest,
- 專案已經以Unity 2021.3.13f1、Fusion 1.1.3f 599及Photon voice 2.31來開發,
- 支援2個虛擬人偶解決方案(自製的簡單虛擬人偶及Ready Player Me 1.9.0虛擬人偶),
在您開始之前
為了運行範例:
在PhotonEngine儀表板中建立一個Fusion應用程式帳號,並且將它貼上到即時設定(可從Fusion選單中到達)中的
App Id Fusion
欄位之中。在PhotonEngine儀表板中建立一個Voice應用程式帳號,並且將它貼上到即時設定中的
App Id Voice
欄位之中然後載入
AvatarSelection
場景並且按下Play
下載
版本 | 發佈日期 | 下載 | ||
---|---|---|---|---|
0.0.19 | 2023年5月12日 | Fusion Expo XR共享0.0.19組建192 |
下載二進位檔
下方是可用的一個Expo的展示版本:
處理輸入
桌面
鍵盤
- 移動:WASD或ZQSD以行走
- 旋轉:QE或AE以旋轉
- 機器人繁衍:按下「B」以繁衍一個機器人。持續按住超過1秒以在放開時建立50個機器人
滑鼠
- 移動:按下您的滑鼠左鍵以顯示一個指標。您將在放開時傳送到任何已接受目標
- 旋轉:持續按下滑鼠右鍵並且移動滑鼠以旋轉視角
- 移動及旋轉:持續按下滑鼠左鍵及右鍵以向前移動。您仍然可以移動滑鼠以旋轉
- 拿取及使用(3D筆):將滑鼠放在物件上,並且使用滑鼠左鍵來拿取它。然後您可以使用鍵盤空白鍵來使用它。
Meta Quest
- 傳送:按下A、B、X、Y,或任何搖桿以顯示一個指標。您將在放開時傳送到任何已接受目標
- 觸碰(也就是針對聊天氣泡鎖定按鈕):簡單地將您的手放在一個按鈕上以切換它
- 拿取:首先將您的手放在物件上,並且使用控制器拿取按鈕來拿取它
- 機器人繁衍:按下左控制器上的選單按鈕以繁衍一個機器人。持續按住超過1秒以在放開時建立50個機器人
資料夾架構
主要資料架/Expo
含有特定於這個範例的所有元素。
資料夾/Expo/Integrations
管理與第三方解決方案的相容性,比如ReadyPlayerMe。
/Photon
資料夾含有Fusion及Photon Voice SDK。
/Photon/FusionXRShared
資料夾含有來自VR共享範例的裝置及拿取邏輯,建立一個FusionXR共享輕量SDK,其可以與其他專案共享。
/Photon/FusionXRShared/Extensions
資料夾含有針對FusionXR共享的延伸模組,針對可重複使用的功能比如已同步射線、運動驗證...
/Plugins
資料夾含有Ready Player Me SDK
/StreamingAssets
資料夾含有預先組建的ReadyPlayerMe虛擬人偶。如果您不希望使用這些預先組建的虛擬人偶,它可以被自由移除。
/XRI
及/XR
資料夾含有針對虛擬實境的設置檔案。
架構概述
Fusion Expo仰賴於與VR共享頁面中描述的相同的程式碼基礎,特別是在裝置同步方面。
這裡使用的拿取系統是在VR共享——本機裝置拿取頁面中描述的替代性「本機裝置拿取」執行方式。
在這個基礎之外,範例含有一些到FusionXR共享的延伸程式,以處理一些可重複使用的功能,比如已同步射線、運動驗證、觸碰、傳送平順或一個凝視系統。
網路連線及應用程式生命週期
ConnexionManager
在共享模式拓撲中啟動一個Fusion遊戲階段,並且針對各個已連線使用者來繁衍一個使用者預製件。如需更多細節,請參見VR共享範例文檔的「連線管理器」章節
SessionEventsManager
觀察Fusion及PhotonVoice連線狀態以警示它們感興趣的元件,特別是處理各種音效的SoundManager
..
聲音
VoiceConnection
及FusionVoiceBridge
元件啟動Fusion遊戲階段的聲音Photon Voice連線,Recorder
元件捕捉麥克風輸入。
針對Oculus Quest任務組建,需要額外的使用者授權,而且這個請求是由MicrophoneAuthorization
指令碼所管理。
使用者預製件含有一個Speaker
及VoiceNetworkObject
放置在它的頭上,以在接收聲音時投射空間化的聲音。
如需更多關於Photon Voice與Fusion整合的資訊,請參見這個頁面:https://doc.photonengine.com/en-us/voice/current/getting-started/voice-for-fusion
裝置
在一個沉浸式應用程式中,裝置描述了代表一個使用者所必要的所有可移動部件,通常是雙手、一個頭,以及遊玩區域(舉例而言,當一個使用者傳送時,它是可以被移動的個人空間),
當在一個已連線遊戲階段時,每個使用者由一個已連線裝置所代表,其各種部件位置透過網路來同步。
關於裝置部件的組織及同步的方式,多個架構為可用,且有效。在這裡,一個使用者由一個單一的NetworkObject
所代表,附有多個巢狀NetworkTransforms
,針對各個裝置部件都有一個。
關於代表本機使用者的網路裝置的具體案例,該裝置必須由硬體輸入來驅動。為了簡化這個流程,已經建立一個獨立的,非連線的裝置,稱為「Hardware rig
」。它使用傳統Unity元件來收集硬體輸入(如同TrackedPoseDriver
)。
NetworkedRig
元件,位於使用者預製件上,針對所有巢狀裝置部件來管理這個追蹤。
在FixedUpdateNetwork()
期間與其他玩家分享裝置部件位置之外,NetworkRig
元件也處理外插:在Render()
期間,移動處理各種裝置部件的NetworkTransforms
的圖形代表的內插補點目標,以確保本機使用者總是看見它們的手在最近的位置,就算再網路刷新之間也是如此。
如需更多關於裝置部件同步的細節,請參見VR共享範例文檔的「裝置——細節」章節
裝置資訊
為了能夠輕鬆地找到HardwareRig
及配對關於本機使用者的NetworkRig
,元件RigInfo
針對進一步的使用來註冊HardwareRig
及本機NetworkedRig
。
互動堆疊
這個範例允許玩家來移動、拿取物件,及觸碰表面。
所有這些操控都在本機完成(在硬體裝置上),獨立於網路,然後透過Fusion到網路裝置的輸入來發送到網路。
運動
在虛擬實境中,透過基於射線的傳送來提供運動,在搖桿上附有可用的額外的固定角度轉身。運動由RayBeamer
及RigLocomotion
類別來管理,如同在VR共享範例文檔的「傳送及運動」章節中所說明。
此外,將同步射線,這樣它們可用於向其他使用者指向某個東西。它是透過HardwareHandRay
類別來完成,其透過一個[Networked]
變數來與其他使用者同步一個RayData
架構。
在桌面版本中,使用者可以以鍵盤移動,或以滑鼠左鍵按下地面以傳送到那裡。DesktopController
及MouseTeleport
元件管理運動,而MouseCamera
元件使用滑鼠右鍵點擊移動來管理相機移動。
針對遠端使用者,遊玩區域移動被平滑化,以逐步移動到目標位置來取代傳送(除非instantPlayareaTeleport
選項被設定為真)。這個平滑在TeleportationSmoother
類別中完成。它包含一個[OrderAfter(typeof(NetworkRig))]
以在自己的FixedUpdateNetwork()
中覆寫由NetworkRig
FixedUpdateNetwork
定義的位置(它只在需要平滑時進行此覆寫)。
運動限制
這個範例應用程式有時候防止使用者前往某些地方(舉例而言,如果已經達到聊天氣泡的最大人數,則不可以進入一個聊天氣泡)。
為了做到這點,每個希望移動玩家的元件都仰賴於泛型運動驗證系統,及與一個特定運動模式有關的限制式。
運動驗證系統
為了確定使用者是否不嘗試前往一個禁止區,每個運動系統首先詢問放置於HardwareRig
上的HardwareLocomotionValidation
元件,它們是否可以以CanMoveHeadset()
方法移動到這個位置。為了回答,HardwareLocomotionValidation
首先以其所有的ILocomotionValidator
下層,以及放置於在網路上代表本機使用者的NetworkedRig
執行個體旁邊的所有NetworkLocomotionValidation
元件的ILocomotionValidator
下層,來檢查移動是否有效。
此外,如果一個使用者將頭放在一個禁止區,視角將淡出,以防止它們「作弊」。它在InvalidMoveCameraFader
類別中處理。
其他限制
此外,運動由其他因素限制,取決於使用的運動系統:
RigLocomotion
:一個使用者只能在碰撞器上透過RigLocomotion
的運動圖層遮罩中的一個圖層進行傳送(比如TeleportTarget
圖層)LocomotionValidatedDesktopController
運動:控制器檢查在一個移動之後的頭位置是否正確,透過檢查它不在一個碰撞器中,以及檢查在移動後一個正確的可行走的導航網格點將在它之下Bot
:它確保機器人將維持在可行走的導航網格點上
可觸碰
為了在手指觸碰上觸發事件,手含有一個Toucher
元件,而有些物件有一個Touchable
元件。完全在硬體裝置中處理事件,並且沒有自動的連結到網路:您必須在由Touchable.OnTouch
調用的元件中處理它。
請注意,桌面控制允許您透過BeamTouchable
及BeamToucher
類別,以滑鼠指標來觸碰Touchable
。這些相同的類別可以允許一個VR使用者來指向及按一下一個UI(取決於在BeamToucher
類別上選擇的能力)。
UI
可透過滑鼠來使用畫布按鈕及滑桿。
為了能夠以使用者的手指或VR中的指標來觸碰它們,UITouchButton
元件確保當使用者觸碰3D按鈕方盒碰撞器時,觸碰時事件被轉傳到UI按鈕。TouchableSlider
元件以相同的方式管理滑桿值。
為了在一個畫布中的按鈕及滑桿上自動地新增這些元件,TouchableCanvas
元件管理含有它們的預製件的自動具現化。
拿取
在這個範例中,拿取只用來處理筆及繪圖操控。
這裡使用的這個拿取系統是VR共享——本機裝置拿取頁面中描述的替代性的「本機裝置拿取」執行方式。
虛擬人偶
使用者由一個圖形代表所代表,稱為一個虛擬人偶。這個範例支援兩種虛擬人偶,來自Ready Player Me的及一個自訂的較簡單的虛擬人偶。
凝視者
為了提供一個更自然的虛擬人偶代表,一個專用系統處理自動眼睛追蹤:當一個興趣物件出現在一個虛擬人偶之前時,它的眼睛將找到這個目標並且跟隨它。如果一個較近的目標出現,眼睛的聚焦將改變。
如果沒有可用的目標,眼睛將隨著時間隨機地移動。
最後,所有在這個範例中可用的虛擬人偶系統都處理眨眼,也為了讓其顯得更為自然。
為了成為一個潛在的眼睛目標,一個遊戲物件必須有一個GazeTarget
元件。在預先組建的預製件中,所有虛擬人偶的眼睛及頭預設有該元件。這些GazeTarget
在GazeInfo
管理器中註冊。
Gazer
元件透過詢問GazeInfo
潛在(以有效最終視角及目標距離)GazeTarget
的一個排序清單(按照距離),來驅動眼睛。
當有很多可用的目標非常靠近的時候,整理過程非常繁重,並且是在背景執行緒中完成。
手
這裡使用的手模型來自Oculus範例框架(由Facebook Technologies, LLC及其關係企業在一個BSD-3授權下發布)。
驅動手移動的輸入動作在本機上收集,並且透過Fusion共享,以在所有客戶端上顯示手移動。
稍微遠端地離散化手移動,以減少改變的頻率。
手顏色匹配使用的虛擬人偶代表的皮膚顏色。
虛擬人偶代表
各個虛擬人偶儲存一個虛擬人偶URL,透過放置在NetworkRig
上的UserInfo
元件中的一個Fusion [已連線] 變數來共享。
在更改時,這個URL被AvatarRepresentation
元件剖析,以確定它是否代表:
一個簡化的虛擬人偶說明URL
(舉例而言:simpleavatar://?hairMesh=2&skinMat=0&clothMat=3&hairMat=0)
一個Ready Player Me模型URL(舉例而言:https://d1a370nemizbjq.cloudfront.net/0922cf14-763d-4e48-aafc-4344d7b01c2c.glb)
簡單虛擬人偶
簡單虛擬人偶系統提供一個簡單且價格低廉的虛擬人偶模型。
嘴部動畫是基於音量偵測,並且沒有準確的唇型同步。
Ready Player Me
Ready Player Me虛擬人偶系統可以顯示https://readyplayer.me提供的任何虛擬人偶。
嘴部動畫提供唇型同步,其基於Oculus唇型同步庫,其在Oculus聲音SDK授權 (https://developer.oculus.com/licenses/audio-3.3/)下發布。
為了最佳化虛擬人偶的下載及載入,針對一個給定的虛擬人偶URL,虛擬人偶物件可以透過幾種方式來載入:
- 如果這個URL已經針對一個啟用的虛擬人偶來使用,則複製現有的虛擬人偶
- 如果這個URL與一個預製件相關聯,則繁衍預製件,而非下載及剖析glb檔案
- 如果這些選項不相關,則下載及剖析glb檔案。請注意,一個URL可以描述在串流資產資料夾中的一個glb檔案,透過針對URL來使用語法
%StreamingAssets%/Woman1.glb
,以略過下載。如果您這麼做,您應該放置Ready Player Me提供的相關聯的Woman1.json
中繼資料檔案在Woman1.glb
旁邊(為了下載它,簡單地在Ready Player Me提供的原始URL中以.json替換.glb副檔名)。
LOD
在有大量的使用者(或機器人)的遊戲階段中,虛擬人偶可能給效能帶來很大負擔。
為了避免這個,虛擬人偶代表管理幾個LOD:
- 常規虛擬人偶(簡單的虛擬人偶或Ready Player Me)
- 一個簡單的虛擬人偶的低多邊形版本,附有匹配常規虛擬人偶的頭髮/皮膚/衣服顏色
- 一個告示板總是面對使用者相機。
聊天氣泡
這個範例展示了聊天氣泡。場景包含4個靜態聊天氣泡。當2個使用者彼此靠近時,應用程式也可以建立一個動態聊天氣泡。
靜態聊天氣泡
預設下,在expo場景中,使用者不會聽到彼此。
但是當他們進入相同的靜態聊天氣泡時,他們將能夠透過Photon Voice的空間化的聲音來一起討論。
在範例中,一個區系統追蹤NetworkRig
靠近一個Zone
的ZoneUser
元件。如果它發生,ZoneUser
將進入區,並且觸發各種Zone
及 ZoneUser
接聽者。
一個Zone
可以有一個與它們相關的PhotonVoice興趣團體,所以如果本機使用者進入/離開一個區,ZoneAudioInterestChanger
元件可以更改本機使用者的聲音接聽及錄製群。如果本機使用者應該聽到聲音,它也啟用及停用一個使用者的裝置的聲音來源。
當靜態聊天氣泡中達到最大使用者數量時,將被自動地鎖住,但是可以透過觸碰在每個靜態聊天氣泡中的鎖定按鈕,在這之前鎖住它們。
動態聊天氣泡
代表使用者的預製件含有一個DynamicZoneSource
元件。
這個元件註冊到一個DynamicZonePool
元件,這樣之後它可以檢查另一個現有的DynamicZoneSource
是否是近接,如同DynamicZonePool.size
中所定義。在這個案例中,DynamicZonepool
可以提供一個區,其被繁衍(或被重新使用)以讓兩個使用者來使用。
其他使用者稍後可以加入他們,直到達到區的最大容量
機器人
為了展示範例支援一個充滿人的Expo的方式,在常規使用者之外,可以建立機器人。
機器人是常規已連線預製件,其聲音已經被停用,而且其由一個導航網格所驅動,而非使用者輸入。
Bot
類別也使用運動驗證系統,並且因此感知到聊天氣泡。在此之外,因為它們不會說話,它們被禁止進入任何區,不論該區是否鎖住。
繪畫
3D繪畫
Expo場景含有3D筆,其可以建立3D繪畫:一個線轉譯器的群,附有一個常見的手柄,其可以被拿取和移動。
3D筆持有一個Drawer
元件,其繁衍一個持有Draw
元件的繪畫預製件。Draw
元件確保所有被繪製的點都透過Fusion被同步。它透過一個[Networked]
變數來完成。因為它不能持有無限數量的點,因此如果需要,可以將繪畫分開為多個部分,當任何使用者移動它時,第二個Draw
跟隨第一個Draw
,使它顯示為一個單一繪畫。
2D繪畫
Expo場景中的白板可以使用其周圍的筆來書寫它,而且最終繪畫隨後可以透過一個類似於3D筆繪畫手柄的手柄,在白板上移動。
事實上,它是一種特殊的3D繪畫,其使用一個圖層相機不可見,但是與白板相關的相機可見的圖層。隨後相機在一個在白板上顯示的轉譯材質上轉譯繪畫圖片。
為了效能的考量,這個相機只在筆靠近使用中的白板時啟用,或是在移動使用筆建立的繪畫時啟用。
場景切換
玩家可以透過使用位於場景中的橋,來移動到一個新的世界。各個橋觸發一個特定的場景載入。
為了這樣做,各個橋有一個NewSceneLoader
類別,其負責在玩家與方盒碰撞器碰撞時載入一個新的場景。
請注意,在載入新的場景之前,NewSceneLoader
關機Runner
,因為它不能在新的場景中被重新使用:各個場景有其自己的Runner
。
舉例而言,名為ExpoRoomMainWithBridge
的主要場景有兩種橋。第一座橋將載入ExpoRoomNorth
場景,而另一座橋將觸發ExpoRoomSecondScene
載入。
所以現在關於玩家繁衍位置有三個可能性:
- 當玩家最初加入遊戲時的靠近棕櫚樹的隨機位置,
- 當玩家從
ExpoRoomNorth
場景返回時的第一座橋附近的位置, - 當玩家從
ExpoRoomSecondScene
場景返回時的第二座橋附近的位置。
為了確定正確的繁衍位置,在各個場景中需要一個SpawnManager
。
它改變RandomizeStartPosition
元件的預設行為,以定義當玩家從另一個場景回來時(或在重新連線的情況下)玩家應該出現的位置。
在處理多個場景時,需要記住的另一個點是,如果場景不相同,則不可以使用相同的房間名稱。
換句話說,各個場景的房間名稱必須不同。我們不靜態地設定這個名稱,而是使用Space
元件(位於Runner
上)以基於包含場景名稱在內的多個參數自動地設定一個房間名稱。
第三方元件
- Oculus整合
- Oculus唇型同步
- Oculus範例框架手
- Ready player me
- 聲音
已知問題
- 如果一個使用者連線的同時,一個繪畫的授權正在中斷連線,新的使用者將不會收到繪畫資料。
更改記錄
Fusion Expo 0.0.19
- 新增新的場景及從一個場景切換到另一個場景的能力
- 虛擬人偶選擇UI跟隨玩家的頭部位置
- 玩家可以指定他的暱稱
- 各種改進及修復問題
Fusion Expo 0.0.18
- 當發生一個網路問題時,修復錯誤訊息顯示
Fusion Expo 0.0.17
- 更新到Fusion SDK 1.1.3 F 組建 599
Fusion Expo 0.0.16
- 使用VR共享技術範例中描述的核心VR執行方式
- 使用VR共享本機裝置拿取範例中描述的本機拿取執行方式
- 使用行業元件,與舞台範例共享
- 移除XR互動工具組依賴性