const xrCamera = new WebXRCamera("nameOfCamera", scene, xrSessionManager);
WebXR Camera是專為VR/AR體驗設計的攝影機,所以只要是XR攝影機基本上就是選這款。
它本質上是FreeCamera的擴展,但增加了處理XR數據和雙眼渲染的能力。
比較個別的是WebXR Camera不接受初始位置,WebXR攝影機的位置是根據裝置的當前位置相對於參考空間計算出來的。攝影機的位置會在 第一個XRFrame渲染時,被來自XR裝置的數據自動填入。也會根據XRFrame持續發送裝置大概位置的訊息並逐幀更新裝置攝影機的位置。
當進行WebXR傳送移動的時候並非直接移動攝影機的位置,而是根據傳送前後的位置變化,計算出一個新的參考空間再做計算。
在使用XR攝影機的時候可以透過取得使用者身高(從地板量起),來進行更準確的操作,但要注意這個身高回傳的值,會依據參考空間類型而有所不同,如果是local-floor
就會提供使用者的身高;當是viewer
的話就會是設定上的高度:
const userHeight = xrCamera.realWorldHeight;
WebXR的一大進步在於能夠支援多樣化的輸入設備,包括動作控制器、觸控螢幕,甚至是手部追蹤。Babylon.js 支援 WebXR的Input Profiles repository,Input Profiles repository是一個由 W3C 社群推動的開源資料庫,裡面包含了幾乎所有市面上 XR 控制器(如 Oculus Touch、Valve Index、HTC Vive 等)的標準化定義和 3D 模型。因此可以實現自動下載並加載與硬體相符的 3D 控制器模型。開發者只需要訂閱 onMeshLoadedObservable
來確認模型是否準備好就可以使用了,或是訂閱onMotionControllerInitObservable
來確認控制器的初始化或載入好沒有。而開發者則可以專注在邏輯上的開發。
在WexXR,使用者輸入的來源有三種:
tracked-pointer
:控制器手把輸入screen
:觸控螢幕輸入gaze
:基於凝視的輸入而Babylon 的WebXRInput會自動處理它們,他會偵測和管理所有XR控制器的連線和斷開,每個連接的輸入源都會自動建立一個WebXRInputSource負責連接控制器和連接組件並載入模型。
我們只要放心地知道他會自動處理這塊,就能把精力放在邏輯開發,並透過它的Observable onControllerAddedObservable
和 onControllerRemovedObservable
來啟動和結束就好了。
onControllerAddedObservable
: 當偵測到新的輸入來源並建立其對應的WebXRInputSource時觸發
onControllerRemovedObservable
: 當控制器離開體驗時,在其WebXRInputSource實例被處理之前觸發。
另外每個輸入源都有兩個特別的參考空間,用於定義不同的互動行為:
空間名稱 | 目的 | 程式碼 |
---|---|---|
targetRay |
瞄準與點擊。 代表雷射線、手指尖或注視點的方向。 | xrInputSource.getWorldPointerRayToRef(pointerRay) |
gripSpace |
抓取與定位。 代表控制器手柄底座或手掌的中心位置。 | xrInputSource.getWorldPointerRayToRef(gripRay, true) |
控制器的元件
由於各大廠家的XR裝置會有不同定義的主要元件,可以透過下方這段取得主要元件。
const mainComponent = motionController.getMainComponent();
常見的有Trigger
(板機)、Squeeze
(握持)、Thumbstick
(搖桿)、Touchpad
(觸摸板)和 Button
(按鈕)。元件會逐幀更新,常見會有不同狀態如touched
、pressed
、 axes
(一個從 0 到 1 的值,0 表示完全未按下,1 表示完全按下)。可以透過 ID 或 Type 來獲取元件,它具有唯一的元件 ID,與實際硬體相對應。若要取得可用元件的列表,可以使用getComponentIds
會傳回一個包含所有ID的字串array:
const ids = motionController.getComponentIds();
// ids = ["a-button", "b-button", "xr-standard-trigger", .....]
// 透過 ID 獲取扳機
const triggerComponent = motionController.getComponent("xr-standard-trigger");
// 獲取所有按鈕類型的元件
const buttonComponents = motionController.getAllComponentsOfType("button");