XRReferenceSpace: getOffsetReferenceSpace() 方法

可用性有限

此特性不是基線特性,因為它在一些最廣泛使用的瀏覽器中不起作用。

安全上下文: 此功能僅在安全上下文(HTTPS)中可用,且支援此功能的瀏覽器數量有限。

XRReferenceSpace 介面的 getOffsetReferenceSpace() 方法返回一個新的參考空間物件,該物件描述了呼叫該方法的物件與 3D 空間中給定點之間的位置相對差異。getOffsetReferenceSpace() 返回的物件在以下情況時為 XRReferenceSpace:在 XRReferenceSpace 上呼叫;在 XRBoundedReferenceSpace 物件上呼叫時則返回 XRBoundedReferenceSpace

換句話說,當您在 3D 空間中有一個物件,並需要相對於該物件定位另一個物件時,可以呼叫 getOffsetReferenceSpace(),並將您希望第二個物件擁有的位置和方向作為引數傳入,這些位置和方向是相對於呼叫 getOffsetReferenceSpace() 的物件的初始位置和方向

然後,在繪製場景時,您可以使用偏移參考空間來不僅定位物件之間的相對位置,還可以應用必要的變換,以根據檢視者的位置正確渲染物件。這在示例 基於非 XR 輸入實現旋轉 中得到了演示,該示例展示了一種使用此方法讓使用者使用滑鼠來俯仰和偏航他們的視角的方法。

語法

js
getOffsetReferenceSpace(originOffset)

引數

originOffset

一個 XRRigidTransform 物件,指定了新參考空間的源點的偏移量。這些值會加到當前參考空間的位置和方向上,然後將結果用作新建立的 XRReferenceSpace 的位置和方向。

返回值

一個與呼叫該方法的參考空間具有相同本地原點的 XRReferenceSpace 物件,但其原點偏移量表示從物件到 originOffset 給定點之間的距離。

如果呼叫此方法的物件是 XRBoundedReferenceSpace,則返回的物件也是一個 XRBoundedReferenceSpace。新參考空間的 boundsGeometry 會設定為原始物件的 boundsGeometry,其每個點的座標都乘以 originOffset 的逆矩陣。

示例

下面是一些展示如何使用 getOffsetReferenceSpace() 的示例。

傳送或設定檢視者的位置

在首次建立場景時,您可能需要設定使用者在 3D 世界中的位置。您可以使用 getOffsetReferenceSpace() 來實現這一點。

js
xrSession.requestReferenceSpace("local").then((refSpace) => {
  xrReferenceSpace = refSpace;
  xrReferenceSpace = xrReferenceSpace.getOffsetReferenceSpace(
    new XRRigidTransform(startPosition, { x: 0, y: 0, z: 1.0, w: 1.0 }),
  );
  xrSession.requestAnimationFrame(drawFrame);
});

在這段程式碼中,我們獲取了一個本地參考空間,然後使用 getOffsetReferenceSpace() 建立了一個新的空間,其原點調整為 startPosition 指定的位置,並且其方向直接指向 Z 軸。然後,使用 XRSessionrequestAnimationFrame() 請求第一個動畫幀。

基於非 XR 輸入實現旋轉

WebXR 直接支援的輸入控制元件都是專用的 VR 或 AR 輸入裝置。為了使用滑鼠、鍵盤或其他輸入裝置來移動或以其他方式轉換 3D 空間中的物件,或者讓使用者在空間中移動,您需要編寫一些程式碼來讀取輸入並執行相應的移動。

這是 getOffsetReferenceSpace() 的另一個很好的用例。在此示例中,我們將展示一段程式碼,允許使用者透過右鍵單擊並移動滑鼠來更改視角,從而環顧四周。

首先,我們為 mousemove 事件新增一個事件處理程式,當按下滑鼠右鍵時,該處理程式會呼叫我們的程式碼來執行旋轉。請注意,我們還透過呼叫 preventDefault() 來忽略 oncontextmenu 事件。這可以防止右鍵單擊導致瀏覽器顯示上下文選單。

js
canvas.oncontextmenu = (event) => {
  event.preventDefault();
};
canvas.addEventListener("mousemove", (event) => {
  if (event.buttons & 2) {
    rotateViewBy(event.movementX, event.movementY);
  }
});

接下來是 rotateViewBy() 函式,它根據 mousemove 事件中的滑鼠 delta 值更新滑鼠視角的偏航和俯仰。俯仰角度受到限制,以防止您看向正上方或正下方。每次呼叫此函式時,都會使用新的偏移量來更新 mousePitchmouseYaw 的當前值。

js
let mouseYaw = 0.0;
let mousePitch = 0.0;
const inverseOrientation = quat.create();
const MOUSE_SPEED = 0.003;

function rotateViewBy(dx, dy) {
  mouseYaw += dx * MOUSE_SPEED;
  mousePitch += dy * MOUSE_SPEED;

  if (mousePitch < -Math.PI * 0.5) {
    mousePitch = -Math.PI * 0.5;
  } else if (mousePitch > Math.PI * 0.5) {
    mousePitch = Math.PI * 0.5;
  }
}

最後,我們需要一些實際將計算出的偏航和俯仰應用到檢視者方向的程式碼。此函式 applyMouseMovement() 負責處理。

js
function applyMouseMovement(refSpace) {
  if (!mouseYaw && !mousePitch) {
    return refSpace;
  }

  quat.identity(inverseOrientation);
  quat.rotateX(inverseOrientation, inverseOrientation, -mousePitch);
  quat.rotateY(inverseOrientation, inverseOrientation, -mouseYaw);

  let newTransform = new XRRigidTransform(
    { x: 0, y: 0, z: 0 },
    {
      x: inverseOrientation[0],
      y: inverseOrientation[1],
      z: inverseOrientation[2],
      w: inverseOrientation[3],
    },
  );

  return refSpace.getOffsetReferenceSpace(newTransform);
}

此函式從當前的俯仰和偏航值建立一個反向方向矩陣(用於定向檢視者),然後使用該矩陣作為呼叫 XRRigidTransform() 的方向源。然後獲取新的 XRRigidTransform 的參考空間並將其返回給呼叫者。

這個新的參考空間使得檢視者的位置保持不變,但其方向已根據由累積的滑鼠輸入生成的俯仰和偏航值進行了更改。applyMouseMovement() 應在繪製幀時呼叫,緊接在透過 getViewerPose() 獲取檢視者姿態之前,並且渲染應在此參考空間中執行。

您可以在我們更廣泛的 WebXR 教程文章 Movement, orientation, and motion 中看到類似的程式碼。特別是,請檢視名為 Starting up the WebXR session 的部分。

規範

規範
WebXR Device API
# dom-xrreferencespace-getoffsetreferencespace

瀏覽器相容性