OpenXR 算繪模型
OpenXR API 設計的一大基石,就是盡可能與平台無關。其典型例子是 OpenXR 的動作對應系統:即使目前使用的硬體沒有對應的互動設定檔,XR 執行階段也必須支援核心互動設定檔作為退回選項。這可確保 OpenXR 應用程式即便在發佈時尚不存在、或開發者無法取得的硬體上使用時,仍能正常運作。
其結果之一,是應用程式開發者無法確定實際使用中的硬體,因為 XR 執行階段可能在模擬其他硬體。於是,開發者無法展示與「實際硬體」相關的內容;最常見的需求就是顯示使用者手上正在握持的控制器。
顯示正確的控制器模型並正確定位,對維持良好的沉浸感至關重要。
這正是 OpenXR 的 Render Models API 派上用場的地方。此 API 允許我們向 XR 執行階段查詢與實際使用之硬體相符的 3D 資產。它也允許我們查詢該硬體在追蹤空間中的位置,以及其子元件的正確定位。
例如,我們可以正確定位並驅動扳機的動畫,或顯示按鈕被按下的狀態。
對於支援 手部追蹤控制器資料來源 的執行階段,我們也能依控制器的形狀正確定位使用者的手指與手。請注意,這需要搭配 手部關節活動範圍擴充 使用,以避免手指穿模。
OpenXR 算繪模型節點
OpenXRRenderModelManager 節點可用來自動化多數算繪模型的功能。此節點會追蹤 XR 執行階段目前提供的作用中算繪模型。
它會為每個作用中的算繪模型建立子節點,並據此顯示對應的算繪模型。
此節點必須有一個 XROrigin3D 節點作為其祖先。
若將 tracker 設為 Any,本節點會顯示目前所有被追蹤的算繪模型。此情況下,本節點必須是 XROrigin3D 的直接子節點。
若將 tracker 設為 None set,本節點只會顯示尚未識別追蹤器的算繪模型。此情況下,本節點同樣必須是 XROrigin3D 的直接子節點。
若將 tracker 設為 Left Hand 或 Right Hand,本節點將分別只顯示與左手或右手相關的算繪模型。此情況下,本節點可以放在場景樹更深的位置。
警告
對多數 XR 執行階段來說,這表示算繪模型代表使用者實際握持的控制器,但不保證一定如此。有些 XR 執行階段即使控制器未被持握、只是在被追蹤,也會一律將追蹤器設定為左手或右手。因此請務必測試,否則可能導致不期望的行為。
在此情境中,我們也可以將 make_local_to_pose 屬性設定為某個姿勢的動作,來指定動作對應表中的姿勢。配合同樣使用該姿勢的 XRController3D 節點,即可新增一個層級,讓控制器與其相關的算繪模型得以偏離原先的追蹤位置(見下方範例)。
備註
將上述方法與手部追蹤結合時,會遇到一個問題:手部追蹤與動作對應系統完全獨立。你需要結合手部追蹤與控制器追蹤的姿勢,才能正確地對算繪模型做偏移。
這超出本文件的範圍。
算繪模型管理員範例
你可以下載 我們的算繪模型示範專案,其中實作了下述的設定。
在此設定中,我們在 XROrigin3D 節點底下放了一個 OpenXRRenderModelManager 節點。其 target 屬性設為 None set,用以顯示目前與左右手控制器無關的所有算繪模型。
接著左右手使用相同的設定,因此以下只專注在左手。
我們有一個 XRController3D 節點用來追蹤手的位置。
備註
本例使用 grip 姿勢。嚴格來說 palm 姿勢更適合且更可預期,但並非所有 XR 執行階段都支援。請參考手部追蹤示範專案,了解如何根據支援度在這些姿勢間切換。
作為其子節點,我們加入了一個 AnimatableBody3D,它會跟隨手部的追蹤位置,但 同時會與物理物件互動,避免玩家的手穿過牆面等。此節點具備包覆手部的碰撞形狀。
備註
務必設定物理優先順序,使這段邏輯在任何會移動 XROrigin3D 的物理邏輯之後執行,否則手部會落後一個畫面幀。
以下腳本展示了基本的實作,可在此基礎上擴充。
class_name CollisionHands3D
extends AnimatableBody3D
func _ready():
# Make sure these are set correctly.
top_level = true
sync_to_physics = false
process_physics_priority = -90
func _physics_process(_delta):
# Follow our parent node around.
var dest_transform = get_parent().global_transform
# We just apply rotation for this example.
global_basis = dest_transform.basis
# Attempt to move to where our tracked hand is.
move_and_collide(dest_transform.origin - global_position)
最後,還有另一個 OpenXRRenderModelManager 節點,這次將 target 設為對應的手,並將 make_local_to_pose 設為正確的姿勢。如此可確保與該手相關的算繪模型能正確顯示,且在碰撞處理改變位置時能正確做出偏移。
算繪模型節點
OpenXRRenderModel 節點實作了顯示與定位算繪模型所需的全部邏輯,這些模型由 Render Models API 提供。
此節點的實例由上文使用的算繪模型管理員節點新增,不過若需要,你也可以直接與這些實例互動。
每當 Godot 取得一個新算繪模型的資訊時,會建立一個 RID 來參照該算繪模型。
將該 RID 指定給本節點的 render_model 屬性後,此節點就會開始顯示該算繪模型,並同時管理將其放置在正確位置所需的轉換,以及所有子物件的動畫。
get_top_level_path 函式會回傳與此算繪模型關聯的最高層路徑,指向左手或右手。由於最高層路徑會隨使用者拾起或放下控制器而被設定或清除,你可以連接 render_model_top_level_path_changes 訊號以回應這些變化。
依據你設定的 OpenXRRenderModelManager 節點,算繪模型會隨其最高層路徑的變化而被移除或加入。
後端存取
上述節點已為我們處理所有顯示邏輯,但你也可以直接與其背後的資料互動,並自行實作。
為此,你可以存取 OpenXRRenderModelExtension 單例。
此物件也可用於查詢目前裝置是否支援並啟用了算繪模型,方法是呼叫此物件的 is_active 函式。
內建邏輯實作了 Interaction Render Model API,會列出動作對應表中與控制器及類似裝置相關的所有算繪模型,並自動建立與移除透過此 API 暴露的算繪模型實體。
未來若出現其他擴充功能,可透過 GDExtension 外掛來實作。此類外掛可呼叫 render_model_create 與 render_model_destroy,建立可透過核心 Render Models API 存取該算繪模型的物件。
不應在此邏輯之外銷毀算繪模型。
你可以連接 render_model_added 與 render_model_removed 訊號,以得知何時有新的算繪模型被加入或移除。
以下列出操作此 API 的核心方法:
函式 |
說明 |
|---|---|
render_model_get_all |
提供所有正在被追蹤之算繪模型的 RID 陣列。 |
render_model_new_scene_instance |
提供一個新場景,包含顯示該算繪模型所需的所有網格。 |
render_model_get_subaction_paths |
提供動作對應表中與此算繪模型相關的子動作路徑列表。 |
render_model_get_top_level_path |
回傳與此算繪模型關聯的最高層路徑(若有)。可透過 |
render_model_get_confidence |
回傳此算繪模型追蹤資料的追蹤信心度。 |
render_model_get_root_transform |
回傳此算繪模型在目前參考空間中的根轉換,可用於將算繪模型放置到空間中。 |
render_model_get_animatable_node_count |
回傳此算繪模型場景中可被驅動動畫的節點數量 |
render_model_get_animatable_node_name |
回傳可被驅動動畫之節點的名稱。請注意,此節點可能位於場景中任意深度的階層。 |
render_model_is_animatable_node_visible |
若此可動畫節點應可見則回傳 true |
render_model_get_animatable_node_transform |
回傳此可動畫節點的轉換。這是可直接套用的區域轉換。 |