Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
OpenXR 手部追蹤
前言
備註
本頁重點說明 OpenXR 所提供的手部追蹤功能,部分介紹的功能同樣適用於 WebXR,或可由其他 XR 介面提供。
在討論手部追蹤時,需注意各平台對於功能範圍界定有所不同。這導致不同 OpenXR 執行環境在實作上會有差異。你可能會遇到某些硬體不支援特定功能,或其實作方式與其他平台不同,因此需額外處理相容性問題。
不過,OpenXR 規範近期已有顯著進步,正逐步縮小這些差異。隨著各平台陸續實作這些改進,未來將更容易實現跨平台相容,或至少能明確偵測平台支援的功能。
回顧 VR 初期,各大平台主要著重於追蹤控制器輸入。此時追蹤的是一個實體裝置,並可藉由按鈕等進行額外輸入。雖可藉由追蹤資料推算玩家手部位置,但無法獲得更多細節,通常需由遊戲自行實作手部顯示及手指動畫,根據控制器按鈕或接近感應器等輸入來決定手指動作。手指的動作也常依情境調整,例如玩家手上拿著什麼、目前正在執行什麼動作等。
近年來,光學手部追蹤成為主流解決方案,利用攝影機偵測使用者雙手,取得完整的手部與手指位置資料。許多廠商視此與控制器追蹤完全獨立,並提供專用 API 以讀取手部與手指的位置及朝向。至於輸入辨識,則通常由遊戲開發者自行實作手勢偵測機制。
這種區分在 OpenXR 中也存在:控制器追蹤主要透過動作對應(Action Map)系統處理,而光學手部追蹤則主要透過手部追蹤 API 擴充來實現。
然而,實務上情況並非如此二分化,實際上有許多情境會跨越這條界線:
有些裝置同時屬於兩者,例如具備手指追蹤功能的手套或像 Index 控制器這類可追蹤手指的控制器。
某些 XR 執行環境會根據控制器數據推算手部位置,以解決多控制器下的手指擺放問題。
一些 XR 應用則希望能無縫切換控制器與手部追蹤,讓使用者不論採用哪種方式都能有一致體驗。
OpenXR 也正透過新增各種擴充功能來回應這些需求,讓我們能查詢 XR 執行環境/硬體的功能支援,或跨越傳統分野提供更多功能。不過,這些擴充尚未被所有平台廣泛支援,因此部分平台可能無法完整回報功能能力。開發時必須針對不同硬體測試實際支援狀態,並調整對應策略。
展示專案
本頁所介紹的內容已用於建置一份展示專案,專案可於此處取得:https://github.com/godotengine/godot-demo-projects/tree/master/xr/openxr_hand_tracking_demo 。
手部追蹤 API
如前述,手部追蹤 API 主要用於光學手部追蹤,且多數平台僅於使用者未持控制器時可用。部分平台則支援從控制器數據推算手部追蹤,因此即使玩家手持控制器也能取得手部追蹤資料。目前支援的有 SteamVR、Meta Quest(目前僅原生支援,Meta Link 預計未來也會支援),其他平台也預期陸續支援。
Godot 的手部追蹤功能已標準化,採用 Godot Humanoid Skeleton(人形骨架),可同時用於 OpenXR 與 WebXR。以下說明皆適用於這兩種環境。
在 OpenXR 環境使用手部追蹤 API 前,需先於專案設定中啟用相關功能:
某些獨立式 XR 裝置(如 Meta Quest)還需於匯出設定中啟用手部追蹤擴充功能:
接著,請在場景中為每隻手分別加入以下三個元件:
一個用於定位手部的追蹤節點。
一個綁定好骨架與蒙皮的手部網格(Mesh)。
一個骨架修改器,用於將手指追蹤資料套用至骨架。
手部追蹤節點
手部追蹤系統會針對玩家雙手分別建立追蹤器,在追蹤空間中即時追蹤手部位置。
這項設計主要針對下列情境進行區分:
追蹤會在 XROrigin3D 節點的本地座標空間進行。必須將手部追蹤節點設為 XROrigin3D 的子節點,才能正確定位。
當你使用帶有手臂的上半身網格(而非單獨的手部網格)時,也可以將手部追蹤節點作為 IK(反向運動學)的目標節點。
在某些情境下(如虛擬人偶創建 UI、鏡像效果等),手部的實際顯示位置可能不會嚴格綁定追蹤資料,因而手部網格與手指追蹤可能會被定位到其他位置。
以下將僅聚焦於第一種使用情境。
你需要在 XROrigin3D 節點下新增一個 XRNode3D 節點。
在該節點上,將
tracker設為/user/hand_tracker/left或/user/hand_tracker/right,分別對應左手或右手。
pose屬性需保持default,其他選項無法正常運作。勾選
Show When Tracked(有追蹤時顯示)時,若無追蹤資料則自動隱藏節點,有追蹤資料時則顯示。
綁定骨架的手部網格
要顯示手部模型,需要一個綁定好骨架與蒙皮的手部網格。Godot 採用 Godot Humanoid 定義的手部骨架結構,每根手指也可額外加入指尖骨骼。
OpenXR 手部追蹤展示專案 中包含已正確綁定骨架的 glTF 手部範例檔案。
以下將以這些範例檔案為例,並將其作為 XRNode3D 的子節點。你也需要啟用可編輯子節點,以便存取 Skeleton3D 節點。
手部骨架修改器
最後,需在 Skeleton3D 節點下新增一個 XRHandModifier3D 節點。此節點會從 OpenXR 取得手指追蹤資料,並套用到手部模型上。
請將 Hand Tracker 屬性設為 /user/hand_tracker/left 或 /user/hand_tracker/right,分別對應左手或右手。
你也可以設定此節點的 Bone Update (骨骼更新)模式。
選擇
Full(完整)模式時,會完整套用手部追蹤資料,骨架位置將反映實際使用者的手部尺寸。如果網格權重設置不當,可能會出現模型擠壓的現象。使用光學手部追蹤時,請務必用各種不同手型多做測試!選擇
Rotation Only(僅旋轉)時,只會將手部骨骼旋轉套用至骨架,骨骼長度不變,手部網格大小也不會改變。
完成上述設置後,執行專案時若支援手部追蹤,應可正確顯示手部模型。
手部追蹤資料來源
這是一個 OpenXR 擴充功能,可提供手部追蹤資料來源的資訊。目前僅少數執行環境實作此功能,但只要有支援,Godot 會自動啟用。
若此擴充功能不被支援(回傳 unknown),可依下列假設推斷:
若使用 SteamVR(含 Steam Link),僅支援以控制器為基礎的手部追蹤。
其他執行環境若支援手部追蹤,則僅支援光學手部追蹤 (註:Meta Link 目前也屬此類)。
其餘情況皆不支援手部追蹤。
你可以透過程式碼存取這項資訊:
var hand_tracker : XRHandTracker = XRServer.get_tracker('/user/hand_tracker/left')
if hand_tracker:
if hand_tracker.has_tracking_data:
if hand_tracker.hand_tracking_source == XRHandTracker.HAND_TRACKING_SOURCE_UNKNOWN:
print("Hand tracking source unknown")
elif hand_tracker.hand_tracking_source == XRHandTracker.HAND_TRACKING_SOURCE_UNOBSTRUCTED:
print("Hand tracking source is optical hand tracking")
elif hand_tracker.hand_tracking_source == XRHandTracker.HAND_TRACKING_SOURCE_CONTROLLER:
print("Hand tracking data is inferred from controller data")
else:
print("Unknown hand tracking source ", hand_tracker.hand_tracking_source)
else:
print("Hand is currently not being tracked")
else:
print("No hand tracker registered")
此範例會記錄左手的追蹤狀態。
若 get_tracker 未回傳任何手部追蹤器,表示該 XR 執行環境完全不支援手部追蹤 API。
若有追蹤器但 has_tracking_data 為 false,表示目前使用者的手未被追蹤。常見原因如下:
玩家的手未被頭戴裝置上的任何追蹤攝影機偵測到
玩家正在使用控制器,且頭戴裝置僅支援光學手部追蹤
控制器已關閉,且僅支援控制器手部追蹤。
處理使用者輸入
若使用控制器,建議透過 XR 動作對應 處理使用者動作。在動作對應表中,可將控制器的扳機鍵、搖桿等輸入對應到特定動作,再據此驅動遊戲邏輯。
早期使用手部追蹤時並無對應的輸入,必須透過使用者手勢(如握拳表抓取、拇指與食指捏合表選取等)來操作。這部分通常需由開發者自行實作。
隨著越來越多應用需要在控制器與手部追蹤間無縫切換,且需具備基本輸入能力,OpenXR 規範新增了多項擴充,提供基本手勢辨識,可與動作對應表(Action Map)結合使用。
手部互動設定檔
手部互動設定檔擴充 為全新核心擴充,支援捏合(Pinch)、抓握(Grasp)、點按(Poke)等手勢及相關姿勢。目前僅有部分執行環境支援,未來預計會有更多平台支援。
捏合手勢(Pinch)是指拇指與食指捏在一起,常用於選取動作(如選單選擇),類似以控制器指向物件並按下扳機選取,通常也會這樣對應。
pinch pose(捏合姿勢)會定位在拇指與食指指尖的中間,並以適合進行射線檢測的方向排列,以便偵測選取目標。
pinch(捏合)輸入為浮點數,0.0 代表拇指與食指分開,1.0 代表指尖接觸。
pinch ready(捏合就緒)輸入在指尖接觸(或非常接近)時為 true。
抓握手勢(Grasp)為握拳動作,常用於拾取物品,與控制器上的壓握(Squeeze)輸入類似。
grasp(抓握)輸入為浮點數,0.0 代表手掌張開,1.0 代表握拳。
grasp ready(抓握就緒)輸入在使用者握拳時為 true。
點按手勢(Poke)是將食指伸直,常用於點擊可互動物件。 poke pose (點按姿勢)會定位於食指指尖。
最後,aim activate (ready) 輸入在食指伸直並指向可啟動目標時會為 1.0/true,不過不同執行環境可能解讀方式略有差異。
完成上述設定後,會使用標準的 left_hand 與 right_hand 追蹤器,因此可在控制器與手部追蹤間無縫切換輸入方式。
備註
你需要在 OpenXR 專案設定中啟用手部互動設定檔擴充功能。
Microsoft 手部互動設定檔
Microsoft 手部互動設定檔擴充 由微軟提出,設計上大致模仿簡易控制器設定檔。Meta 也已支援此擴充,但僅限其原生 OpenXR 用戶端,目前在 Meta Link 上尚未提供。
捏合動作可透過 select 輸入取得:拇指與食指分開時值為 0.0,指尖接觸時為 1.0。
注意,此設定檔中 aim pose (瞄準姿勢)重新定義為拇指與食指之間的位置,並以便於進行射線檢測的方向排列。
抓握動作可透過 squeeze 輸入取得:手掌張開時值為 0.0,握拳時為 1.0。
完成上述設定後,會使用標準的 left_hand 與 right_hand 追蹤器,因此可在控制器與手部追蹤間無縫切換輸入方式。
HTC 手部互動設定檔
HTC 手部互動設定檔擴充 由 HTC 提出,定義方式與 Microsoft 擴充類似。目前僅 HTC Focus 3 與 Elite XR 頭顯支援。
手勢支援請參考 Microsoft 手部互動設定檔。
主要差異在於,該擴充額外引入 /user/hand_htc/left 與 /user/hand_htc/right 兩個追蹤器。當使用者放下或拿起控制器時,需額外撰寫邏輯在預設追蹤器與 HTC 專屬追蹤器間切換。
簡易控制器設定檔
簡易控制器設定檔是標準核心設定檔,作為無專屬設定檔之控制器的備援方案。
有些 OpenXR 執行環境會在手部追蹤時模擬成簡易控制器設定檔。
遺憾的是,目前無法可靠區分究竟是未知控制器,還是手部追蹤透過此設定檔模擬為控制器。
各 XR 執行環境可自行定義簡易控制器設定檔的行為,因此手勢對應方式也不盡相同,無法統一保證。
最常見的對應方式為:當拇指與食指指尖接觸且手掌朝外時, select click (選取點擊)為 true;手掌朝內時, menu click (選單點擊)為 true。
完成上述設定後,會使用標準的 left_hand 與 right_hand 追蹤器,因此可在控制器與手部追蹤間無縫切換輸入方式。
備註
由於這些互動設定檔部分功能重疊,你可以將多個設定檔加入動作對應表,XR 執行環境會自動選取最合適的設定檔。
例如,Meta Quest 同時支援 Microsoft 手部互動設定檔與簡易控制器設定檔,若兩者皆指定,則會優先使用 Microsoft 設定檔。
預期未來 Meta 一旦支援核心手部互動設定檔擴充,將會優先於 Microsoft 與簡易控制器設定檔。
基於手勢的輸入
若平台在手部追蹤時不支援任何互動設定檔,或你需要更複雜的手勢支援,則需自行實作手勢辨識系統。
你可以透過每隻手的 XRHandTracker 資源取得完整手部追蹤資料。可呼叫 XRServer.get_tracker 並以 /user/hand_tracker/left 或 /user/hand_tracker/right 做為追蹤器名稱,取得對應手部追蹤器。這個資源可存取該手所有關節資訊。
完整的手勢辨識演算法超出本手冊範疇,不過你可以參考下列社群專案: