WebXR デバイス API

W3C 勧告候補草案,

この文書の詳細
このバージョン:
https://www.w3.org/TR/2025/CRD-webxr-20250930/
最新版公開バージョン:
https://www.w3.org/TR/webxr/
編集者ドラフト:
https://immersive-web.github.io/webxr/
以前のバージョン:
履歴:
https://www.w3.org/standards/history/webxr/
実装レポート:
https://wpt.fyi/results/webxr?label=master&label=experimental&aligned
フィードバック:
GitHub
編集者:
(Google)
(Google [2020年までMozilla])
(Meta)
元編集者:
(Amazon [2018年までMicrosoft])
参加方法:
Issueの作成 (オープン中のIssue)
メーリングリストアーカイブ
W3Cの #immersive-web IRC

要約

この仕様は、Web上でセンサーやヘッドマウントディスプレイを含むバーチャルリアリティ(VR)および拡張現実(AR)デバイスへアクセスするためのサポートについて記述しています。

この文書のステータス

このセクションは、この文書が公開された時点でのステータスについて説明します。現在の W3C 公開物と、この技術レポートの最新改訂版は W3C 標準および草案一覧 で確認できます。

Immersive Web Working Group は グループがまだ対応していない全バグ報告のリスト を管理しています。このドラフトでは、ワーキンググループでまだ議論が必要な保留中の課題の一部を強調しています。これらの課題の妥当性を含め、結論についてはまだ決まっていません。 未解決の課題に対する仕様文案の Pull Request を強く推奨します。

この文書は Immersive Web Working Group によって 勧告トラック を用いて 候補勧告ドラフトとして公開されました。この文書は W3C 勧告となることを意図しています。

候補勧告としての公開は W3C およびそのメンバーによる支持を意味するものではありません。 候補勧告ドラフトは、ワーキンググループが次の候補勧告スナップショットに含める予定の、前回の候補勧告からの変更を統合しています。 この文書はドラフトであり、今後随時更新、差し替え、または廃止される可能性があります。この文書を進行中の作業以外のものとして引用するのは適切ではありません。

この文書が提案勧告段階へ進むための基準は、本仕様の全機能を実装した2つ以上の独立かつ相互運用可能なユーザーエージェントが存在し、 ワーキンググループが作成したテストスイートのユーザーエージェントテストに合格することで判断されます。ワーキンググループは進捗を追跡するために実装レポートを準備します。

この文書は W3C特許ポリシー の下で運営されているグループによって作成されました。 W3Cは、グループの成果物に関連して行われた 特許開示の公開リスト を管理しています。そのページには特許開示の方法についても記載されています。個人が、必須特許請求項 を含むと信じる特許について実際に知っている場合、その情報は W3C特許ポリシー第6節 に従って開示する必要があります。

この文書は 2025年8月18日 W3Cプロセス文書 により管理されています。

前回のドラフト以降の変更点については、「変更点」のセクションを参照ください。

1. はじめに

バーチャルリアリティ(VR)や拡張現実(AR)アプリケーションを実現するハードウェアは、現在では消費者向けにも広く提供されており、没入型コンピューティングプラットフォームとして新たな機会と課題の両方をもたらしています。没入型ハードウェアと直接やり取りできる能力は、ウェブがこの環境で一級市民として機能するために極めて重要です。

没入型コンピューティングは、満足のいく体験を提供するために高精度かつ低遅延の通信が厳しく求められます。また、ウェブのようなプラットフォームに特有のセキュリティ上の懸念も生じます。WebXR Device APIは、開発者がさまざまなハードウェア形態に対応した魅力的で快適かつ安全な没入型アプリケーションをウェブ上で構築するために必要なインターフェイスを提供します。

他のウェブインターフェイス、たとえばRelativeOrientationSensorAbsoluteOrientationSensor などは、一部のデバイスからの入力を取得して、限定的な状況でWebXR Device APIのポリフィルとして利用されることがあります。しかし、これらのインターフェイスは、6DoFトラッキングやヘッドセット周辺機器への表示、トラッキング入力デバイスなど、高度な没入型体験の複数の機能をサポートできません。

1.1. 用語

本書ではXRという略語を、バーチャルリアリティ、拡張現実、およびその他関連技術のために使用されるハードウェア、アプリケーション、手法の総称として用いています。例として、以下が挙げられますが、これらに限りません:

これらに共通する重要な特徴は、仮想コンテンツのビューをシミュレートするための空間トラッキングを何らかの形で提供する点です。

「XRデバイス」「XRアプリケーション」などの用語は、一般的に上記のいずれにも適用されるものと理解されます。本書のうち、これらのデバイスの一部にのみ該当する部分については、適切にその旨が示されます。

3DoF6DoF という用語は、本書全体を通してXRデバイスのトラッキング機能を表すために使用されます。

1.2. アプリケーションの流れ

WebXR Device APIを利用するほとんどのアプリケーションは、次のような利用パターンに従います:

2. モデル

2.1. XRデバイス

XRデバイスとは、ユーザーに没入型コンテンツを提示できる物理的なハードウェアユニットを指します。コンテンツが「没入型」と見なされるのは、視覚・聴覚・触覚またはその他の感覚出力によってユーザーの環境の様々な要素をシミュレートまたは拡張する場合です。多くの場合、これはユーザーの空間的な動きをトラッキングし、その動きと同期した出力を生成することを伴います。デスクトップクライアントでは通常ヘッドセット周辺機器であり、モバイルクライアントではビューアーハーネスと組み合わせてモバイルデバイス自体を表す場合もあります。ステレオ表示機能は無いが高度なトラッキングを備えたデバイスも含まれます。

XRデバイスは、対応モードのリストリスト文字列))を持ち、そのリストには、そのXRデバイスがサポートするXRSessionMode の列挙値が含まれます。

XRデバイスは、対応モードごとにXRSessionMode に対して許可された機能のセットを持ちます。これはセットであり、機能記述子のセットで、初期状態では空のセットでなければなりません。

ユーザーエージェントは、没入型XRデバイスのリストリストXRデバイス))を持ち、初期状態では空のリストでなければなりません。

ユーザーエージェントは、没入型XRデバイスnullまたはXRデバイス)を持ちます。これは初期状態ではnullであり、没入型XRデバイスのリストから選ばれるアクティブなXRデバイスを表します。このオブジェクトは別スレッド上に存在し、非同期に更新されることがあります。

ユーザーエージェントは、デフォルトインラインXRデバイスを持たなければなりません。これはXRデバイスであり、その対応モードのリスト"inline" を含んでいなければなりません。デフォルトインラインXRデバイスは、ポーズ情報を報告してはならず、ポインターイベントによって生成されるもの以外のXR入力ソースやイベントを報告してはなりません。

注記: デフォルトインラインXRデバイスは、開発者の利便性のために存在し、インライン/没入型の両方のコンテンツで同じ描画・入力ロジックを利用できるようにします。デフォルトインラインXRデバイスは、ページ上の他の仕組み(入力用のポインターイベントなど)を通じて既に開発者が利用できる情報以外を公開しません。単にXR中心の形式で値を提供するだけです。

ユーザーエージェントは、インラインXRデバイスを持たなければなりません。これはXRデバイスであり、その対応モードのリスト"inline" を含んでいなければなりません。インラインXRデバイスは、そのトラッキングがインラインコンテンツに公開するのが適切であれば没入型XRデバイスと同一であってもよく、そうでなければデフォルトインラインXRデバイスでなければなりません。

注記: スマートフォンでは、インラインXRデバイスはジャイロスコープや加速度センサーなどの内部センサーから導出されたポーズ情報を報告する場合があります。類似センサーのないデスクトップやノートパソコンでは、インラインXRデバイスはポーズを報告できず、その場合デフォルトインラインXRデバイスにフォールバックすべきです。既にXRデバイス上でユーザーエージェントが動作している場合、インラインXRデバイスは同じデバイスとなり、複数のビューをサポートすることがあります。デフォルトインラインXRデバイスが公開する機能を超えるトラッキングや入力機能を提供する場合は、ユーザーの同意が必要です。

現在の没入型XRデバイスのリストインラインXRデバイス没入型XRデバイスの値は、別スレッド上で非同期に更新されることがあります。これらのオブジェクトは、並列実行していない手順から直接アクセスすべきではありません。

3. 初期化

partial interface Navigator {
  [SecureContext, SameObject] readonly attribute XRSystem xr;
};

xr属性のgetterは、それに関連付けられたXRSystemオブジェクトを返さなければなりません。

3.2. XRSystem

[SecureContext, Exposed=Window] interface XRSystem : EventTarget {
  // Methods
  Promise<boolean> isSessionSupported(XRSessionMode mode);
  [NewObject] Promise<XRSession> requestSession(XRSessionMode mode, optional XRSessionInit options = {});

  // Events
  attribute EventHandler ondevicechange;
};

ユーザーエージェントは、XRSystemオブジェクトをNavigatorオブジェクトの作成時に生成し、そのオブジェクトに関連付けなければなりません。

XRSystemオブジェクトはAPIのエントリーポイントであり、ユーザーエージェントで利用可能なXR機能の問い合わせや、XRSessionの生成を通じてXRハードウェアとの通信を開始するために使用されます。

ユーザーエージェントは、システムに接続された没入型XRデバイスの列挙ができなければなりません。このとき、利用可能な各デバイスは没入型XRデバイスのリストに追加されます。その後の列挙要求アルゴリズムは、キャッシュされた没入型XRデバイスのリストを再利用しなければなりません。デバイスの列挙はデバイストラッキングを初期化すべきではありません。最初の列挙後、ユーザーエージェントはデバイスの接続・切断を監視し、接続されたデバイスを没入型XRデバイスのリストに追加し、切断されたデバイスを除外します。

没入型XRデバイスのリストが変更されるたびに、ユーザーエージェントは次の手順で没入型XRデバイスの選択を行うべきです:

  1. oldDevice没入型XRデバイスとする。

  2. 没入型XRデバイスのリストが空のリストである場合、没入型XRデバイスnullに設定する。

  3. 没入型XRデバイスのリストサイズが1の場合、没入型XRデバイス没入型XRデバイスのリスト[0]に設定する。

  4. 没入型XRデバイスを以下のように設定する:

    アクティブなXRSessionが存在し、かつ没入型XRデバイスのリストoldDevice含む場合:

    没入型XRデバイスoldDeviceに設定する。

    それ以外の場合:

    ユーザーエージェントが選択したデバイスを没入型XRデバイスに設定する。

  5. 必要に応じて、インラインXRデバイス没入型XRデバイスに更新するか、そうでなければデフォルトインラインXRデバイスに設定してもよい。

  6. これが初回のデバイス列挙である場合、またはoldDevice没入型XRデバイスと等しい場合、これ以降の手順を中止する。

  7. アクティブなXRSessionシャットダウンする。

  8. タスクをキューし、全てのWebGLRenderingContextBaseインスタンスのXR compatibleブール値をfalseに設定する。

  9. タスクをキューし、イベントdevicechangeを、該当するGlobal objectnavigatorxrに発火する。

  10. タスクをキューし、没入型XRデバイスインラインXRデバイスの変更によって影響を受ける全てのXRPermissionStatusオブジェクトに適切なchangeイベントを発火する。

注記: これらの手順は常に並列で実行されるべきです。

注記: 没入型XRデバイスのリストに複数のデバイスが含まれている場合、ユーザーエージェントは任意の基準で没入型XRデバイスを選択できます。例えば、常にリストの先頭のデバイスを選択したり、ユーザーがデバイスの優先度を管理できる設定UIを提供しても構いません。理想的には、デフォルトデバイスを選択するアルゴリズムは安定していて、複数回のブラウジングセッションでも同じデバイスが選択される結果となるべきです。

ユーザーエージェントは、次の手順を実行することで没入型XRデバイスが選択されていることを保証できます:

  1. 没入型XRデバイスnullでない場合、没入型XRデバイスを返し、これ以降の手順を中止する。

  2. 没入型XRデバイスを列挙する。

  3. 没入型XRデバイスを選択する。

  4. 没入型XRデバイスを返す。

注記: これらの手順は常に並列で実行されるべきです。

ondevicechange属性は、イベントハンドラーIDL属性であり、devicechangeイベントタイプのためのものです。

isSessionSupported(mode)メソッドは、指定されたmodeがユーザーエージェントおよびデバイス機能によってサポートされる可能性があるかどうかを問い合わせます。

このメソッドが呼び出されたとき、次の手順を実行しなければなりません:

  1. promiseを、このXRSystem関連realm新しいPromiseとする。

  2. mode"inline"の場合、resolve promisetrueで解決し、返す。

  3. 要求元ドキュメントのオリジンが"xr-spatial-tracking"permissions policyの利用を許可されていない場合、reject promiseを"SecurityError" DOMExceptionで拒否し、返す。

  4. セッションmodeがサポートされているかどうかを次のように確認する:

    ユーザーエージェントおよびシステムがmodeセッションを決してサポートしないことが分かっている場合

    resolve promisefalseで解決する。

    ユーザーエージェントおよびシステムがmodeセッションを通常サポートすることが分かっている場合

    このユーザーエージェントの全てのUA文字列で区別できないインスタンスがここで同じ結果を返す場合に限り、promisetrueで解決してもよい。

    それ以外の場合

    次の手順を並列で実行する:

    1. device没入型XRデバイスが選択されていることを保証した結果とする。

    2. deviceがnullの場合、resolve promisefalseで解決し、これ以降の手順を中止する。

    3. device対応モードのリストmode含まない場合、タスクをキューし、resolve promisefalseで解決し、これ以降の手順を中止する。

    4. 強力な機能"xr-session-supported"の利用許可を、XRSessionSupportedPermissionDescriptormodemodeを指定してリクエストする。"denied"が返された場合は、タスクをキューし、resolve promisefalseで解決し、これ以降の手順を中止する。詳細はフィンガープリンティングに関する考慮を参照。

    5. タスクをキューし、resolve promisetrueで解決する。

  5. promiseを返す。

注記: isSessionSupported()の目的は、ユーザーエージェントがXRSessionを作成できるかを完全に正確に報告することではなく、指定のmodeセッションを作成できる旨を案内すべきかどうかをページに通知することです。必要なハードウェアやソフトウェアを事前に確認しても、ある程度の偽陽性が発生することがあります(例えば、適切なハードウェアが存在していても、セッション要求時に他のアプリケーションに排他的アクセス権が与えられている場合など)。

ほとんどのXRコンテンツを含むページは、ドキュメントのライフサイクルの早い段階でisSessionSupported()を呼び出すことが想定されます。そのため、isSessionSupported()の呼び出しでは、モーダルUIやその他ユーザーの操作を妨げるUIを表示すべきではありません。isSessionSupported()の呼び出しは、デバイス選択UIを表示してはならず、システム上で実行中のXRアプリケーションを妨げてはならず、システムトレイやストアフロント等XR関連アプリケーションを起動させてはなりません。

次のコードは、immersive-vrセッションがサポートされているかどうかを確認します。
const supported = await navigator.xr.isSessionSupported('immersive-vr');
if (supported) {
  // 'immersive-vr' セッションがサポートされている可能性があります。
  // ページはユーザーへサポートを案内すべきです。
} else {
  // 'immersive-vr' セッションはサポートされていません。
}

XRSystemオブジェクトは、未処理の没入型セッションブール値(初期値はfalse)、アクティブな没入型セッション(初期値はnull)、およびインラインセッションのリスト(初期値は空)を持ちます。

requestSession(mode, options) メソッドは、可能であれば指定したmodeXRSessionを初期化し、必要に応じて没入型モードに入ろうとします。

このメソッドが呼び出されたとき、ユーザーエージェントは次の手順を実行しなければなりません:

  1. promiseを、このXRSystem関連realm新しいPromiseとする。

  2. mode没入型セッションモードであればimmersivetrue、それ以外はfalseとする。

  3. global objectを、このメソッドが呼び出されたXRSystem該当するGlobal objectとする。

  4. セッション要求が許可されているかを次のように確認する:

    immersivetrueの場合:
    1. 没入型セッション要求が許可されているか確認し、許可されていなければreject promiseを"SecurityError" DOMExceptionで拒否し、promiseを返す。

    2. 未処理の没入型セッションtrueまたはアクティブな没入型セッションnullでない場合、reject promiseを"InvalidStateError" DOMExceptionで拒否し、promiseを返す。

    3. 未処理の没入型セッションtrueに設定する。

    それ以外の場合:

    インラインセッション要求が許可されているか確認し、許可されていなければreject promiseを"SecurityError" DOMExceptionで拒否し、promiseを返す。

  5. 次の手順を並列で実行する:

    1. requiredFeaturesoptionsrequiredFeaturesとする。

    2. optionalFeaturesoptionsoptionalFeaturesとする。

    3. devicemoderequiredFeaturesoptionalFeaturesに対する現在のデバイスの取得結果とする。

    4. タスクをキューし、以下の手順を実行する:

      1. devicenullまたはdevice対応モードのリストmode含まない場合、以下の手順を実行する:

        1. reject promiseを"NotSupportedError" DOMExceptionで拒否する。

        2. immersivetrueの場合、未処理の没入型セッションfalseに設定する。

        3. これ以降の手順を中止する。

      2. descriptormoderequiredFeaturesoptionalFeaturesで初期化したXRPermissionDescriptorを設定する。

      3. statusに初期値nullXRPermissionStatusを設定する。

      4. xrパーミッションを要求し、descriptorstatusを指定する。

      5. statusstate"denied"の場合、以下の手順を実行する:

        1. reject promiseを"NotSupportedError" DOMExceptionで拒否する。

        2. immersivetrueの場合、未処理の没入型セッションfalseに設定する。

        3. これ以降の手順を中止する。

      6. grantedstatusgrantedから取得したセットとする。

      7. sessionを、このXRSystem関連realm新しいXRSessionオブジェクトとする。

      8. セッションの初期化session, mode, granted, deviceで実施する。

      9. アクティブな没入型セッションを次のように設定する場合がある:

        immersivetrueの場合:

        アクティブな没入型セッションsessionに設定し、未処理の没入型セッションfalseに設定する。

        それ以外の場合:

        sessionインラインセッションのリストに追加する。

      10. resolve promisesessionで解決する。

      11. タスクをキューし、以下の手順を実施する:

        注記: これらの手順は、初回のinputsourceschangeイベントがセッションの解決後に発生するようにするためのものです。
        1. sessionpromise resolvedフラグをtrueに設定する。

        2. sourcessessionに接続されている既存の入力ソースとする。

        3. sourcesが空でない場合、以下の手順を実施する:

          1. sessionアクティブなXR入力ソースのリストsourcesに設定する。

          2. session上で、XRInputSourcesChangeEventイベントinputsourceschangeaddedsourcesを設定して発火する。

  6. promiseを返す。

XRSessionModemoderequiredFeaturesoptionalFeaturesに対してユーザーエージェントが現在のデバイスを取得するには、次の手順を実行しなければなりません:

  1. deviceを次のように選択する:

    mode没入型セッションモードの場合:

    device没入型XRデバイスが選択されていることを保証した結果を設定する。

    requiredFeaturesまたはoptionalFeaturesが空でない場合:

    deviceインラインXRデバイスに設定する。

    それ以外の場合:

    deviceデフォルトインラインXRデバイスに設定する。

  2. deviceを返す。

注記: これらの手順は常に並列で実行されるべきです。

次のコードは、immersive-vr XRSessionの取得を試みます。
const xrSession = await navigator.xr.requestSession("immersive-vr");

3.3. XRSessionMode

XRSessionMode 列挙型は、XRSessionが動作できるモードを定義します。

enum XRSessionMode {
  "inline",
  "immersive-vr",
  "immersive-ar"
};

本書では、インラインセッションinline セッションと同義であり、没入型セッションimmersive-vr またはimmersive-ar セッションを指します。

イマーシブセッションは、必ず何らかのレベルのビューアトラッキングを提供しなければならず、コンテンツはユーザーおよび/または周囲の環境に対して適切なスケールで表示されなければなりません。さらに、イマーシブセッションイマーシブXRデバイスへの排他的アクセスを必ず付与されなければなりません。つまり、イマーシブセッション"visible" の間、HTMLドキュメントはイマーシブXRデバイスのディスプレイに表示されず、他のソースのコンテンツが排他的アクセスを持つこともありません。排他的アクセスはユーザーエージェント自身のUIオーバーレイを妨げるものではありませんが、このUIは最小限であるべきです。

注記: UAはアクセシビリティや安全性のために、ガーディアン境界・障害物・入力手段がない場合はユーザーの手などを重ねて表示することがあります。

注記: 将来の仕様やモジュールにより、没入型セッションの定義に追加のセッションモードが加わる場合があります。

注記: 排他的アクセスが提供される例として、VRヘッドセットでのステレオコンテンツ表示などが挙げられます。

注記: オーバーレイUIの例として、没入型セッション中にユーザーエージェントやOSが通知を描画コンテンツの上に表示することがあります。

注記: 没入型XRデバイスのディスプレイでは没入型セッション中にHTMLドキュメントは表示されませんが、別のディスプレイ(たとえばPCの2Dブラウザから没入型セッションを開始した場合など)では表示されることがあります。

3.4. 機能の依存関係

XRSessionの一部の機能は、様々な理由で普遍的に利用可能でない場合があります。その理由には、すべてのXRデバイスがすべての機能に対応できるわけではない点が含まれます。もう一つの考慮点は、いくつかの機能が機微な情報を公開するため、動作前に明確なユーザーの意図のシグナルが必要となる場合があることです。

基盤となるXRプラットフォームを初期化しXRSessionを作成しても、すぐにアプリケーションが正しく動作できないことをユーザーに通知するのは悪いユーザー体験であるため、開発者は必須機能XRSessionInit 辞書をrequestSession()に渡すことで指定できます。 これにより、必須機能のいずれかがデバイスの制限やユーザーの意図の明確なシグナルがない場合に利用できなければ、XRSessionの作成をブロックします。

また、開発者はより高機能なデバイスで機能が段階的に向上する体験を設計することが推奨されます。オプション機能(必須ではないが利用可能であれば利用する機能)も、XRSessionInit 辞書内で指定し、必要に応じてユーザーの意図が確認されてから有効化できるようにすべきです。

dictionary XRSessionInit {
  sequence<DOMString> requiredFeatures;
  sequence<DOMString> optionalFeatures;
};

requiredFeatures配列は体験における必須機能を含みます。リスト内のいずれかの値が認識されていない機能記述子であれば、XRSessionは作成されません。requiredFeatures 配列内の機能のいずれかがXRデバイスでサポートされていない、または必要に応じてユーザーの意図の明確なシグナルがない場合、XRSessionは作成されません。

optionalFeatures配列は体験におけるオプション機能を含みます。リスト内のいずれかの値が認識されていない機能記述子であれば無視されます。optionalFeatures 配列内で指定された機能は、XRデバイスでサポートされ、かつ必要に応じてユーザーの意図が明確であれば有効化されますが、存在しなくてもXRSessionの作成を妨げません。

機能リストに指定された値は、以下のいずれかに該当すれば有効な機能記述子とみなされます:

今後の本仕様のバージョンや追加モジュールによって、受け付け可能な機能記述子のリストが拡張される場合があります。

注記: 追加の初期化が必要な機能がある場合、XRSessionInit にその機能用の新しいフィールドを追加すべきです。

リクエストされたXRSessionModeによって、特定の機能記述子requiredFeatures またはoptionalFeatures リストにデフォルトで追加されます。次の表は、各セッションタイプと機能リストに対応するデフォルト機能を示します:

機能 セッション リスト
"viewer" インラインセッション および 没入型セッション requiredFeatures
"local" 没入型セッション requiredFeatures

requiredFeatures およびoptionalFeatures で指定された機能記述子の組み合わせは、そのXRSessionリクエスト機能とみなされます。

一部の機能記述子は、リクエスト機能リストに含まれる場合、permissions policyや、ユーザーの意図が明確である(明示的同意または黙示的同意による)ことが有効化の要件となります。次の表は有効化前に満たすべき機能要件を示します:

機能 Permissions Policy 必須 同意 必須
"local" "xr-spatial-tracking" インラインセッション は同意が必要
"local-floor" "xr-spatial-tracking" 常に同意が必要
"bounded-floor" "xr-spatial-tracking" 常に同意が必要
"unbounded" "xr-spatial-tracking" 常に同意が必要

注記: "local" は、没入型セッションリクエスト機能に常にデフォルト機能として含まれており、したがって没入型セッションでは常に明示的同意または黙示的同意を得る必要があります。

リクエスト機能 は、そのXRデバイスサポート可能である場合にのみセッションで有効化できます。これは、その機能がXRデバイスで一部の構成でサポートされることが分かっている場合を意味します(たとえ現在の構成でサポートが確認できていなくとも)。ユーザー体験の一貫性向上のため、ユーザーエージェントはより厳格な制約を適用しても構いません。

注記: 例えば複数のVRデバイスは、ユーザーが移動できる安全な境界を設定する構成と、境界設定をスキップしユーザーがその場に立っていることを前提とする構成の両方をサポートします。このようなデバイスは、現時点で安全境界が構成されていなくても、体験がそれを必要とする場合ユーザーが適切に設定できると期待されるため、"bounded-floor" XRReferenceSpaceサポート可能とみなされます。これは、ユーザーエージェントがリクエスト機能の解決前にXRデバイスを完全に初期化したり、ユーザーの環境認識を待機せずに済むようにするためです。ただし、ユーザーエージェントがセッションリクエスト時に追加の初期化なしで境界状態を把握できるなら、安全境界が未設定の場合は"bounded-floor" 機能を拒否する選択もできます。

4. セッション

4.1. XRSession

XRハードウェアとのあらゆるやり取りは、XRSession オブジェクトを通じて行われます。このオブジェクトはXRSystem オブジェクトのrequestSession()を呼び出すことでのみ取得できます。セッションの取得に成功した後は、ビューアの姿勢をポーリングしたり、ユーザーの環境に関する情報を問い合わせたり、画像をユーザーに提示するために利用できます。

ユーザーエージェントは、可能な限り、XRSession が取得されるまで、デバイストラッキングやレンダリング機能を初期化すべきではありません。これは、XR機能を単に広告表示するためにXRハードウェアの存在をテストしたいだけのページに初めて移動したときなど、XRシステムが積極的に使用されていないのに副作用(バッテリー消費増加や関連ユーティリティアプリの表示など)が発生するのを防ぐためです。ただし、全てのXRプラットフォームがトラッキングの初期化なしにハードウェアの存在を検出できるわけではないため、これは強い推奨事項に留まります。

enum XRVisibilityState {
  "visible",
  "visible-blurred",
  "hidden",
};

[SecureContext, Exposed=Window] interface XRSession : EventTarget {
  // Attributes
  readonly attribute XRVisibilityState visibilityState;
  readonly attribute float? frameRate;
  readonly attribute Float32Array? supportedFrameRates;
  [SameObject] readonly attribute XRRenderState renderState;
  [SameObject] readonly attribute XRInputSourceArray inputSources;
  [SameObject] readonly attribute XRInputSourceArray trackedSources;
  readonly attribute FrozenArray<DOMString> enabledFeatures;
  readonly attribute boolean isSystemKeyboardSupported;

  // Methods
  undefined updateRenderState(optional XRRenderStateInit state = {});
  Promise<undefined> updateTargetFrameRate(float rate);
  [NewObject] Promise<XRReferenceSpace> requestReferenceSpace(XRReferenceSpaceType type);

  unsigned long requestAnimationFrame(XRFrameRequestCallback callback);
  undefined cancelAnimationFrame(unsigned long handle);

  Promise<undefined> end();

  // Events
  attribute EventHandler onend;
  attribute EventHandler oninputsourceschange;
  attribute EventHandler onselect;
  attribute EventHandler onselectstart;
  attribute EventHandler onselectend;
  attribute EventHandler onsqueeze;
  attribute EventHandler onsqueezestart;
  attribute EventHandler onsqueezeend;
  attribute EventHandler onvisibilitychange;
  attribute EventHandler onframeratechange;
};

XRSessionは、modeXRSessionModeの値のいずれか)を持ちます。

XRSessionは、アニメーションフレームを持ちます。これはactivefalseanimationFrametruesessionをこのXRSessionに設定して初期化したXRFrameです。

XRSessionは、許可された機能のセットを持ちます。これはセットであり、DOMString値として許可された機能記述子を表します。

enabledFeatures属性は、許可された機能のセットに含まれる機能をDOMStringの新しい配列で返します。

isSystemKeyboardSupported属性は、XRSystemXRSession のアクティブ中にシステムキーボードを表示する機能を持つかどうかを示します。isSystemKeyboardSupportedtrueの場合、Web API(focusなど)でオーバーレイキーボードを呼び出すとシステムキーボードが表示されます。キーボードが表示されている間、XRSession"visible-blurred"visibility stateを設定しなければなりません。

session, mode, granted, deviceを与えられたとき、ユーザーエージェントがセッションを初期化するには、次の手順を実行しなければなりません:

  1. sessionmodemodeに設定する。

  2. sessionXRデバイスdeviceに設定する。

  3. session許可された機能のセットgrantedに設定する。

  4. レンダーステートを初期化する。

  5. 他のユーザーエージェントの機能がまだ実行していない場合は、デバイスのトラッキングおよびレンダリング機能を初期化するために必要なプラットフォーム固有の手順(ユーザーへの指示表示などを含む)を実行する。

注記: デバイスによっては起動時に追加のユーザー指示が必要な場合があります。例:スマートフォンベースのヘッドセットで没入モードに入るにはスマートフォンをヘッドセットに挿入する必要があり、デスクトップブラウザで外部ヘッドセットを利用する場合はヘッドセットを装着する必要があります。こうした指示を表示する責任は著者ではなくユーザーエージェントにあります。

さまざまな状況でセッションがシャットダウンされることがあります。これは恒久的かつ不可逆です。一度セッションがシャットダウンされると、XRデバイスのトラッキングやレンダリング機能を再び利用するには新たなセッションを取得する必要があります。各XRSessionは、endedブール値(初期値はfalse)を持ち、シャットダウンされたかどうかを示します。

XRSession sessionがシャットダウンされると、次の手順を実行します:

  1. sessionendedの値をtrueに設定する。

  2. active immersive sessionsessionと等しければ、active immersive sessionnullに設定する。

  3. sessionlist of inline sessionsから削除する。

  4. Rejectsessionが返した未解決のpromiseをInvalidStateErrorで拒否する。ただしend()が返したpromiseは除く。

  5. 他にユーザーエージェントの機能がそれらを積極的に使用していなければ、デバイスのトラッキングおよびレンダリング機能をシャットダウンするために必要なプラットフォーム固有の手順を実行する。これには必ず以下が含まれる:

  6. タスクをキューし、session上でXRSessionEventendという名前のイベントを発火する。

end()メソッドはセッションを手動でシャットダウンする方法を提供します。呼び出されたとき、次の手順を実行しなければなりません:

  1. promiseを、このXRSession関連realm新しいPromiseとする。

  2. ended の値がtrueであれば、reject promiseを"InvalidStateError" DOMExceptionで拒否し、promiseを返す。

  3. セッションをシャットダウンする(this)。

  4. タスクをキューして次の手順を実行する:

    1. セッションのシャットダウンに関連するプラットフォーム固有の手順が完了するまで待機する。

    2. resolve promise

  5. promiseを返す。

XRSessionは、アクティブレンダーステート(新しいXRRenderState)と、保留レンダーステート(初期値はnullXRRenderState)を持ちます。

renderState属性は、XRSessionアクティブレンダーステートを返します。

XRSessionは、最小インライン視野最大インライン視野(ラジアン単位)を持ちます。値はユーザーエージェントが決定し、0からPIの範囲でなければなりません。

XRSessionは、最小ニアクリップ面及び最大ファークリップ面(メートル単位)を持ちます。値はユーザーエージェントが決定し、非負でなければなりません。最小ニアクリップ面0.1未満が望ましく、最大ファークリップ面1000.0より大きい(または無限大)ことが望ましいです。

ユーザーエージェントがXRSession sessionおよびXRRenderStateInit newState保留レイヤーステートを更新する場合、次の手順を実行しなければなりません:

  1. newStatelayers の値がnullでない場合、NotSupportedErrorをスローする。

注記: WebXR layers moduleがこのアルゴリズムに新しい意味づけを導入します。

ユーザーエージェントがXRSession sessionrate名目フレームレートを適用したい場合、次の手順を実行しなければなりません:

  1. ratesession内部名目フレームレートと同じ場合、この手順を中止する。

  2. sessionended値がtrueの場合、この手順を中止する。

  3. session内部名目フレームレートrateに設定する。

  4. XRSessionEvent イベント名frameratechangesessionに発火する。

updateTargetFrameRate(rate) メソッドはXRSessionターゲットフレームレートrateを伝えます。

このメソッドが呼び出されたとき、ユーザーエージェントは次の手順を実行しなければなりません:

  1. sessionthisとする。

  2. promisesession関連realm新しいPromiseとする。

  3. session内部名目フレームレートを持たない場合、reject promiseを"InvalidStateError" DOMExceptionで拒否し、promiseを返す。

  4. sessionended値がtrueの場合、reject promiseを"InvalidStateError" DOMExceptionで拒否し、promiseを返す。

  5. ratesupportedFrameRatesに含まれていない場合、reject promiseを"TypeError" DOMExceptionで拒否し、promiseを返す。

  6. session内部ターゲットフレームレートrateに設定する。

  7. タスクをキューして次の手順を実行する:

    1. XRコンポジタrateを使って新しい表示フレームレート名目フレームレートを計算してもよい。

    2. newrateを新しい名目フレームレートとする。

    3. タスクをキューして次の手順を実行する:

      1. XRSystem名目フレームレートnewrateに更新するアクションが反映されるまで待機する。

      2. 名目フレームレートを適用する(newrate, session)。

      3. resolve promise

  8. promiseを返す。

XRコンポジタが何らかの理由(例:"visible-blurred"イベント中)で名目フレームレートを変更した場合、原因となったイベントが終了したら内部ターゲットフレームレートを使用するべきです。

updateRenderState(newState) メソッドは、アクティブレンダーステートの更新をキューし、次のフレームで適用します。このメソッドに渡されたXRRenderStateInit newStateの未設定フィールドは変更されません。

このメソッドが呼び出されたとき、ユーザーエージェントは次の手順を実行しなければなりません:

  1. sessionthisとする。

  2. sessionended値がtrueの場合、InvalidStateErrorをスローし、この手順を中止する。

  3. newStatebaseLayersession以外のXRSessionで作成された場合、InvalidStateErrorをスローし、この手順を中止する。

  4. newStateinlineVerticalFieldOfView が設定されており、かつsession没入型セッションの場合、InvalidStateErrorをスローし、この手順を中止する。

  5. newStatedepthNeardepthFarinlineVerticalFieldOfViewbaseLayerlayers のいずれも設定されていなければ、この手順を中止する。

  6. 保留レイヤーステートを更新session, newState)。

  7. activeStatesessionアクティブレンダーステートとする。

  8. session保留レンダーステートnullの場合、activeStateのコピーで設定する。

  9. newStatepassthroughFullyObscured が設定されていれば、session保留レンダーステートpassthroughFullyObscurednewStateの同名属性で設定する。

  10. newStatedepthNear が設定されていれば、session保留レンダーステートdepthNearnewStateの同名属性で設定する。

  11. newStatedepthFar が設定されていれば、session保留レンダーステートdepthFarnewStateの同名属性で設定する。

  12. newStateinlineVerticalFieldOfView が設定されていれば、session保留レンダーステートinlineVerticalFieldOfViewnewStateの同名属性で設定する。

  13. newStatebaseLayer が設定されていれば、session保留レンダーステートbaseLayernewStateの同名属性で設定する。

要求された場合、XRSession sessionは、次の手順を実行して保留中のレンダーステートを適用しなければなりません:

  1. activeStatesessionアクティブレンダーステートとする。

  2. newStatesession保留レンダーステートとする。

  3. session保留レンダーステートnullに設定する。

  4. oldBaseLayeractiveStatebaseLayerとする。

  5. oldLayersactiveStatelayersとする。

  6. タスクをキューして、次の手順を実行する:

    1. activeStatenewStateに設定する。

    2. oldBaseLayeractiveStatebaseLayerと等しくない、またはoldLayersactiveStatelayersと等しくない、またはいずれかのレイヤーの寸法が変更された場合、ビューポートを更新する(session用)。

    3. activeStateinlineVerticalFieldOfViewsession最小インライン視野より小さい場合、activeStateinlineVerticalFieldOfViewsession最小インライン視野に設定する。

    4. activeStateinlineVerticalFieldOfViewsession最大インライン視野より大きい場合、activeStateinlineVerticalFieldOfViewsession最大インライン視野に設定する。

    5. activeStatedepthNearsession最小ニアクリップ面より小さい場合、activeStatedepthNearsession最小ニアクリップ面に設定する。

    6. activeStatedepthFarsession最大ファークリップ面より大きい場合、activeStatedepthFarsession最大ファークリップ面に設定する。

    7. baseLayeractiveStatebaseLayerとする。

    8. activeStatecomposition enabledおよびoutput canvasを以下のように設定する:

      sessionmode"inline"であり、baseLayerXRWebGLLayerのインスタンスでcomposition enabledfalseの場合:

      activeStatecomposition enabledブール値をfalseに設定する。

      activeStateoutput canvasbaseLayercontextcanvasに設定する。

      それ以外の場合:

      activeStatecomposition enabledブール値をtrueに設定する。

      activeStateoutput canvasnullに設定する。

requestReferenceSpace(type) メソッドは、可能であれば指定されたtypeXRReferenceSpace を構築します。

このメソッドが呼び出されたとき、ユーザーエージェントは次の手順を実行しなければなりません:

  1. promiseを、このXRSession関連realm新しいPromiseとする。

  2. 次の手順を並列で実行する:

    1. reference space is supportedtype, session)の結果がfalseの場合は、タスクをキューしてreject promiseNotSupportedErrorで拒否し、この手順を中止する。

    2. type型のリファレンススペースをトラッキングするために必要なプラットフォームリソースをセットアップする。

      ユーザーエージェントは、このようなリファレンススペースのトラッキングが確立されるのを待たずにrequestReferenceSpace()を解決してよい。 セッションが最初にトラッキング確立を試みている間は、getViewerPose()nullを返してもよいし、コンテンツはこの時間をスプラッシュ画面等の表示に利用できる。type"bounded-floor"で、境界がまだ確立されていない場合、ユーザーエージェントは最初は小さなエリアを境界とし、境界が確定したらresetイベントで通知してもよい。
    3. タスクをキューして次の手順を実行する:

    4. リファレンススペースを作成し、referenceSpaceとし、typesessionを設定する。

    5. resolve promisereferenceSpaceで解決する。

  3. promiseを返す。

XRSessionは、アクティブなXR入力ソースのリストリストXRInputSource))およびアクティブなXRトラッキングソースのリストリストXRInputSource))を持ち、どちらも初期状態は空のリストでなければなりません。

XRSessionは、初期化時に設定されるXRデバイスXRデバイス)を持ちます。

inputSources属性は、XRSessionアクティブなXR入力ソースのリストを返します。

trackedSources属性は、XRSessionアクティブなXRトラッキングソースのリストを返します。

ユーザーエージェントは、XRデバイスに関連付けられたすべてのXR入力ソースを監視し、XR入力ソースが追加・削除・変更されたことを検知しなければなりません。

XRSessionは、初期値falsepromise resolvedフラグを持ちます。

注記: このフラグは、ユーザーコードが実際にイベントリスナーをアタッチできるようになるまで入力ソース追加入力ソース削除入力ソース変更アルゴリズムを実行しないためのものです。実装によっては、セッション解決後に入力ソースの監視を開始するだけでこのフラグは不要な場合もあります。

XRSession sessionに対して新しいXR入力ソースが利用可能になる場合、ユーザーエージェントは次の手順を実行しなければなりません:

  1. sessionpromise resolvedフラグがセットされていなければ、この手順を中止する。

  2. added primary sourcesを新しいリストとする。

  3. added tracked sourcesを新しいリストとする。

  4. 各新しいXR入力ソースについて:

    1. inputSourceを、このXRSession関連realm新しいXRInputSourceとし、次の分岐を行う:

      inputSourceプライマリ入力ソースの場合:

      inputSourceadded primary sourcesに追加する。

      それ以外の場合:

      inputSourceadded tracked sourcesに追加する。

  5. タスクをキューして、次の手順を実行する:

    1. 拡張sessionアクティブなXR入力ソースのリストadded primary sourcesを追加する。

    2. added primary sourcesが空でない場合、XRInputSourcesChangeEventイベント名inputsourceschangeを、sessionaddedとしてadded primary sourcesを指定して発火する。

    3. 拡張sessionアクティブなXRトラッキングソースのリストadded tracked sourcesを追加する。

    4. added tracked sourcesが空でない場合、XRInputSourcesChangeEventイベント名trackedsourceschangeを、sessionaddedとしてadded tracked sourcesを指定して発火する。

これまでに追加されたXR入力ソースが利用できなくなった場合XRSession sessionについて、ユーザーエージェントは次の手順を実行しなければなりません:

  1. sessionpromise resolvedフラグが設定されていなければ、この手順を中止する。

  2. removed primary sourcesを新しいリストとする。

  3. removed tracked sourcesを新しいリストとする。

  4. 利用できなくなった各XR入力ソースについて:

    1. inputSourceを、そのXR入力ソースに関連付けられたsessionアクティブなXR入力ソースのリスト内のXRInputSourceとし、次の分岐を行う:

      inputSourceプライマリ入力ソースの場合:

      inputSourceremoved primary sourcesに追加する。

      それ以外の場合:

      inputSourceremoved tracked sourcesに追加する。

  5. タスクをキューして、以下の手順を実行する:

    1. 削除で、removed primary sources内の各XRInputSourcesessionアクティブなXR入力ソースのリストから削除する。

    2. removed primary sourcesが空でなければ、XRInputSourcesChangeEventイベント名inputsourceschangesessionに対してremovedremoved primary sourcesを設定して発火する。

    3. 削除で、removed tracked sources内の各XRInputSourcesessionアクティブなXRトラッキングソースのリストから削除する。

    4. removed tracked sourcesが空でなければ、XRInputSourcesChangeEventイベント名trackedsourceschangesessionに対してremovedremoved tracked sourcesを設定して発火する。

注記: ユーザーエージェントは、入力ソースが一時的に位置・姿勢トラッキングを両方とも失ったとき、このイベントを発火してもよいです。これは物理的なハンドヘルドコントローラー入力ソースにのみ推奨されます。トラッキングハンド入力ソースでは頻繁に発生するため、このイベントを発火するのは推奨されません。また、トラッカーオブジェクト入力ソースの場合も、アプリケーションが識別性を維持しにくくなるため推奨されません。

handednesstargetRayModeprofilesgripSpaceの有無、 またはプライマリ入力ソーストラッキング入力ソースかのステータスが XR入力ソースで変化した場合XRSession sessionについて、ユーザーエージェントは次の手順を実行しなければなりません:

  1. sessionpromise resolvedフラグが設定されていなければ、この手順を中止する。

  2. added primary sourcesを新しいリストとする。

  3. removed primary sourcesを新しいリストとする。

  4. added tracked sourcesを新しいリストとする。

  5. removed tracked sourcesを新しいリストとする。

  6. 変更された各XR入力ソースについて:

    1. oldInputSourceを、そのXR入力ソースに以前関連付けられていたsessionアクティブなXR入力ソースのリスト内のXRInputSourceとし、次の分岐を行う:

      oldInputSourceプライマリ入力ソースであるか、またはその状態がプライマリ入力ソースからトラッキング入力ソースに変化した場合:

      oldInputSourceremoved primary sourcesに追加する。

      それ以外の場合:

      oldInputSourceremoved tracked sourcesに追加する。

    2. newInputSourceを、session関連realm新しいXRInputSourceとし、次の分岐を行う:

      newInputSourceプライマリ入力ソースであるか、またはその状態がトラッキング入力ソースからプライマリ入力ソースに変化した場合:

      newInputSourceadded primary sourcesに追加する。

      それ以外の場合:

      newInputSourceadded tracked sourcesに追加する。

  7. タスクをキューして、以下の手順を実行する:

    1. 削除で、removed primary sources内のXRInputSourcesessionアクティブなXR入力ソースのリストから削除する。

    2. 拡張sessionアクティブなXR入力ソースのリストadded primary sourcesを追加する。

    3. added primary sourcesまたはremoved primary sourcesが空でなければ、XRInputSourcesChangeEventイベント名inputsourceschangesessionに対してaddedadded primary sourcesremovedremoved primary sourcesを設定して発火する。

    4. 削除で、removed tracked sources内のXRInputSourcesessionアクティブなXRトラッキングソースのリストから削除する。

    5. 拡張sessionアクティブなXR入力ソースのリストadded tracked sourcesを追加する。

    6. added tracked sourcesまたはremoved tracked sourcesが空でなければ、XRInputSourcesChangeEventイベント名trackedsourceschangesessionに対してaddedadded tracked sourcesremovedremoved tracked sourcesを設定して発火する。

XRSessionごとにvisibility state値(enum)がある。インラインセッションの場合、visibility stateDocumentvisibilityStateを反映しなければならない。没入型セッションの場合、visibility stateは次のいずれか、そのセッション状態に最も合致する値に設定しなければならない。

visibilityState属性は、XRSessionvisibility stateを返します。onvisibilitychange属性は、イベントハンドラーIDL属性であり、visibilitychange イベントタイプ用です。

visibility stateは、XRアニメーションフレームの処理中以外の任意のタイミングでユーザーエージェントにより変更されてもよく、可能な場合ユーザーエージェントはXRプラットフォームを監視してセッションの可視性が外部要因で変化した場合にvisibility stateを更新すべきです。

注記: XRSessionvisibility stateは、必ずしもHTMLドキュメントの可視性を意味するものではありません。システム構成によっては、イマーシブセッションがアクティブな間もページが引き続き表示される場合があります。(例えば、PCに接続されたヘッドセットでは、ヘッドセットでイマーシブセッションのコンテンツが表示されている間も、モニター上にページが表示され続けることがあります。)開発者はページの可視性の判定には引き続きPage Visibilityを利用してください。

注記: XRSessionvisibility stateは、没入型セッションがアクティブな間も2Dコンテンツが表示されているテザードセッションでマウス動作には影響・制限を与えません。マウスの挙動をより厳密に制御したい場合は[pointerlock] APIの利用を検討してください。

XRSystemでは、フレームレートを表す定義がいくつかあります:

XRSessionターゲットフレームレートとなる内部ターゲットフレームレートを持つ場合があります。

XRSession名目フレームレートとなる内部名目フレームレートを持つ場合があります。実効フレームレート名目フレームレートより低い場合、XRコンポジタがリプロジェクション等で体験を改善する場合があります。これはオプションであり、inlineセッションでは存在してはなりません。

frameRate属性は内部名目フレームレートを反映します。XRSession内部名目フレームレートを持たない場合はnullを返します。

onframeratechange属性は、イベントハンドラーIDL属性であり、frameratechange イベントタイプ用です。XRSession名目フレームレートが何らかの理由で変更された場合、新しい名目フレームレートとともに名目フレームレートを適用しなければなりません。

supportedFrameRates属性は、サポートされるターゲットフレームレート値のリストを返します。この属性はオプションであり、inlineセッションやフレームレートの制御を著者に許可しないXRSystemでは存在してはなりません。XRSessionsupportedFrameRates属性をサポートする場合、frameRateもサポートしなければなりません。

XRSessionごとに、型XRReferenceSpace"viewer"かつ単位変換origin offsetをもつビューアリファレンススペースがある。

XRSessionごとにリストviewに対応したビューリストがあり、XRデバイスが提供するビューに対応します。XRSessionrenderStatecomposition enabledブール値がfalseの場合、ビューリストは単一のviewのみを含まなければなりません。ビューリストXRSession中は不変であり、セッション中に現れる可能性のあるすべてのview(初期状態でactiveでない副ビューを含む)を含まなければなりません。

onend属性は、イベントハンドラーIDL属性であり、end イベントタイプ用です。

oninputsourceschange属性は、イベントハンドラーIDL属性であり、inputsourceschange イベントタイプ用です。

onselectstart属性は、イベントハンドラーIDL属性であり、selectstart イベントタイプ用です。

onselectend属性は、イベントハンドラーIDL属性であり、selectend イベントタイプ用です。

onselect属性は、イベントハンドラーIDL属性であり、select イベントタイプ用です。

onsqueezestart属性は、イベントハンドラーIDL属性であり、squeezestart イベントタイプ用です。

onsqueezeend属性は、イベントハンドラーIDL属性であり、squeezeend イベントタイプ用です。

onsqueeze属性は、イベントハンドラーIDL属性であり、squeeze イベントタイプ用です。

4.2. XRRenderState

XRRenderState は、XRSession の出力がどのように合成されるかに影響する、設定可能な値のセットを表します。ある XRSessionアクティブレンダーステート はフレームの境界間のみ変更でき、updateRenderState() を使って更新をキューできます。

dictionary XRRenderStateInit {
  double depthNear;
  double depthFar;
  boolean passthroughFullyObscured;
  double inlineVerticalFieldOfView;
  XRWebGLLayer? baseLayer;
  sequence<XRLayer>? layers;
};

[SecureContext, Exposed=Window] interface XRRenderState {
  readonly attribute double depthNear;
  readonly attribute double depthFar;
  readonly attribute boolean? passthroughFullyObscured;
  readonly attribute double? inlineVerticalFieldOfView;
  readonly attribute XRWebGLLayer? baseLayer;
};

XRRenderState出力キャンバス を持ちます。これは HTMLCanvasElement であり、初期値は null です。出力キャンバス は、"inline" XRSession の描画コンテンツを表示するDOM要素です。

XRRenderStatecomposition enabled ブール値を持ち、初期値は true です。XRRenderStatecomposition enabled の場合、APIが提供するサーフェスに対してレンダリングコマンドが実行され、その結果が XRコンポジタ によって表示されます。もし "inline" XRSession で直接 出力キャンバス に描画される場合、その XRRenderStatecomposition enabled フラグは false でなければなりません。

注記: この段階では XRRenderStatecomposition enabledfalse の場合にのみ 出力キャンバス を持ちますが、将来の仕様ではミラーやレイヤー合成など、composition を要する高度な用途のため 出力キャンバス を設定するメソッドが導入される可能性があります。

XRRenderState オブジェクトが XRSession session のために作成されるとき、ユーザーエージェントは次の手順で レンダーステートを初期化 しなければなりません:

  1. statesession関連realm新しい XRRenderState オブジェクトとする。

  2. statedepthNear0.1 に初期化する。

  3. statedepthFar1000.0 に初期化する。

  4. statepassthroughFullyObscuredfalse に初期化する。

  5. stateinlineVerticalFieldOfView を以下のように初期化する:

    sessionインラインセッション の場合:

    stateinlineVerticalFieldOfViewPI * 0.5 に初期化する。

    それ以外の場合:

    stateinlineVerticalFieldOfViewnull に初期化する。

  6. statebaseLayernull に初期化する。

depthNear 属性は、viewer からのニアクリップ面までの距離(メートル)を定義します。depthFar 属性は、viewer からのファークリップ面までの距離(メートル)を定義します。

depthNeardepthFarprojectionMatrixXRView)の計算に使われます。描画時に projectionMatrix が使われるとき、viewer からの距離が depthNear 以上 depthFar 以下でない限りジオメトリは描画されません。また XRWebGLLayer のデプスバッファ値の解釈にも影響します。depthNeardepthFar より大きくても構いません。

注記: 通常パースペクティブ投影行列を構築する際、開発者は視錐台とニア・ファークリップ面を指定します。没入型XRデバイス への表示時は、正しい視錐台は光学系やディスプレイ、カメラ等の組み合わせで決まりますが、クリップ面の値はレンダリングするコンテンツの種類によって適切な値が変わるため、アプリケーション側で変更できます。

passthroughFullyObscured 属性は、著者がビューポート全体を仮想コンテンツで完全に覆う意図があることを XRSystem に伝えるヒントです。ビューポートが不透明ピクセルで覆われなくなったら、このフラグを false に戻すべきです。

注記: XRSystem はこれをヒントに一時的にパススルーを無効化することがあります。シースルー光学デバイスではユーザーは実環境を見続けるため、このフラグに効果はありません。

inlineVerticalFieldOfView 属性は、"inline" XRSession の投影行列計算時に使われるデフォルトの縦視野(ラジアン単位)を定義します。投影行列の計算では 出力キャンバス のアスペクト比も考慮されます。この値は 没入型セッション では必ず null でなければなりません。

baseLayer 属性は、XRコンポジタ が画像を取得する XRWebGLLayer を定義します。

4.3. アニメーションフレーム

XRSessionXRデバイスのトラッキング状態に関する情報を提供する主な方法は、XRSession インスタンスでrequestAnimationFrame() を呼び出してスケジュールされたコールバックを通じて行われます。

callback XRFrameRequestCallback = undefined (DOMHighResTimeStamp time, XRFrame frame);

XRFrameRequestCallback オブジェクトは、初期値falsecancelledブール値を持ちます。

XRSessionは、 初期状態で空のアニメーションフレームコールバックのリスト、 同じく空の実行中アニメーションフレームコールバックのリスト、 さらに初期値0のアニメーションフレームコールバック識別子(数値)を持ちます。

requestAnimationFrame(callback) メソッドは、ユーザーエージェントが次にデバイス用のアニメーションフレームを実行したいときにcallbackが実行されるようキューします。

このメソッドが呼び出されたとき、ユーザーエージェントは次の手順を実行しなければなりません:

  1. sessionthisとする。

  2. sessionended値がtrueの場合、0を返してこの手順を中止する。

  3. sessionアニメーションフレームコールバック識別子を1増やす。

  4. callbackを、現在のアニメーションフレームコールバック識別子の値と関連付けてsessionアニメーションフレームコールバックのリストに追加する。

  5. sessionアニメーションフレームコールバック識別子の現在値を返す。

cancelAnimationFrame(handle) メソッドは、アニメーションフレームコールバック識別子handleで指定された既存のアニメーションフレームコールバックをキャンセルします。

このメソッドが呼び出されたとき、ユーザーエージェントは次の手順を実行しなければなりません:

  1. sessionthisとする。

  2. sessionanimation frame callbacks のリストまたは session現在実行中の animation frame callbacks のリストの中で、値handleに関連付けられたエントリを探す。

  3. そのようなエントリが存在する場合、そのcancelledブール値をtrueに設定し、sessionanimation frame callbacks のリストから削除する。

レイヤーステートを確認するには、renderState stateについて、ユーザーエージェントは次の手順を実行しなければなりません:
  1. statebaseLayernullであればfalseを返す。

  2. trueを返す。

注記: WebXR layers moduleはこのアルゴリズムに新たな意味を導入します。

フレームが描画されるべきかどうかXRSession sessionについて判定するには、ユーザーエージェントは次の手順を実行しなければなりません:
  1. sessionrenderStateレイヤーステートを確認falseならfalseを返す。

  2. sessionmode"inline"であり、 かつsessionrenderStateoutput canvasnullならfalseを返す。

  3. trueを返す。

XRSession sessionviewer状態の更新(タイムスタンプframeTime)をXRデバイスから受け取ったとき、XRアニメーションフレームを実行し、アニメーションフレームコールバックのリストが空かどうかに関わらず次の手順を必ず実行する:

  1. タスクをキューして次の手順を実行:

    1. now現在の高精度時刻とする。

    2. framesessionアニメーションフレームとする。

    3. frametimeframeTimeに設定する。

    4. framepredictedDisplayTimeframeTimeに設定する。

    5. sessionmode"inline"でない場合、 framepredictedDisplayTimeXRコンポジタがこのXRアニメーションフレームを表示する平均タイムスタンプに設定する。

    6. ビューリスト内の各viewについて、viewviewport modifiableフラグをtrueにする。

    7. 前回のXRアニメーションフレーム以降で ビューリスト内のいずれかのviewのactiveフラグが変化していたら、 ビューポートを更新する。

    8. このフレームが描画されるべき場合:

      1. session実行中アニメーションフレームコールバックのリストsessionアニメーションフレームコールバックのリストにする。

      2. sessionアニメーションフレームコールバックのリストを空リストにする。

      3. frameactiveブール値をtrueにする。

      4. フレーム更新を適用する(frame)。

      5. session実行中アニメーションフレームコールバックのリストの各entryについて、順に:

      6. entrycancelledブール値がtrueなら次のentryへ。

      7. コールバック関数を呼び出すentry, «now, frame», "report")。

      8. session実行中アニメーションフレームコールバックのリストを空リストにする。

      9. frameactiveブール値をfalseにする。

    9. session保留レンダーステートnullでなければ、保留レンダーステートを適用する。

Window インターフェイスのrequestAnimationFrame() メソッドは、アクティブなXRSession が存在するかどうかによって動作が変わることはなく、requestAnimationFrame()XRSession 上で呼び出してもWindowrequestAnimationFrame() とは相互作用しません。アクティブな没入型セッションは、ページが隠されている場合に レンダリング機会 に影響を与えることがあります。2Dブラウザビューがアクティブな没入型セッション中も可視な場合(例:テザードヘッドセット)、WindowrequestAnimationFrame()requestIdleCallback() のコールバックのタイミングは、セッションのrequestAnimationFrame() とは一致しない場合があり、ユーザーはXRコンテンツのレンダリングのためにそれに依存すべきではありません。

注記: XRSessionrequestAnimationFrame()WindowrequestAnimationFrame() でスケジュールされたコールバック中に呼び出された場合、ユーザーエージェントは開発者コンソールに警告を表示したいかもしれません。なぜならアクティブな没入型セッションレンダリング機会 に影響を与えると、これらのコールバックは発生しない保証がなく、発生しても正しいタイミングではないためです。

没入型セッションレンダリング機会を妨げる場合、WindowrequestAnimationFrame() に渡したコールバックはセッション中に処理されないことがあります。これは利用するデバイスの種類に依存し、特にモバイルやスタンドアロンデバイスのように没入コンテンツがHTMLドキュメントを完全に覆い隠す場合に発生しやすいです。そのため、開発者はWindowrequestAnimationFrame() コールバックでXRSessionrequestAnimationFrame() コールバックをスケジュールしたり、その逆をしたりしてはいけません。たとえ描画ロジックを共有していてもです。このガイダンスに従わないアプリケーションは、すべてのプラットフォームで正しく動作しない場合があります。2種類のアニメーションループを切り替えたいアプリケーションのより効果的なパターン例を以下に示します:
let xrSession = null;

function onWindowAnimationFrame(time) {
  window.requestAnimationFrame(onWindowAnimationFrame);

  // 没入セッションが一部デバイス(例: テザードヘッドセットのデスクトップなど)で実行中にも呼ばれることがあります。
  // 2つのループが並行描画しないよう、セッション終了までここでの描画をスキップします。
  if (!xrSession) {
    renderFrame(time, null);
  }
}

// windowアニメーションループはページロード直後から開始できる。
window.requestAnimationFrame(onWindowAnimationFrame);

function onXRAnimationFrame(time, xrFrame) {
  xrSession.requestAnimationFrame(onXRAnimationFrame);
  renderFrame(xrFrame.predictedDisplayTime, xrFrame);
}

function renderFrame(time, xrFrame) {
  // 共通描画処理
}

// 他のユーザー操作イベントから呼ばれると仮定。
async function startXRSession() {
  xrSession = await navigator.xr.requestSession('immersive-vr');
  xrSession.addEventListener('end', onXRSessionEnded);
  // 必要なセッションセットアップ処理
  // セッションのアニメーションループを開始
  xrSession.requestAnimationFrame(onXRAnimationFrame);
}

function onXRSessionEnded() {
  xrSession = null;
}

"inline" セッションでHTMLドキュメント描画を行う場合、特別なアニメーションループ調整は不要です。ユーザーエージェントが"inline" セッションのアニメーションループを、没入型セッションがアクティブな間は自動的に中断します。

4.4. XRコンポジタ

ユーザーエージェントは、XRコンポジタを維持しなければなりません。これはXRデバイスへの表示やフレームタイミングを担当します。コンポジタはドキュメントが作成したグラフィックスコンテキストとは独立したレンダリングコンテキストを用い、その状態は分離されなければなりません。コンポジタはページが他のページやアプリケーションの内容を破壊したり読み取ったりできないようにしなければなりません。さらに、ページのパフォーマンスとユーザーへの新しい画像表示能力を適切なフレームレートで切り離すため、コンポジタは別スレッドまたはプロセスで動作しなければなりません。コンポジタはデバイスメニューなどの追加のデバイスまたはユーザーエージェントUIを描画コンテンツ上に合成してもかまいません。

注記: この仕様の将来の拡張では、同一ページからの複数レイヤーの合成にもコンポジタを利用する可能性があります。

5. フレームループ

5.1. XRFrame

XRFrameは、XRSessionにおけるすべてのトラッキング対象オブジェクトの状態のスナップショットを表します。アプリケーションはXRSessionrequestAnimationFrame()を呼び出し、XRFrameRequestCallbackによりXRFrameを取得できます。コールバックが呼び出されると、XRFrameが引数として渡されます。selectイベントなど、トラッキング状態を伝達する必要があるイベントもXRFrameを提供します。

[SecureContext, Exposed=Window] interface XRFrame {
  [SameObject] readonly attribute XRSession session;
  readonly attribute DOMHighResTimeStamp predictedDisplayTime;

  XRViewerPose? getViewerPose(XRReferenceSpace referenceSpace);
  XRPose? getPose(XRSpace space, XRSpace baseSpace);
};

XRFrameは、初期値falseactiveブール値、および初期値falseanimationFrameブール値を持ちます。

session 属性は、このXRFrameを生成したXRSessionを返します。

没入型セッションの場合、predictedDisplayTime 属性は、このXRFrameがデバイスのディスプレイに表示されると予想される平均時刻に対応するDOMHighResTimeStampを返さなければなりません。"inline" XRSessionの場合、predictedDisplayTimeXRFrameRequestCallbackに渡されたタイムスタンプと同じ値を返さなければなりません。

predictedDisplayTime は、フレームが表示される時点でアニメーションされたXRシーンの状態を描画できるようにすることを目的としています。これは、requestAnimationFrame()のコールバックがスケジュールされた時や実行された時点ではありません。

predictedDisplayTime は、アプリケーションがレンダリングに使える残り時間を推測するためのものではありません。XRコンポジタは通常、フレーム提出後に追加処理を行う必要があります。predictedDisplayTimeまで処理できると仮定すると、XRコンポジタは提出フレームを利用できず、アプリケーションは目標フレームレートを維持できません。

XRFrameは、ある時刻におけるすべてのトラッキング対象オブジェクトの状態を表し、その時刻の状態について具体的な情報を格納または問い合わせできます。

getViewerPose(referenceSpace) メソッドは、XRFrame時刻におけるreferenceSpaceに対するviewerの姿勢をXRViewerPoseとして返します。

このメソッドが呼び出されたとき、ユーザーエージェントは次の手順を実行しなければなりません:

  1. framethisとする。

  2. sessionframesessionオブジェクトとする。

  3. frameanimationFrameブール値がfalseなら、InvalidStateErrorをスローし手順を中止する。

  4. posesession関連realm新しいXRViewerPoseオブジェクトとする。

  5. populate the posesessionviewer reference spacereferenceSpaceframeの表す時刻、force emulation = trueposeに適用する。

  6. posenullならnullを返す。

  7. xrviewsを空のリストとする。

  8. offset0 とする。

  9. activeview viewsessionlist of views から 1つずつ取り出し、以下の手順を実行する:

    1. xrviewsessionrelevant realm における新しい XRView オブジェクトとする。

    2. xrviewunderlying viewview に初期化する。

    3. xrvieweyevieweye に初期化する。

    4. xrviewindexoffset に初期化する。

    5. xrviewframeframe に初期化する。

    6. xrviewsessionsession に初期化する。

    7. xrviewreference spacereferenceSpace に初期化する。

    8. viewtransformsessionrelevant realm における view offset と等しい 新しい XRRigidTransform オブジェクトとする。

    9. xrviewtransform プロパティを、XRViewerPosetransformviewtransform transform を 乗算した結果(session の relevant realm で)に設定する。

    10. Appendxrviewxrviews に追加する。

    11. offset1 増やす。

  10. poseviewsxrviewsに設定する。

  11. poseを返す。

getPose(space, baseSpace) メソッドは、XRFrameの時刻におけるbaseSpaceに対するspaceの姿勢をXRPoseとして返します。

このメソッドが呼び出されたとき、ユーザーエージェントは次の手順を実行しなければなりません:

  1. framethisとする。

  2. poseframe関連realm新しいXRPoseオブジェクトとする。

  3. populate the posespacebaseSpaceframeの時刻でposeに適用する。

  4. poseを返す。

フレームアップデートは、XRFrameを与えて実行されるアルゴリズムであり、各XRFrameごとに実行されることを意図しています。

すべてのXRSessionフレームアップデートのリストリスト)を持ち、初期状態は空のリストです。

あるXRFrameframeに対してフレームアップデートを適用するには、ユーザーエージェントは次の手順を実行しなければなりません:

  1. framesessionフレームアップデートのリスト内の各frame updateについて、次を実行:

    1. frame updateframeで実行する。

注記: 本仕様ではフレームアップデートは定義されていませんが、他の仕様で追加される場合があります。

6. Space(空間)

WebXR Device APIのコア機能の一つは空間トラッキングを提供できることです。Spaceは、アプリケーションがトラッキングされる実体同士やユーザーの物理環境との空間的関係を解釈するためのインターフェイスです。

6.1. XRSpace

XRSpace は、物理的な位置に対応した原点を持つ仮想座標系を表します。APIから要求またはAPIに提供される空間データは、必ず特定のXRSpaceおよび特定のXRFrameで定義される時点に対する関係として表現されます。姿勢の座標値などの数値は、そのspaceの原点を基準とした座標です。このインターフェイスは意図的に不透明に設計されています。

[SecureContext, Exposed=Window] interface XRSpace : EventTarget {

};

XRSpaceは、 そのXRSpaceを作成したXRSessionに設定されるsessionを持ちます。

XRSpaceは、 空間内の位置と姿勢を表すネイティブ原点を持ちます。XRSpaceネイティブ原点XRデバイスの基盤となるトラッキングシステムによって更新される場合があり、異なるXRSpaceはそのネイティブ原点がどのようにトラッキング・更新されるかに異なる意味付けを持ちます。

XRSpaceは、 有効原点を持ち、これはXRSpace座標系の基準となります。

有効spaceからネイティブ原点空間への変換は、原点オフセットで定義されます。これは初期値が単位変換XRRigidTransformです。つまり有効原点原点オフセットネイティブ原点乗算することで得られます。

XRSpace有効原点は、他のXRSpaceの座標系内でのみ、XRPoseとして観測できます。これはXRFramegetPose()メソッドで返されます。XRSpace同士の空間関係はXRFrameごとに変化する場合があります。

populate the poseとは、XRSpacespaceを、XRSpacebaseSpaceにおいて、XRFrameframeで示される時点の、 XRPoseposeに対して、オプションでforce emulationフラグを指定して、次の手順をユーザーエージェントが実行しなければならないことを指す。

  1. frameactiveブール値がfalseなら、InvalidStateErrorをスローして中止。

  2. sessionframesessionとする。

  3. spacesessionsessionでなければ、InvalidStateErrorをスローして中止。

  4. baseSpacesessionsessionでなければ、InvalidStateErrorをスローして中止。

  5. 姿勢が報告可能かを判定し、不可ならSecurityErrorをスローして中止。

  6. sessionvisibilityState"visible-blurred"で、かつspaceまたはbaseSpaceXRInputSourceに関連付けられている場合、posenullにして中止。

  7. limitspacebaseSpace間で姿勢制限が必要かの判定結果を設定。

  8. transformposetransformとする。

  9. XRデバイスのトラッキングシステムに、frame時刻におけるspacebaseSpaceに対する姿勢の問い合わせを行い、次の分岐を実行:

    limitfalseで、トラッキングシステムがspacebaseSpaceに対する6DoFの位置が積極的にトラッキングまたは静的に既知である場合:

    transformorientationを、baseSpace座標系内でのspace有効原点の向きに設定。

    transformpositionを、baseSpace座標系内でのspace有効原点の位置に設定。

    サポートされていれば、poselinearVelocityを、baseSpace座標系に対するspace有効原点の線形速度に設定。

    サポートされていれば、poseangularVelocityを、baseSpace座標系に対するspace有効原点の角速度に設定。

    poseemulatedPositionfalseに設定。

    それ以外でlimitfalseかつ3DoFまたは6DoFだが位置が積極的にトラッキングされていない/静的に既知でない場合:

    transformorientationを、baseSpace座標系内でのspace有効原点の向きに設定。

    transformpositionを、baseSpace座標系内でのspace有効原点の位置の推定値に設定。これは首や腕モデルなどのオフセットを含む場合がある。位置推定がなければ直前の既知位置を使う。

    poselinearVelocitynullに設定。

    poseangularVelocitynullに設定。

    poseemulatedPositiontrueに設定。

    さらに、spacebaseSpaceに対する姿勢が過去に確定していて、force emulationtrueの場合:

    transformpositionを、baseSpace座標系内でのspace有効原点の直前の既知位置に設定。

    transformorientationを、baseSpace座標系内でのspace有効原点の直前の既知向きに設定。

    poselinearVelocitynullに設定。

    poseangularVelocitynullに設定。

    poseemulatedPositiontrueに設定。

    それ以外の場合:

    posenullに設定。

注記: XRPoseemulatedPositionブール値は、baseSpaceの位置がエミュレートかどうかを示すものではなく、あくまでspacebaseSpaceに対する位置評価がエミュレーションに依存しているかどうかのみを示します。例えば3DoFトラッキングのコントローラーでtargetRaySpacegripSpaceXRReferenceSpaceに対して問い合わせるとemulatedPositiontrueになりますが、targetRaySpacegripSpaceに対して問い合わせた場合、その関係は正確に分かっているはずなのでemulatedPositionfalseとなります。

6.2. XRReferenceSpace

XRReferenceSpace は、アプリケーションがユーザーの物理環境との空間的関係を確立するために利用できる、いくつかの共通XRSpaceの1つです。

XRReferenceSpace は通常、XRSessionの間は静的であることが期待されていますが、最も一般的な例外はユーザーによるセッション途中の再設定です。すべてのXRReferenceSpaceネイティブ原点は、+Xが「右」、+Yが「上」、-Zが「前方」とみなされる座標系を記述します。

enum XRReferenceSpaceType {
  "viewer",
  "local",
  "local-floor",
  "bounded-floor",
  "unbounded"
};

[SecureContext, Exposed=Window]
interface XRReferenceSpace : XRSpace {
  [NewObject] XRReferenceSpace getOffsetReferenceSpace(XRRigidTransform originOffset);

  attribute EventHandler onreset;
};

XRReferenceSpace は、typeXRReferenceSpaceType)を持ちます。

XRReferenceSpace は、通常requestReferenceSpace()を呼び出して取得されます。これは、渡されたXRReferenceSpaceTypeのenum値がサポートされている場合、XRReferenceSpace(またはその拡張インターフェイス)のインスタンスを生成します。typeはそのリファレンススペースのトラッキングの挙動を示します:

注記: 基盤プラットフォームのリファレンススペースのY軸に関する慣例は、異なるXRReferenceSpaceタイプ間でも一貫していると想定されています。つまり、複数のリファレンススペースをサポートするXRシステムでは、それらのY軸は互いに平行で同じ方向を向き、同じXRSessionの間は維持されます。ただし"viewer"は基盤プラットフォームの慣例に依存しません。"unbounded"リファレンススペースは、原点が近い場合は他のリファレンススペースとY軸を揃えるべきですが、ユーザーが大きく動いた場合はずれることがあります。

"local" リファレンススペースをサポートするデバイスは、"local-floor" リファレンススペースも(必要ならエミュレーションで)サポートしなければなりませんし、その逆も同様です。

onreset属性は、イベントハンドラーIDL属性であり、reset イベントタイプ用です。

XRReferenceSpaceXRReferenceSpaceType typeXRSession session用に要求されたとき、ユーザーエージェントは次の手順でリファレンススペースを作成しなければなりません:

  1. referenceSpaceを次のように初期化する:

    typebounded-floorの場合:

    referenceSpacesession関連realm新しいXRBoundedReferenceSpaceとする。

    それ以外の場合:

    referenceSpacesession関連realm新しいXRReferenceSpaceとする。

  2. referenceSpacetypetypeに初期化する。

  3. referenceSpacesessionsessionに初期化する。

  4. referenceSpaceを返す。

リファレンススペースがサポートされているか確認するには、与えられたリファレンススペース型typeXRSession sessionについて、次の手順を実行する:
  1. typesession許可された機能のセット含まれていない場合、falseを返す。

  2. typeviewerの場合、trueを返す。

  3. typelocalまたはlocal-floorで、session没入型セッションの場合、trueを返す。

  4. typelocalまたはlocal-floorで、XRデバイスが方位データの報告をサポートしている場合、trueを返す。

  5. typebounded-floorで、session没入型セッションの場合、境界付きリファレンススペースがサポートされているかsessionXRデバイスで判定してその結果を返す。

  6. typeunboundedで、session没入型セッションかつ、XRデバイスがユーザー近傍で無制限距離の安定トラッキングをサポートしていれば、trueを返す。

  7. falseを返す。

getOffsetReferenceSpace(originOffset) メソッドが呼び出されたとき、必ず次の手順を実行しなければなりません:
  1. baseをこのメソッドが呼ばれたXRReferenceSpaceとする。

  2. offsetSpaceを次のように初期化する:

    baseXRBoundedReferenceSpaceのインスタンスの場合:

    offsetSpacebase関連realm新しいXRBoundedReferenceSpaceとし、offsetSpaceboundsGeometrybaseboundsGeometryに設定し、各点にoriginOffsetinverseを乗算する。

    それ以外の場合:

    offsetSpacebase関連realm新しいXRReferenceSpaceとする。

  3. offsetSpacetypebasetypeに設定する。

  4. offsetSpace原点オフセットを、base原点オフセットoriginOffset乗算した結果で更新する(baseの関連realm)。

  5. offsetSpaceを返す。

注記: 一部のアプリケーションはgetOffsetReferenceSpace() を利用して、マウス・キーボード・タッチ・ゲームパッド入力によるシーンナビゲーション制御を実装することが想定されています。その場合、入力がアクティブな間は少なくとも1フレームごとにgetOffsetReferenceSpace() が頻繁に呼ばれます。したがってUAはgetOffsetReferenceSpace() による新しいXRReferenceSpace の作成を軽量な処理とするよう強く推奨されます。

6.3. XRBoundedReferenceSpace

XRBoundedReferenceSpaceXRReferenceSpace を拡張し、boundsGeometry(ユーザーの空間の事前構成境界)を含みます。

[SecureContext, Exposed=Window]
interface XRBoundedReferenceSpace : XRReferenceSpace {
  readonly attribute FrozenArray<DOMPointReadOnly> boundsGeometry;
};

XRBoundedReferenceSpace の原点は必ず床上(Y軸が床レベルで0)に配置されなければなりません。XZの位置や向きは基盤プラットフォームの慣例に基づき初期化され、通常は部屋の中央付近で論理的前方を向くことが期待されます。

注記: 他のXRプラットフォームでは、bounded-floor リファレンススペースによるトラッキングを「ルームスケール」トラッキングなどと呼ぶことがあります。XRBoundedReferenceSpace は複数部屋、床高さが不均一な場所、非常に広い空間を扱うことは想定していません。これらに対応するにはunbounded リファレンススペースを使うべきです。

XRBoundedReferenceSpace は、ユーザーが安全に移動できる範囲の境界を記述するネイティブ境界ジオメトリを持ちます。多角形境界はDOMPointReadOnly配列として与えられ、安全空間の縁にある点のループを表現します。各点は原点からのメートル単位のオフセットです。点は上から見て時計回り(Y軸負方向から見下ろし)で並べる必要があります。各点のy 値は0w 値は1でなければなりません。境界は床上から無限に上方へ広がると考えます。形状は凸でも凹でも可です。

ネイティブ境界ジオメトリ内の各点は、そのリファレンススペースのネイティブ原点から合理的な距離内に制限されなければなりません。

注記: ネイティブ境界ジオメトリの点は、すべての方向で原点から15メートル以内に制限することが推奨されます。

ネイティブ境界ジオメトリ内の各点は、フィンガープリント防止のため十分に量子化されなければならず、ユーザー安全のため量子化後の点がプラットフォーム報告境界外になってはなりません。

注記: ネイティブ境界ジオメトリの点は5cm単位で量子化することが推奨されます。

boundsGeometry属性は、 DOMPointReadOnlyの配列です。 各エントリは、XRBoundedReferenceSpaceネイティブ境界ジオメトリの各エントリに、 inverse を掛けたものと等しくなります。つまり、これは有効原点に対して XRBoundedReferenceSpace 座標で同じ境界線を提供します。

ネイティブ境界ジオメトリが一時的に利用不可な場合(XRデバイス初期化・追跡ロス長期化・事前構成空間間の移動など)、boundsGeometry は空配列を返さなければなりません。

境界付きリファレンススペースがサポートされているか確認は、次の手順を実行します:
  1. XRデバイスが境界を報告できない場合、falseを返す。

  2. XRデバイスがユーザーの物理床の高さを特定できない場合、falseを返す。

  3. trueを返す。

注記: 境界や床高さがリファレンススペース要求時点で未確定でも、デバイスがサポートしていれば境界付きリファレンススペースが返される場合があります。

注記: コンテンツはboundsGeometry外へのユーザーの移動を必須にすべきではありません。物理的に可能なら境界外にも移動でき、その場合ポリゴン外の値になりますが、これはエラーではなくページ側で丁寧に処理すべきです。

注記: 安全に関わる情報はユーザーエージェントが管理すべきなので、boundsGeometryの可視化は一般にコンテンツ側で行うべきではありません。

7. ビュー

7.1. XRViewGeometry

XRViewGeometry インターフェイスミックスインを含むオブジェクトは、ユーザーへの画像提示用ディスプレイや、現実世界の映像情報収集用センサーなどであり、ビュー幾何を持ちます。

ビュー幾何は、ビューアリファレンススペース座標系と、含有オブジェクトスクリーンスペース間の変換に使う内在パラメータ・外在パラメータセットです。

ビュー幾何には含有オブジェクト(このビュー幾何がデータを持つ物理ハードウェア)が関連付けられます。

ビュージオメトリ包含オブジェクトには、関連付けられたスクリーンスペースが存在します。これは、この包含オブジェクトがデータを読み取るか、またはデータを描画する2D平面として記述されます。

ビュー幾何にはビューオフセットXRRigidTransform、含有オブジェクトのビューアリファレンススペースでの位置・向き)が関連付けられます。

注記: ビューオフセットに制約はなく、ビューごとに向きも異なり得ます。HMDで目のディスプレイが角度付きで配置されていたり、CAVEレンダリングのような極端なケースでも起こり得ます。このためzソートやカリング等を目ごとに行う必要がある場合があります。

ビュー幾何には投影行列(基盤XRデバイスが与える含有オブジェクト描画時の行列)も関係付けられます。この投影行列は、単純なフラスタムで表せないシアー変換などを含む場合もあります。

注記: この行列の逆行列は、スクリーンスペース上のピクセルを座標系(含有オブジェクトが原点)へ戻すのに使えます。

[SecureContext, Exposed=Window] interface mixin XRViewGeometry {
  readonly attribute Float32Array projectionMatrix;
  [SameObject] readonly attribute XRRigidTransform transform;
};

XRViewGeometry には、その含有オブジェクト投影行列を格納する、初期値null内部投影行列が関連付けられています。

注記: transform は多くのレンダリングライブラリでカメラオブジェクトの配置に利用できます。従来のビュー行列が必要なら transform.inverse.matrix で得られます。

projectionMatrix属性は、基盤ビュー幾何投影行列です。アプリケーションはこの行列を改変・分解せずそのまま使うことが強く推奨されます。これを用いずに描画すると、フレームが歪んだり不整合を起こし、ユーザーに不快感を与えることがあります。この属性は投影行列の取得で計算されなければなりません。

transform属性はこのオブジェクトのXRRigidTransformであり、取得元XRReferenceSpaceでの位置・向きを表します。

XRViewGeometry view geometryについて投影行列の取得を行うには:

  1. もしview geometryinternal projection matrixnullでない場合、以下の手順を実行する:

    1. internal projection matrixに対して操作IsDetachedBuffer を行い、その結果がfalseであれば、view geometryinternal projection matrixを返す。

  2. view geometryinternal projection matrixに、 新しい matrixview geometry関連realmで、view geometryprojection matrixと等しいもの)を設定する。

  3. view geometryinternal projection matrixを返す。

7.2. XRView

XRViewは、あるフレームのXRシーンにおける1つのビューを記述します。

ビューは、XRデバイスがユーザーに画像を提示するために用いるディスプレイまたはその一部に対応します。ビューは、視野・アイオフセット・その他の光学特性など、ビューの物理的出力特性に正確に合わせて描画するために必要な情報を取得するために使われます。ビューはユーザーの視野の重複領域もカバーし得ます。どのXRデバイスが何個のビューを使うかや順序について保証はなく、XRSessionの期間中もビュー数は一定である必要はありません。

ビューには、どちらの目に表示するかを示すeyeXREye)が関連付けられます。ビュー自体が目に紐付かない場合(単眼ディスプレイ等)は、この値は"none"でなければなりません。

ビューには、XRSessionのライフサイクル中に変化しうるactiveフラグがあります。プライマリビューは常にactiveフラグがtrueでなければなりません。

注記: 多くのHMDは左目・右目用の2つのビューを要求しますが、マジックウィンドウデバイスは1つのみの場合が多いです。ただしアプリケーションはビュー構成を仮定すべきではありません。例えばマジックウィンドウデバイスでもステレオ出力対応時は2ビューを要求し、パフォーマンス理由で1ビューに戻ることもあります。同様に、HMDも広視野や異なるピクセル密度表示のため2つ以上のビューを要求する場合があります。

ビューには、viewport modifiableフラグ(この時点でrequestViewportScale()でビューポートスケール変更可能か)があり、アニメーションフレーム開始時にtruegetViewport()呼び出しでfalseになります。

ビューには、システムが動的ビューポートスケーリングをサポートする場合にrequestViewportScale()で変更できるリクエスト済みスケール値requested viewport scaleがあります。初期値は1.0。

ビューには、システム内部で現在使用中のスケール値current viewport scaleがあります。初期値は1.0。getViewport()でリクエスト済みスケールに更新されます。

ビューには、reference space(このビューgetViewerPose()で取得した際のXRReferenceSpace)があります。

注記: 動的ビューポートスケーリングでは、フレーム単位でスケールを効率的に切り替えられます。描画の正確性のためアプリケーションとXRシステムがアクティブなビューポートで合意している必要があります。アプリケーションは1フレーム中に複数回requestViewportScale()を呼べますが、実際に反映されるのはgetViewport()呼び出し時です。最初のgetViewport呼び出しでそのフレームのスケールが反映され、それ以降はロックされ、次フレームのデフォルトにもなります。recommendedViewportScale属性で推奨値が得られる場合もあります。

enum XREye {
  "none",
  "left",
  "right"
};

[SecureContext, Exposed=Window] interface XRView {
  readonly attribute XREye eye;
  readonly attribute unsigned long index;
  readonly attribute double? recommendedViewportScale;

  undefined requestViewportScale(double? scale);
};

XRView includes XRViewGeometry;

transformは、そのreference spaceで与えられます。

eye属性は、基礎となるeyeを示します。これはプリレンダーステレオコンテンツで左右の内容を正しい目に表示するために重要です。

index 属性は、この XRViewviews 配列内で getViewerPose() により返される際のオフセットを示します。

オプションのrecommendedViewportScale属性は、UAが推奨するビューポートスケール値です。アプリケーションはこれをrequestViewportScale()に使えます。システムが推奨値決定メソッドを持たない場合はnull。nullでない場合は0.0より大きく1.0以下の数値かつ量子化済みでなければなりません。

注記: 推奨ビューポートスケールは、短い候補値リストへの丸めやヒステリシスを使って量子化し、境界付近で即座に変化しないようにするのが推奨されます(急激なスケール振動は不快感を与えるため)。

XRViewには、それを生成したsessionXRSession)があります。

XRViewには、それを生成したframeXRFrame)があります。

XRViewには、表現する基礎となるunderlying viewview)があります。

requestViewportScale(scale)メソッドは、このビューポートのrequested viewport scaleを指定値に設定するようユーザーエージェントに要求します。

このメソッドがXRViewxrviewで呼び出された場合、ユーザーエージェントは次の手順を実行します:

  1. scaleがnullまたはundefinedなら中止。

  2. scaleが0.0以下なら中止。

  3. scaleが1.0より大きい場合、scaleを1.0にする。

  4. viewxrviewunderlying viewとする。

  5. viewrequested viewport scale値をscaleに設定する。

注記: nullやundefinedのスケール値を無視することで、推奨スケール未対応システムでもview.requestViewportScale(view.recommendedViewportScale)を安全に呼べます。

いずれかのactiveフラグがビューリスト内で変化した場合、XRSessionsessionについて次の手順でビューポートを更新できます:

  1. layerrenderStatebaseLayerとする。

  2. layernullなら中止。

  3. layerビューポートオブジェクトリストを空リストに設定。

  4. ビューリスト内の各activeビューviewについて:

    1. viewportfull-sized viewportリストからスケール済みビューポートの取得で得る。

    2. Appendviewportlayerビューポートオブジェクトリストに追加。

XRViewviewXRSessionsessionについてスケール済みビューポートの取得を行うには:

  1. glFullSizedViewportviewに紐付くWebGL viewport(full-sized viewportリスト)とする。

  2. scaleviewcurrent viewport scaleとする。

  3. ユーザーエージェントはscaleに最小スケールファクタを適用してもよい。

  4. glViewportを新しいWebGL viewportとする。

  5. glViewportwidthを、glFullSizedViewportwidth×scale以下の整数値に設定。

  6. glViewportwidthが1未満なら1に設定。

  7. glViewportheightを、glFullSizedViewportheight×scale以下の整数値に設定。

  8. glViewportheightが1未満なら1に設定。

  9. glViewportxを、glFullSizedViewportx以上、かつglFullSizedViewportx+glFullSizedViewportwidth-glViewportwidth以下の整数値に設定。

  10. glViewportyを、glFullSizedViewporty以上、かつglFullSizedViewporty+glFullSizedViewportheight-glViewportheight以下の整数値に設定。

  11. viewportsession新しいXRViewportとする(関連realm)。

  12. viewportxglViewportxに設定。

  13. viewportyglViewportyに設定。

  14. viewportwidthglViewportwidthに設定。

  15. viewportheightglViewportheightに設定。

  16. viewportを返す。

注記: 幅/高さの計算はUAに委ねられています。単純な切り捨ても有効ですが、パワーオブツー境界に合わせる等、範囲内で調整しても構いません。スケール済みビューポートはfull-sized viewport内に完全に収まる必要がありますが、配置はUA裁量です。計算はセッション内で同じ入力に対し必ず同じ結果を返さなければなりません。

7.3. プライマリビューとセカンダリビュー

ビューは、没入型体験において描画が必須な場合、プライマリビューとなります。プライマリビューは、XRSessionの期間中常にactiveでなければなりません。

ビューは、コンテンツがそれに描画しなくても没入型体験が成立する場合、セカンダリビューとなります。これらのビューにコンテンツが描画しない場合、ユーザーエージェントはリプロジェクション等で再構成できる場合があります。セカンダリビューは、"secondary-views"機能が有効でない限り、activeであってはなりません。

プライマリビューの例としては、ハンドヘルドARセッションの主モノビュー、ヘッドマウントAR/VRの左右の主ステレオビュー、CAVEセッションのすべての壁ビューなどがあります。

セカンダリビューの例としては、ビデオキャプチャ用の一人称オブザーバービューや、1つの目に2つの異なる解像度・視野のビューがある「クワッドビュー」などがあります。

コンテンツは任意の数のビューが存在しうることを想定して書くべきですが、実際には多くのコンテンツがviews 配列の内容を誤って仮定し、2つを超えるビューで動作しなくなると予想されます。

ユーザーエージェントはリプロジェクションなどの仕組みでセカンダリビューへの描画を代替できる場合があるため、コンテンツがこれらのセカンダリビューを自力で扱うつもりか、そうでないかを区別できることが望ましいです。

このため、セカンダリビューを公開するユーザーエージェントは、ヒントとして"secondary-views"フィーチャーディスクリプタをサポートしなければなりません。この機能を有効化したコンテンツは次を想定してください:

"secondary-views"が有効な場合、ユーザーエージェントは必要に応じて、デバイスがサポートするセカンダリビューXRSessionに公開してもかまいません。この場合、ユーザーエージェントはリプロジェクションによるセカンダリビュー再構成を行わず、コンテンツ側の描画に従う必要があります。

注記: 最大限の互換性のため、optionalFeatures で"secondary-views"を有効化することを推奨します。

セカンダリビューが低いフレームレートで動作する場合、XRSessionは次の対応を取ることがあります:

7.4. XRViewport

XRViewport オブジェクトはグラフィックスサーフェス上のビューポート(矩形領域)を記述します。

[SecureContext, Exposed=Window] interface XRViewport {
  readonly attribute long x;
  readonly attribute long y;
  readonly attribute long width;
  readonly attribute long height;
};

x属性とy属性はサーフェス原点からのオフセットを、width属性とheight属性はビューポートの矩形サイズを定義します。

ビューポート値の解釈は利用するグラフィックスAPIの慣例に依存します:

次のコードは、XRViewすべてについて、XRViewerPoseから取得し、各XRWebGLLayerXRViewportを取得して、適切なWebGL viewportで描画する例です。
xrSession.requestAnimationFrame((time, xrFrame) => {
  const viewer = xrFrame.getViewerPose(xrReferenceSpace);

  gl.bindFramebuffer(xrWebGLLayer.framebuffer);
  for (xrView of viewer.views) {
    let xrViewport = xrWebGLLayer.getViewport(xrView);
    gl.viewport(xrViewport.x, xrViewport.y, xrViewport.width, xrViewport.height);

    // WebGL draw calls will now be rendered into the appropriate viewport.
  }
});

8. 幾何プリミティブ

8.1. 行列

WebXRは各種変換を行列の形式で提供します。WebXRではWebGLの慣例に従い、4x4行列は16要素のFloat32Array(カラムメジャー)として渡され、列ベクトルに対して左側から前置乗算で適用されます。そのままWebGLのuniformMatrix4fv関数に渡したり、DOMMatrix相当の生成や、外部の数値ライブラリでも利用可能です。

WebXR Device APIが返す行列は以下のような16要素Float32Arrayです:
[a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15]

この行列をDOMPointReadOnly型の列ベクトルに適用すると:

{x:X, y:Y, z:Z, w:1}

次のような結果になります:

a0 a4 a8  a12  *  X  =  a0 * X + a4 * Y +  a8 * Z + a12
a1 a5 a9  a13     Y     a1 * X + a5 * Y +  a9 * Z + a13
a2 a6 a10 a14     Z     a2 * X + a6 * Y + a10 * Z + a14
a3 a7 a11 a15     1     a3 * X + a7 * Y + a11 * Z + a15

8.2. 正規化

ベクトルやクォータニオンを正規化(各成分の合成ノルムを1.0にする)するアルゴリズムがいくつかあります。

normalizeを成分リストに対し行うには、UAは次の手順を実行しなければなりません:

  1. 各成分の2乗和の平方根をlengthとする。

  2. length0ならInvalidStateErrorをスローし中止。

  3. 各成分をlengthで割り、成分値を設定する。

8.3. XRRigidTransform

XRRigidTransform は、positionorientationで記述される変換です。 XRRigidTransform を解釈する際は、orientation が常にpositionより先に適用されます。

XRRigidTransform には行列である内部行列を持ちます。

[SecureContext, Exposed=Window]
interface XRRigidTransform {
  constructor(optional DOMPointInit position = {}, optional DOMPointInit orientation = {});
  [SameObject] readonly attribute DOMPointReadOnly position;
  [SameObject] readonly attribute DOMPointReadOnly orientation;
  readonly attribute Float32Array matrix;
  [SameObject] readonly attribute XRRigidTransform inverse;
};

XRRigidTransform(position, orientation) コンストラクタが呼び出されたとき、次の手順を実行しなければなりません:

  1. transform新しいXRRigidTransformcurrent realm)とする。

  2. transformposition新しいDOMPointReadOnly(current realm)とする。

  3. positionw 値が1.0でなければ、TypeErrorをスローし中止。

  4. positionorientationのいずれかの値がNaNや非有限値(無限大等)なら、TypeErrorをスローし中止。

  5. transformpositionxpositionのx辞書メンバー、 yをyメンバー、 zをzメンバー、 wをwメンバーに設定。

  6. transformorientation新しいDOMPointReadOnly(current realm)とする。

  7. transformorientationxorientationのxメンバー、 yをyメンバー、 zをzメンバー、 wをwメンバーに設定。

  8. transform内部行列nullに設定。

  9. transformorientationxyzw 成分を正規化する。

  10. transformを返す。

position属性は、変換の並進成分を示す3次元点(単位:メートル)です。positionw 属性は1.0でなければなりません。

orientation属性は変換の回転成分を示すクォータニオンです。orientationはノルムが1.0に正規化されていなければなりません。

matrix属性は、positionorientation で記述される変換を行列として返します。この属性はXRRigidTransformに対し行列の取得で計算されなければなりません。

注記: この行列を列ベクトルに前置乗算すると、まずorientationで回転し、その後positionで平行移動します。数式的には列ベクトル表記でM = T * R(T=平行移動, R=回転)です。

XRRigidTransform transformについて行列の取得を行うには:

  1. もしtransforminternal matrixnullでない場合、以下の手順を実行する:

    1. internal matrixに対しIsDetachedBuffer 操作を行い、その結果がfalseであれば、transforminternal matrixを返す。

  2. translationを新たなmatrixとし、これはpositionに対応するカラムベクトル形式の並進行列である。 数学的には、position(x, y, z)のとき、この行列は次の通り。

    Mathematical expression for column-vector translation matrix

  3. rotationを新たなmatrixとし、これはorientationに対応するカラムベクトル形式の回転行列である。 数学的には、orientation が単位クォータニオン (qx, qy, qz, qw)のとき、この行列は次の通り。

    Mathematical expression for column-vector rotation matrix

  4. transforminternal matrixを、新しい Float32Arraytransform関連realmで、translationrotationtranslationを左にして乗算した結果(translation * rotation)で初期化)に設定する。 数学的には、この行列は以下の通り。

    Mathematical expression for matrix of multiplying translation and rotation with translation on the left

  5. transforminternal matrixを返す。

inverse属性は、XRRigidTransform transformで、同じrealm内でtransformで変換済みのオブジェクトに適用すると元の姿勢に戻すことができるXRRigidTransformを返します。この属性は遅延評価されるべきです。inverseで返されたインスタンスはtransforminverseとして返さなければなりません。

XRRigidTransformposition{ x: 0, y: 0, z: 0 w: 1 }orientation{ x: 0, y: 0, z: 0, w: 1 }のものを単位変換と呼びます。

2つのXRRigidTransformの乗算BARealmrealm)は、UAが次の手順を実行します:

  1. resultrealm新しいXRRigidTransformとする。

  2. resultmatrix を、realm新しいFloat32ArrayAmatrixBmatrixを左から前置乗算した結果に設定。

  3. resultorientation を、realm新しいDOMPointReadOnlyresultmatrix左上3×3部分行列が表すクォータニオンに設定。

  4. resultposition を、realm新しいDOMPointReadOnlyresultmatrix第4列ベクトルに設定。

  5. resultを返す。

resultAのソース空間からBのデスティネーション空間への変換です。

注記: これは、XRRigidTransform を構築するのと同等です。そのorientationAのorientationとBのorientationの合成、positionApositionBorientationで回転させ、 Bposition を加えたものと等しいです。

9. Pose

9.1. XRPose

XRPoseは、XRSpaceに対する空間内の位置と姿勢を表します。

[SecureContext, Exposed=Window] interface XRPose {
  [SameObject] readonly attribute XRRigidTransform transform;
  [SameObject] readonly attribute DOMPointReadOnly? linearVelocity;
  [SameObject] readonly attribute DOMPointReadOnly? angularVelocity;

  readonly attribute boolean emulatedPosition;
};

transform属性は、基準XRSpaceに対する位置と姿勢を示します。

linearVelocity属性は、基準XRSpaceに対する毎秒メートル単位の並進速度を示します。ユーザーエージェントが値を設定できない場合、nullを返しても構いません。

angularVelocity属性は、基準XRSpaceに対する毎秒ラジアン単位の角速度を示します。ユーザーエージェントが値を設定できない場合、nullを返しても構いません。

emulatedPosition属性は、transformがセンサー読み取りに基づくアクティブにトラッキングされた6DoF姿勢であればfalseposition値に首や腕モデルのような計算オフセットが含まれる場合はtrueとなります。推定床レベルは、XRPose計算オフセットを含むかどうかの判定には利用してはいけません。

9.2. XRViewerPose

XRViewerPose は、XRデバイスによってトラッキングされるXRシーンのビューアの状態を表すXRPoseです。ビューアは、トラッキングされたハードウェア、ハードウェアに対するユーザー頭部の観測位置、またはXRシーンへの一連の視点を計算する他の手段などを表す場合があります。XRViewerPoseXRReferenceSpaceに対してのみクエリ可能です。これは、XRPoseの値に加え、視点や投影行列を示す剛体変換を含むビューの配列を提供します。これらの値はXRシーンのフレームを描画する際にアプリケーションが利用すべきものです。

[SecureContext, Exposed=Window] interface XRViewerPose : XRPose {
  [SameObject] readonly attribute FrozenArray<XRView> views;
};

views配列は、XRViewerPoseがクエリされたXRReferenceSpace基準でXRシーンの視点を記述するXRViewの列です。この配列のすべてのビューを描画しなければXRデバイス上で正しく表示できません。各XRViewは視点・投影行列を示す剛体変換を含み、必要に応じてレイヤーからXRViewportを問い合わせることができます。

注記: XRViewerPosetransformは、シーンの観戦者ビューやマルチユーザーインタラクション向けのビューアのグラフィックス表現の配置に利用できます。

10. 入力

10.1. XRInputSource

XRInputSource は、XR入力ソースを表します。これは、ユーザーがviewerと同じ仮想空間内でターゲットアクションを実行できるあらゆる入力手段です。XR入力ソースの例としては、ハンドヘルドコントローラー、光学的にトラッキングされた手、viewerの姿勢に基づく視線入力方式などがあります。XRデバイスに明示的に関連付けられていない入力手段(従来のゲームパッド、マウス、キーボードなど)は、XR入力ソースとは見なすべきではありません。

enum XRHandedness {
  "none",
  "left",
  "right"
};

enum XRTargetRayMode {
  "gaze",
  "tracked-pointer",
  "screen",
  "transient-pointer"
};

[SecureContext, Exposed=Window]
interface XRInputSource {
  readonly attribute XRHandedness handedness;
  readonly attribute XRTargetRayMode targetRayMode;
  [SameObject] readonly attribute XRSpace targetRaySpace;
  [SameObject] readonly attribute XRSpace? gripSpace;
  [SameObject] readonly attribute FrozenArray<DOMString> profiles;
  readonly attribute boolean skipRendering;
};

注記: XRInputSource インターフェイスは WebXR Gamepads Module によっても拡張されます。

handedness 属性は、このXR入力ソースがどちらの手に対応するかを示します。自然な利き手を持たない入力ソース(ヘッドセット取り付け型コントローラ等)や現在利き手が不明な場合は、この属性を"none"に設定しなければなりません。

targetRayMode 属性はターゲットレイの生成方法を示し、アプリケーションがユーザーにターゲットレイをどのように表示すべきかを示します。

targetRaySpace属性はXRSpaceであり、targetRayModeで定義されるXRInputSourceの推奨指向レイ(-Z軸方向)の位置・姿勢をトラッキングします。

targetRayMode"transient-pointer"の場合、このtargetRaySpaceはインタラクション開始時のターゲットへのレイを表します。この姿勢は当該XRInputのgripSpace内で静的であるべきです。

gripSpace属性はXRSpaceであり、バーチャルオブジェクトがユーザーの手に握られて見えるようにするための姿勢をトラッキングします。ユーザーが棒を持った場合、このXRSpaceの原点は指を握った中心に置かれ、-Z軸が親指方向に棒の長さ方向を指します。X軸は手の甲に垂直で、右手の甲は+X、左手の甲は-X方向、Y軸はX軸とZ軸の関係から決まり、+Y軸はおおよそ腕方向になります。

skipRendering属性は、この入力が可視であり、現在のセッションでレンダリング不要かもしれないことを示します。skipRenderingがtrueかつtargetRayModeが"tracked-pointer"なら、ユーザーエージェントは必ずXR入力ソースの表示をユーザーに保証しなければなりません。

コントローラーがユーザーに見える例としては、コントローラーがディスプレイとユーザーの間にある、ディスプレイが透明である、またはコントローラーがOSによって描画される場合などがあります。

skipRendering は、コントローラーなどの入力ソースの描画省略に関する開発者向けヒントです。レイやカーソルは描画すべきです。

targetRayMode"transient-pointer"の場合、gripSpaceは関連ユーザーのジェスチャ空間があればそれを、なければViewerSpaceや他のXRInputのgripSpace/targetRaySpace等を使うべきです。これはユーザーがtargetRaySpaceを操作できるようにするためです。

gripSpace は、入力ソースが本質的にトラッキング不可な場合(targetRayModeが"gaze""screen"の場合)はnullでなければなりません。

profiles属性は、入力ソースの推奨ビジュアル表現や挙動を示すリスト入力プロファイル名)です。

入力プロファイル名は、スペースなしASCII小文字DOMStringで、単語は-で連結します。説明的な名称は可能ならデバイスベンダの用語を使うべきです。プラットフォームが適切なID(USBベンダID等)を与える場合は利用可。シリアル番号など一意個体識別値は禁止。入力プロファイル名には利き手情報を含めてはいけません。同一デバイスを複数UAが公開する場合は同じ入力プロファイル名を報告する努力をすること。管理にはWebXR Input Profiles Registryの利用が推奨されます。

プロファイルは特異性の高い順に並びます。リスト2番目以降はfallback値で、より一般的・旧バージョンや類似デバイス・型名(例: "generic-trigger-touchpad")など。複数プロファイルがあれば全て互いにレイアウトが包含/被包含の関係であるべきです。

XRSessionmode"inline"なら、profilesは空リストでなければなりません。

UAは適宜、汎用入力プロファイル名や空リストのみを返しても構いません。これはデバイスが特定できない・既知プロファイルがない・デバイスを秘匿したい場合などに適用されます。

例:Samsung HMD Odysseyのコントローラーは標準Windows Mixed Realityコントローラーの設計バリアントで、レイアウトが共通です。この場合、profiles["samsung-odyssey", "microsoft-mixed-reality", "generic-trigger-squeeze-touchpad-thumbstick"] などとなり、1番目が最も正確な外観を、2番目が許容代替を、最後が大雑把な汎用表現を示します(トリガ・グリップ・タッチパッド・スティック付きコントローラー)。
同様にValve IndexコントローラーはHTC Viveコントローラーと互換性がありますが機能追加があります。この場合、profiles["valve-index", "htc-vive", "generic-trigger-squeeze-touchpad-thumbstick"] など。"valve-index""htc-vive"の上位互換レイアウト、外観は異なるがUAが許容した場合。最後は汎用fallback。
(実際のプロファイル名はWebXR Input Profiles Registryで管理されます)

注記: XRInputSourceは、XRSessioninputSources配列内で「ライブ」です。値はその場で更新されるため、あるフレームでの属性値を保存し次のフレームの属性と比較しても同じオブジェクトとなり状態変化検出には使えません。比較したい場合は値内容をコピーして比較してください。

XR入力ソースは、プライマリ入力ソースである場合、プライマリアクションをサポートします。プライマリアクションは、プラットフォーム固有のアクションで、実行時にselectstartselectendselectイベントが発生します。例:トリガ・タッチパッド・ボタン押下、音声コマンド、ハンドジェスチャ等。ガイドラインで推奨プライマリ入力が定義されていればそれを使い、なければUAが自由に選択可。デバイスは最低1つのプライマリ入力ソースをサポートしなければなりません。

XR入力ソースは、プライマリアクションをサポートしない場合、トラッキング入力ソースです。これらは主に姿勢データ提供が目的です。 注記: トラッキング入力ソースの例は脚やプロップ用のトラッキングアタッチメント等。ハンドジェスチャ検出しない手トラッキングもこれに該当します。

XR入力ソースsourceが、XRSessionsessionプライマリアクションを開始したとき、UAは次の手順を実行しなければなりません:

  1. framesession新しいXRFrame(関連realm)とし、sessionsessiontimeにアクション発生時刻を設定。

  2. タスクをキューして、input source event(名前selectstart、frame frame、source source)を発火。

XR入力ソースsourceが、XRSessionsessionプライマリアクションを終了したとき、UAは次の手順を実行しなければなりません:

  1. framesession新しいXRFrame(関連realm)とし、sessionsessiontimeにアクション発生時刻を設定。

  2. タスクをキューして、次を実行:

    1. input source event(名前select、frame frame、source source)を発火。

    2. input source event(名前selectend、frame frame、source source)を発火。

XR入力ソースは、プライマリスクイーズアクションを定義しても構いません。プライマリスクイーズアクションは、実行時にsqueezestartsqueezeendsqueezeイベントが発生するプラットフォーム固有アクションです。つかむ・握る操作に相当するアクションで利用してください。例:グリップトリガや握る手ジェスチャ等。ガイドラインで推奨があればそれを使い、なければUAが選択可。

XR入力ソースsourceが、XRSessionsessionプライマリスクイーズアクションを開始したとき、UAは次の手順を実行しなければなりません:

  1. framesession新しいXRFrame(関連realm)とし、sessionsessiontimeにアクション発生時刻を設定。

  2. タスクをキューして、input source event(名前squeezestart、frame frame、source source)を発火。

XR入力ソースsourceが、XRSessionsessionプライマリスクイーズアクションを終了したとき、UAは次の手順を実行しなければなりません:

  1. framesession新しいXRFrame(関連realm)とし、sessionsessiontimeにアクション発生時刻を設定。

  2. タスクをキューして、次を実行:

    1. input source event(名前squeeze、frame frame、source source)を発火。

    2. input source event(名前squeezeend、frame frame、source source)を発火。

プラットフォーム固有の動作により、プライマリアクションプライマリスクイーズアクションが中断・キャンセルされる場合があります。例えば、XR入力ソースがアクション開始後〜終了前にXRデバイスから削除された場合など。

XR入力ソースsourceが、XRSessionsessionプライマリアクションがキャンセルされたとき、UAは次の手順を実行:

  1. framesession新しいXRFrame(関連realm)とし、sessionsessiontimeにアクション発生時刻を設定。

  2. タスクをキューして、input source event(名前selectend、frame frame、source source)を発火。

XR入力ソースsourceが、XRSessionsessionプライマリスクイーズアクションがキャンセルされたとき、UAは次の手順を実行:

  1. framesession新しいXRFrame(関連realm)とし、sessionsessiontimeにアクション発生時刻を設定。

  2. タスクをキューして、input source event(名前squeezeend、frame frame、source source)を発火。

10.2. 一時的入力

一部のXRデバイスは、一時的入力ソースをサポートする場合があります。これは、XR入力ソース一時的アクションプライマリ入力ソースプライマリアクション、またはトラッキング入力ソースのデバイス固有補助アクション)の実行中のみ意味を持つものです。

例えば、"inline" XRSessionでのマウス・タッチ・スタイラス入力は、XRInputSourcetargetRayModescreen)として一時的に生成され、プライマリポインタに対してはプライマリアクションとして、非プライマリポインタでは補助アクションとして扱われます。

もう一つの例は、視線などセンシティブな情報から直接公開できないOSインテントによる入力です。これらは、XRInputSourcetargetRayModetransient-pointer)として一時的に生成され、プライマリアクションとして扱われます。

一時的入力ソースは、一時的アクションの継続中のみセッションのアクティブなXR入力ソースのリストに存在します。

一時的入力ソースは、プライマリアクションの非一時的なアルゴリズムの代わりに、次の手順で一時的アクションを処理します:

一時的入力ソースsourceXRSessionsession一時的アクションを開始したとき、UAは次の手順を実行:

  1. framesession新しいXRFrame(関連realm)とし、sessionsession、アクション発生時刻を設定。

  2. タスクをキューして、次を実行:

    1. 必要に応じてXR入力ソースのアクションによって生成された"pointerdown"イベントを発火。

    2. XR入力ソースをアクティブなXR入力ソースのリストに追加

    3. 一時的アクションプライマリアクションなら、input source event(名前selectstart、frame frame、source source)を発火。

一時的入力ソースsourceXRSessionsession一時的アクションを終了したとき、UAは次の手順を実行:

  1. framesession新しいXRFrame(関連realm)とし、sessionsession、アクション発生時刻を設定。

  2. タスクをキューして、次を実行:

    1. 一時的アクションプライマリアクションなら、input source event(名前select、frame frame、source source)を発火。

    2. 必要に応じてXR入力ソースのアクションによる"click"イベントを発火。

    3. 一時的アクションプライマリアクションなら、input source event(名前selectend、frame frame、source source)を発火。

    4. XR入力ソースをアクティブなXR入力ソースのリストから削除

    5. 必要に応じてXR入力ソースのアクションによる"pointerup"イベントを発火。

一時的入力ソースsourceXRSessionsession一時的アクションがキャンセルされたとき、UAは次の手順を実行:

  1. framesession新しいXRFrame(関連realm)とし、sessionsession、アクション発生時刻を設定。

  2. タスクをキューして、次を実行:

    1. 一時的アクションプライマリアクションなら、input source event(名前selectend、frame frame、source source)を発火。

    2. XR入力ソースをアクティブなXR入力ソースのリストから削除

    3. 必要に応じてXR入力ソースのアクションによる"pointerup"イベントを発火。

10.3. XRInputSourceArray

XRInputSourceArray は、リストXRInputSourceのリスト) を表します。frozen array typeの代わりに、 リストの内容が時間とともに変化することが想定される場合(例えばXRSessioninputSources属性など)に使用されます。

[SecureContext, Exposed=Window]
interface XRInputSourceArray {
  iterable<XRInputSource>;
  readonly attribute unsigned long length;
  getter XRInputSource(unsigned long index);
};

XRInputSourceArraylength属性は、 XRInputSourceArray内に含まれる XRInputSource の数を示します。

XRInputSourceArrayインデックスプロパティゲッターは、指定したインデックスの XRInputSource を取得します。

11. レイヤー

注記: 本仕様ではXRWebGLLayer レイヤーのみ定義されていますが、将来的な拡張で他のレイヤー種や画像ソースも追加される予定です。

11.1. XRLayer

[SecureContext, Exposed=Window]
interface XRLayer : EventTarget {};

XRLayerは、 XRWebGLLayer や将来の拡張で導入される他のレイヤー型の基底クラスです。

11.2. XRWebGLLayer

XRWebGLLayer は、WebGLフレームバッファを描画先として提供し、XRデバイス上で3Dグラフィックスのハードウェアアクセラレート描画を実現するレイヤーです。

typedef (WebGLRenderingContext or
         WebGL2RenderingContext) XRWebGLRenderingContext;

dictionary XRWebGLLayerInit {
  boolean antialias = true;
  boolean depth = true;
  boolean stencil = false;
  boolean alpha = true;
  boolean ignoreDepthValues = false;
  double framebufferScaleFactor = 1.0;
};

[SecureContext, Exposed=Window]
interface XRWebGLLayer: XRLayer {
  constructor(XRSession session,
             XRWebGLRenderingContext context,
             optional XRWebGLLayerInit layerInit = {});
  // Attributes
  readonly attribute boolean antialias;
  readonly attribute boolean ignoreDepthValues;
  attribute float? fixedFoveation;

  [SameObject] readonly attribute WebGLFramebuffer? framebuffer;
  readonly attribute unsigned long framebufferWidth;
  readonly attribute unsigned long framebufferHeight;

  // Methods
  XRViewport? getViewport(XRView view);

  // Static Methods
  static double getNativeFramebufferScaleFactor(XRSession session);
};

XRWebGLLayer は、初期値nullcontextオブジェクトを持ちます。これはWebGLRenderingContext またはWebGL2RenderingContextのインスタンスです。

XRWebGLLayer は、生成時に使われたXRSessionを関連付けられたsessionとして持ちます。

XRWebGLLayer(session, context, layerInit) コンストラクタが呼び出されたとき、次の手順を実行しなければなりません:

  1. layersession関連realmXRWebGLLayerの新しいインスタンスとする。

  2. sessionended値がtrueなら、InvalidStateErrorをスローし中止。

  3. contextがロストしていれば、InvalidStateErrorをスローし中止。

  4. session没入型セッションで、contextXR compatibleブール値がfalseなら、InvalidStateErrorをスローし中止。

  5. layercontextcontextに初期化。

  6. layersessionsessionに初期化。

  7. layerignoreDepthValues を次のように初期化:

    layerInitignoreDepthValues値がfalseかつXRコンポジタがdepth値を利用する場合:

    layerignoreDepthValuesfalseに初期化。

    それ以外の場合:

    layerignoreDepthValuestrueに初期化。

  8. layercomposition enabledブール値を次のように初期化:

    sessionインラインセッションの場合:

    layercomposition enabledfalseに初期化。

    それ以外の場合:

    layercomposition enabledtrueに初期化。

  9. layercomposition enabledtrueの場合:
    1. layerantialiaslayerInitantialias 値で初期化。

    2. scaleFactorlayerInitframebufferScaleFactorとする。

    3. UAはここでscaleFactorをパフォーマンス上パワーオブツー等に丸めてもよい。

    4. framebufferSize推奨WebGLフレームバッファ解像度の幅・高さにscaleFactorを個別乗算したものとする。

    5. layerframebuffercontextの関連realmで新しいWebGLFramebufferopaqueフレームバッファ、サイズframebufferSizecontextで生成、sessionsessionで初期化、layerInitdepthstencilalpha値で)に初期化。

    6. layerの合成をサポートするため、必要に応じてsessionXRデバイス互換のリソース(GPUバッファ等)を割り当て・初期化。

    7. リソース初期化に失敗した場合はOperationErrorをスローし中止。

    それ以外の場合:
    1. layerantialiaslayercontext実際のコンテキストパラメータantialias値に初期化。

    2. layerframebuffernullに初期化。

  10. layerを返す。

注記: XRWebGLLayercomposition enabled ブール値がfalseの場合、 XRWebGLLayerInit オブジェクト上のすべての値は無視されます。なぜならWebGLRenderingContext のデフォルトフレームバッファはすでにコンテキストの実際のコンテキストパラメータを使って割り当てられており、上書きできないためです。

context 属性は、WebGLRenderingContext であり、XRWebGLLayer が生成された際に使われたものです。

XRWebGLLayerは、初期値がtruecomposition enabledブール値を持ちます。これがfalseに設定された場合、そのXRWebGLLayerは独自のWebGLFramebufferを割り当ててはならず、XRWebGLLayerframebufferプロパティに関連するすべてのプロパティは、かわりにcontextのデフォルトフレームバッファのプロパティを反映しなければなりません。

framebuffer属性は、XRWebGLLayer の場合、WebGLFramebuffer のインスタンスであり、composition enabledtrueならopaqueとしてマークされ、そうでなければnullです。framebuffer のサイズはXRWebGLLayer 作成後に開発者が調整することはできません。

opaque framebufferは、通常のWebGLFramebuffer と同様に機能しますが、以下の点が異なり、デフォルトフレームバッファに近い挙動となります:

注記: UAはdepth およびstenciltrueの場合、WebGLのdrawing buffer生成時と同様に、これを尊重する必要があります。

opaque framebufferにアタッチされているバッファは、初回生成時または各XRアニメーションフレーム処理前に下表の値でクリアされなければなりません。これはWebGLコンテキストのデフォルトフレームバッファと同一挙動です。Opaque framebufferは関連WebGLコンテキストのpreserveDrawingBuffer 値に関係なく必ずクリアされます。

バッファ クリア値
Color (0, 0, 0, 0)
Depth 1.0
Stencil 0

注記: 実装は必要な場合、opaque framebufferの暗黙クリア操作を最適化して省略できます(開発者が明示的にクリアした場合など)。ただし他プロセスからバッファ内容にアクセスできないことが保証できる場合のみです。

XRWebGLLayeralpha trueで生成された場合、framebufferRGBA カラーフォーマットのテクスチャで裏打ちされます。 XRWebGLLayeralpha falseで生成された場合、framebufferRGB カラーフォーマットのテクスチャで裏打ちされなければなりません。

ただしXR Compositorframebuffer の裏打ちピクセルをSRGB8_ALPHA8 またはSRGB8 colorFormatであるかのように扱う必要があります。

注記: これはXR CompositorRGBARGBからリニア→ガンマ変換をしてはならないことを意味します。そうしないと最終描画が明るくなり、通常の2D WebGLRenderingContext の描画と一致しません。

XRWebGLLayer没入型セッションbaseLayer に設定された場合、opaque framebufferの内容はXRアニメーションフレーム終了直後に没入型XRデバイスに提示されます。ただし前回のXRアニメーションフレーム以降、次のいずれかが発生している場合のみです。

opaque framebufferが没入型XRデバイスに提示される直前、UAはすべての描画操作がopaque framebufferにフラッシュされていることを保証します。

XRWebGLLayer には、target framebufferがあり、これはframebuffer (composition enabledがtrueの時)またはcontextのデフォルトフレームバッファ(それ以外)です。

framebufferWidth属性とframebufferHeight属性は、target framebufferのアタッチメントの幅と高さを返します。

antialias属性は、target framebufferがUA選択の手法でアンチエイリアスをサポートする場合true、しない場合false

ignoreDepthValues属性がtrueの場合、XR Compositorはデプスバッファの値を描画時に利用してはならないことを示します。falseの場合、レイヤーに描画したシーンのデプスバッファ内容がXR Compositorによって利用されることを意味します。

バッファ内のデプス値は0.0depthNearの距離)から1.0depthFarの距離)まで、WebGLのデフォルトのようにリニアに補間されます。(詳細はdepthRange関数参照)

注記: シーンのデプスバッファをコンポジタで利用できると、一部プラットフォームで高品質リプロジェクションなどの品質・快適性向上が可能となります。

fixedFoveation属性はXR Compositorによるフォベーション量を制御します。UAやデバイスがこの属性をサポートしない場合、取得時null、設定はno-opとしてください。fixedFoveationに0未満を設定すると0に、1超を設定すると1になります。0は最小、1は最大のフォベーションです。解釈はUA依存です。値変更は次のXRFrameから反映されます。

注記: 固定フォベーションは、ユーザー視野端の描画解像度を下げる手法で、GPUフィルレート制約経験の改善に有効です。消費電力低減・アイテクスチャ解像度向上にも役立ちます。背景画像など低コントラストには有効ですが、テキストや高詳細画像にはあまり適しません。パフォーマンスと画質の最適バランスのため、フレームごとに調整することができます。

XRWebGLLayer は、全サイズビューポートのリストを必ず持たなければなりません。これは、リストであり、XRSessionが公開する可能性のある各viewごとにWebGL ビューポートを1つ含みます。これには、現在アクティブではないが、セッション中にアクティブになる可能性のあるセカンダリビューも含みます。各ビューポートはwidthおよび height0より大きく、かつターゲットフレームバッファの範囲を超えない矩形でなければなりません。ビューポート同士が重なってはなりません。composition enabledfalseの場合、全サイズビューポートのリストは、contextのデフォルトフレームバッファ全体を覆う単一のWebGL ビューポートのみを含まなければなりません。

XRWebGLLayer は、list of viewport objectsリスト)を持ち、これは現在XRSessionが公開する各アクティブビューごとに1つのXRViewportを含みます。

getViewport() は、指定されたXRView がこのレイヤーに描画する際に使用すべきXRViewportを返します。

getViewport(view)メソッドは、XRWebGLLayer layerで呼び出された場合、次の手順を実行します:

  1. sessionviewsessionとする。

  2. framesessionanimation frameとする。

  3. sessionlayersessionでなければInvalidStateErrorをスローし中止。

  4. frameactiveブール値がfalseならInvalidStateErrorをスローし中止。

  5. viewframeframeでなければInvalidStateErrorをスローし中止。

  6. viewport modifiableフラグがtrueかつ viewrequested viewport scalecurrent viewport scaleなら:

    1. current viewport scalerequested viewport scaleに設定。

    2. list of viewport objects内で、 viewに紐付くXRViewportobtain a scaled viewportの結果で更新。

  7. viewviewport modifiableフラグをfalseに設定。

  8. viewportviewに紐付くlist of viewport objectsから取得。

  9. viewportを返す。

注記: viewport modifiableフラグは、current viewport scaleに変更がなくても意図的にfalseに設定されます。これにより、getViewport(view)の呼び出しはそのアニメーションフレーム内で常に一貫した結果を返し、最初に取得された値がそのフレームの残りの間ロックされます。アプリケーションがrequestViewportScale()getViewport()の後に呼び出した場合、その値は次のフレームで再度getViewport()が呼ばれるまで適用されません。

XRSession は、ネイティブWebGLフレームバッファ解像度を特定しなければなりません。これは、XRデバイスの物理的なピクセル解像度に一致させるために必要なWebGLフレームバッファのピクセル解像度です。

ネイティブWebGLフレームバッファ解像度は、XRSession sessionに対して次の手順で決定されます:

  1. sessionmode値が"inline"でない場合、 ネイティブWebGLフレームバッファ解像度を、そのセッションの全XRViewを収容できるフレームバッファピクセルと、表示領域の物理スクリーンピクセルが1:1対応するのに必要な解像度とし、これ以降の手順を中止します。記載の方法でネイティブ解像度が決定できない場合は、推奨WebGLフレームバッファ解像度を用いても構いません。

  2. sessionmode値が"inline"の場合、 ネイティブWebGLフレームバッファ解像度を、sessionrenderStateoutput canvasの物理ディスプレイピクセルのサイズとし、キャンバスサイズやoutput canvasが変更されるたびに再評価します。

さらに、XRSession は、推奨WebGLフレームバッファ解像度を特定しなければなりません。これは、セッションの全XRViewを収容可能で、一般的なアプリケーションにとって性能と画質のバランスが良いと見込まれるWebGLフレームバッファ解像度の推定値です。これはネイティブWebGLフレームバッファ解像度より小さくても大きくても同じでも構いません。新しいopaque framebuffer はこの解像度で作成され、幅と高さはXRWebGLLayerInitframebufferScaleFactor により個別にスケールされます。

注記: ユーザーエージェントは推奨WebGLフレームバッファ解像度を算出する方法を自由に選択できます。プラットフォーム固有の推奨サイズを取得する方法がある場合はそれを利用することが推奨されますが、必須ではありません。 framebufferScaleFactorgetNativeFramebufferScaleFactor()のスケールは幅・高さ個別に適用されるため、2倍スケールならピクセル数は4倍となります。ピクセル数ベースの面積スケールを公開するプラットフォームでは、その平方根をWebXRスケールファクターに変換する必要があります。

getNativeFramebufferScaleFactor(session) メソッドが呼び出された時、次の手順を実行します:

  1. sessionthisとする。

  2. sessionended値がtrueなら0.0を返し、この手順を中止。

  3. session推奨WebGLフレームバッファ解像度の幅・高さを個別に乗算してsessionネイティブWebGLフレームバッファ解像度になる値を返す。

11.3. WebGLコンテキストの互換性

WebGLコンテキストをイマーシブXR画像のソースとして使用するには、互換性のあるグラフィックスアダプター上で作成されている必要があります。何が互換性のあるグラフィックスアダプターとみなされるかはプラットフォーム依存ですが、これはそのグラフィックスアダプターがイマーシブXRデバイスに遅延なく画像を供給できることを意味します。WebGLコンテキストがまだ互換性のあるグラフィックスアダプター上で作成されていない場合、XRWebGLLayerで利用する前に、通常そのアダプター上で再作成する必要があります。

注記: XRプラットフォームにGPUが1つしかない場合、そのGPUはプラットフォームが広告するイマーシブXRデバイスと互換性があると安全にみなすことができ、ハードウェアアクセラレートされたWebGLコンテキストも同様に互換です。統合型GPUとディスクリートGPUが両方搭載されたPCでは、ディスクリートGPUが一般的に高性能なため、互換性のあるグラフィックスアダプターとみなされることが多いです。複数のグラフィックスアダプターを搭載したデスクトップPCでは、イマーシブXRデバイスが物理的に接続されているアダプターが互換性のあるグラフィックスアダプターとみなされる可能性が高いです。

注記: "inline" セッションはキャンバスと同じグラフィックスアダプターを使って描画されるため、xrCompatible コンテキストは不要です。

partial dictionary WebGLContextAttributes {
    boolean xrCompatible = false;
};

partial interface mixin WebGLRenderingContextBase {
    [NewObject] Promise<undefined> makeXRCompatible();
};

ユーザーエージェントが本仕様を実装する際には、すべてのWebGLRenderingContextBaseに、初期値falseXR compatibleブール値を設定しなければなりません。XR compatibleブール値がtrueに設定されると、そのコンテキストは現在のイマーシブXRデバイスからリクエストされた任意のXRSession用レイヤーで利用できるようになります。

注記: このフラグは遅い同期挙動を引き起こすため推奨されません。非同期的な解決策としてmakeXRCompatible() を呼び出すことを検討してください。

XR compatibleブール値は、コンテキスト作成時または作成後に設定でき、その際コンテキストロストが発生する可能性があります。コンテキスト作成時にXR compatibleブール値を設定するには、WebGLコンテキスト取得時にxrCompatible コンテキスト生成属性をtrueに指定する必要があります。リクエスト元ドキュメントのオリジンに"xr-spatial-tracking"のPermissions Policyが許可されていない場合、xrCompatible は効果を持ちません。

xrCompatible フラグがWebGLContextAttributestrueの場合、ユーザーエージェントにWebGLコンテキストを互換性のあるグラフィックスアダプターイマーシブXRデバイス向けに作成するよう要求します。これに成功した場合、作成されたコンテキストのXR compatibleブール値はtrueとなります。イマーシブXRデバイスを取得するためには、イマーシブXRデバイスの選択確定を呼び出すべきです。

注記: イマーシブXRデバイスの選択確定並列で実行する必要があり、メインスレッド上で遅い同期挙動を引き起こします。ユーザーエージェントは、かわりにmakeXRCompatible() の使用を推奨する警告をコンソールに表示するべきです。

次のコードは、イマーシブXRデバイスと互換性のあるWebGLコンテキストを作成し、それを使ってXRWebGLLayerを生成する例です。
function onXRSessionStarted(xrSession) {
  const glCanvas = document.createElement("canvas");
  const gl = glCanvas.getContext("webgl", { xrCompatible: true });

  loadWebGLResources();

  xrSession.updateRenderState({ baseLayer: new XRWebGLLayer(xrSession, gl) });
}

コンテキスト作成後にXR compatibleブール値を設定するには、makeXRCompatible() メソッドを利用します。

注記: 一部のシステムでは、このフラグにより高性能なディスクリートGPUが有効になる場合や、すべてのコマンドがデバイス上のGPUにプロキシされる場合があります。XRを利用するかどうかが未定の場合は、イマーシブセッションを開始する際にのみmakeXRCompatible()を呼び出すことが推奨されます。

makeXRCompatible() メソッドは、WebGLRenderingContextBase互換性のあるグラフィックスアダプター上でイマーシブXRデバイス用に動作していることを保証します。

このメソッドが呼び出されたとき、ユーザーエージェントは次の手順を実行しなければなりません:

  1. リクエスト元ドキュメントのオリジンが"xr-spatial-tracking"のPermissions Policyを利用できない場合は、resolve promiseし、それを返す。XR permissions policyが無効な場合、このケースではXRデバイスが存在しないかのように振る舞いたいため、makeXRCompatible() はset-and-forgetメソッドとする。

  2. promise新しいPromiseとして、このWebGLRenderingContextBaseのRealmで作成する。

  3. contextthisとする。

  4. 次の手順を並列で実行する:

    1. deviceイマーシブXRデバイスの選択確定の結果とする。

    2. contextXR compatibleブール値を次のように設定する:

      もしcontextWebGL context lost flagがセットされている場合:

      タスクをキューに入れて、contextXR compatibleブール値をfalseにし、InvalidStateErrorpromiseをrejectする。

      もしdevicenullなら:

      タスクをキューに入れて、contextXR compatibleブール値をfalseにし、InvalidStateErrorpromiseをrejectする。

      もしcontextXR compatibleブール値がtrueなら:

      タスクをキューに入れて、promiseをresolveする。

      もしcontextdevice用の互換性のあるグラフィックスアダプター上で作成されていた場合:

      タスクをキューに入れて、contextXR compatibleブール値をtrueにし、promiseをresolveする。

      それ以外の場合:

      WebGLタスクソースで次の手順を実行するタスクをキューに入れる:

      1. contextを強制的にロストさせる。

      2. WebGL仕様に従い、コンテキストロストを処理する:

        1. canvascontextキャンバスとする。

        2. もしcontextwebgl context lost flagがセットされていれば、これ以降の手順を中止する。

        3. contextwebgl context lost flagをセットする。

        4. contextにより生成された各WebGLObject インスタンスのinvalidatedフラグをセットする。

        5. "WEBGL_lose_context"以外のすべての拡張機能を無効化する。

        6. WebGLタスクソースで次の手順を実行するタスクをキューに入れる:

          1. WebGL context event eとして"webglcontextlost"イベントをcanvasに、statusMessage を""にして発火する。

          2. もしecanceled flagがセットされていなければ、AbortErrorpromiseをrejectし、これ以降の手順を中止する。

          3. 次の手順を並列で実行する。

            1. device用の互換性のあるグラフィックスアダプターでリストア可能な描画バッファを待つ。

            2. WebGLタスクソースで次の手順を実行するタスクをキューに入れる:

              1. コンテキストをリストアし、device用の互換性のあるグラフィックスアダプター上で行う。

              2. contextXR compatibleブール値をtrueにする。

              3. promiseをresolveする。

  5. promiseを返す。

さらに、任意のWebGLコンテキストがロストしたときは、"webglcontextlost"イベントを発火する前に次の手順を実行する:

  1. そのコンテキストのXR compatibleブール値をfalseにセットする。

次のコードは、既存のWebGLコンテキストからXRWebGLLayerを作成する例です。
const glCanvas = document.createElement("canvas");
const gl = glCanvas.getContext("webgl");

loadWebGLResources();

glCanvas.addEventListener("webglcontextlost", (event) => {
  // WebGLコンテキストがリストア可能であることを示す。
  event.canceled = true;
});

glCanvas.addEventListener("webglcontextrestored", (event) => {
  // コンテキストロスト後はWebGLリソースの再生成が必要。
  loadWebGLResources();
});

async function onXRSessionStarted(xrSession) {
  // 利用したいcanvasコンテキストがデバイスと互換であることを確認。
  // これによりコンテキストロストが発生する場合がある。
  await gl.makeXRCompatible();
  xrSession.updateRenderState({ baseLayer: new XRWebGLLayer(xrSession, gl) });
}

12. イベント

本仕様でキューされるすべてのタスクソースは、特に指定がない限りXRタスクソースです。

12.1. XRSessionEvent

XRSessionEventは、 XRSessionの状態変化を通知するために発火されます。

[SecureContext, Exposed=Window]
interface XRSessionEvent : Event {
  constructor(DOMString type, XRSessionEventInit eventInitDict);
  [SameObject] readonly attribute XRSession session;
};

dictionary XRSessionEventInit : EventInit {
  required XRSession session;
};

session属性は、このイベントを発生させたXRSessionを示します。

12.2. XRInputSourceEvent

XRInputSourceEventは、 XRInputSourceの状態変化を通知するために発火されます。

[SecureContext, Exposed=Window]
interface XRInputSourceEvent : Event {
  constructor(DOMString type, XRInputSourceEventInit eventInitDict);
  [SameObject] readonly attribute XRFrame frame;
  [SameObject] readonly attribute XRInputSource inputSource;
};

dictionary XRInputSourceEventInit : EventInit {
  required XRFrame frame;
  required XRInputSource inputSource;
};

inputSource属性は、このイベントを発生させたXRInputSourceを示します。

frame属性は、イベント発生時点のXRFrameを表します。これは過去のデータを示す場合があります。getViewerPose()frameで呼び出された場合、例外を投げなければなりません。

ユーザーエージェントが入力ソースイベントを発火する必要がある場合、名前nameXRFrame frameXRInputSource sourceを用いて、次の手順を実行しなければなりません:

  1. XRInputSourceEvent eventを、type nameframe frameinputSource sourceで生成する。

  2. frameactiveブール値をtrueに設定する。

  3. フレーム更新を適用する。

  4. eventframesession にディスパッチする。

  5. frameactiveブール値をfalseに設定する。

12.3. XRInputSourcesChangeEvent

XRInputSourcesChangeEventは、 有効なXR入力ソースのリストの変化を通知するために、XRSessionに対して発火されます。

[SecureContext, Exposed=Window]
interface XRInputSourcesChangeEvent : Event {
  constructor(DOMString type, XRInputSourcesChangeEventInit eventInitDict);
  [SameObject] readonly attribute XRSession session;
  [SameObject] readonly attribute FrozenArray<XRInputSource> added;
  [SameObject] readonly attribute FrozenArray<XRInputSource> removed;
};

dictionary XRInputSourcesChangeEventInit : EventInit {
  required XRSession session;
  required sequence<XRInputSource> added;
  required sequence<XRInputSource> removed;

};

session属性は、このイベントを発生させたXRSessionを示します。

added属性は、イベント発生時にXRSessionに追加されたXRInputSourceリストです。

removed属性は、イベント発生時にXRSessionから削除されたXRInputSourceリストです。

12.4. XRReferenceSpaceEvent

XRReferenceSpaceEventは、 XRReferenceSpaceの状態変化を通知するために発火されます。

[SecureContext, Exposed=Window]
interface XRReferenceSpaceEvent : Event {
  constructor(DOMString type, XRReferenceSpaceEventInit eventInitDict);
  [SameObject] readonly attribute XRReferenceSpace referenceSpace;
  [SameObject] readonly attribute XRRigidTransform? transform;
};

dictionary XRReferenceSpaceEventInit : EventInit {
  required XRReferenceSpace referenceSpace;
  XRRigidTransform? transform = null;
};

referenceSpace属性は、このイベントを発生させたXRReferenceSpaceを示します。

オプションのtransform属性は、イベント後のreferenceSpaceネイティブ原点の位置と姿勢を、イベント前の座標系で表します。この属性は、XRSystemが新旧座標系間の差分を特定できない場合、nullとなることがあります。

注記: referenceSpacereferenceSpaceは、ヘッドセットが2つの異なる場所で着脱された場合などに該当します。このような場合、体験がワールドロックされたコンテンツに依存している場合は、ユーザーに警告し、シーンをリセットするべきです。

12.5. XRVisibilityMaskChangeEvent

由于视锥体并不总是与矩形显示器精确相交,XRLayer 的整个区域可能不会被显示。该事件将通知体验哪些 XRView 区域被展示给用户。

当用户代理需要告知体验 XRLayer 的显示区域发生变化时,会触发 XRVisibilityMaskChangeEvent 事件。 体验可以选择只绘制该区域,这有助于提升性能。

注意:体验必须在 requestSession 的 promise 解决期间注册该事件,否则事件可能会触发且遮罩信息会丢失。

[SecureContext, Exposed=Window]
interface XRVisibilityMaskChangeEvent : Event {
  constructor(DOMString type, XRVisibilityMaskChangeEventInit eventInitDict);
  [SameObject] readonly attribute XRSession session;
  readonly attribute XREye eye;
  readonly attribute unsigned long index;
  [SameObject] readonly attribute Float32Array vertices;
  [SameObject] readonly attribute Uint32Array indices;
};

dictionary XRVisibilityMaskChangeEventInit : EventInit {
  required XRSession session;
  required XREye eye;
  required unsigned long index;
  required Float32Array vertices;
  required Uint32Array indices;
};

session 属性表示生成该事件的 XRSession

eye 属性表示该遮罩所应用的 XREye

index 属性表示该遮罩应用到的 XRView视图列表 中的偏移量。

vertices 属性是一个 列表,包含 XY 坐标。体验必须假定 Z 坐标为 -1。每组 XYZ 坐标描述一个顶点。如果该数组为空,则应绘制 XRView 的整个区域。

indices 属性是一个 列表,用于描述 vertices 顶点列表中的索引。这些索引将描述该眼睛的 XRView 应绘制的区域。如果该数组为空,则应绘制 XRView 的整个区域。

该区域必须使用 projectionMatrixXRVieweye)和默认 XRRigidTransform 进行绘制。

注意:这意味着该区域不得使用当前 XRViewXRRigidTransformeye)进行绘制。

12.6. イベントタイプ

ユーザーエージェントは、以下の新しいイベントを必ず提供しなければなりません。イベントの登録および発火はDOMイベントの通常の挙動に従う必要があります。

ユーザーエージェントは、イベントを発火し、devicechange という名前のイベントを XRSystem オブジェクト上で発火しなければなりません。これは、イマーシブXRデバイス の利用可能性が変化したことを示します。ただし、ドキュメントの オリジン が "xr-spatial-tracking" パーミッションポリシー の利用を許可されていない場合は除きます。

ユーザーエージェントは、イベントを発火し、visibilitychange という名前のイベントを XRSessionEvent を使って XRSession 上で、visibility state が変化するたびに発火しなければなりません。

ユーザーエージェントは、イベントを発火し、end という名前のイベントを XRSessionEvent を使って XRSession 上で、セッションがアプリケーションまたはユーザーエージェントによって終了したときに発火しなければなりません。

ユーザーエージェントは、イベントを発火し、inputsourceschange という名前のイベントを XRInputSourcesChangeEvent を使って XRSession 上で、セッションの list of active XR input sources が変化したときに発火しなければなりません。

ユーザーエージェントは、イベントを発火し、trackedsourceschange という名前のイベントを XRInputSourcesChangeEvent を使って XRSession 上で、セッションの list of active XR tracked sources が変化したときに発火しなければなりません。

ユーザーエージェントは、イベントを発火し、selectstart という名前のイベントを XRInputSourceEvent を使って XRSession 上で、その XRInputSource のうち1つが primary action を開始したときに発火しなければなりません。イベントの型は . でなければなりません。

ユーザーエージェントは、イベントを発火し、selectend という名前のイベントを XRInputSourceEvent を使って XRSession 上で、その XRInputSource のうち1つが primary action を終了したとき、または XRInputSourceprimary action を開始した状態で切断されたときに発火しなければなりません。

ユーザーエージェントは、イベントを発火し、select という名前のイベントを XRInputSourceEvent を使って XRSession 上で、その XRInputSource のうち1つが primary action を完全に完了したときに発火しなければなりません。

ユーザーエージェントは、イベントを発火し、squeezestart という名前のイベントを XRInputSourceEvent を使って XRSession 上で、その XRInputSource のうち1つが primary squeeze action を開始したときに発火しなければなりません。

ユーザーエージェントは、イベントを発火し、squeezeend という名前のイベントを XRInputSourceEvent を使って XRSession 上で、その XRInputSource のうち1つが primary squeeze action を終了したとき、または XRInputSourceprimary squeeze action を開始した状態で切断されたときに発火しなければなりません。

ユーザーエージェントは、イベントを発火し、squeeze という名前のイベントを XRInputSourceEvent を使って XRSession 上で、その XRInputSource のうち1つが primary squeeze action を完全に完了したときに発火しなければなりません。

ユーザーエージェントは、イベントを発火し、frameratechange という名前のイベントを XRSessionEvent を使って XRSession 上で、XRコンポジタXRSessioninternal nominal framerate を変更したときに発火しなければなりません。

ユーザーエージェントは、イベントを発火し、reset という名前のイベントを XRReferenceSpaceEvent を使って XRReferenceSpace 上で、native origin または effective origin の不連続が発生したとき(つまり、原点の位置または向きがユーザー環境に対して大きく変化した場合)に発火しなければなりません。(例:ユーザーがXRデバイスを再キャリブレーションした場合や、デバイスがトラッキングを失い再取得した場合など)reset イベントは、boundsGeometryXRBoundedReferenceSpace で変更された場合にも必ず発火しなければなりません。 reset イベントは、viewer のポーズが不連続になっただけで XRReferenceSpace の原点の物理的対応付けが安定している場合(たとえば、viewer が一時的にトラッキングを失い同じトラッキングエリアで再取得した場合など)は発火してはなりません。また、unbounded 参照空間が、ユーザーの近くで空間安定性を維持するために native origin を少しずつ調整しても、大きな不連続が発生していない限りイベントは発火してはなりません。このイベントは新しい原点を使う XRアニメーションフレーム の実行前に必ずディスパッチされる必要があります。reset イベントが発火した参照空間の全てのオフセット参照空間にも reset イベントを必ずディスパッチし、その boundsGeometry も再計算されるべきです。

注: これはつまり、セッションは XRReferenceSpacereset リスナーを持つものに対して強参照を保持する必要があることを意味します。

注: viewer の位置ジャンプは、アプリケーション側で emulatedPosition ブール値を監視することで対処できます。もし viewer の位置ジャンプが emulatedPositiontrue から false に切り替わると同時に発生した場合、それは viewer がトラッキングを再取得し、新しい位置がそれまでのエミュレート値から補正されたことを示します。「テレポート」機能のない体験では、これは通常アプリケーションが望む挙動です。しかし、体験に「テレポート」機能がある場合、トラッキング復帰時に viewer の位置を元に戻すのは不自然かもしれません。その場合、トラッキング復帰時には現在のVR空間内位置から再開し、そのジャンプ量をテレポートのオフセットに吸収するのがよいでしょう。そのためには、開発者は getOffsetReferenceSpace() を呼び出して、effective originviewer の前フレームからのジャンプ分だけ調整した新しい参照空間を作成します。

13. セキュリティ、プライバシー、および快適性に関する考慮事項

WebXR Device APIは強力な新機能を提供しますが、それに伴い、ユーザーエージェントが対策を講じる必要がある、いくつかの独自のプライバシー、セキュリティ、快適性のリスクももたらします。

13.1. 機微な情報

XRの文脈において、機微な情報には、瞳孔間距離(IPD)などのユーザー設定可能なデータや、XRPoseのようなセンサーベースのデータなどが含まれますが、これらに限定されません。すべてのイマーシブセッションでは、ユーザーの姿勢情報が描画に必要なため、ある程度の機微なデータが公開されます。しかし、場合によっては、同じ機微な情報が"inline"セッションを通じても公開されることがあります。

13.2. ユーザーの意図

ユーザーの意図とは、特定のアクションがユーザーの意思によるものであり、同意があることを示すユーザーからのシグナルです。

機微な情報を公開したり、ユーザー体験に大きな影響を与えるアクションを許可したりする前に、ユーザーの意図を確認する必要がある場合が多くあります。この意図は、さまざまな方法で伝達または観察されることがあります。

注記: ユーザーの意図を判断する一般的な方法は、UIコントロール(通常は「VRに入る」ボタン)の一時的なアクティベーションです。アクティベーションは一時的であるため、XRセッションを要求するブラウジングコンテキストは、UIコントロールを含むコンテキストの祖先または同一オリジンドメイン子孫であり、かつ最近アクティブドキュメントであった必要があります。

13.2.1. ユーザーアクティベーション

一時的なアクティベーションは、いくつかの状況でユーザーの意図の指標となる場合があります。

13.2.2. ウェブアプリケーションの起動

一部の環境では、ページがアプリケーションとして表示され、イマーシブコンテンツを実行する明確な意図でインストールされる場合があります。その場合、ウェブアプリケーションの起動ユーザーの意図の指標となる場合があります。

暗黙的な同意とは、ユーザーエージェントがユーザーに明示的に尋ねることなく、たとえばウェブアプリケーションのインストール状況、訪問頻度や直近の利用、またはユーザーがイマーシブ体験に入りたいという明確な意図を示すユーザーエージェント定義のアクションなどに基づいて、ユーザーの同意を判断する場合を指します。XRデータの機微性を考慮し、暗黙的なシグナルに依存する場合は十分な注意が必要です。

明示的な同意とは、ユーザーエージェントがユーザーに明確に尋ねた上で、ユーザーの同意を判断する場合を指します。明示的な同意を取得する際、ユーザーエージェントは何が要求されているかの説明を提示し、ユーザーに拒否する選択肢を提供します。ユーザーの同意を求めるリクエストは、保護される機能やユーザーエージェントの選択に応じて、さまざまな視覚的形式で提示できます。ウェブアプリケーションのインストール状況は、インストール時に何らかの明示的な同意が求められる場合、明示的な同意のシグナルと見なされることがあります。

特定の明示的な同意が特定のオリジンに対して付与された場合、この同意はブラウジングコンテキストが終了するまで持続することが推奨されます。ユーザーエージェントは、ユーザーの意図の暗黙的または明示的なシグナルに基づいて、この同意の有効期間を延長または短縮することができますが、特に暗黙的なシグナルに依存する場合は、この推奨から逸脱する際には慎重に対応することが求められます。たとえば、イマーシブコンテンツを実行する明確な意図でインストールされたウェブアプリケーションの場合は、ユーザーの同意を持続させることが適切ですが、イマーシブコンテンツが副次的な機能である場合はそうではありません。

ユーザーエージェントがユーザーの同意をどれだけ持続させるかにかかわらず、機微な情報は、XRSession終了していない場合にのみ公開されなければなりません。

ユーザーエージェントが機能の利用に明示的な同意を求める原因となる、複数の非XR APIがあります。ユーザーエージェントがアクティブなイマーシブセッション中にユーザーの同意を求める場合、ユーザーエージェントは同意リクエストを表示する前に、必ずセッションを終了しなければなりません。機能に対するユーザーの同意がアクティブなイマーシブセッションの作成前にすでに付与されていた場合は、セッションを終了する必要はありません。

注記: この制限は、すべてのユーザーエージェント間で動作の一貫性を確保するためのものであり、ユーザーエージェントがセッション中の明示的な同意をどのように管理すべきかについて合意が得られるまでの暫定的な要件です。長期的な要件となることは想定されていません。

13.4. データ調整

場合によっては、データ調整(スロットリング、量子化、丸め、制限、またはその他の方法でXRデバイスから報告されるデータを操作すること)によって、セキュリティやプライバシー上の脅威を緩和できる場合があります。これは、ユーザーの意図が確立されている場合でも、フィンガープリント対策として必要になることがあります。ただし、データ調整による緩和策は、ユーザーの不快感を引き起こさない状況でのみ使用しなければなりません。

13.4.1. スロットリング

スロットリングとは、機微な情報が本来可能な頻度よりも低い頻度で報告されることを指します。この緩和策は、サイトがユーザーの意図や位置を推測したり、ユーザープロファイリングを行う能力を低減させる可能性があります。しかし、適切に使用しない場合、スロットリングはユーザーの不快感を引き起こす重大なリスクがあります。さらに、多くの状況では、完全な緩和策としては不十分な場合があります。

13.4.2. 丸め、量子化、ファジング

丸め、量子化、ファジングは、本来開発者に返される生データを修正する3つの緩和策のカテゴリです。丸めは、データを表現する際の桁数を減らすことで精度を下げます。量子化は、連続的なデータを離散的な値のサブセットに制限します。ファジングは、データにわずかなランダム誤差を導入することです。これらの緩和策は、フィンガープリント対策として有効であり、特にユーザーの快適性に目立った影響を与えない場合に有用です。

13.4.3. 制限

制限とは、データが特定の範囲内にある場合にのみ報告されることを指します。たとえば、ユーザーが承認された場所から特定の距離を超えて移動した場合に、位置姿勢データの報告を快適に制限することが可能です。この緩和策を採用する際は、ユーザー体験が損なわれないよう注意が必要です。範囲の終端で「ハードストップ」を避けることが望ましい場合が多く、これはユーザー体験を妨げる可能性があるためです。

13.5. 保護された機能

APIによって公開される機微な情報は、脅威プロファイルやそれらの脅威に対する必要な保護策を共有するカテゴリに分類できます。

13.5.1. イマーシブ性

ユーザーはイマーシブセッションの作成タイミングを自分で制御できなければなりません。なぜなら、イマーシブセッションの作成はユーザーのマシンに侵襲的な変化をもたらすためです。たとえば、イマーシブセッションを開始すると、XRデバイスのセンサーが有効化され、デバイスのディスプレイへのアクセスが奪われ、イマーシブコンテンツの表示が始まり、他のアプリケーションによるXRハードウェアへのアクセスが終了する場合があります。また、一部のシステムでは大きな電力やパフォーマンスの負荷が発生したり、ステータストレイやストアフロントの起動がトリガーされることもあります。

特定のglobal objectに対してイマーシブセッションリクエストが許可されるかどうかを判定するには、ユーザーエージェントは次の手順を実行しなければなりません:

  1. リクエストがglobal object一時的なアクティベーション中、またはウェブアプリケーションの起動時に行われていない場合、falseを返す

  2. イマーシブセッションの開始に対するユーザーの意図が、明示的な同意または暗黙的な同意によって十分に理解されていない場合、falseを返す

  3. trueを返す

"inline" セッションの開始には同じ要件は自動的には適用されませんが、セッションの要求された機能によって追加の要件が課される場合があります。

特定のglobal objectに対してインラインセッションリクエストが許可されるかどうかを判定するには、ユーザーエージェントは次の手順を実行しなければなりません:

  1. セッションリクエストに必須機能またはオプション機能が含まれており、かつリクエストがglobal object一時的なアクティベーション中、またはウェブアプリケーションの起動時に行われていない場合、falseを返す。

  2. global objectWindowでない場合、falseを返す。

  3. trueを返す。

13.5.2. ポーズ

センサーデータに基づく場合、XRPoseXRViewerPoseは、入力スニッフィング、視線追跡、フィンガープリントなど、さまざまな方法で悪用される可能性のある機微な情報を公開します。

XRSession sessionに対してポーズを報告できるかどうかを判定するには、ユーザーエージェントは次の手順を実行しなければなりません:

  1. session関連グローバルオブジェクト現在のグローバルオブジェクトでない場合、falseを返す。

  2. sessionvisibilityState"hidden"の場合、falseを返す。

  3. ポーズデータが返せるかどうかを次のように判定する:

    ユーザーエージェントがポーズデータがフィンガープリント可能なセンサーデータを公開しないと判断している場合

    trueを返す。

    データ調整がフィンガープリントやプロファイリング防止のために基礎センサーデータに適用される場合

    trueを返す。

    ユーザーの意図明示的な同意または暗黙的な同意によって十分に理解されている場合

    trueを返す。

    それ以外の場合

    falseを返す。

注記: ポーズがフィンガープリント可能なデータを公開しないとユーザーエージェントが判断する方法は、ユーザーエージェントの裁量に委ねられます。

XRViewerPoseXRPose の主な違いは、XRView 情報が含まれている点です。 複数の view が存在し、かつそれらの物理的な関係がユーザーによって設定可能な場合、これらの view 間の関係はセンシティブな情報と見なされます。なぜなら、これはユーザーのフィンガープリントやプロファイリングに利用される可能性があるためです。

もし XRView 間の関係が XRデバイス を一意に識別できる場合、ユーザーエージェントはフィンガープリント防止のため、XRView データを匿名化しなければなりません。匿名化の方法はユーザーエージェントの裁量によります。

注: さらに、XRView 間の関係がユーザー設定の瞳孔間距離(IPD)によって影響を受ける場合は、ユーザーエージェントは 明示的な同意 をセッション作成時、いかなる XRView データを報告する前に取得することが強く推奨されます。

13.5.3. リファレンス空間

使用されるリファレンス空間によって、アプリケーションに公開される機微な情報の種類が異なります。

そのため、さまざまなリファレンス空間タイプには、公開される機微な情報が安全に取り扱われるよう、作成に制限が設けられています:

ほとんどのリファレンス空間では、その利用に対するユーザーの意図明示的な同意または暗黙的な同意によって十分に理解されている必要があります。詳細は機能要件の表を参照してください。

"local""local-floor""bounded-floor" のいずれかのリファレンス空間が相互に関連付け可能な場合、それらは共通のネイティブ原点を共有しなければなりません。この制限は、"unbounded"リファレンス空間の作成が制限されている場合にのみ適用されます。

2つの空間spacebaseSpace間でポーズを制限しなければならないかどうかを判定するには、ユーザーエージェントは次の手順を実行しなければなりません:

  1. spaceまたはbaseSpaceのいずれかがXRBoundedReferenceSpaceであり、もう一方の空間のネイティブ原点ネイティブ境界ジオメトリからユーザーエージェントが定める合理的な距離より外側にある場合、trueを返す。

  2. spaceまたはbaseSpaceのいずれかがXRReferenceSpaceであり、そのtype"local"または"local-floor"であり、両空間のネイティブ原点間の距離がユーザーエージェントが定める合理的な距離を超える場合、trueを返す。

  3. falseを返す。

注記: ドキュメントの可視性要件は[DEVICE-ORIENTATION]に基づきます。

注記: "local"または"local-floor"リファレンス空間に対して報告されるポーズは、XRReferenceSpaceネイティブ原点から15メートル以内に制限することが推奨されます。

注記: XRBoundedReferenceSpaceに対して報告されるポーズは、XRBoundedReferenceSpaceネイティブ境界ジオメトリから1メートル外まで制限することが推奨されます。

13.6. 信頼された環境

信頼されたUIとは、ユーザーエージェントによって提示され、ユーザーが操作できるがページ側からは操作できないインターフェースです。ユーザーエージェントは信頼されたUIの表示をサポートしなければなりません。

信頼されたUIは、次の特性を持たなければなりません:

一般的に、信頼されたUIをサポートしたいユーザーエージェントには2つの選択肢があります。1つは信頼されたイマーシブUIで、これはイマーシブモードを終了しない信頼されたUIです。信頼されたイマーシブUIの実装は困難な場合があります。なぜならXRWebGLLayerバッファがXRデバイスのディスプレイ全体を占有し、ユーザーエージェントが自身のためのピクセルを「予約」しないことが多いためです。ユーザーエージェントは信頼されたイマーシブUIをサポートする必要はなく、代わりに一時的にイマーシブモードを停止・終了し、非イマーシブな信頼されたUIをユーザーに表示しても構いません。

注記: 信頼されたUIの例としては:

入力情報(ヘッドポーズ、入力ポーズなど)を読み取る機能は、信頼されたUI の完全性にリスクをもたらします。なぜなら、ページがこの情報を使って 信頼されたUI でユーザーが行った選択を盗み見たり、キーボード入力を推測したりする可能性があるからです。このリスクを防ぐため、ユーザーエージェントは、ユーザーが 信頼されたUIイマーシブか非イマーシブ、たとえばURLバーやシステムダイアログ)を操作している間、すべての XRSessionvisibility state"hidden" または "visible-blurred" に設定しなければなりません。さらに、悪意あるページが他のページの入力を監視できないようにするため、ユーザーエージェントは XRSessionvisibility state"hidden" に設定しなければなりません。これは、現在フォーカスされている領域 が、 XRSession を作成したドキュメントに属していない場合です。

信頼されたUIの特定のインスタンスで"hidden""visible-blurred"のどちらを使うか選択する際、ユーザーエージェントは頭部姿勢情報がセキュリティリスクとなるかどうかを考慮しなければなりません。たとえば、テキスト入力(特にパスワード入力)を含む信頼されたUIでは、入力中の頭部姿勢から入力内容が漏洩する可能性があります。このような場合、ユーザーエージェントは視線追跡関連情報の公開も停止すべきです。

ユーザーエージェントは権限プロンプトの表示に信頼されたUIを使用しなければなりません。

仮想環境がユーザーの頭部動作を低遅延かつ高フレームレートで一貫してトラッキングできない場合、ユーザーは混乱したり体調不良になる可能性があります。ページに一貫して高パフォーマンスかつ正しいコンテンツを強制することは不可能なため、ユーザーエージェントはトラッキングされた信頼された環境と、ページコンテンツとは非同期で動作するXRコンポジタを提供しなければなりません。コンポジタは信頼されたコンテンツと信頼されていないコンテンツの合成を担当します。コンテンツがパフォーマンス不足、フレーム未送信、または予期せず終了した場合でも、ユーザーエージェントは応答性の高い信頼されたUIの表示を継続できるべきです。

また、ページコンテンツはパフォーマンス以外の理由でもユーザーに不快感を与える可能性があります。トラッキングの誤用、点滅色、不快・恐怖・威圧を意図したコンテンツなどは、ユーザーが迅速にXR体験を終了したくなる原因となります。このような場合、XRデバイスを外すことが迅速または現実的でない場合もあります。これに対応するため、ユーザーエージェントは、予約されたハードウェアボタンの押下やジェスチャーなど、WebXRコンテンツから脱出してユーザーエージェントの信頼されたUIを表示するアクションをユーザーに提供しなければなりません。

13.7. コンテキスト分離

信頼されたUIは、ページで使用されるレンダリングコンテキスト(例: WebGLレンダリングコンテキスト)とは独立したレンダリングコンテキストによって描画され、その状態は分離されていなければなりません。これは、ページが信頼されたUIのコンテキストの状態を破壊し、トラッキング環境の正しい描画を妨げることを防ぐためです。また、ページが信頼されたUIの画像をキャプチャし、プライベート情報が漏洩する可能性も防ぎます。

さらに、CORS関連の脆弱性を防ぐため、各ブラウジングコンテキストはAPIから返されるオブジェクト(XRSessionなど)の新しいインスタンスを参照します。context属性のように、ある関連レルムで設定されたXRWebGLLayerは、同一オリジンでない別のXRWebGLLayerから読み取ることはできません。同様に、APIで呼び出されるメソッドは他のブラウジングコンテキストに観測可能な状態変化を引き起こしてはなりません。例えば、システムレベルのオリエンテーションリセットを有効にするメソッドは公開されません。これは悪意のあるページが他のページのトラッキングを妨害するために繰り返し呼び出す可能性があるためです。ただし、ユーザーのジェスチャーやシステムメニューによるシステムレベルのオリエンテーションリセットはユーザーエージェントが尊重しなければなりません。

注記: これは、あるブラウジングコンテキストがイマーシブモードに入り、デバイスのロックを取得し、他のブラウジングコンテキストdevicechangeイベントが発火するなど、状態変化が発生する場合には適用されません。

13.8. フィンガープリント

このAPIはユーザーが利用可能なハードウェアやその機能を記述するため、フィンガープリントのための追加の表面を必然的に提供します。完全に回避することは不可能ですが、ユーザーエージェントはこの問題を緩和するための措置を講じるべきです。本仕様では、利用可能なハードウェアの報告を常に1台のデバイスに限定しており、複数のヘッドセットが接続されているという稀なケースをフィンガープリントのシグナルとして利用できないようにしています。また、報告されるデバイスには文字列識別子がなく、XRSessionが作成されるまでデバイスの機能に関する情報もほとんど公開されません。XRSessionの作成時には機微な情報が公開されるため、追加の保護が必要です。

13.8.1. isSessionSupported()のフィンガープリントに関する考慮

isSessionSupported()はユーザーアクティベーションなしで呼び出せるため、フィンガープリントのベクトルとして利用される可能性があります。

"xr-session-supported"は、強力な機能としてisSessionSupported()APIへのアクセスを制御します。

"xr-session-supported"の権限関連アルゴリズムと型は次の通りです:

permission descriptor type
dictionary XRSessionSupportedPermissionDescriptor: PermissionDescriptor {
  XRSessionMode mode;
};

name for XRPermissionDescriptor is "xr-session-supported"です。

13.8.2. "xr-session-supported"を自動的に付与する場合の考慮事項

Web上ではプライバシーとパーソナライズの間にしばしば緊張関係があります。このセクションでは、そのトレードオフをどこで制限できるか、またユーザーエージェントがisSessionSupported()を通じてサイトにブラウザのWebXR機能をプライバシーを損なうことなく伝えられる場合について指針を示します。

"xr-session-supported"は、以下の基準に基づき一部のシステムで自動的に付与される場合があります。これによりユーザー体験が向上し、権限疲れを軽減できます。

ユーザーエージェントの集合が、すべて同じuserAgentおよびappVersionを報告する場合、それらはユーザーエージェント文字列で区別できないといいます。こうしたクラスは通常、ブラウザのバージョンやプラットフォーム/デバイスによって特定されますが、接続された外部デバイスの状態では区別できません。ユーザーエージェント文字列で区別できないユーザーエージェントの概念を使うことで、フィンガープリントリスクを適切に評価できます。

一部のユーザーエージェント文字列で区別できないユーザーエージェントは、特定のXRSessionModeのセッションを決してサポートしません例: モバイルARサポート要件を満たさないことが分かっている機種のスマートフォン上で動作するユーザーエージェント。この場合、isSessionSupported()が常にXRSessionModeがサポートされていないと報告しても、すべての該当デバイスが一貫して同じ値を返すため、フィンガープリントリスクはほとんどありません。また、デバイスの種類やモデルはuserAgentなど他の方法でも推測できると考えられます。したがって、このようなシステムでは、ユーザーエージェントは該当するXRSessionModeに対して"xr-session-supported"を自動的に拒否すべきです。

他のユーザーエージェント文字列で区別できないユーザーエージェントは、特定のXRSessionModeのセッションを通常サポートします例: VRヘッドセット内でのみ動作し、WebXRをサポートすることが分かっているユーザーエージェントは、ユーザーによって明示的にブロックされていない限り、"immersive-vr"セッションをサポートする可能性が高い。この場合、XRSessionModeがサポートされていないと報告することは、より一意な識別情報を与えることになります。そのため、XRSessionModeが常に利用可能と報告され、requestSession()が失敗する方がプライバシー保護につながり、ユーザーに混乱を与えることも少ないでしょう。このようなシステムでは、ユーザーエージェントは該当するXRSessionModeに対して"xr-session-supported"を自動的に付与すべきです。

XR機能の可用性が非常に可変的なユーザーエージェント文字列で区別できないユーザーエージェント(例: XR周辺機器をサポートするデスクトップシステム)は、最も高いフィンガープリントリスクを持ちます。このようなデバイス上のユーザーエージェントは、"xr-session-supported"を自動的に付与し、isSessionSupported()APIが追加のフィンガープリント情報を提供することを許してはなりません。

注記: このような場合の許容されるアプローチ例は以下の通りです:
  • isSessionSupported()が呼ばれた際、明示的な同意(キャッシュされた権限プロンプト等も含む)を常に判定する。

  • "xr-session-supported"を自動的に付与するが、XRハードウェアやソフトウェアの有無にかかわらず、isSessionSupported()が常にtrueを返すようにする。この場合、XRコンテンツを利用できないユーザーにも案内が表示されるためユーザー体験は低下する。

  • 適切なハードウェアが存在する場合のみisSessionSupported()明示的な同意を要求し、ハードウェアが存在しない場合は適切にランダムな時間経過後にfalseを返す。この場合、コンテンツはユーザーエージェントがXRハードウェアに接続されていない場合と、ユーザーが明示的な同意を拒否した場合を区別できてはならない。

どの手法を選択する場合でも、明示的な同意なしに接続されたXRハードウェアに関する追加情報を公開してはなりません。

14. 統合

14.1. Permissions Policy

この仕様は、空間トラッキングの利用を必要とするXRSessionrequestSession()で返されるかどうか、また空間トラッキングを必要とするセッションモードのサポートがisSessionSupported()devicechangeイベントで示されるかどうかを制御するポリシー制御機能を定義します。

この機能の識別子は"xr-spatial-tracking"です。

デフォルト許可リスト["self"]です。

注記: ドキュメントのオリジン"xr-spatial-tracking"permissions policyの利用を許可されていない場合、すべてのイマーシブセッションはブロックされます。なぜなら、すべてのイマーシブセッションは空間トラッキングの利用を必要とするためです。インラインセッションは引き続き許可されますが、"viewer" XRReferenceSpaceのみ利用可能に制限されます。

14.2. Permissions API統合

[permissions] APIは、ウェブサイトがユーザーに権限を要求したり、どの権限が付与されているかを照会したりするための統一的な方法を提供します。

"xr" 強力な機能の権限関連アルゴリズムと型は次の通りです:

permission descriptor type
dictionary XRPermissionDescriptor: PermissionDescriptor {
  XRSessionMode mode;
  sequence<DOMString> requiredFeatures;
  sequence<DOMString> optionalFeatures;
};

name for XRPermissionDescriptor is "xr"です。

permission result type
[Exposed=Window]
interface XRPermissionStatus: PermissionStatus {
  attribute FrozenArray<DOMString> granted;
};
permission query algorithm
"xr"パーミッションをXRPermissionDescriptor descriptorXRPermissionStatus statusで照会するには、UAは次の手順を実行しなければなりません:
  1. statusstatedescriptorpermission stateに設定する。

  2. もしstatusstate"denied"なら、statusgranted を空のFrozenArrayに設定し、これ以降の手順を中止する。

  3. resultを、descriptorrequiredFeaturesoptionalFeaturesmodeを使って要求された機能の解決を行った結果とする。

  4. もしresultnullなら、次の手順を実行する:

    1. statusgranted を空のFrozenArrayに設定する。

    2. statusstate"denied"に設定する。

    3. これ以降の手順を中止する。

  5. resultの各フィールド(consentRequired, consentOptional, granted)を取得する。

  6. statusgrantedgrantedに設定する。

  7. もしconsentRequiredconsentOptionalがいずれもなら、statusstate"granted"に設定し、これ以降の手順を中止する

  8. statusstate"prompt"に設定する。

permission request algorithm
XRPermissionDescriptor descriptorXRPermissionStatus status"xr"パーミッションをリクエストするには、UAは次の手順を実行しなければなりません:
  1. statusgranted を空のFrozenArrayに設定する。

  2. requiredFeaturesdescriptorrequiredFeaturesとする。

  3. optionalFeaturesdescriptoroptionalFeaturesとする。

  4. deviceを、moderequiredFeaturesoptionalFeatures現在のデバイスの取得を行った結果とする。

  5. resultを、requiredFeaturesoptionalFeaturesmode要求された機能の解決を行った結果とする。

  6. もしresultnullなら、次の手順を実行する:

    1. statusstate"denied"に設定する。

    2. これ以降の手順を中止する。

  7. resultの各フィールド(consentRequired, consentOptional, granted)を取得する。

  8. UAはこの時点でconsentRequiredおよびconsentOptionalのいずれかの機能の利用についてユーザーの許可を求めてもよい。これらのプロンプトの結果は、これらの機能を有効にするユーザーの意図が明確かどうかの判定に含めるべきです。

  9. consentRequired内の各featureについて次を実行する:

    1. UAはこの時点でfeatureの利用についてユーザーの許可を求めてもよい。これらのプロンプトの結果は、featureを有効にするユーザーの意図が明確かどうかの判定に含めるべきです。

    2. featureを有効にするユーザーの意図が明確でない場合、statusstate"denied"に設定し、これ以降の手順を中止する。

    3. featuregrantedに含まれていなければ、grantedに追加する。

  10. consentOptional内の各featureについて次を実行する:

    1. UAはこの時点でfeatureの利用についてユーザーの許可を求めてもよい。これらのプロンプトの結果は、featureを有効にするユーザーの意図が明確かどうかの判定に含めるべきです。

    2. featureを有効にするユーザーの意図が明確でない場合、次のエントリに進む。

    3. featuregrantedに含まれていなければ、grantedに追加する。

  11. statusgrantedgrantedに設定する。

  12. すべてのgrantedの要素をdeviceset of granted featuresmode用)に追加する。

  13. statusstate"granted"に設定する。

注記: UAは、ユーザーの意図が明確かどうかを判定する際、すべての要求機能について権限プロンプトをまとめて表示しても、1つずつ表示してもよいです。

注記: ウェブアプリケーションのユーザーの意図を判定する際、ユーザーエージェントは必ずユーザーによって明示的にウェブアプリケーションとして起動されたことを確認しなければなりません。単にオリジンがインストール済みウェブアプリケーションと一致するかどうかだけを確認してはなりません。

requiredFeaturesおよびoptionalFeaturesXRSessionMode modeが与えられたときに要求された機能の解決を行うには、ユーザーエージェントは次の手順を実行しなければなりません:

  1. consentRequired を空の リスト(型は DOMString)とする。

  2. consentOptional を空の リスト(型は DOMString)とする。

  3. granted を空の リスト(型は DOMString)とする。

  4. devicemoderequiredFeaturesoptionalFeatures に対して 現在のデバイスを取得する の結果とする。

  5. previouslyEnableddevice許可された機能のセットmode 用)とする。

  6. もし devicenull または deviceサポートされているモードのリストmode を含まない 場合、次の手順を実行する:

    1. タプル (consentRequired, consentOptional, granted) を返す。

  7. mode に紐づく デフォルト機能 テーブル内のすべての feature descriptorgranted に、未登録なら追加する。

  8. requiredFeatures の各 feature について、次の手順を実行する:

    1. もし featurenull なら、次のエントリに進む

    2. もし feature が有効な feature descriptor でなければ、null を返す。

    3. もし featuregranted に既に含まれていれば、次のエントリに進む。

    4. リクエストしているドキュメントの オリジン が、feature requirements テーブルで示される feature に必要な permissions policy のいずれかを許可されていない場合、null を返す。

    5. もし sessionXR devicefeature で説明される機能をサポートできない、またはユーザーエージェントがその機能を拒否することを決定した場合、null を返す。

    6. もし feature で説明される機能が 明示的な同意 を必要とし、featurepreviouslyEnabled に含まれていなければ、consentRequired に追加する。

    7. そうでなければ featuregranted に追加する。

  9. optionalFeatures の各 feature について、次の手順を実行する:

    1. もし featurenull なら、次のエントリに進む

    2. もし feature が有効な feature descriptor でなければ、次のエントリに進む

    3. もし featuregranted に既に含まれていれば、次のエントリに進む。

    4. リクエストしているドキュメントの origin が feature requirements テーブルで示される feature に必要な permissions policy のいずれかを許可されていなければ、次のエントリに進む。

    5. もし sessionXR devicefeature で説明される機能をサポートできない、またはユーザーエージェントがその機能を拒否した場合、次のエントリに進む。

    6. もし feature で説明される機能が 明示的な同意 を必要とし、featurepreviouslyEnabled に含まれていなければ、consentOptional に追加する。

    7. そうでなければ featuregranted に追加する。

  10. タプル (|consentRequired|, |consentOptional|, |granted|) を返す。

変更点

2022年3月31日 Candidate Recommendation Snapshot からの変更点

2020年7月24日 Working Draft からの変更点

2019年10月10日 Working Draft からの変更点

新機能:

変更点:

2019年2月5日 最初の公開ワーキングドラフト からの変更点

新機能:

削除された機能:

変更点:

15. 謝辞

WebXR Device API仕様への貢献に感謝します(敬称略):

また、このプロジェクトを始動させてくれた Vladimir Vukicevic (Unity) に特別な感謝を捧げます!

適合性

文書の規約

適合要件は、記述的な断言とRFC 2119の用語の組み合わせで表現されています。 この文書の規範的な部分における “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL” というキーワードは、RFC 2119で説明されている通りに解釈されます。 ただし、可読性のため、これらの単語は本仕様書内ですべて大文字では表記されていません。

本仕様のすべてのテキストは、明示的に非規範的、例、注記と記載されているセクションを除き、規範的です。[RFC2119]

本仕様の例は「for example」という語で始まるか、または class="example" で規範的テキストから区別されて示されます。例:

これは情報提供のための例です。

情報的な注記は「Note」で始まり、class="note" で規範的テキストから区別されて示されます。例:

Note, これは情報的な注記です。

適合するアルゴリズム

アルゴリズムの一部として命令形で記述された要件(例:「先頭の空白文字をすべて除去する」や「falseを返してこれらの手順を中止する」など)は、アルゴリズムの導入時に使われているキーワード("must"、"should"、"may"など)の意味で解釈されます。

アルゴリズムや特定の手順として表現された適合要件は、最終的な結果が同等である限り、どのような方法で実装しても構いません。 特に、本仕様で定義されているアルゴリズムは理解しやすいことを意図しており、性能を意図したものではありません。 実装者は最適化を推奨します。

索引

本仕様で定義されている用語

参照によって定義される用語

参考文献

規範的な参考文献

[DOM]
Anne van Kesteren. DOM 標準。Living Standard。 URL: https://dom.spec.whatwg.org/
[ECMASCRIPT]
ECMAScript 言語仕様。URL: https://tc39.es/ecma262/multipage/
[GEOMETRY-1]
Simon Pieters; Chris Harrelson。Geometry Interfaces Module Level 1。2018年12月4日。CR。URL: https://www.w3.org/TR/geometry-1/
[HR-TIME-3]
Yoav Weiss。高精度時刻(High Resolution Time)。2024年11月7日。WD。URL: https://www.w3.org/TR/hr-time-3/
[HTML]
Anne van Kesteren ほか。HTML 標準。Living Standard。URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola。Infra 標準。Living Standard。URL: https://infra.spec.whatwg.org/
[PERMISSIONS]
Marcos Caceres; Mike Taylor。Permissions。2025年9月26日。WD。URL: https://www.w3.org/TR/permissions/
[PERMISSIONS-POLICY-1]
Ian Clelland。Permissions Policy。2025年8月6日。WD。URL: https://www.w3.org/TR/permissions-policy-1/
[POINTEREVENTS]
Jacob Rossi; Matt Brubeck。Pointer Events。2019年4月4日。REC。URL: https://www.w3.org/TR/pointerevents/
[POINTERLOCK]
Vincent Scheib。Pointer Lock。2016年10月27日。REC。URL: https://www.w3.org/TR/pointerlock/
[REQUESTIDLECALLBACK]
Scott Haseley。requestIdleCallback()。2025年5月21日。WD。URL: https://www.w3.org/TR/requestidlecallback/
[RFC2119]
S. Bradner。RFCで要求レベルを示すキーワード。1997年3月。Best Current Practice。URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBGL-2]
Dean Jackson; Jeff Gilbert。WebGL 2.0 仕様。2017年8月12日。URL: https://www.khronos.org/registry/webgl/specs/latest/2.0/
[WEBIDL]
Edgar Chen; Timothy Gu。Web IDL 標準。Living Standard。URL: https://webidl.spec.whatwg.org/
[WEBXRLAYERS-1]
Rik Cabanier。WebXR Layers API Level 1。2025年9月12日。WD。URL: https://www.w3.org/TR/webxrlayers-1/

参考情報

[DEVICE-ORIENTATION]
Reilly Grant、Marcos Caceres。デバイスの方向および動作。2025年2月12日。CRD。URL: https://www.w3.org/TR/orientation-event/
[WEBXR-AR-MODULE-1]
Brandon Jones、Manish Goregaokar、Rik Cabanier。WebXR 拡張現実モジュール - レベル1。2025年4月25日。CRD。URL: https://www.w3.org/TR/webxr-ar-module-1/

IDL索引

partial interface Navigator {
  [SecureContext, SameObject] readonly attribute XRSystem xr;
};

[SecureContext, Exposed=Window] interface XRSystem : EventTarget {
  // Methods
  Promise<boolean> isSessionSupported(XRSessionMode mode);
  [NewObject] Promise<XRSession> requestSession(XRSessionMode mode, optional XRSessionInit options = {});

  // Events
  attribute EventHandler ondevicechange;
};

enum XRSessionMode {
  "inline",
  "immersive-vr",
  "immersive-ar"
};

dictionary XRSessionInit {
  sequence<DOMString> requiredFeatures;
  sequence<DOMString> optionalFeatures;
};

enum XRVisibilityState {
  "visible",
  "visible-blurred",
  "hidden",
};

[SecureContext, Exposed=Window] interface XRSession : EventTarget {
  // Attributes
  readonly attribute XRVisibilityState visibilityState;
  readonly attribute float? frameRate;
  readonly attribute Float32Array? supportedFrameRates;
  [SameObject] readonly attribute XRRenderState renderState;
  [SameObject] readonly attribute XRInputSourceArray inputSources;
  [SameObject] readonly attribute XRInputSourceArray trackedSources;
  readonly attribute FrozenArray<DOMString> enabledFeatures;
  readonly attribute boolean isSystemKeyboardSupported;

  // Methods
  undefined updateRenderState(optional XRRenderStateInit state = {});
  Promise<undefined> updateTargetFrameRate(float rate);
  [NewObject] Promise<XRReferenceSpace> requestReferenceSpace(XRReferenceSpaceType type);

  unsigned long requestAnimationFrame(XRFrameRequestCallback callback);
  undefined cancelAnimationFrame(unsigned long handle);

  Promise<undefined> end();

  // Events
  attribute EventHandler onend;
  attribute EventHandler oninputsourceschange;
  attribute EventHandler onselect;
  attribute EventHandler onselectstart;
  attribute EventHandler onselectend;
  attribute EventHandler onsqueeze;
  attribute EventHandler onsqueezestart;
  attribute EventHandler onsqueezeend;
  attribute EventHandler onvisibilitychange;
  attribute EventHandler onframeratechange;
};

dictionary XRRenderStateInit {
  double depthNear;
  double depthFar;
  boolean passthroughFullyObscured;
  double inlineVerticalFieldOfView;
  XRWebGLLayer? baseLayer;
  sequence<XRLayer>? layers;
};

[SecureContext, Exposed=Window] interface XRRenderState {
  readonly attribute double depthNear;
  readonly attribute double depthFar;
  readonly attribute boolean? passthroughFullyObscured;
  readonly attribute double? inlineVerticalFieldOfView;
  readonly attribute XRWebGLLayer? baseLayer;
};

callback XRFrameRequestCallback = undefined (DOMHighResTimeStamp time, XRFrame frame);

[SecureContext, Exposed=Window] interface XRFrame {
  [SameObject] readonly attribute XRSession session;
  readonly attribute DOMHighResTimeStamp predictedDisplayTime;

  XRViewerPose? getViewerPose(XRReferenceSpace referenceSpace);
  XRPose? getPose(XRSpace space, XRSpace baseSpace);
};

[SecureContext, Exposed=Window] interface XRSpace : EventTarget {

};

enum XRReferenceSpaceType {
  "viewer",
  "local",
  "local-floor",
  "bounded-floor",
  "unbounded"
};

[SecureContext, Exposed=Window]
interface XRReferenceSpace : XRSpace {
  [NewObject] XRReferenceSpace getOffsetReferenceSpace(XRRigidTransform originOffset);

  attribute EventHandler onreset;
};

[SecureContext, Exposed=Window]
interface XRBoundedReferenceSpace : XRReferenceSpace {
  readonly attribute FrozenArray<DOMPointReadOnly> boundsGeometry;
};

[SecureContext, Exposed=Window] interface mixin XRViewGeometry {
  readonly attribute Float32Array projectionMatrix;
  [SameObject] readonly attribute XRRigidTransform transform;
};

enum XREye {
  "none",
  "left",
  "right"
};

[SecureContext, Exposed=Window] interface XRView {
  readonly attribute XREye eye;
  readonly attribute unsigned long index;
  readonly attribute double? recommendedViewportScale;

  undefined requestViewportScale(double? scale);
};

XRView includes XRViewGeometry;

[SecureContext, Exposed=Window] interface XRViewport {
  readonly attribute long x;
  readonly attribute long y;
  readonly attribute long width;
  readonly attribute long height;
};

[SecureContext, Exposed=Window]
interface XRRigidTransform {
  constructor(optional DOMPointInit position = {}, optional DOMPointInit orientation = {});
  [SameObject] readonly attribute DOMPointReadOnly position;
  [SameObject] readonly attribute DOMPointReadOnly orientation;
  readonly attribute Float32Array matrix;
  [SameObject] readonly attribute XRRigidTransform inverse;
};

[SecureContext, Exposed=Window] interface XRPose {
  [SameObject] readonly attribute XRRigidTransform transform;
  [SameObject] readonly attribute DOMPointReadOnly? linearVelocity;
  [SameObject] readonly attribute DOMPointReadOnly? angularVelocity;

  readonly attribute boolean emulatedPosition;
};

[SecureContext, Exposed=Window] interface XRViewerPose : XRPose {
  [SameObject] readonly attribute FrozenArray<XRView> views;
};

enum XRHandedness {
  "none",
  "left",
  "right"
};

enum XRTargetRayMode {
  "gaze",
  "tracked-pointer",
  "screen",
  "transient-pointer"
};

[SecureContext, Exposed=Window]
interface XRInputSource {
  readonly attribute XRHandedness handedness;
  readonly attribute XRTargetRayMode targetRayMode;
  [SameObject] readonly attribute XRSpace targetRaySpace;
  [SameObject] readonly attribute XRSpace? gripSpace;
  [SameObject] readonly attribute FrozenArray<DOMString> profiles;
  readonly attribute boolean skipRendering;
};

[SecureContext, Exposed=Window]
interface XRInputSourceArray {
  iterable<XRInputSource>;
  readonly attribute unsigned long length;
  getter XRInputSource(unsigned long index);
};

[SecureContext, Exposed=Window]
interface XRLayer : EventTarget {};


typedef (WebGLRenderingContext or
         WebGL2RenderingContext) XRWebGLRenderingContext;

dictionary XRWebGLLayerInit {
  boolean antialias = true;
  boolean depth = true;
  boolean stencil = false;
  boolean alpha = true;
  boolean ignoreDepthValues = false;
  double framebufferScaleFactor = 1.0;
};

[SecureContext, Exposed=Window]
interface XRWebGLLayer: XRLayer {
  constructor(XRSession session,
             XRWebGLRenderingContext context,
             optional XRWebGLLayerInit layerInit = {});
  // Attributes
  readonly attribute boolean antialias;
  readonly attribute boolean ignoreDepthValues;
  attribute float? fixedFoveation;

  [SameObject] readonly attribute WebGLFramebuffer? framebuffer;
  readonly attribute unsigned long framebufferWidth;
  readonly attribute unsigned long framebufferHeight;

  // Methods
  XRViewport? getViewport(XRView view);

  // Static Methods
  static double getNativeFramebufferScaleFactor(XRSession session);
};

partial dictionary WebGLContextAttributes {
    boolean xrCompatible = false;
};

partial interface mixin WebGLRenderingContextBase {
    [NewObject] Promise<undefined> makeXRCompatible();
};

[SecureContext, Exposed=Window]
interface XRSessionEvent : Event {
  constructor(DOMString type, XRSessionEventInit eventInitDict);
  [SameObject] readonly attribute XRSession session;
};

dictionary XRSessionEventInit : EventInit {
  required XRSession session;
};

[SecureContext, Exposed=Window]
interface XRInputSourceEvent : Event {
  constructor(DOMString type, XRInputSourceEventInit eventInitDict);
  [SameObject] readonly attribute XRFrame frame;
  [SameObject] readonly attribute XRInputSource inputSource;
};

dictionary XRInputSourceEventInit : EventInit {
  required XRFrame frame;
  required XRInputSource inputSource;
};

[SecureContext, Exposed=Window]
interface XRInputSourcesChangeEvent : Event {
  constructor(DOMString type, XRInputSourcesChangeEventInit eventInitDict);
  [SameObject] readonly attribute XRSession session;
  [SameObject] readonly attribute FrozenArray<XRInputSource> added;
  [SameObject] readonly attribute FrozenArray<XRInputSource> removed;
};

dictionary XRInputSourcesChangeEventInit : EventInit {
  required XRSession session;
  required sequence<XRInputSource> added;
  required sequence<XRInputSource> removed;

};

[SecureContext, Exposed=Window]
interface XRReferenceSpaceEvent : Event {
  constructor(DOMString type, XRReferenceSpaceEventInit eventInitDict);
  [SameObject] readonly attribute XRReferenceSpace referenceSpace;
  [SameObject] readonly attribute XRRigidTransform? transform;
};

dictionary XRReferenceSpaceEventInit : EventInit {
  required XRReferenceSpace referenceSpace;
  XRRigidTransform? transform = null;
};

[SecureContext, Exposed=Window]
interface XRVisibilityMaskChangeEvent : Event {
  constructor(DOMString type, XRVisibilityMaskChangeEventInit eventInitDict);
  [SameObject] readonly attribute XRSession session;
  readonly attribute XREye eye;
  readonly attribute unsigned long index;
  [SameObject] readonly attribute Float32Array vertices;
  [SameObject] readonly attribute Uint32Array indices;
};

dictionary XRVisibilityMaskChangeEventInit : EventInit {
  required XRSession session;
  required XREye eye;
  required unsigned long index;
  required Float32Array vertices;
  required Uint32Array indices;
};

dictionary XRSessionSupportedPermissionDescriptor: PermissionDescriptor {
  XRSessionMode mode;
};

dictionary XRPermissionDescriptor: PermissionDescriptor {
  XRSessionMode mode;
  sequence<DOMString> requiredFeatures;
  sequence<DOMString> optionalFeatures;
};

[Exposed=Window]
interface XRPermissionStatus: PermissionStatus {
  attribute FrozenArray<DOMString> granted;
};

MDN

Navigator/xr

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

WebGLRenderingContext/makeXRCompatible

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?

WebGLRenderingContext/makeXRCompatible

In only one current engine.

FirefoxNoneSafariNoneChrome79+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera MobileNone
MDN

XRBoundedReferenceSpace/boundsGeometry

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRBoundedReferenceSpace

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRFrame/getPose

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRFrame/getViewerPose

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRFrame/session

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRFrame

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSource/gripSpace

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSource/handedness

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSource/profiles

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSource/targetRayMode

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSource/targetRaySpace

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSource

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSourceArray/length

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSourceArray

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSourceEvent/XRInputSourceEvent

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSourceEvent/frame

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSourceEvent/inputSource

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSourceEvent

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSourcesChangeEvent/XRInputSourcesChangeEvent

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSourcesChangeEvent/added

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSourcesChangeEvent/removed

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSourcesChangeEvent/session

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRInputSourcesChangeEvent

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRLayer

In only one current engine.

FirefoxNoneSafariNoneChrome84+
Opera?Edge84+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

XRPose/angularVelocity

In no current engines.

FirefoxNoneSafariNoneChromeNone
Opera?EdgeNone
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRPose/emulatedPosition

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRPose/linearVelocity

In no current engines.

FirefoxNoneSafariNoneChromeNone
Opera?EdgeNone
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRPose/transform

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRPose

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRReferenceSpace/getOffsetReferenceSpace

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRReferenceSpace/reset_event

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRReferenceSpace/reset_event

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRReferenceSpace

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRReferenceSpaceEvent/XRReferenceSpaceEvent

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRReferenceSpaceEvent/referenceSpace

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRReferenceSpaceEvent/transform

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRReferenceSpaceEvent

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRRenderState/baseLayer

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRRenderState/depthFar

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRRenderState/depthNear

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRRenderState/inlineVerticalFieldOfView

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRRenderState

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRRigidTransform/XRRigidTransform

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRRigidTransform/inverse

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRRigidTransform/matrix

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRRigidTransform/orientation

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRRigidTransform/position

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRRigidTransform

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/cancelAnimationFrame

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/end

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/end_event

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/end_event

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/inputSources

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/inputsourceschange_event

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/inputsourceschange_event

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/renderState

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/requestAnimationFrame

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/requestReferenceSpace

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/select_event

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/select_event

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/selectend_event

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/selectend_event

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/selectstart_event

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/selectstart_event

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/squeeze_event

In only one current engine.

FirefoxNoneSafariNoneChrome83+
Opera?Edge83+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRSession/squeeze_event

In only one current engine.

FirefoxNoneSafariNoneChrome83+
Opera?Edge83+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRSession/squeezeend_event

In only one current engine.

FirefoxNoneSafariNoneChrome83+
Opera?Edge83+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRSession/squeezeend_event

In only one current engine.

FirefoxNoneSafariNoneChrome83+
Opera?Edge83+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRSession/squeezestart_event

In only one current engine.

FirefoxNoneSafariNoneChrome83+
Opera?Edge83+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRSession/squeezestart_event

In only one current engine.

FirefoxNoneSafariNoneChrome83+
Opera?Edge83+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRSession/updateRenderState

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/visibilitychange_event

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/visibilitychange_event

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession/visibilityState

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSession

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSessionEvent/XRSessionEvent

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSessionEvent/session

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSessionEvent

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSpace

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRSystem/devicechange_event

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRSystem/devicechange_event

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRSystem/isSessionSupported

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRSystem/requestSession

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRSystem

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRView/eye

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRView/recommendedViewportScale

In only one current engine.

FirefoxNoneSafariNoneChrome90+
Opera?Edge90+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRView/requestViewportScale

In only one current engine.

FirefoxNoneSafariNoneChrome90+
Opera?Edge90+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

XRView

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRViewerPose/views

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRViewerPose

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRViewport/height

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRViewport/width

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRViewport/x

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRViewport/y

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRViewport

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRWebGLLayer/XRWebGLLayer

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRWebGLLayer/antialias

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRWebGLLayer/fixedFoveation

In no current engines.

FirefoxNoneSafariNoneChromeNone
Opera?EdgeNone
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

XRWebGLLayer/framebuffer

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRWebGLLayer/framebufferHeight

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRWebGLLayer/framebufferWidth

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRWebGLLayer/getNativeFramebufferScaleFactor_static

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRWebGLLayer/getViewport

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRWebGLLayer/ignoreDepthValues

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

XRWebGLLayer

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet11.2+Opera Mobile?
MDN

Headers/Feature-Policy/xr-spatial-tracking

In only one current engine.

FirefoxNoneSafariNoneChrome79+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera MobileNone

Headers/Permissions-Policy/xr-spatial-tracking

In only one current engine.

FirefoxNoneSafariNoneChrome88+
Opera?Edge88+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera MobileNone