WebXR 장치 API

W3C 후보 권고안 초안,

이 문서에 대한 자세한 정보
이 버전:
https://www.w3.org/TR/2026/CRD-webxr-20260609/
최신 공개 버전:
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])
참여:
문제 제기 (열린 문제)
메일링 리스트 아카이브
W3C의 #immersive-web IRC

초록

이 명세는 센서와 헤드 마운트 디스플레이를 포함하여, 웹에서 가상 현실(VR) 및 증강 현실(AR) 장치에 접근하기 위한 지원을 설명한다.

이 문서의 상태

이 절은 이 문서가 공개된 시점의 상태를 설명한다. 현재 W3C 공개 문서 목록과 이 기술 보고서의 최신 개정판은 W3C 표준 및 초안 색인에서 찾을 수 있다.

Immersive Web Working Group은 그룹이 아직 처리하지 않은 모든 버그 보고서 목록을 관리한다. 이 초안은 작업 그룹에서 아직 논의해야 하는 일부 보류 중인 이슈를 강조한다. 이러한 이슈의 결과에 대해서는, 유효한지 여부를 포함하여, 아직 어떠한 결정도 내려지지 않았다. 미해결 이슈에 대한 명세 텍스트를 제안하는 풀 리퀘스트를 강력히 권장한다.

이 문서는 Immersive Web Working Group권고안 트랙을 사용하여 후보 권고안 초안으로 공개했다. 이 문서는 W3C 권고안이 되는 것을 목적으로 한다.

후보 권고안으로 공개되었다고 해서 W3C 및 그 회원들의 승인을 의미하지는 않는다. 후보 권고안 초안은 작업 그룹이 이후의 후보 권고안 스냅샷에 포함하려는 이전 후보 권고안의 변경 사항을 통합한다. 이는 초안 문서이며 언제든지 다른 문서로 갱신, 대체 또는 폐기될 수 있다. 이 문서를 진행 중인 작업 이외의 것으로 인용하는 것은 부적절하다.

이 문서가 제안 권고안 단계에 진입하기 위한 진입 기준은 이 명세의 모든 기능을 구현하는 최소 두 개의 독립적이고 상호 운용 가능한 사용자 에이전트를 보유하는 것이며, 이는 작업 그룹이 개발한 테스트 스위트에 정의된 사용자 에이전트 테스트를 통과함으로써 결정된다. 작업 그룹은 진행 상황을 추적하기 위해 구현 보고서를 준비할 것이다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹이 작성했다. W3C는 그룹의 산출물과 관련하여 이루어진 모든 특허 공개의 공개 목록을 유지한다. 해당 페이지에는 특허를 공개하기 위한 지침도 포함되어 있다. 개인이 필수 청구항을 포함한다고 믿는 특허에 대해 실제 지식을 가진 경우, 그 개인은 W3C 특허 정책 6절에 따라 해당 정보를 공개해야 한다.

이 문서는 2025년 8월 18일 W3C Process Document의 적용을 받는다.

마지막 초안 이후의 변경 사항은 변경 사항 절을 참조하라.

1. 소개

가상 현실(VR) 및 증강 현실(AR) 애플리케이션을 가능하게 하는 하드웨어는 이제 소비자에게 널리 제공되고 있으며, 새로운 기회와 과제를 모두 갖춘 몰입형 컴퓨팅 플랫폼을 제공한다. 몰입형 하드웨어와 직접 상호작용할 수 있는 능력은 웹이 이 환경에서 일급 시민으로 동작할 수 있도록 보장하는 데 중요하다.

몰입형 컴퓨팅은 허용 가능한 경험을 제공하기 위해 고정밀, 저지연 통신에 대한 엄격한 요구 사항을 도입한다. 또한 웹과 같은 플랫폼에 고유한 보안 우려도 가져온다. WebXR Device API는 개발자가 다양한 하드웨어 폼 팩터 전반에서 웹상에 매력적이고, 편안하며, 안전한 몰입형 애플리케이션을 구축할 수 있도록 하는 데 필요한 인터페이스를 제공한다.

RelativeOrientationSensorAbsoluteOrientationSensor와 같은 다른 웹 인터페이스는 제한된 상황에서 WebXR Device API를 폴리필하기 위해 일부 장치의 입력을 노출하도록 용도를 바꿀 수 있다. 그러나 이러한 인터페이스는 6DoF 추적, 헤드셋 주변 장치로의 프레젠테이션, 또는 추적되는 입력 장치와 같은 고급 몰입형 경험의 여러 기능을 지원할 수 없다.

1.1. 용어

이 문서는 가상 현실, 증강 현실 및 기타 관련 기술에 사용되는 하드웨어, 애플리케이션 및 기법의 스펙트럼을 가리키기 위해 전반적으로 약어 XR을 사용한다. 예시는 다음을 포함하지만 이에 한정되지 않는다.

이들 사이의 중요한 공통점은 가상 콘텐츠의 뷰를 시뮬레이션하는 데 사용할 수 있는 어느 정도의 공간 추적을 제공한다는 점이다.

"XR device", "XR application" 등과 같은 용어는 일반적으로 위의 모든 것에 적용되는 것으로 이해된다. 이 문서에서 이러한 장치의 하위 집합에만 적용되는 부분은 적절하게 이를 표시한다.

3DoF6DoF라는 용어는 이 문서 전반에서 XR 장치의 추적 기능을 설명하는 데 사용된다.

1.2. 애플리케이션 흐름

WebXR Device API를 사용하는 대부분의 애플리케이션은 유사한 사용 패턴을 따른다.

2. 모델

2.1. XR 장치

XR 장치는 사용자에게 몰입형 콘텐츠를 제공할 수 있는 물리적 하드웨어 단위이다. 콘텐츠가 사용자의 환경의 다양한 측면을 시뮬레이션하거나 증강하는 시각, 오디오, 햅틱 또는 기타 감각 출력을 생성하는 경우, 해당 콘텐츠는 "몰입형"으로 간주된다. 가장 흔히 이는 공간에서 사용자의 움직임을 추적하고 사용자의 움직임과 동기화된 출력을 생성하는 것을 포함한다. 데스크톱 클라이언트에서는 일반적으로 헤드셋 주변 장치이다. 모바일 클라이언트에서는 뷰어 하니스와 결합된 모바일 장치 자체를 나타낼 수 있다. 또한 스테레오 프레젠테이션 기능은 없지만 더 고급 추적 기능을 갖춘 장치를 나타낼 수도 있다.

XR 장치지원되는 모드 목록(list of strings)을 가지며, 이는 해당 contains the enumeration values of XRSessionMode that the XR device supports.

XR 장치는 해당 지원되는 모드 목록의 각 XRSessionMode에 대해 허가된 기능 집합을 가지며, 이는 처음에는 빈 set이어야 하는 기능 설명자set이다.

사용자 에이전트는 몰입형 XR 장치 목록(list of XR device)을 가지며, 이는 처음에는 빈 list여야 한다.

사용자 에이전트는 몰입형 XR 장치(null 또는 XR device)를 가지며, 이는 처음에는 null이고 몰입형 XR 장치 목록에서 활성 XR 장치를 나타낸다. 이 객체는 별도의 스레드에 존재할 수 있으며 비동기적으로 갱신될 수 있다.

사용자 에이전트는 기본 인라인 XR 장치를 가져야 하며, 이는 자신의 지원되는 모드 목록"inline"을 반드시 contain해야 하는 XR 장치이다. 기본 인라인 XR 장치는 어떤 포즈 정보도 보고해서는 안 되며, pointer events에 의해 생성된 것 이외의 XR 입력 소스나 이벤트를 보고해서도 안 된다.

참고: 기본 인라인 XR 장치는 개발자를 위한 편의 목적으로만 존재하며, 인라인 콘텐츠와 몰입형 콘텐츠 모두에 동일한 렌더링 및 입력 로직을 사용할 수 있게 한다. 기본 인라인 XR 장치는 페이지의 다른 메커니즘(예: 입력을 위한 pointer events)을 통해 개발자가 이미 사용할 수 있는 정보 이외의 정보를 노출하지 않으며, 단지 해당 값을 XR 중심 형식으로 노출할 뿐이다.

사용자 에이전트는 인라인 XR 장치를 가져야 하며, 이는 자신의 지원되는 모드 목록"inline"을 반드시 contain해야 하는 XR 장치이다. 인라인 XR 장치는 지원되는 기본 뷰를 HTML 문서의 일부로 노출할 수 있다면 inline-stereo 기능 설명자지원할 수 있는 상태일 수 있다. 인라인 XR 장치는 제공하는 추적을 인라인 콘텐츠에 노출하는 것이 타당하다면 몰입형 XR 장치일 수 있고, 그렇지 않으면 기본 인라인 XR 장치일 수 있다.

참고: 휴대폰에서는 인라인 XR 장치가 자이로스코프 및 가속도계와 같은 휴대폰의 내부 센서에서 파생된 포즈 정보를 보고할 수 있다. 유사한 센서가 없는 데스크톱과 노트북에서는 인라인 XR 장치가 포즈를 보고할 수 없으므로 기본 인라인 XR 장치로 폴백해야 한다. 사용자 에이전트가 이미 XR 장치에서 실행 중인 경우, 인라인 XR 장치는 동일한 장치가 되며 여러 를 지원할 수 있다. 기본 인라인 XR 장치가 노출하는 것을 넘어서는 추적 또는 입력 기능이 제공되기 전에 사용자 동의를 받아야 한다.

몰입형 XR 장치 목록, 인라인 XR 장치, 및 몰입형 XR 장치의 현재 값은 별도의 스레드에 존재할 수 있으며 비동기적으로 갱신될 수 있다. 이러한 객체는 in parallel로 실행되지 않는 단계에서 직접 접근해서는 안 된다.

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;
};

사용자 에이전트는 Navigator 객체가 생성될 때 XRSystem 객체를 생성하고 이를 해당 객체와 연결해야 한다.

XRSystem 객체는 API의 진입점으로, 사용자 에이전트에서 사용할 수 있는 XR 기능을 질의하고 XRSession 생성 을 통해 XR 하드웨어와의 통신을 시작하는 데 사용된다.

사용자 에이전트는 시스템에 연결된 몰입형 XR 장치를 열거할 수 있어야 하며, 이때 사용 가능한 각 장치는 몰입형 XR 장치 목록에 배치된다. 열거를 요청하는 후속 알고리즘은 캐시된 몰입형 XR 장치 목록을 재사용해야 한다. 장치를 열거하는 것은 장치 추적을 초기화해서는 안 된다. 첫 번째 열거 이후 사용자 에이전트는 장치 연결 및 연결 해제를 모니터링하기 시작해야 하며, 연결된 장치를 몰입형 XR 장치 목록에 추가하고 연결 해제된 장치를 제거해야 한다.

몰입형 XR 장치 목록이 변경될 때마다 사용자 에이전트는 다음 단계를 실행하여 몰입형 XR 장치를 선택해야 한다.

  1. oldDevice몰입형 XR 장치로 둔다.

  2. 몰입형 XR 장치 목록이 빈 list라면, 몰입형 XR 장치null로 설정한다.

  3. 몰입형 XR 장치 목록size가 하나라면, 몰입형 XR 장치몰입형 XR 장치 목록[0]으로 설정한다.

  4. 몰입형 XR 장치를 다음과 같이 설정한다.

    활성 XRSession이 있고 몰입형 XR 장치 목록oldDevicecontains하는 경우:

    몰입형 XR 장치oldDevice로 설정한다.

    그렇지 않은 경우:

    몰입형 XR 장치를 사용자 에이전트가 선택한 장치로 설정한다.

  5. 사용자 에이전트는 적절하다면 인라인 XR 장치몰입형 XR 장치로 갱신할 수 있고, 그렇지 않으면 기본 인라인 XR 장치로 갱신할 수 있다.

  6. 장치가 처음으로 열거된 경우 또는 oldDevice몰입형 XR 장치와 같다면, 이 단계를 중단한다.

  7. 활성 XRSession을 모두 종료한다.

  8. 모든 WebGLRenderingContextBase 인스턴스의 XR compatible boolean을 false로 설정하기 위해 작업을 큐에 넣는다.

  9. 작업을 큐에 넣어 이벤트를 발생시키되, 관련 Global 객체navigatorxr에서 devicechange라는 이름으로 발생시킨다.

  10. 작업을 큐에 넣어 몰입형 XR 장치 또는 인라인 XR 장치의 변경에 영향을 받는 모든 XRPermissionStatus 객체에서 적절한 change 이벤트를 발생시킨다.

참고: 이러한 단계는 항상 in parallel로 실행되어야 한다.

참고: 몰입형 XR 장치 목록에 여러 장치가 포함되어 있을 때 사용자 에이전트는 몰입형 XR 장치를 선택하기 위해 원하는 어떤 기준이든 사용할 수 있다. 예를 들어, 사용자 에이전트는 항상 목록의 첫 번째 항목을 선택하거나, 사용자가 장치 우선순위를 관리할 수 있는 설정 UI를 제공할 수 있다. 기본 장치를 선택하는 데 사용되는 알고리즘은 안정적이고 여러 브라우징 세션에 걸쳐 동일한 장치가 선택되는 결과를 낳는 것이 이상적이다.

사용자 에이전트는 다음 단계를 실행하여 몰입형 XR 장치가 선택되도록 보장할 수 있다.

  1. 몰입형 XR 장치null이 아니면, 몰입형 XR 장치를 반환하고 이 단계를 중단한다.

  2. 몰입형 XR 장치를 열거한다.

  3. 몰입형 XR 장치를 선택한다.

  4. 몰입형 XR 장치를 반환한다.

참고: 이러한 단계는 항상 in parallel로 실행되어야 한다.

ondevicechange 속성은 Event handler IDL attribute로, devicechange 이벤트 유형을 위한 것이다.

isSessionSupported(mode) 메서드는 주어진 mode가 사용자 에이전트 및 장치 기능에 의해 지원될 수 있는지를 질의한다.

이 메서드가 호출되면 다음 단계를 실행해야 한다.

  1. promise를 이 XRSystem관련 realm에 있는 새 Promise로 둔다.

  2. mode"inline"이면, promisetrueresolve하고 이를 반환한다.

  3. mode몰입형 세션 모드이고 요청하는 문서의 origin이 "xr-spatial-tracking" 권한 정책을 사용할 수 있도록 허용되지 않은 경우, promise를 "SecurityError" DOMException으로 reject하고 이를 반환한다.

  4. 세션 mode가 지원되는지 다음과 같이 확인한다.

    사용자 에이전트와 시스템이 mode 세션을 절대 지원하지 않는 것으로 알려진 경우

    promisefalseResolve한다.

    사용자 에이전트와 시스템이 mode 세션을 보통 지원하는 것으로 알려진 경우

    사용자 에이전트 문자열로 구별할 수 없는 이 사용자 에이전트의 모든 인스턴스가 여기에서 동일한 결과를 생성한다면, promisetrueresolved될 수 있다.

    그렇지 않은 경우

    다음 단계를 in parallel로 실행한다.

    1. devicemode, 빈 list, 및 빈 list에 대해 현재 장치를 얻은 결과로 둔다.

    2. device가 null이면, promisefalseresolve하고 이 단계를 중단한다.

    3. device지원되는 모드 목록modecontain하지 않으면, promisefalseresolve하도록 작업을 큐에 넣고 이 단계를 중단한다.

    4. modemode와 같은 XRSessionSupportedPermissionDescriptor강력한 기능 "xr-session-supported"을 사용하기 위한 권한을 요청한다. 이것이 "denied"를 반환하면, promisefalseresolve하도록 작업을 큐에 넣고 이 단계를 중단한다. 자세한 내용은 핑거프린팅 고려 사항을 참조하라.

    5. promisetrueresolve하도록 작업을 큐에 넣는다.

  5. promise를 반환한다.

참고: isSessionSupported()의 목적은 사용자 에이전트가 XRSession을 생성할 수 있는지를 완벽한 정확도로 보고하는 것이 아니라, 주어진 모드의 세션을 생성할 수 있음을 페이지가 알리는 것이 권장되는지 여부를 알려 주는 것이다. 사용자 에이전트가 메서드를 resolve하기 전에 필요한 하드웨어/소프트웨어의 존재를 확인하는 경우에도, 어느 정도의 false-positive가 예상된다. (예를 들어, 적절한 하드웨어가 존재하더라도 세션이 요청될 때 다른 애플리케이션에 독점 접근 권한을 부여했을 수 있다.)

XR 콘텐츠가 있는 대부분의 페이지는 문서 생명주기의 초기에 isSessionSupported()를 호출할 것으로 예상된다. 따라서 isSessionSupported() 호출은 모달 또는 기타 방해가 되는 UI를 표시하는 것을 피해야 한다. isSessionSupported() 호출은 장치 선택 UI를 트리거해서는 안 되며, 시스템에서 실행 중인 XR 애플리케이션을 방해해서는 안 되며, 시스템 트레이나 스토어프런트와 같은 XR 관련 애플리케이션이 실행되도록 해서도 안 된다.

다음 코드는 immersive-vr 세션이 지원되는지 확인한다.
const supported = await navigator.xr.isSessionSupported('immersive-vr');
if (supported) {
  // 'immersive-vr' sessions may be supported.
  // Page should advertise support to the user.
} else {
  // 'immersive-vr' sessions are not supported.
}

XRSystem 객체는 처음에는 false여야 하는 대기 중인 몰입형 세션 boolean, 처음에는 null이어야 하는 활성 몰입형 세션, 그리고 처음에는 비어 있어야 하는 인라인 세션 목록을 가진다.

requestSession(mode, options) 메서드는 가능한 경우 주어진 mode에 대해 XRSession을 초기화하려고 시도하며, 필요한 경우 몰입형 모드로 진입한다.

이 메서드가 호출되면 사용자 에이전트는 다음 단계를 실행해야 한다.

  1. promise를 이 XRSystem관련 realm에 있는 새 Promise로 둔다.

  2. mode몰입형 세션 모드이면 immersivetrue로 두고, 그렇지 않으면 false로 둔다.

  3. global object를 이 메서드가 호출된 XRSystem관련 Global 객체로 둔다.

  4. 세션 요청이 허용되는지 다음과 같이 확인한다.

    immersivetrue인 경우:
    1. global object에 대해 몰입형 세션 요청이 허용되는지 확인하고, 그렇지 않다면 promise를 "SecurityError" DOMException으로 reject하고 promise를 반환한다.

    2. 대기 중인 몰입형 세션true이거나 활성 몰입형 세션null이 아니면, promise를 "InvalidStateError" DOMException으로 reject하고 promise를 반환한다.

    3. 대기 중인 몰입형 세션true로 설정한다.

    그렇지 않은 경우:

    global object에 대해 인라인 세션 요청이 허용되는지 확인하고, 그렇지 않다면 promise를 "SecurityError" DOMException으로 reject하고 promise를 반환한다.

  5. 다음 단계를 in parallel로 실행한다.

    1. requiredFeaturesoptionsrequiredFeatures로 둔다.

    2. optionalFeaturesoptionsoptionalFeatures로 둔다.

    3. devicemode, requiredFeatures, 및 optionalFeatures에 대해 현재 장치를 얻은 결과로 설정한다.

    4. 다음 단계를 수행하도록 작업을 큐에 넣는다:

      1. devicenull이거나 device지원되는 모드 목록modecontain하지 않으면, 다음 단계를 실행한다:

        1. promise를 "NotSupportedError" DOMException으로 Reject한다.

        2. immersivetrue이면, 대기 중인 몰입형 세션false로 설정한다.

        3. 이 단계를 중단한다.

      2. descriptormode, requiredFeatures, 및 optionalFeatures로 초기화된 XRPermissionDescriptor로 둔다

      3. status를 처음에는 nullXRPermissionStatus로 둔다

      4. descriptorstatusxr 권한을 요청한다.

      5. statusstate"denied"이면 다음 단계를 실행한다:

        1. promise를 "NotSupportedError" DOMException으로 Reject한다.

        2. immersivetrue이면, 대기 중인 몰입형 세션false로 설정한다.

        3. 이 단계를 중단한다.

      6. grantedstatusgranted에서 얻은 set으로 둔다.

      7. session을 이 XRSystem관련 realm에 있는 XRSession 객체로 둔다.

      8. session, mode, granted, 및 device세션을 초기화한다.

      9. 활성 몰입형 세션을 잠재적으로 다음과 같이 설정한다:

        immersivetrue인 경우:

        활성 몰입형 세션session으로 설정하고, 대기 중인 몰입형 세션false로 설정한다.

        그렇지 않은 경우:

        session인라인 세션 목록에 추가한다.

      10. promisesession으로 Resolve한다.

      11. 다음 단계를 수행하도록 작업을 큐에 넣는다:

        참고: 이러한 단계는 초기 inputsourceschange 이벤트가 초기 세션이 resolve된 후에 발생하도록 보장한다.
        1. sessionpromise resolved 플래그를 true로 설정한다.

        2. sourcessession에 연결된 기존 입력 소스로 둔다.

        3. sources가 비어 있지 않다면, 다음 단계를 수행한다:

          1. session활성 XR 입력 소스 목록sources로 설정한다.

          2. XRInputSourcesChangeEventinputsourceschange라는 이름으로 session에서 발생시키되, addedsources로 설정한다.

  6. promise를 반환한다.

XRSessionMode mode, requiredFeatures, 및 optionalFeatures에 대해 현재 장치를 얻으려면 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. device를 다음과 같이 선택한다:

    mode몰입형 세션 모드인 경우:

    device몰입형 XR 장치가 선택되도록 보장한 결과로 설정한다.

    그렇지 않고 requiredFeatures 또는 optionalFeatures가 비어 있지 않은 경우:

    device인라인 XR 장치로 설정한다.

    그렇지 않은 경우:

    device기본 인라인 XR 장치로 설정한다.

  2. device를 반환한다.

참고: 이러한 단계는 항상 in parallel로 실행되어야 한다.

다음 코드는 immersive-vr XRSession을 가져오려고 시도한다.
const xrSession = await navigator.xr.requestSession("immersive-vr");

3.3. XRSessionMode

XRSessionMode enum은 XRSession이 동작할 수 있는 모드를 정의한다.

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

이 문서에서 인라인 세션이라는 용어는 inline 세션을 가리키며, 몰입형 세션이라는 용어는 immersive-vr 또는 immersive-ar 세션을 가리킨다.

몰입형 세션은 어느 정도의 viewer 추적을 제공해야 하며, 콘텐츠는 사용자 및/또는 주변 환경에 상대적인 적절한 스케일로 표시되어야 한다. 또한 몰입형 세션몰입형 XR 장치에 대한 독점 접근을 부여받아야 한다. 이는 몰입형 세션"visible"인 동안 HTML 문서가 몰입형 XR 장치의 디스플레이에 표시되지 않으며, 다른 소스의 콘텐츠도 독점 접근을 가지지 않음을 의미한다. 독점 접근은 사용자 에이전트가 자체 UI를 오버레이하는 것을 막지는 않지만, 이 UI는 최소화되어야 한다.

참고: UA는 대체 입력 소스가 없을 때 보호 경계, 장애물 또는 사용자의 손과 같은 접근성 또는 안전을 위한 콘텐츠를 오버레이하도록 선택할 수 있다.

참고: 향후 명세 또는 모듈은 몰입형 세션의 정의를 추가 세션 모드를 포함하도록 확장할 수 있다.

참고: 독점 접근이 제공될 수 있는 방식의 예에는 가상 현실 헤드셋에 표시되는 스테레오 콘텐츠가 포함된다.

참고: 오버레이된 UI의 예로, 몰입형 세션에서 사용자 에이전트 또는 운영 체제가 렌더링된 콘텐츠 위에 알림을 표시할 수 있다.

참고: 몰입형 XR 장치의 디스플레이에는 몰입형 세션 동안 HTML 문서가 표시되지 않지만, 별도의 디스플레이에는 여전히 표시될 수 있다. 예를 들어 사용자가 자신의 몰입형 XR 장치에 연결된 컴퓨터의 2d 브라우저에서 몰입형 세션에 진입하는 경우가 그렇다.

3.4. 기능 의존성

XRSession의 일부 기능은 여러 이유로 보편적으로 사용할 수 없을 수 있으며, 그중 하나는 모든 XR 장치가 전체 기능 집합을 지원할 수 있는 것은 아니라는 점이다. 또 다른 고려 사항은 일부 기능이 민감한 정보를 노출하여 동작하기 전에 사용자 의도의 명확한 신호를 요구할 수 있다는 점이다.

기저 XR 플랫폼을 초기화하고 XRSession을 생성한 직후 애플리케이션이 올바르게 동작할 수 없음을 사용자에게 알리는 것은 나쁜 사용자 경험이므로, 개발자는 requestSession()XRSessionInit dictionary를 전달하여 필수 기능을 표시할 수 있다. 이는 장치 제한으로 인해 또는 해당 기능과 관련된 민감한 정보를 노출하려는 사용자 의도의 명확한 신호가 없는 경우 필수 기능 중 하나라도 사용할 수 없으면 XRSession 생성이 차단되도록 한다.

또한 개발자는 더 유능한 장치에서 실행될 때 기능을 점진적으로 향상시키는 경험을 설계하도록 권장된다. 경험에 필수는 아니지만 사용 가능할 때 활용할 선택적 기능도 필요한 경우 기능을 활성화하기 전에 사용자 의도를 결정할 수 있도록 XRSessionInit dictionary에 표시되어야 한다.

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

requiredFeaturesoptionalFeatures가 제공하는 기능 설명자의 결합 목록은 XRSession에 대한 요청된 기능으로 집합적으로 간주된다.

요청된 기능 목록에 있을 때, 일부 기능 설명자권한 정책 및/또는 해당 기능을 사용하려는 사용자 의도명시적 동의 또는 묵시적 동의를 통해 잘 이해되어야 한다는 요구 사항의 적용을 받는다. 다음 표는 활성화되기 전에 충족되어야 하는 기능 요구 사항을 설명한다:

기능 Permissions Policy 필요 여부 동의 필요 여부
"local" "xr-spatial-tracking" 인라인 세션은 동의가 필요함
"local-floor" "xr-spatial-tracking" 항상 동의가 필요함
"bounded-floor" "xr-spatial-tracking" 항상 동의가 필요함
"unbounded" "xr-spatial-tracking" 항상 동의가 필요함

참고: "local"몰입형 세션요청된 기능기본 기능으로 항상 포함되며, 따라서 몰입형 세션은 항상 명시적 동의 또는 묵시적 동의를 얻어야 한다.

inline-stereo 기능 설명자는 인라인 세션이 인라인 프레젠테이션을 위해 스테레오 기본 뷰를 노출하도록 요청한다. 활성화되면, 뷰 목록은 두 개의 기본 뷰를 포함해야 하며, 하나의 eye"left"이고, 다른 하나의 eye"right"이다.

inline-stereo 기능 설명자는 "inline" 세션에만 적용된다. 이는 몰입형 세션에 부여되어서는 안 된다.

요청된 기능XR 장치가 해당 기능을 지원할 수 있는 경우에만 세션에 대해 활성화될 수 있다. 이는 현재 구성이 아직 해당 기능을 지원하는 것으로 검증되지 않았더라도, 어떤 구성에서는 해당 기능이 XR 장치에서 지원되는 것으로 알려져 있음을 의미한다. 사용자 에이전트는 더 일관된 사용자 경험을 산출하기 위해 원한다면 더 엄격한 제약을 적용할 수 있다.

참고: 예를 들어, 여러 VR 장치는 사용자가 그 안에서 움직일 수 있는 안전 경계를 구성하거나, 경계 구성을 건너뛰고 사용자가 제자리에서 서 있을 것으로 예상되는 모드에서 동작하도록 구성하는 것 중 하나를 지원한다. 이러한 장치는 현재 안전 경계가 구성되어 있지 않더라도 "bounded-floor" XRReferenceSpace지원할 수 있는 것으로 간주될 수 있다. 이는 경험이 이를 요구한다면 사용자가 장치를 적절히 구성할 수 있을 것으로 예상되기 때문이다. 이는 사용자 에이전트가 원한다면 요청된 기능을 resolve하기 전에 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;
};

XRSessionXRSessionMode의 값 중 하나인 mode를 가진다.

XRSessionanimation frame을 가지며, 이는 activefalse로, animationFrametrue로, 그리고 session이 해당 XRSession으로 설정되어 초기화된 XRFrame이다.

XRSession허가된 기능 집합을 가지며, 이는 해당 XRSession에 허가된 기능 설명자에 대응하는 DOMString들의 set이다.

enabledFeatures 속성은 허가된 기능 집합의 기능들을 DOMString의 새 배열로 반환한다.

isSystemKeyboardSupported 속성은 XRSystemXRSession이 활성 상태인 동안 시스템 키보드를 표시할 수 있음을 나타낸다. isSystemKeyboardSupportedtrue이면, 오버레이 키보드를 트리거하는 Web API(예: focus)는 시스템 키보드를 표시한다. XRSession은 키보드가 표시되는 동안 XRSessionvisibility state"visible-blurred"로 설정해야 한다.

session, mode, granted, 그리고 device가 주어졌을 때 세션을 초기화하려면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. sessionmodemode로 설정한다.

  2. sessionXR 장치device로 설정한다.

  3. session허가된 기능 집합granted로 설정한다.

  4. 렌더 상태를 초기화한다.

  5. 사용자 에이전트의 다른 기능이 아직 그렇게 하지 않았다면, 필요한 안내를 사용자에게 표시하는 것을 포함하여, 장치의 추적 및 렌더링 기능을 초기화하는 데 필요한 플랫폼별 단계를 수행한다.

참고: 일부 장치는 활성화를 위해 추가적인 사용자 안내가 필요하다. 예를 들어, 휴대폰 기반 헤드셋 장치에서 몰입형 모드로 들어가려면 휴대폰을 헤드셋에 삽입해야 하며, 외부 헤드셋에 연결된 데스크톱 브라우저에서 그렇게 하려면 헤드셋을 착용해야 한다. 이러한 안내가 표시되도록 보장하는 책임은 작성자가 아니라 사용자 에이전트에 있다.

여러 다른 상황에서 세션을 종료할 수 있으며, 이는 영구적이고 되돌릴 수 없다. 세션이 종료된 뒤 XR 장치의 추적 또는 렌더링 기능에 다시 접근하는 유일한 방법은 새 세션을 요청하는 것이다. 각 XRSession은 처음에 false로 설정되는 ended boolean을 가지며, 이는 해당 세션이 종료되었는지를 나타낸다.

XRSession session이 종료되면 다음 단계가 실행된다:

  1. sessionended 값을 true로 설정한다.

  2. 활성 몰입형 세션session과 같으면, 활성 몰입형 세션null로 설정한다.

  3. session인라인 세션 목록에서 제거한다.

  4. end()가 반환한 promise를 제외하고, session이 반환한 미해결 promise를 모두 InvalidStateErrorReject한다.

  5. 사용자 에이전트의 다른 기능이 이를 능동적으로 사용하고 있지 않다면, 장치의 추적 및 렌더링 기능을 종료하는 데 필요한 플랫폼별 단계를 수행한다. 여기에는 다음이 포함되어야 한다:

  6. XRSessionEventend라는 이름으로 session에서 발생시키는 작업을 큐에 넣는다.

end() 메서드는 세션을 수동으로 종료하는 방법을 제공한다. 호출되면 다음 단계를 실행해야 한다:

  1. promise를 이 XRSession관련 realm에 있는 새 Promise로 둔다.

  2. thisended 값이 true이면, promise를 "InvalidStateError" DOMException으로 reject하고 promise를 반환한다.

  3. this종료한다.

  4. 다음 단계를 수행하도록 작업을 큐에 넣는다:

    1. 세션 종료와 관련된 모든 플랫폼별 단계가 완료될 때까지 기다린다.

    2. promiseResolve한다.

  5. promise를 반환한다.

XRSession은 새 XRRenderState활성 렌더 상태와, 처음에는 nullXRRenderState대기 중인 렌더 상태를 가진다.

renderState 속성은 XRSession활성 렌더 상태를 반환한다.

XRSession은 라디안 단위로 정의되는 최소 인라인 시야각최대 인라인 시야각을 가진다. 값은 사용자 에이전트가 결정해야 하며 0에서 PI 범위에 있어야 한다.

XRSession은 미터 단위로 정의되는 최소 near clip plane최대 far clip plane을 가진다. 값은 사용자 에이전트가 결정해야 하며 음수가 아니어야 한다. 최소 near clip plane0.1보다 작아야 한다. 최대 far clip plane1000.0보다 커야 한다 (그리고 무한대일 수 있다).

사용자 에이전트가 XRSession sessionXRRenderStateInit newState대기 중인 레이어 상태를 갱신하려고 할 때, 다음 단계를 실행해야 한다:

  1. newStatelayers 값이 null이 아니면, NotSupportedError를 throw한다.

참고: WebXR layers module은 이 알고리즘에 새로운 의미를 도입할 것이다.

사용자 에이전트가 XRSession session에 명목 프레임 속도 rate적용하려고 할 때, 다음 단계를 실행해야 한다:

  1. ratesession내부 명목 프레임 속도와 같으면, 이 단계를 중단한다.

  2. sessionended 값이 true이면, 이 단계를 중단한다.

  3. session내부 명목 프레임 속도rate로 설정한다.

  4. XRSessionEvent 이벤트를 frameratechange라는 이름으로 session에서 발생시킨다.

updateTargetFrameRate(rate) 메서드는 목표 프레임 속도 rateXRSession에 전달한다.

이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. sessionthis로 둔다.

  2. promisesession관련 realm에 있는 새 Promise로 둔다.

  3. session내부 명목 프레임 속도가 없으면, promise를 "InvalidStateError" DOMException으로 reject하고 promise를 반환한다.

  4. sessionended 값이 true이면, promise를 "InvalidStateError" DOMException으로 reject하고 promise를 반환한다.

  5. ratesupportedFrameRates에 없으면, promise를 "TypeError" DOMException으로 reject하고 promise를 반환한다.

  6. session내부 목표 프레임 속도rate로 설정한다.

  7. 다음 단계를 수행하도록 작업을 큐에 넣는다:

    1. XR Compositorrate를 사용하여 새 디스플레이 프레임 속도 및/또는 명목 프레임 속도를 계산할 수 있다.

    2. newrate를 새 명목 프레임 속도로 둔다.

    3. 다음 단계를 수행하도록 작업을 큐에 넣는다:

      1. XRSystem명목 프레임 속도newrate로 갱신하는 동작이 효과를 발휘할 때까지 기다린다.

      2. newratesession으로 명목 프레임 속도를 적용한다.

      3. promiseResolve한다.

  8. promise를 반환한다.

XR Compositor가 어떤 이유로든(예: "visible-blurred" 이벤트 중) 명목 프레임 속도를 변경하는 경우, 프레임 속도 변경을 일으킨 이벤트가 종료되면 내부 목표 프레임 속도를 사용해야 한다.

updateRenderState(newState) 메서드는 다음 프레임에 적용될 활성 렌더 상태 갱신을 큐에 넣는다. 이 메서드에 전달된 XRRenderStateInit newState의 설정되지 않은 필드는 변경되지 않는다.

이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. sessionthis로 둔다.

  2. sessionended 값이 true이면, InvalidStateError를 throw하고 이 단계를 중단한다.

  3. newStatebaseLayersession이 아닌 XRSession으로 생성된 경우, InvalidStateError를 throw하고 이 단계를 중단한다.

  4. newStateinlineVerticalFieldOfView가 설정되어 있고 session몰입형 세션인 경우, InvalidStateError를 throw하고 이 단계를 중단한다.

  5. newStatedepthNear, depthFar, inlineVerticalFieldOfView, baseLayer, layers 중 어느 것도 설정되어 있지 않으면, 이 단계를 중단한다.

  6. sessionnewState대기 중인 레이어 상태 갱신을 실행한다.

  7. activeStatesession활성 렌더 상태로 둔다.

  8. session대기 중인 렌더 상태null이면, 이를 activeState의 복사본으로 설정한다.

  9. newStatepassthroughFullyObscured 값이 설정되어 있으면, session대기 중인 렌더 상태passthroughFullyObscurednewStatepassthroughFullyObscured로 설정한다.

  10. newStatedepthNear 값이 설정되어 있으면, session대기 중인 렌더 상태depthNearnewStatedepthNear로 설정한다.

  11. newStatedepthFar 값이 설정되어 있으면, session대기 중인 렌더 상태depthFarnewStatedepthFar로 설정한다.

  12. newStateinlineVerticalFieldOfView가 설정되어 있으면, session대기 중인 렌더 상태inlineVerticalFieldOfViewnewStateinlineVerticalFieldOfView로 설정한다.

  13. newStatebaseLayer가 설정되어 있으면, session대기 중인 렌더 상태baseLayernewStatebaseLayer로 설정한다.

요청되면, 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최소 near clip plane보다 작으면, activeStatedepthNearsession최소 near clip plane으로 설정한다.

    6. activeStatedepthFarsession최대 far clip plane보다 크면, activeStatedepthFarsession최대 far clip plane으로 설정한다.

    7. baseLayeractiveStatebaseLayer로 둔다.

    8. activeStatecomposition enabledoutput canvas를 다음과 같이 설정한다:

      session인라인 세션이고 baseLayercomposition enabledfalse로 설정된 XRWebGLLayer의 인스턴스인 경우:

      activeStatecomposition enabled boolean을 false로 설정한다.

      activeStateoutput canvasbaseLayercontextcanvas로 설정한다.

      그렇지 않은 경우:

      activeStatecomposition enabled boolean을 true로 설정한다.

      activeStateoutput canvasnull로 설정한다.

requestReferenceSpace(type) 메서드는 가능한 경우 주어진 type의 새 XRReferenceSpace를 구성한다.

이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. promise를 이 XRSession관련 realm에 있는 새 Promise로 둔다.

  2. 다음 단계를 in parallel로 실행한다:

    1. typesession에 대해 reference space is supported를 실행한 결과가 false이면, promiseNotSupportedErrorreject하도록 작업을 큐에 넣고 이 단계를 중단한다.

    2. type 유형의 참조 공간을 추적하는 데 필요한 플랫폼 리소스를 설정한다.

      사용자 에이전트는 이러한 참조 공간에 대한 추적이 수립될 때까지 requestReferenceSpace()를 resolve하기를 기다릴 필요가 없다. 세션이 처음 추적을 수립하려고 시도하는 동안 getViewerPose()null을 반환해도 괜찮으며, 콘텐츠는 이 시간을 사용하여 스플래시 화면이나 다른 것을 표시할 수 있다. type"bounded-floor"이고 경계가 아직 수립되지 않은 경우, 사용자 에이전트는 경계를 작은 초기 영역으로 설정하고 경계가 수립될 때 reset 이벤트를 사용할 수 있음에 유의하라.
    3. 다음 단계를 실행하도록 작업을 큐에 넣는다:

    4. typesession으로 참조 공간을 생성하고, referenceSpace로 둔다.

    5. promisereferenceSpaceResolve한다.

  3. promise를 반환한다.

XRSession활성 XR 입력 소스 목록(XRInputSourcelist)과 활성 XR 추적 소스 목록(XRInputSourcelist)을 가지며, 둘 다 처음에는 빈 list여야 한다.

XRSession은 초기화 시 설정되는 XR 장치XR 장치를 가진다.

inputSources 속성은 XRSession활성 XR 입력 소스 목록을 반환한다.

trackedSources 속성은 XRSession활성 XR 추적 소스 목록을 반환한다. 활성 XR 추적 소스 목록tracked-sources허가된 기능 집합에 포함되어 있는 경우에만 채워져야 한다.

사용자 에이전트는 XR 장치와 관련된 모든 XR 입력 소스를 모니터링해야 하며, 여기에는 XR 입력 소스가 추가, 제거 또는 변경되는 때를 감지하는 것이 포함된다.

XRSession은 처음에는 falsepromise resolved 플래그를 가진다.

참고: 이 플래그의 목적은 사용자 코드가 실제로 이벤트 리스너를 연결할 기회를 얻기 전까지 입력 소스 추가, 입력 소스 제거, 및 입력 소스 변경 알고리즘이 실행되지 않도록 보장하는 것이다. 구현은 세션이 resolve된 후 입력 소스 변경을 듣기 시작하도록 선택한다면 이 플래그가 필요하지 않을 수 있다.

XRSession session에 대해 새로운 XR 입력 소스사용 가능해지면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. sessionpromise resolved 플래그가 설정되어 있지 않으면, 이 단계를 중단한다.

  2. added primary sources를 새 list로 둔다.

  3. added tracked sources를 새 list로 둔다.

  4. 각 새 XR 입력 소스에 대해:

    1. inputSource를 이 XRSession관련 realm에 있는 XRInputSource 객체로 두고, 다음 단계를 수행한다:

      inputSource기본 입력 소스인 경우:

      inputSourceadded primary sources에 추가한다.

      그렇지 않고, tracked-sourcessession허가된 기능 집합에 포함되어 있는 경우:

      inputSourceadded tracked sources에 추가한다.

  5. 다음 단계를 수행하도록 작업을 큐에 넣는다:

    1. session활성 XR 입력 소스 목록added primary sourcesExtend한다.

    2. added primary sources가 비어 있지 않으면, XRInputSourcesChangeEventinputsourceschange라는 이름으로 session에서 발생시키되, addedadded primary sources로 설정한다.

    3. session활성 XR 추적 소스 목록added tracked sourcesExtend한다.

    4. added tracked sources가 비어 있지 않으면, XRInputSourcesChangeEventtrackedsourceschange라는 이름으로 session에서 발생시키되, addedadded tracked sources로 설정한다.

XRSession session에 대해 이전에 추가된 XR 입력 소스가 더 이상 사용 가능하지 않게 되면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. sessionpromise resolved 플래그가 설정되어 있지 않으면, 이 단계를 중단한다.

  2. removed primary sources를 새 list로 둔다.

  3. removed tracked sources를 새 list로 둔다.

  4. 더 이상 사용 가능하지 않은 각 XR 입력 소스에 대해:

    1. inputSource를 해당 XR 입력 소스와 관련되어 있던, session활성 XR 입력 소스 목록 안의 XRInputSource로 두고, 다음 단계를 수행한다:

      inputSource기본 입력 소스인 경우:

      inputSourceremoved primary sources에 추가한다.

      그렇지 않고, tracked-sourcessession허가된 기능 집합에 포함되어 있는 경우:

      inputSourceremoved tracked sources에 추가한다.

  5. 다음 단계를 수행하도록 작업을 큐에 넣는다:

    1. removed primary sources 안의 각 XRInputSourcesession활성 XR 입력 소스 목록에서 Remove한다.

    2. removed primary sources가 비어 있지 않으면, XRInputSourcesChangeEventinputsourceschange라는 이름으로 session에서 발생시키되, removedremoved primary sources로 설정한다.

    3. removed tracked sources 안의 각 XRInputSourcesession활성 XR 추적 소스 목록에서 Remove한다.

    4. removed tracked sources가 비어 있지 않으면, XRInputSourcesChangeEventtrackedsourceschange라는 이름으로 session에서 발생시키되, removedremoved tracked sources로 설정한다.

참고: 사용자 에이전트는 입력 소스가 위치 및 방향 추적을 일시적으로 모두 잃었을 때 이 이벤트를 발생시킬 수 있다. 이는 물리적 핸드헬드 컨트롤러 입력 소스에 대해서만 수행하는 것이 권장된다. 추적되는 손 입력 소스에 대해 이러한 일이 발생할 때는 자주 발생하므로 이 이벤트를 발생시키는 것은 권장되지 않으며, 트래커 객체 입력 소스에 대해 이러한 일이 발생할 때도 애플리케이션이 정체성의 개념을 유지하기 더 어렵게 만들기 때문에 권장되지 않는다.

XRSession session에 대해 어떤 XR 입력 소스handedness, targetRayMode, profiles, gripSpace의 존재 여부, 또는 기본 입력 소스 혹은 추적 입력 소스로서의 상태가 변경되면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. sessionpromise resolved 플래그가 설정되어 있지 않으면, 이 단계를 중단한다.

  2. added primary sources를 새 list로 둔다.

  3. removed primary sources를 새 list로 둔다.

  4. added tracked sources를 새 list로 둔다.

  5. removed tracked sources를 새 list로 둔다.

  6. 변경된 각 XR 입력 소스에 대해:

    1. oldInputSource를 해당 XR 입력 소스와 이전에 관련되어 있던, session활성 XR 입력 소스 목록 안의 XRInputSource로 두고, 다음 단계를 수행한다:

      oldInputSource기본 입력 소스이거나 그 상태가 기본 입력 소스에서 추적 입력 소스로 변경된 경우:

      oldInputSourceremoved primary sources에 추가한다.

      그렇지 않고, tracked-sourcessession허가된 기능 집합에 포함되어 있는 경우:

      oldInputSourceremoved tracked sources에 추가한다.

    2. newInputSourcesession관련 realm에 있는 XRInputSource 객체로 두고, 다음 단계를 수행한다:

      newInputSource기본 입력 소스이거나 그 상태가 추적 입력 소스에서 기본 입력 소스로 변경된 경우:

      newInputSourceadded primary sources에 추가한다.

      그렇지 않고, tracked-sourcessession허가된 기능 집합에 포함되어 있는 경우:

      newInputSourceadded tracked sources에 추가한다.

  7. 다음 단계를 수행하도록 작업을 큐에 넣는다:

    1. removed primary sources 안의 각 XRInputSourcesession활성 XR 입력 소스 목록에서 Remove한다.

    2. session활성 XR 입력 소스 목록added primary sourcesExtend한다.

    3. added primary sources 또는 removed primary sources가 비어 있지 않으면, XRInputSourcesChangeEventinputsourceschange라는 이름으로 session에서 발생시키되, addedadded primary sources로 설정하고 removedremoved primary sources로 설정한다.

    4. removed tracked sources 안의 각 XRInputSourcesession활성 XR 추적 소스 목록에서 Remove한다.

    5. session활성 XR 입력 소스 목록added tracked sourcesExtend한다.

    6. added tracked sources 또는 removed tracked sources가 비어 있지 않으면, XRInputSourcesChangeEventtrackedsourceschange라는 이름으로 session에서 발생시키되, addedadded tracked sources로 설정하고 removedremoved tracked sources로 설정한다.

XRSession은 enum인 visibility state 값을 가진다. 인라인 세션의 경우 visibility stateDocumentvisibilityState를 반영해야 한다. 몰입형 세션의 경우 visibility state는 세션의 상태와 가장 잘 일치하는 다음 값 중 하나로 설정되어야 한다.

visibilityState 속성은 XRSessionvisibility state를 반환한다. onvisibilitychange 속성은 visibilitychange 이벤트 유형을 위한 이벤트 핸들러 IDL 속성이다.

visibility stateXR animation frame을 처리하는 중이 아닌 때라면 언제든지 사용자 에이전트에 의해 변경될 수 있으며, 사용자 에이전트는 가능할 때 XR 플랫폼을 모니터링하여 세션 가시성이 사용자 에이전트 외부에서 영향을 받은 시점을 관찰하고 그에 따라 visibility state를 갱신해야 한다.

참고: XRSessionvisibility state가 반드시 HTML 문서의 가시성을 의미하는 것은 아니다. 시스템 구성에 따라 몰입형 세션이 활성 상태인 동안에도 페이지가 계속 보일 수 있다. (예를 들어 PC에 연결된 헤드셋은 헤드셋이 몰입형 세션의 콘텐츠를 보는 동안에도 모니터에 페이지를 계속 표시할 수 있다.) 개발자는 페이지 가시성을 결정하기 위해 계속 Page Visibility에 의존해야 한다.

참고: XRSessionvisibility state몰입형 세션이 활성 상태인 동안에도 2D 콘텐츠가 여전히 보이는 테더링된 세션에서 마우스 동작에 영향을 주거나 이를 제한하지 않는다. 콘텐츠가 마우스 동작을 더 강하게 제어하고자 한다면 [pointerlock] API 사용을 고려해야 한다.

XRSystem에는 프레임 속도를 설명할 수 있는 여러 정의가 있다:

XRSession목표 프레임 속도internal target frameRate를 가질 수 있다.

XRSession명목 프레임 속도internal nominal frameRate를 가질 수 있다. 유효 프레임 속도명목 프레임 속도보다 낮으면, XR Compositor는 경험을 개선하기 위해 reprojection 또는 기타 기법을 사용할 수 있다. 이는 선택 사항이며 인라인 세션에는 존재해서는 안 된다.

frameRate 속성은 내부 명목 프레임 속도를 반영한다. XRSession내부 명목 프레임 속도가 없으면 null을 반환한다.

onframeratechange 속성은 frameratechange 이벤트 유형을 위한 이벤트 핸들러 IDL 속성이다. 어떤 이유로든 XRSession명목 프레임 속도가 변경되면, 새 명목 프레임 속도 및 해당 XRSession으로 명목 프레임 속도를 적용해야 한다.

supportedFrameRates 속성은 지원되는 목표 프레임 속도 값의 목록을 반환한다. 이 속성은 선택 사항이며 인라인 세션이나 작성자가 프레임 속도를 제어하도록 허용하지 않는 XRSystem에는 존재해서는 안 된다. XRSessionsupportedFrameRates 속성을 지원한다면, frameRate도 지원해야 한다.

XRSessionidentity transform origin offset을 가진 "viewer" 유형의 XRReferenceSpaceviewer reference space를 가진다.

XRSessionXR 장치가 제공하는 뷰에 대응하는 viewlist뷰 목록을 가진다. 뷰 목록XRSession 동안 불변이며, 처음에는 active가 아닐 수 있는 보조 뷰를 포함하여 세션 중 노출될 수 있는 모든 를 포함해야 한다.

뷰 목록기본 뷰XRSessionmode허가된 기능 집합에 의해 결정되어야 한다:

onend 속성은 end 이벤트 유형을 위한 이벤트 핸들러 IDL 속성이다.

oninputsourceschange 속성은 inputsourceschange 이벤트 유형을 위한 이벤트 핸들러 IDL 속성이다.

onselectstart 속성은 selectstart 이벤트 유형을 위한 이벤트 핸들러 IDL 속성이다.

onselectend 속성은 selectend 이벤트 유형을 위한 이벤트 핸들러 IDL 속성이다.

onselect 속성은 select 이벤트 유형을 위한 이벤트 핸들러 IDL 속성이다.

onsqueezestart 속성은 squeezestart 이벤트 유형을 위한 이벤트 핸들러 IDL 속성이다.

onsqueezeend 속성은 squeezeend 이벤트 유형을 위한 이벤트 핸들러 IDL 속성이다.

onsqueeze 속성은 squeeze 이벤트 유형을 위한 이벤트 핸들러 IDL 속성이다.

4.2. XRRenderState

XRRenderStateXRSession의 출력이 합성되는 방식에 영향을 주는 구성 가능한 값들의 집합을 나타낸다. 주어진 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는 처음에 null로 설정되는 HTMLCanvasElement출력 캔버스를 가진다. 출력 캔버스인라인 세션에 대해 렌더링된 모든 콘텐츠를 표시할 DOM 요소이다.

XRRenderState는 또한 처음에는 truecomposition enabled boolean을 가진다. API가 제공하고 XR Compositor가 표시하는 표면에 대해 렌더링 명령이 수행되는 경우, XRRenderStatecomposition enabled를 가진 것으로 간주된다. 렌더링이 인라인 세션에 대해 출력 캔버스 안에 직접 표시되는 방식으로 수행되는 경우, 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로부터 near clip plane까지의 거리를 미터 단위로 정의한다. depthFar 속성은 viewer로부터 far clip plane까지의 거리를 미터 단위로 정의한다.

depthNeardepthFarXRViewprojectionMatrix 계산에 사용된다. 렌더링 중 projectionMatrix가 사용될 때, viewer까지의 거리가 depthNeardepthFar 사이에 있는 지오메트리만 그려진다. 또한 이들은 XRWebGLLayer 깊이 버퍼의 값이 해석되는 방식을 결정한다. depthNeardepthFar보다 클 수 있다.

참고: 일반적으로 렌더링을 위한 원근 투영 행렬을 구성할 때 개발자는 viewing frustum과 near 및 far clip plane을 지정한다. 몰입형 XR 장치에 표시할 때 올바른 viewing frustum은 사용되는 광학 장치, 디스플레이 및 카메라의 어떤 조합에 의해 결정된다. 그러나 near 및 far clip plane은 렌더링되는 콘텐츠의 유형에 따라 적절한 값이 달라지므로 애플리케이션이 수정할 수 있다.

passthroughFullyObscured 속성은 작성자가 뷰포트를 가상 콘텐츠로 완전히 덮으려는 의도를 나타내기 위해 XRSystem에 제공하는 힌트이다. 작성자는 뷰포트가 더 이상 불투명 픽셀로 덮이지 않으면 이 플래그를 false로 다시 설정해야 한다.

참고: XRSystem은 이를 passthrough를 일시적으로 비활성화하기 위한 힌트로 사용할 수 있다. see-through 광학 장치가 있는 장치에서는 사용자가 계속 자신의 환경을 보게 되며 이 플래그는 영향을 주지 않는다.

inlineVerticalFieldOfView 속성은 "inline" XRSession에 대해 투영 행렬을 계산할 때 사용되는 기본 수직 시야각을 라디안 단위로 정의한다. 투영 행렬 계산은 출력 캔버스의 종횡비도 고려한다. inline-stereo가 활성화된 인라인 세션의 경우, 사용자 에이전트는 출력 캔버스 지오메트리를 사용하여 뷰별 투영 행렬을 계산해야 한다. 이 값은 몰입형 세션에서는 null이어야 한다.

baseLayer 속성은 XR compositor가 이미지를 가져올 XRWebGLLayer를 정의한다.

4.3. 애니메이션 프레임

XRSessionXR 장치의 추적 상태에 대한 정보를 제공하는 주된 방법은 XRSession 인스턴스에서 requestAnimationFrame()을 호출하여 예약된 콜백을 통하는 것이다.

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

XRFrameRequestCallback 객체는 처음에 false로 설정되는 cancelled boolean을 가진다.

XRSession은 처음에는 비어 있는 애니메이션 프레임 콜백 목록, 역시 처음에는 비어 있는 현재 실행 중인 애니메이션 프레임 콜백 목록, 그리고 처음에는 0인 숫자인 애니메이션 프레임 콜백 식별자를 가진다.

requestAnimationFrame(callback) 메서드는 사용자 에이전트가 다음에 장치에 대해 애니메이션 프레임을 실행하려고 할 때 callback이 실행되도록 큐에 넣는다.

이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. sessionthis로 둔다.

  2. sessionended 값이 true이면, 0을 반환하고 이 단계를 중단한다.

  3. session애니메이션 프레임 콜백 식별자를 1 증가시킨다.

  4. callbacksession애니메이션 프레임 콜백 목록에 추가하되, session애니메이션 프레임 콜백 식별자의 현재 값과 연결한다.

  5. session애니메이션 프레임 콜백 식별자의 현재 값을 반환한다.

cancelAnimationFrame(handle) 메서드는 주어진 애니메이션 프레임 콜백 식별자 handle에 해당하는 기존 애니메이션 프레임 콜백을 취소한다.

이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. sessionthis로 둔다.

  2. session애니메이션 프레임 콜백 목록 또는 session현재 실행 중인 애니메이션 프레임 콜백 목록에서 handle 값과 연결된 항목을 찾는다.

  3. 그러한 항목이 있다면, 그 항목의 cancelled boolean을 true로 설정하고 session애니메이션 프레임 콜백 목록에서 제거한다.

renderState state레이어 상태를 확인하려면, 사용자 에이전트는 다음 단계를 실행해야 한다:
  1. statebaseLayernull이면, false를 반환한다.

  2. true를 반환한다.

참고: WebXR layers module은 이 알고리즘에 새로운 의미를 도입할 것이다.

XRSession session에 대해 프레임이 렌더링되어야 하는지 판단하려면, 사용자 에이전트는 다음 단계를 실행해야 한다:
  1. sessionrenderState레이어 상태 확인을 수행한 결과가 false이면, false를 반환한다.

  2. session인라인 세션이고 sessionrenderState출력 캔버스null이면, false를 반환한다.

  3. true를 반환한다.

XRSession sessionXR 장치로부터 timestamp frameTime에 대한 갱신된 viewer 상태를 받으면, XR animation frame을 실행하며, 이는 애니메이션 프레임 콜백 목록이 비어 있는지 여부와 관계없이 다음 단계를 실행해야 한다:

  1. 다음 단계를 수행하도록 작업을 큐에 넣는다:

    1. now현재 고해상도 시간으로 둔다.

    2. framesessionanimation frame으로 둔다.

    3. frametimeframeTime으로 설정한다.

    4. framepredictedDisplayTimeframeTime으로 설정한다.

    5. session몰입형 세션이면, framepredictedDisplayTimeXR Compositor가 이 XR animation frame을 표시할 것으로 예상되는 평균 timestamp로 설정한다.

    6. 뷰 목록의 각 view에 대해, viewviewport modifiable 플래그를 true로 설정한다.

    7. 뷰 목록 안의 어떤 viewactive 플래그가 마지막 XR animation frame 이후 변경되었다면, 뷰포트를 갱신한다.

    8. session에 대해 프레임이 렌더링되어야 한다면:

      1. session현재 실행 중인 애니메이션 프레임 콜백 목록session애니메이션 프레임 콜백 목록으로 설정한다.

      2. session애니메이션 프레임 콜백 목록을 빈 목록으로 설정한다.

      3. frameactive boolean을 true로 설정한다.

      4. frame에 대해 프레임 갱신을 적용한다.

      5. session현재 실행 중인 애니메이션 프레임 콜백 목록 안의 각 entry에 대해, 순서대로:

      6. entrycancelled boolean이 true이면, 다음 항목으로 계속한다.

      7. entry를 « now, frame » 및 "report"로 Invoke한다.

      8. session현재 실행 중인 애니메이션 프레임 콜백 목록을 빈 list로 설정한다.

      9. frameactive boolean을 false로 설정한다.

    9. session대기 중인 렌더 상태null이 아니면, 대기 중인 렌더 상태를 적용한다.

Window 인터페이스의 requestAnimationFrame() 메서드의 동작은 활성 XRSession의 존재로 변경되지 않으며, 어떤 XRSession에서 requestAnimationFrame()을 호출해도 WindowrequestAnimationFrame()과 어떤 식으로도 상호작용하지 않는다. 활성 몰입형 세션은 페이지가 가려지게 하는 경우 브라우징 컨텍스트렌더링 기회에 영향을 줄 수 있다. 활성 몰입형 세션 동안 2D 브라우저 뷰가 보이는 경우 (즉, 세션이 테더링된 헤드셋에서 실행 중인 경우), WindowrequestAnimationFrame()requestIdleCallback()으로 실행되는 콜백의 타이밍은 세션의 requestAnimationFrame()과 일치하지 않을 수 있으며, 사용자는 XR 콘텐츠 렌더링을 위해 이에 의존해서는 안 된다.

참고: 활성 몰입형 세션브라우징 컨텍스트렌더링 기회에 영향을 주는 경우 이러한 콜백은 발생이 보장되지 않으며, 실행되더라도 올바른 타이밍을 가지지 않을 수 있으므로, 사용자 에이전트는 WindowrequestAnimationFrame()을 통해 예약된 콜백 중에 XRSessionrequestAnimationFrame()이 호출되면 개발자 콘솔에 경고를 표시하기를 원할 수 있다.

몰입형 세션렌더링 기회를 막는 경우, Window requestAnimationFrame()에 제공된 콜백은 세션이 활성인 동안 처리되지 않을 수 있다. 이는 사용되는 장치의 유형에 따라 달라지며, 몰입형 콘텐츠가 HTML 문서를 완전히 가리는 모바일 또는 독립형 장치에서 발생할 가능성이 가장 높다. 따라서 개발자는 동일한 렌더링 로직을 공유하더라도 XRSession requestAnimationFrame() 콜백을 예약하기 위해 Window requestAnimationFrame() 콜백에 의존해서는 안 되며, 그 반대도 마찬가지이다. 이 지침을 따르지 않는 애플리케이션은 모든 플랫폼에서 제대로 실행되지 않을 수 있다. 이러한 두 유형의 애니메이션 루프 사이를 전환하려는 애플리케이션을 위한 더 효과적인 패턴은 아래에示되어 있다:
let xrSession = null;

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

  // This may be called while an immersive session is running on some devices,
  // such as a desktop with a tethered headset. To prevent two loops from
  // rendering in parallel, skip drawing in this one until the session ends.
  if (!xrSession) {
    renderFrame(time, null);
  }
}

// The window animation loop can be started immediately upon the page loading.
window.requestAnimationFrame(onWindowAnimationFrame);

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

function renderFrame(time, xrFrame) {
  // Shared rendering logic.
}

// Assumed to be called by a user gesture event elsewhere in code.
async function startXRSession() {
  xrSession = await navigator.xr.requestSession('immersive-vr');
  xrSession.addEventListener('end', onXRSessionEnded);
  // Do necessary session setup here.
  // Begin the session's animation loop.
  xrSession.requestAnimationFrame(onXRAnimationFrame);
}

function onXRSessionEnded() {
  xrSession = null;
}

HTML 문서로 렌더링하기 위해 인라인 세션을 사용하는 애플리케이션은 애니메이션 루프를 조정하기 위해 별도의 특별한 단계를 수행할 필요가 없다. 사용자 에이전트가 몰입형 세션이 활성인 동안 모든 인라인 세션의 애니메이션 루프를 자동으로 일시 중단하기 때문이다.

4.4. XR Compositor

사용자 에이전트는 XR 장치로의 프레젠테이션과 프레임 타이밍을 처리하는 XR Compositor를 유지해야 한다. compositor는 문서가 생성한 어떤 그래픽 컨텍스트의 상태와도 격리된 독립적인 렌더링 컨텍스트를 사용해야 한다. compositor는 페이지가 compositor 상태를 훼손하거나 다른 페이지 또는 애플리케이션의 콘텐츠를 다시 읽는 것을 방지해야 한다. 또한 compositor는 별도의 스레드 또는 프로세스에서 실행되어, 페이지의 성능과 적절한 프레임 속도로 사용자에게 새 이미지를 제시할 수 있는 능력을 분리해야 한다. compositor는 장치 메뉴와 같은 추가 장치 또는 사용자 에이전트 UI를 렌더링된 콘텐츠 위에 합성할 수 있다.

참고: 이 명세의 향후 확장은 같은 페이지에서 오는 여러 레이어를 합성하기 위해 compositor를 활용할 수도 있다.

5. 프레임 루프

5.1. XRFrame

XRFrameXRSession에 대해 추적되는 모든 객체 상태의 스냅샷을 나타낸다. 애플리케이션은 XRFrameRequestCallback과 함께 XRSession에서 requestAnimationFrame()을 호출하여 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은 처음에 false로 설정되는 active boolean과, 처음에 false로 설정되는 animationFrame boolean을 가진다.

session 속성은 XRFrame을 생성한 XRSession을 반환한다.

몰입형 세션의 경우 predictedDisplayTime 속성은 이 XRFrame이 장치의 디스플레이에 표시될 것으로 예상되는 평균 시점에 대응하는 DOMHighResTimeStamp를 반환해야 한다. 인라인 세션의 경우, predictedDisplayTimeXRFrameRequestCallback에 전달된 timestamp와 같은 값을 반환해야 한다.

predictedDisplayTime은 애니메이션된 XR 장면을 requestAnimationFrame() 콜백이 예약되었거나 실행된 때가 아니라, 프레임이 표시될 때 있어야 할 상태로 렌더링할 수 있도록 하기 위한 것이다.

predictedDisplayTime은 애플리케이션이 렌더링에 사용할 수 있는 시간이 얼마나 되는지를 추론하는 데 사용되도록 의도된 것이 아니다. 이는 일반적으로 XR Compositor가 프레임이 제출된 후 추가 처리를 수행해야 하기 때문이다. 경험이 predictedDisplayTime까지 처리할 수 있다고 가정하면, XR Compositor는 제출된 프레임을 활용할 수 없게 되고, 애플리케이션은 목표 프레임 속도를 달성하지 못할 것이다.

XRFrame은 주어진 time에 대한 모든 추적 객체의 상태를 나타내며, 이 상태에 관한 구체적인 정보를 해당 time에 저장하거나 질의할 수 있다.

getViewerPose(referenceSpace) 메서드는 XRFrametime에서, referenceSpace에 상대적인 viewer의 포즈를 XRViewerPose로 제공한다.

이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. framethis로 둔다.

  2. sessionframesession 객체로 둔다.

  3. frameanimationFrame boolean이 false이면, InvalidStateError를 throw하고 이 단계를 중단한다.

  4. posesession관련 realm에 있는 XRViewerPose 객체로 둔다.

  5. frame이 나타내는 시간에 sessionviewer reference space의 포즈를 referenceSpace 안에서 pose채우되, force emulationtrue로 설정한다.

  6. posenull이면 null을 반환한다.

  7. xrviews를 빈 list로 둔다.

  8. offset0으로 둔다.

  9. session뷰 목록 안의 각 active view view에 대해 다음 단계를 수행한다:

    1. xrviewsession관련 realm에 있는 새 XRView 객체로 둔다.

    2. xrviewunderlying viewview로 초기화한다.

    3. xrvieweyevieweye로 초기화한다.

    4. xrviewindexoffset으로 초기화한다.

    5. xrviewframeframe으로 초기화한다.

    6. xrviewsessionsession으로 초기화한다.

    7. xrviewreference spacereferenceSpace로 초기화한다.

    8. viewtransformsession관련 realm에서 viewview offset과 같은 XRRigidTransform 객체로 둔다.

    9. xrviewtransform 속성을, session의 관련 realm에서 XRViewerPosetransformviewtransform transform을 곱한 결과로 설정한다.

    10. xrviewxrviewsAppend한다.

    11. offset1만큼 증가시킨다.

  10. poseviewsxrviews로 설정한다

  11. pose를 반환한다.

getPose(space, baseSpace) 메서드는 XRFrame이 나타내는 시간에 baseSpace에 상대적인 space의 포즈를 XRPose로 제공한다.

이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. framethis로 둔다.

  2. poseframe관련 realm에 있는 XRPose 객체로 둔다.

  3. frame이 나타내는 시간에 baseSpace 안의 space의 포즈를 pose채운다.

  4. pose를 반환한다.

프레임 갱신XRFrame이 주어졌을 때 실행될 수 있는 알고리즘이며, 각 XRFrame마다 실행되도록 의도된다.

모든 XRSession프레임 갱신들의 list프레임 갱신 목록을 가지며, 처음에는 빈 list이다.

XRFrame frame에 대해 프레임 갱신을 적용하려면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. framesession프레임 갱신 목록 안의 각 frame update에 대해, 다음 단계를 수행한다:

    1. frame updateframe으로 실행한다.

참고: 이 명세는 어떤 프레임 갱신도 정의하지 않지만, 다른 명세가 일부를 추가할 수 있다.

6. 공간

WebXR Device API의 핵심 기능은 공간 추적을 제공하는 능력이다. 공간은 추적되는 엔티티들이 사용자의 물리적 환경 및 서로와 공간적으로 어떻게 관련되는지 애플리케이션이 추론할 수 있게 하는 인터페이스이다.

6.1. XRSpace

XRSpace는 물리적 위치에 대응하는 원점을 가진 가상 좌표계를 나타낸다. API에서 요청되거나 API에 제공되는 공간 데이터는 항상 특정 XRSpace에 상대적으로, 특정 XRFrame의 시점에서 표현된다. 포즈 위치와 같은 수치 값은 해당 공간에서 그 원점에 상대적인 좌표이다. 이 인터페이스는 의도적으로 불투명하다.

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

};

XRSpace는 해당 XRSpace를 생성한 XRSession으로 설정되는 session을 가진다.

XRSpace는 공간 내의 위치와 방향인 native origin을 가진다. XRSpacenative originXR 장치의 underlying tracking system에 의해 갱신될 수 있으며, 서로 다른 XRSpace들은 자신들의 native origin이 추적되고 갱신되는 방식에 관해 서로 다른 의미를 정의할 수 있다.

XRSpace는 해당 XRSpace좌표계의 기반인 effective origin을 가진다.

effective space에서 native origin의 공간으로의 transform은 origin offset으로 정의되며, 이는 처음에 identity transform으로 설정되는 XRRigidTransform이다. 달리 말하면, effective originorigin offsetnative origin곱하여 얻을 수 있다.

XRSpaceeffective origin은 다른 XRSpace의 좌표계에서 XRPose로만 관찰될 수 있으며, 이는 XRFramegetPose() 메서드가 반환한다. XRSpace들 사이의 공간적 관계는 XRFrame들 사이에서 변경될 수 있다.

XRSpace space의 포즈를, XRFrame frame이 나타내는 시간에 XRSpace baseSpace 안에서, XRPose pose채우려면, 선택적인 force emulation 플래그와 함께, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. frameactive boolean이 false이면, InvalidStateError를 throw하고 이 단계를 중단한다.

  2. sessionframesession 객체로 둔다.

  3. spacesessionsession과 같지 않으면, InvalidStateError를 throw하고 이 단계를 중단한다.

  4. baseSpacesessionsession과 같지 않으면, InvalidStateError를 throw하고 이 단계를 중단한다.

  5. 포즈가 보고될 수 있는지 확인하고, 그렇지 않다면 SecurityError를 throw하고 이 단계를 중단한다.

  6. sessionvisibilityState"visible-blurred"이고 space 또는 baseSpaceXRInputSource와 연결되어 있으면, posenull로 설정하고 이 단계를 중단한다.

  7. limitspacebaseSpace 사이에서 포즈가 제한되어야 하는지의 결과로 둔다.

  8. transformposetransform으로 둔다.

  9. frametime에서 baseSpace에 상대적인 space의 포즈를 XR 장치의 추적 시스템에 질의한 다음, 다음 단계를 수행한다:

    limitfalse이고 추적 시스템이 baseSpace에 상대적인 space의 포즈에 대해 위치가 능동적으로 추적되거나 정적으로 알려진 6DoF 포즈를 제공하는 경우:

    transformorientationbaseSpace좌표계 안에서 spaceeffective origin의 방향으로 설정한다.

    transformpositionbaseSpace좌표계 안에서 spaceeffective origin의 위치로 설정한다.

    지원된다면, poselinearVelocitybaseSpace좌표계와 비교한 spaceeffective origin의 선속도로 설정한다.

    지원된다면, poseangularVelocitybaseSpace좌표계와 비교한 spaceeffective origin의 각속도로 설정한다.

    poseemulatedPositionfalse로 설정한다.

    그렇지 않고 limitfalse이며 추적 시스템이 3DoF 포즈 또는 baseSpace에 상대적인 space의 포즈에 대해 위치가 능동적으로 추적되지도 않고 정적으로 알려져 있지도 않은 6DoF 포즈를 제공하는 경우:

    transformorientationbaseSpace좌표계 안에서 spaceeffective origin의 방향으로 설정한다.

    transformpositionbaseSpace좌표계 안에서 spaceeffective origin 위치에 대한 추적 시스템의 최선의 추정값으로 설정한다. 여기에는 목 또는 팔 모델과 같은 계산된 offset이 포함될 수 있다. 위치 추정값을 사용할 수 없으면, 마지막으로 알려진 위치를 사용해야 한다.

    poselinearVelocitynull로 설정한다.

    poseangularVelocitynull로 설정한다.

    poseemulatedPositiontrue로 설정한다.

    그렇지 않고 baseSpace에 상대적인 space의 포즈가 과거에 결정된 적이 있으며 force emulationtrue인 경우:

    transformpositionbaseSpace좌표계 안에서 spaceeffective origin의 마지막으로 알려진 위치로 설정한다.

    transformorientationbaseSpace좌표계 안에서 spaceeffective origin의 마지막으로 알려진 방향으로 설정한다.

    poselinearVelocitynull로 설정한다.

    poseangularVelocitynull로 설정한다.

    poseemulatedPosition boolean을 true로 설정한다.

    그렇지 않은 경우:

    posenull로 설정한다.

참고: XRPoseemulatedPosition boolean은 baseSpace의 위치가 에뮬레이션되는지 여부를 나타내지 않으며, 단지 baseSpace에 상대적인 space의 위치를 평가하는 것이 에뮬레이션에 의존하는지 여부만 나타낸다. 예를 들어, 3DoF 추적을 가진 컨트롤러는 자신의 targetRaySpace 또는 gripSpaceXRReferenceSpace에 대해 질의될 때 trueemulatedPosition을 가진 포즈를 보고하지만, targetRaySpace의 포즈가 gripSpace 안에서 질의된 경우에는, 이 두 공간 사이의 관계가 정확히 알려져 있어야 하므로 falseemulatedPosition을 보고한다.

6.2. XRReferenceSpace

XRReferenceSpace는 애플리케이션이 사용자의 물리적 환경과 공간적 관계를 수립하는 데 사용할 수 있는 여러 공통 XRSpace 중 하나이다.

XRReferenceSpace들은 일반적으로 XRSession 동안 정적으로 유지될 것으로 예상되며, 가장 흔한 예외는 사용자가 세션 중 재구성을 수행하는 경우이다. 모든 XRReferenceSpacenative origin+X가 "Right", +Y가 "Up", -Z가 "Forward"로 간주되는 좌표계를 설명한다.

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

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

  attribute EventHandler onreset;
};

XRReferenceSpaceXRReferenceSpaceTypetype을 가진다.

XRReferenceSpace는 가장 흔히 requestReferenceSpace()를 호출하여 얻으며, 이 메서드는 호출에 전달된 XRReferenceSpaceType enum 값이 지원되는 경우 XRReferenceSpace 인스턴스(또는 이를 확장하는 인터페이스)를 생성한다. type은 reference space가 보일 추적 동작을 나타낸다:

참고: reference space의 Y축에 관한 underlying platform의 관례는 여러 유형의 XRReferenceSpace들 사이에서 일관되게 유지된다고 가정한다. 달리 말하면, XR 시스템이 여러 reference space를 지원한다면, 그것들의 Y축은 서로 평행하고, 생성된 XRSession 동안 같은 방향을 가리킨다. 이는 "viewer"에는 적용되지 않는다. 이는 자신의 방향에 대해 underlying platform의 관례에 의존하지 않기 때문이다. "unbounded" reference space는 origin이 가까이 있을 때 다른 reference space와 자신의 Y축을 정렬해야 하지만, 사용자가 큰 거리를 이동하면 벗어날 수 있다.

"local" reference space를 지원하는 장치는 필요한 경우 에뮬레이션을 통해 "local-floor" reference space를 지원해야 하며, 그 반대도 마찬가지이다.

onreset 속성은 reset 이벤트 유형을 위한 이벤트 핸들러 IDL 속성이다.

XRSession session에 대해 XRReferenceSpaceType type으로 XRReferenceSpace가 요청되면, 사용자 에이전트는 다음 단계를 실행하여 참조 공간을 생성해야 한다:

  1. referenceSpace를 다음과 같이 초기화한다:

    typebounded-floor인 경우:

    referenceSpacesession관련 realm에 있는 XRBoundedReferenceSpace 객체로 둔다.

    그렇지 않은 경우:

    referenceSpacesession관련 realm에 있는 XRReferenceSpace 객체로 둔다.

  2. referenceSpacetypetype으로 초기화한다.

  3. referenceSpacesessionsession으로 초기화한다.

  4. referenceSpace를 반환한다.

주어진 reference space type typeXRSession session에 대해 reference space가 지원되는지 확인하려면, 다음 단계를 실행한다:
  1. typesession허가된 기능 집합contained 되어 있지 않으면, false를 반환한다.

  2. typeviewer이면, true를 반환한다.

  3. typelocal 또는 local-floor이고, session몰입형 세션이면, true를 반환한다.

  4. typelocal 또는 local-floor이고, XR 장치가 방향 데이터 보고를 지원하면, true를 반환한다.

  5. typebounded-floor이고 session몰입형 세션이면, XR 장치bounded reference space를 지원하는지의 결과를 반환한다.

  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. offsetSpaceorigin offset을, baseorigin offsetoriginOffsetbase관련 realm에서 곱한 결과로 설정한다.

  5. offsetSpace를 반환한다.

참고: 일부 애플리케이션은 마우스, 키보드, 터치 또는 게임패드 입력을 기반으로 한 장면 탐색 제어를 구현하기 위해 getOffsetReferenceSpace()를 사용할 것으로 예상된다. 이로 인해 getOffsetReferenceSpace()가 활성 입력 기간 동안 적어도 프레임마다 한 번씩 자주 호출될 것이다. 따라서 UA는 getOffsetReferenceSpace()로 새 XRReferenceSpace를 생성하는 작업을 가벼운 작업으로 만들도록 강하게 권장된다.

6.3. XRBoundedReferenceSpace

XRBoundedReferenceSpaceXRReferenceSpace를 확장하여 boundsGeometry를 포함하며, 이는 사용자의 공간에 대해 미리 구성된 경계를 나타낸다.

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

XRBoundedReferenceSpace의 원점은 바닥에 위치해야 하며, 따라서 Y 축은 바닥 수준에서 0과 같아야 한다. XZ 위치와 방향은 underlying platform의 관례를 기반으로 초기화되며, 일반적으로 논리적인 전방 방향을 바라보는 방 중앙 근처일 것으로 예상된다.

참고: 다른 XR 플랫폼에서는 때때로 bounded-floor reference space가 제공하는 추적 유형을 "room scale" 추적이라고 부른다. XRBoundedReferenceSpace는 여러 방으로 이루어진 공간, 바닥 높이가 고르지 않은 영역, 또는 매우 큰 열린 영역을 설명하기 위한 것이 아니다. 그러한 시나리오를 처리해야 하는 콘텐츠는 unbounded reference space를 사용해야 한다.

XRBoundedReferenceSpace는 사용자가 안전하게 그 안에서 움직일 수 있다고 기대할 수 있는, XRBoundedReferenceSpace 주변의 경계를 설명하는 native bounds geometry를 가진다. 다각형 경계는 DOMPointReadOnly의 배열로 주어지며, 안전 공간의 가장자리에 있는 점들의 루프를 나타낸다. 점들은 native origin으로부터의 오프셋을 미터 단위로 설명한다. 점들은 위에서 내려다보며 Y축의 음의 끝을 향해 볼 때 시계 방향 순서로 주어져야 한다. 각 점의 y 값은 0이어야 하며, 각 점의 w 값은 1이어야 한다. bounds는 바닥에서 시작하여 무한히 위로 확장되는 것으로 간주할 수 있다. 그것이 설명하는 형태는 볼록하거나 오목할 수 있다.

native bounds geometry의 각 점은 reference space의 native origin으로부터 합리적인 거리로 제한되어야 한다.

참고: native bounds geometry의 점들은 모든 방향에서 native origin으로부터 15미터로 제한하는 것이 제안된다.

native bounds geometry의 각 점은 또한 핑거프린팅을 방지할 수 있도록 충분히 양자화되어야 한다. 사용자의 안전을 위해, 양자화된 점 값은 플랫폼이 보고한 bounds 밖에 위치해서는 안 된다.

참고: native bounds geometry의 점들은 가장 가까운 5cm로 양자화하는 것이 제안된다.

boundsGeometry 속성은 DOMPointReadOnly들의 배열이며, 각 항목은 XRBoundedReferenceSpacenative bounds geometry 안의 항목에 origin offsetinverse를 미리 곱한 것과 같다. 달리 말하면, 이는 effective origin에 상대적인 XRBoundedReferenceSpace 좌표에서 같은 경계를 제공한다.

native bounds geometry를 일시적으로 사용할 수 없는 경우, 예를 들어 XR 장치 초기화 중, 장기간의 추적 손실, 또는 미리 구성된 공간들 사이의 이동 중에 발생할 수 있으며, boundsGeometry는 빈 배열을 보고해야 한다.

bounded reference space가 지원되는지 확인하려면 다음 단계를 실행한다:
  1. XR 장치가 경계를 보고할 수 없으면, false를 반환한다.

  2. XR 장치가 사용자의 물리적 바닥 높이를 식별할 수 없으면, false를 반환한다.

  3. true를 반환한다.

참고: reference space 요청 시점에 경계 또는 바닥 높이가 아직 해결되지 않았더라도, XR 장치가 이를 지원하는 것으로 알려져 있다면 bounded reference space가 반환될 수 있다.

참고: 콘텐츠는 사용자가 boundsGeometry 너머로 이동하도록 요구해서는 안 된다. 사용자의 물리적 주변 환경이 허용한다면 사용자가 bounds 밖으로 이동할 수 있으며, 그 결과 위치 값이 그들이 설명하는 다각형 밖에 있을 수 있다. 이는 오류 조건이 아니며 페이지 콘텐츠가 우아하게 처리해야 한다.

참고: 콘텐츠는 일반적으로 boundsGeometry의 시각화를 제공해서는 안 된다. 안전에 중요한 정보가 사용자에게 제공되도록 보장하는 것은 사용자 에이전트의 책임이기 때문이다.

7.

7.1. XRViewGeometry

XRViewGeometry interface mixin을 포함하는 객체들은 XR 장치가 사용자에게 이미지를 제시하는 데 사용하는 디스플레이이거나, 실제 세계에 대한 시각 정보를 수집하는 데 사용하는 센서를 나타낸다. 이러한 객체는 view geometry를 포함한다.

view geometryviewer reference space좌표계 안의 점과 containing objectscreen space 안의 점 사이를 변환하는 데 사용되는 intrinsics 및 extrinsics 집합에 대응한다.

view geometryview geometry가 데이터를 포함하는 물리적 하드웨어 조각인 containing object를 가진다.

view geometrycontaining object는 연결된 screen space를 가지며, 이는 이 containing object가 데이터를 읽거나 렌더링하는 2D 평면으로 설명된다.

view geometry는 연결된 view offset을 가지며, 이는 viewer reference space좌표계 안에서 containing object의 위치와 방향을 설명하는 XRRigidTransform이다.

참고: view offset이 무엇일 수 있는지에 대한 제약은 없으며, view들은 서로 다른 방향을 가질 수 있다. 이는 눈 디스플레이가 각도를 두고 중심에 배치된 머리 착용 장치에서 나타날 수 있으며, CAVE 렌더링과 같은 더 극단적인 경우에도 나타날 수 있다. 이 때문에 z-sorting 및 culling 같은 기법은 눈별로 수행해야 할 수 있다.

view geometry는 underlying XR 장치가 제공하는 containing object로 렌더링할 때 사용할 projection을 설명하는 matrix인 연결된 projection matrix를 가진다. projection matrix는 projection이 단순한 frustum으로 정확히 설명되는 것을 방지하는 shearing과 같은 변환을 포함할 수 있다.

참고: 이 matrix의 inverse는 screen space에서 픽셀을 "읽고", 이를 containing object를 원점으로 하는 좌표계로 다시 변환하는 데 적합하다.

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

XRViewGeometry는 그 containing objectprojection matrix를 저장하는 연결된 internal projection matrix를 가진다. 이는 처음에는 null이다.

참고: transform은 많은 렌더링 라이브러리에서 카메라 객체를 배치하는 데 사용할 수 있다. 애플리케이션에 더 전통적인 view matrix가 필요하다면 transform.inverse.matrix를 호출하여 얻을 수 있다.

projectionMatrix 속성은 underlying view geometryprojection matrix이다. 애플리케이션은 이 matrix를 수정하거나 분해하지 않고 사용하는 것이 강하게 권장된다. 렌더링할 때 제공된 projection matrix를 사용하지 않으면 제시된 프레임이 왜곡되거나 심하게 어긋나서, 사용자에게 다양한 정도의 불편함을 초래할 수 있다. 이 속성은 XRViewGeometry에 대해 projection matrix를 얻어 계산되어야 한다.

transform 속성은 객체의 XRRigidTransform이다. 이는 객체를 얻는 데 사용된 XRReferenceSpace 안에서 객체의 위치와 방향을 나타낸다.

주어진 XRViewGeometry view geometry에 대해 projection matrix를 얻으려면:

  1. view geometryinternal projection matrixnull이 아니면, 다음 단계를 수행한다:

    1. internal projection matrix에 대한 IsDetachedBuffer 연산이 false이면, view geometryinternal projection matrix를 반환한다.

  2. view geometryinternal projection matrixview geometry관련 realm에 있는 matrix 객체로 설정하되, 이는 view geometryprojection matrix와 같다.

  3. view geometryinternal projection matrix를 반환한다.

7.2. XRView

XRView는 주어진 프레임에 대해 XR 장면 안으로 들어가는 단일 view를 설명한다.

view는 XR 장치가 사용자에게 이미지를 제시하는 데 사용하는 디스플레이 또는 디스플레이의 일부에 대응한다. view는 시야각, eye offset, 기타 광학 속성을 포함하여, view의 물리적 출력 속성에 잘 정렬된 콘텐츠를 렌더링하는 데 필요한 모든 정보를 얻는 데 사용된다. View들은 사용자의 시야에서 겹치는 영역을 덮을 수 있다. XR 장치가 사용하는 view의 수나 순서에 대해서는 보장되지 않으며, view의 수가 XRSession 동안 일정할 필요도 없다.

view는 이 view가 어느 눈에 표시될 것으로 예상되는지를 설명하는 XREye인 연결된 eye를 가진다. view가 본질적으로 연결된 eye를 가지지 않는 경우(예를 들어 디스플레이가 단안인 경우), 이 값은 "none"으로 설정되어야 한다.

viewXRSession의 생명 주기 동안 변경될 수 있는 active 플래그를 가진다. Primary view들은 항상 active 플래그가 true로 설정되어 있어야 한다.

참고: 많은 HMD는 왼쪽 눈용 하나와 오른쪽 눈용 하나, 총 두 개의 view를 렌더링하도록 콘텐츠에 요청하지만, 대부분의 magic window 장치는 하나의 view만 요청한다. 그러나 애플리케이션은 특정 view 구성을 절대 가정해서는 안 된다. 예를 들어, magic window 장치는 stereo 출력을 할 수 있다면 두 개의 view를 요청할 수 있지만, stereo 출력 모드가 꺼져 있으면 성능상의 이유로 단일 view 요청으로 되돌아갈 수 있다. 마찬가지로 HMD는 넓은 시야각이나 서로 다른 픽셀 밀도의 디스플레이를 지원하기 위해 두 개보다 많은 view를 요청할 수 있다.

view는 세션의 이 시점에서 viewport scale이 requestViewportScale() 호출에 의해 변경될 수 있는지 나타내는 내부 viewport modifiable 플래그를 가진다. 이는 animation frame 시작 시 true로 설정되고, getViewport()가 호출될 때 false로 설정된다.

view는 이 view에 대해 요청된 viewport scale을 나타내는 내부 requested viewport scale 값을 가진다. 이는 처음에 1.0으로 설정되며, 시스템이 dynamic viewport scaling을 지원하는 경우 requestViewportScale() 메서드에 의해 수정될 수 있다.

view는 시스템이 내부적으로 사용하는 이 view의 현재 viewport scale을 나타내는 내부 current viewport scale 값을 가진다. 이는 처음에 1.0으로 설정된다. viewport 변경이 getViewport() 호출에 의해 성공적으로 적용되면, 이는 requested viewport scale과 일치하도록 갱신된다.

viewgetViewerPose()에서 이 view를 얻는 데 사용된 XRReferenceSpace 공간인 reference space를 가진다.

참고: Dynamic viewport scaling은 애플리케이션이 각 animation frame마다 변경될 수 있는 scale factor를 사용하여 전체 크기 viewport의 하위 집합에 렌더링할 수 있게 한다. 이는 재할당 없이 프레임별로 효율적으로 수정 가능하도록 의도된다. 올바른 렌더링을 위해서는 XR 시스템과 애플리케이션이 active viewport에 대해 합의하는 것이 필수적이다. 애플리케이션은 하나의 animation frame 안에서 XRView에 대해 requestViewportScale()을 여러 번 호출할 수 있지만, 요청된 scale은 애플리케이션이 그 view에 대해 getViewport()를 호출할 때까지 적용되지 않는다. animation frame 안의 첫 번째 getViewport 호출은 변경을 적용하고 (현재 animation frame에 즉시 적용됨), 이 animation frame의 나머지 동안 view의 현재 scaled viewport를 고정하며, 그 scale을 향후 animation frame의 새 기본값으로 설정한다. 선택적으로, 시스템은 내부 성능 휴리스틱과 목표 프레임 속도를 기반으로 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 속성은 underlying vieweye를 설명한다. 이 속성의 주된 목적은 미리 렌더링된 stereo 콘텐츠가 올바른 눈에 올바른 콘텐츠 부분을 제시할 수 있도록 보장하는 것이다.

index 속성은 이 XRViewgetViewerPose()에 의해 views 배열 안에서 반환될 때의 offset을 설명한다.

선택적 recommendedViewportScale 속성은 애플리케이션이 dynamic viewport scaling을 구성하기 위해 requestViewportScale() 호출에 사용할 수 있는 UA 권장 viewport scale 값을 포함한다. 시스템이 권장 scale을 결정하기 위한 휴리스틱이나 메서드를 구현하지 않는 경우 이는 null이다. null이 아닌 경우, 값은 0.0보다 크고 1.0 이하인 숫자 값이어야 하며, 상세한 성능 또는 GPU 사용률 데이터를 제공하지 않도록 양자화되어야 한다.

참고: 권장 viewport scale은 가능한 scale 값들의 짧은 목록에서 가장 가까운 값으로 반올림하고, 경계 값에 가까울 때 즉각적인 변경을 피하기 위해 hysteresis를 사용하여 양자화하는 것이 제안된다. (이는 시각적으로 산만하거나 불편할 수 있는 scale 값의 빠른 진동을 피하는 데도 도움이 된다.)

XRView는 이를 생성한 XRSession인 연결된 session을 가진다.

XRView는 이를 생성한 XRFrame인 연결된 frame을 가진다.

XRView는 그것이 나타내는 underlying view인 연결된 underlying view를 가진다.

requestViewportScale(scale) 메서드는 사용자 에이전트가 이 viewport의 requested viewport scale을 요청된 값으로 설정해야 한다고 요청한다.

이 메서드가 XRView xrview에서 호출되면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  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 scale 값을 무시하므로, 애플리케이션은 권장 scale을 제공하지 않는 시스템에서도 안전하게 view.requestViewportScale(view.recommendedViewportScale)을 사용할 수 있다.

뷰 목록의 어떤 viewactive 플래그가 변경되면, 다음 단계를 수행하여 XRSession session에 대한 viewport를 갱신할 수 있다:

  1. layerrenderStatebaseLayer로 둔다.

  2. layernull이면 이 단계를 중단한다.

  3. layerviewport 객체 목록을 빈 list로 설정한다.

  4. 뷰 목록 안의 각 active view view에 대해:

    1. viewportsession에 대해 view와 연결된 전체 크기 viewport 목록에서 scaled viewport를 얻은 결과인 XRViewport로 둔다.

    2. viewportlayerviewport 객체 목록Append한다.

XRSession session에 대해 주어진 XRView viewscaled viewport를 얻으려면:

  1. glFullSizedViewportview와 연결된 전체 크기 viewport 목록에서 가져온 WebGL viewport로 둔다.

  2. scaleviewcurrent viewport scale로 둔다.

  3. 사용자 에이전트는 최소 viewport scale factor를 적용하기 위해 scale을 clamp하도록 선택할 수 있다.

  4. glViewport를 새 WebGL viewport로 둔다.

  5. glViewportwidthglFullSizedViewportwidthscale을 곱한 값 이하인 정수 값으로 설정한다.

  6. glViewportwidth가 1보다 작으면, 이를 1로 설정한다.

  7. glViewportheightglFullSizedViewportheightscale을 곱한 값 이하인 정수 값으로 설정한다.

  8. glViewportheight가 1보다 작으면, 이를 1로 설정한다.

  9. glViewportx 구성 요소를 glFullSizedViewportx 구성 요소(포함)와 glFullSizedViewportx 구성 요소에 glFullSizedViewportwidth를 더한 뒤 glViewportwidth를 뺀 값(포함) 사이의 정수 값으로 설정한다.

  10. glViewporty 구성 요소를 glFullSizedViewporty 구성 요소(포함)와 glFullSizedViewporty 구성 요소에 glFullSizedViewportheight를 더한 뒤 glViewportheight를 뺀 값(포함) 사이의 정수 값으로 설정한다.

  11. viewportsession관련 realm에 있는 XRViewport 객체로 둔다.

  12. viewportxglViewportx 구성 요소로 초기화한다.

  13. viewportyglViewporty 구성 요소로 초기화한다.

  14. viewportwidthglViewportwidth로 초기화한다.

  15. viewportheightglViewportheight로 초기화한다.

  16. viewport를 반환한다.

참고: 구체적인 정수 값 계산은 의도적으로 UA의 재량에 맡겨진다. width/height를 내림하고 xy offset을 그대로 사용하는 간단한 방법은 유효하지만, UA는 효율성을 위해 viewport를 2의 거듭제곱 픽셀 그리드에 정렬하는 등 명시된 제약 안에서 약간 조정된 값을 선택할 수도 있다. scaled viewport는 전체 크기 viewport 안에 완전히 포함되어야 하지만, UA의 재량에 따라 전체 크기 viewport 안의 어느 위치에나 배치될 수 있다. 크기 및 위치 계산은 결정적이어야 하며, 세션 안에서 동일한 입력 값에 대해 일관된 결과를 반환해야 한다.

7.3. Primary 및 Secondary View

view는 XR 경험을 위해 그에 대한 렌더링이 필요한 경우 primary view이다. Primary view들은 XRSession의 전체 기간 동안 active여야 한다.

view는 콘텐츠가 그에 렌더링하지 않기로 선택해도 동작하는 몰입형 경험을 만들 수 있는 경우 secondary view이다. 콘텐츠가 이러한 view에 렌더링하지 않기로 선택하면, 사용자 에이전트는 reprojection을 통해 이를 재구성할 수 있을 수 있다. Secondary view는 "secondary-views" 기능이 활성화되지 않는 한 active여서는 안 된다.

primary view의 예에는 handheld AR session의 주 mono view, headworn AR/VR session 또는 inline-stereo가 활성화된 inline session의 주 stereo view 두 개, 또는 CAVE session의 모든 wall view가 포함된다.

secondary view의 예에는 video capture에 사용되는 first-person observer view, 또는 눈마다 두 개의 view가 있고 해상도와 시야각이 서로 다른 "quad views"가 포함된다.

콘텐츠는 view 수가 임의일 수 있다고 가정하여 작성되어야 하지만, 상당한 양의 콘텐츠가 views 배열에 대해 잘못된 가정을 하고, 따라서 두 개보다 많은 view가 제시되면 깨질 것으로 예상한다.

사용자 에이전트는 콘텐츠 대신 이러한 secondary view에 렌더링하기 위해 reprojection 같은 메커니즘을 사용할 수 있으므로, 이러한 secondary view를 직접 처리할 계획인 콘텐츠와, 그러한 secondary view의 존재를 모르거나 이를 다루고 싶지 않은 콘텐츠를 구별할 수 있는 것이 바람직하다.

이를 제공하기 위해, secondary view를 노출하는 사용자 에이전트는 "secondary-views" feature descriptor를 힌트로 지원해야 한다. 이 기능을 활성화하는 콘텐츠는 다음을 수행할 것으로 예상된다:

"secondary-views"가 활성화되면, 사용자 에이전트는 필요할 때 장치가 지원하는 모든 secondary viewXRSession에 노출할 수 있다. 사용자 에이전트는 이러한 경우 reprojection을 사용하여 secondary view를 재구성해서는 안 되며, 대신 콘텐츠가 렌더링하기로 결정한 것에 의존해야 한다.

참고: 최대 호환성을 보장하기 위해 콘텐츠가 optionalFeatures를 사용하여 "secondary-views"를 활성화할 것을 권장한다.

secondary view의 underlying frame rate가 더 낮은 경우, XRSession은 다음 중 하나 이상을 선택할 수 있다:

7.4. XRViewport

XRViewport 객체는 그래픽 표면의 viewport, 즉 직사각형 영역을 설명한다.

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

xy 속성은 surface origin으로부터의 offset을 정의하고, widthheight 속성은 viewport의 직사각형 크기를 정의한다.

viewport 값의 정확한 해석은 해당 viewport가 연결된 그래픽 API의 관례에 따라 달라진다:

다음 코드는 XRViewerPose의 모든 XRView를 반복하고, 각 view에 대해 XRWebGLLayer에서 XRViewport를 질의하며, 이를 사용하여 렌더링에 적절한 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은 matrix 형태로 다양한 transform을 제공한다. WebXR은 matrix를 전달할 때 WebGL 관례를 사용하며, 여기서 4x4 matrix는 column major storage를 가진 16 요소 Float32Array로 주어지고, 왼쪽에서 matrix를 premultiply하여 column vector에 적용된다. 이들은 WebGL의 uniformMatrix4fv 함수에 직접 전달되거나, 동등한 DOMMatrix를 생성하는 데 사용되거나, 다양한 서드파티 수학 라이브러리와 함께 사용될 수 있다.

WebXR Device API에서 반환되는 matrix는 다음과 같이 배치된 16 요소 Float32Array가 된다:
[a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15]

이 matrix를 다음과 같이 지정된 column vector에 transform으로 적용하면:

{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. 정규화

vector 또는 quaternion을 normalize해야 하는 여러 알고리즘이 있으며, 이는 구성 요소들을 함께 갖는 magnitude가 1.0이 되도록 스케일링한다는 의미이다.

구성 요소 목록을 normalize하려면 UA는 다음 단계를 수행해야 한다:

  1. length를 각 구성 요소 제곱의 합의 제곱근으로 둔다.

  2. length0이면, InvalidStateError를 throw하고 이 단계를 중단한다.

  3. 각 구성 요소를 length로 나누고 그 구성 요소를 설정한다.

8.3. XRRigidTransform

XRRigidTransformpositionorientation으로 설명되는 transform이다. XRRigidTransform을 해석할 때, orientation은 항상 position보다 먼저 적용된다.

XRRigidTransformmatrixinternal matrix를 포함한다.

[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) constructor는 호출되면 다음 단계를 수행해야 한다:

  1. transformcurrent realm에 있는 XRRigidTransform 객체로 둔다.

  2. transformpositioncurrent realm에 있는 DOMPointReadOnly 객체로 둔다.

  3. positionw 값이 1.0이 아니면, TypeError를 throw하고 이 단계를 중단한다.

  4. position 또는 orientation의 값 중 하나 이상이 NaN이거나 infinity 같은 다른 비유한 숫자이면, TypeError를 throw하고 이 단계를 중단한다.

  5. transformpositionx 값을 position의 x dictionary member로, y 값을 position의 y dictionary member로, z 값을 position의 z dictionary member로, 그리고 w 값을 position의 w dictionary member로 설정한다.

  6. transformorientationcurrent realm에 있는 DOMPointReadOnly 객체로 둔다.

  7. transformorientationx 값을 orientation의 x dictionary member로, y 값을 orientation의 y dictionary member로, z 값을 orientation의 z dictionary member로, 그리고 w 값을 orientation의 w dictionary member로 설정한다.

  8. transforminternal matrixnull로 둔다.

  9. transformorientationx, y, z, 및 w 구성 요소를 Normalize한다.

  10. transform을 반환한다.

position 속성은 transform의 translation 구성 요소를 설명하는 3차원 점이며, 미터 단위로 주어진다. positionw 속성은 1.0이어야 한다.

orientation 속성은 transform의 rotational 구성 요소를 설명하는 quaternion이다. orientation은 길이가 1.0이 되도록 normalize되어야 한다.

matrix 속성은 positionorientation 속성이 설명하는 transform을 matrix로 반환한다. 이 속성은 XRRigidTransform에 대해 matrix를 얻어 계산되어야 한다.

참고: 이 matrix를 column vector에 premultiply하면 orientation이 설명하는 3D rotation으로 vector를 회전시킨 다음, 이를 position만큼 translate한다. 수학적으로 column-vector 표기법에서 이는 M = T * R이며, 여기서 Tposition에 대응하는 translation matrix이고, Rorientation에 대응하는 rotation matrix이다.

주어진 XRRigidTransform transform에 대해 matrix를 얻으려면:

  1. transforminternal matrixnull이 아니면, 다음 단계를 수행한다:

    1. internal matrix에 대한 IsDetachedBuffer 연산이 false이면, transforminternal matrix를 반환한다.

  2. translationposition에 대응하는 column-vector translation matrix인 새 matrix로 둔다. 수학적으로, position(x, y, z)이면, 이 matrix는 다음과 같다

    column-vector translation matrix의 수학적 표현

  3. rotationorientation에 대응하는 column-vector rotation matrix인 새 matrix로 둔다. 수학적으로, orientation이 unit quaternion (qx, qy, qz, qw)이면, 이 matrix는 다음과 같다

    column-vector rotation matrix의 수학적 표현

  4. transforminternal matrixtransform관련 realm에 있는 Float32Array 객체로 설정하되, 이는 transform관련 realm에서 translation을 왼쪽에 두고 translationrotation을 곱한 결과(translation * rotation)로 설정된다. 수학적으로, 이 matrix는 다음과 같다

    translation을 왼쪽에 두고 translation과 rotation을 곱한 matrix의 수학적 표현

  5. transforminternal matrix를 반환한다.

XRRigidTransform transforminverse 속성은 transform의 관련 realm 안에 있는 XRRigidTransform을 반환하며, 이는 이전에 transform에 의해 변환된 객체에 적용될 경우 transform을 되돌리고 객체를 초기 pose로 반환한다. 이 속성은 지연 평가되어야 한다. inverse가 반환한 XRRigidTransform은 자신의 inversetransform을 반환해야 한다.

position{ x: 0, y: 0, z: 0 w: 1 }이고, orientation{ x: 0, y: 0, z: 0, w: 1 }XRRigidTransformidentity transform으로 알려져 있다.

Realm realm 안의 BA라는 두 XRRigidTransform곱하려면, UA는 다음 단계를 수행해야 한다:

  1. resultrealm 안의 XRRigidTransform 객체로 둔다.

  2. resultmatrixrealm 안의 Float32Array 객체로 설정하되, 이는 Bmatrix를 왼쪽에서 Amatrix에 premultiply한 결과이다.

  3. resultorientationrealm 안의 DOMPointReadOnly 객체로 설정하되, 이는 resultmatrix의 왼쪽 위 3x3 sub-matrix가 나타내는 rotation을 설명하는 quaternion이다.

  4. resultpositionrealm 안의 DOMPointReadOnly 객체로 설정하되, 이는 resultmatrix의 네 번째 열이 제공하는 vector이다.

  5. result를 반환한다.

resultA의 source space에서 B의 destination space로의 transform이다.

참고: 이는 AB의 orientation의 composition인 orientation과, ApositionBorientation으로 회전시킨 뒤, Bposition에 더한 값과 같은 position을 가진 XRRigidTransform을 구성하는 것과 동등하다.

9. 포즈

9.1. XRPose

XRPoseXRSpace에 상대적인 공간 내 위치와 방향을 설명한다.

[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 속성은 base XRSpace에 상대적인 위치와 방향을 설명한다.

linearVelocity 속성은 base XRSpace에 상대적인 선속도를 초당 미터 단위로 설명한다. 사용자 에이전트가 이를 채울 수 없다면, null을 반환할 수 있다.

angularVelocity 속성은 base XRSpace에 상대적인 각속도를 초당 라디안 단위로 설명한다. 사용자 에이전트가 이를 채울 수 없다면, null을 반환할 수 있다.

emulatedPosition 속성은 transform이 센서 판독값을 기반으로 능동적으로 추적되는 6DoF pose를 나타낼 때 false이고, 그 position 값이 목 또는 팔 모델이 제공하는 것과 같은 computed offset을 포함하는 경우 true이다. XRPosecomputed offset을 포함하는지 결정할 때는 추정 바닥 수준을 고려해서는 안 된다.

9.2. XRViewerPose

XRViewerPoseXR 장치가 추적하는 XR 장면의 viewer 상태를 설명하는 XRPose이다. viewer는 추적되는 하드웨어 조각, 하드웨어에 상대적인 사용자의 관찰된 위치, 또는 XR 장면으로 들어가는 일련의 viewpoint를 계산하는 다른 수단을 나타낼 수 있다. XRViewerPoseXRReferenceSpace에 상대적으로만 질의될 수 있다. 이는 XRPose 값에 더해, viewpoint와 projection matrix를 나타내는 rigid transform을 포함하는 view들의 배열을 제공한다. 이러한 값들은 XR 장면의 프레임을 렌더링할 때 애플리케이션이 사용해야 한다.

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

views 배열은 XR 장면의 viewpoint를 설명하는 XRView들의 sequence이며, 이는 XRViewerPose가 질의된 XRReferenceSpace에 상대적이다. 배열 안의 XR 장면의 모든 viewXR 장치에서 올바르게 표시되도록 렌더링되어야 한다. 각 XRView는 viewpoint와 projection matrix를 나타내는 rigid transform을 포함하며, 필요할 때 layer에서 XRViewport를 질의하는 데 사용할 수 있다.

참고: XRViewerPosetransform은 장면의 spectator view 또는 multi-user interaction을 위해 viewer의 그래픽 표현을 배치하는 데 사용할 수 있다.

10. 入力

10.1. XRInputSource

XRInputSourceXR 入力ソースを表す。 これは、ユーザーが viewer と同じ 仮想空間内で対象指定されたアクションを実行できる任意の入力機構である。XR 入力ソースの例には、 ハンドヘルドコントローラー、光学的にトラッキングされる手、および viewer のポーズ上で動作する視線ベースの入力方式などが含まれるが、 これらに限定されない。従来のゲームパッド、マウス、またはキーボードなど、XR device と明示的に関連付けられていない入力機構は、 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 属性は、XRInputSource の望ましいポインティングレイ(その -Z 軸に沿う)の位置と向きをトラッキングする native origin を持つ XRSpace であり、 targetRayMode によって定義される。

targetRayMode"transient-pointer" である入力ソースについては、targetRaySpace はインタラクション開始時のインタラクション対象へのレイを表す。このポーズは、この XRInput の gripSpace 内で 静的であるべきである。

gripSpace 属性は、仮想オブジェクトがユーザーの手に 保持されているように見えるようレンダリングするために使用されるべきポーズをトラッキングする native origin を持つ XRSpace である。 ユーザーがまっすぐな棒を握った場合、この XRSpace は、 native origin を曲げた指の重心に置き、-Z 軸が棒の長さに沿って親指の方を指す位置に置く。 X 軸は記述対象の手の甲に垂直で、ユーザーの右手の甲は +X の方向を指し、 ユーザーの左手の甲は -X の方向を指す。Y 軸は XZ 軸の関係から含意され、+Y はおおよそユーザーの腕の方向を指す。

skipRendering 属性は、この入力が可視であり、 現在のセッションによってレンダリングする必要がない場合があることを示す。skipRendering が true で、targetRayMode が "tracked-pointer" である場合、ユーザーエージェントは XR 入力ソースの表現が常に ユーザーに表示されることを保証しなければならない。

コントローラーがユーザーに表示される例には、コントローラーがディスプレイとユーザーの間にある場合、ディスプレイが 透明である場合、またはコントローラーがオペレーティングシステムによってレンダリングされる場合が含まれる。

skipRendering は、コントローラーなどの入力ソースをレンダリングしないことについて開発者に与えるヒントである。ピックレイと カーソルは引き続きレンダリングされるべきである。

targetRayMode"transient-pointer" である入力ソースについては、gripSpace は、存在する場合は関連付けられたユーザージェスチャーであるべきであり、そうでなければ ViewerSpace、 あるいは別の XRInput の gripSpace または targetRaySpace など、ユーザーが制御する別の空間であるべきである。 これは、ユーザーがなお targetRaySpace を操作できるようにするためである。

入力ソースが本質的にトラッキング可能でない場合、たとえば targetRayMode"gaze" または "screen" である入力ソースのような場合、gripSpacenull でなければならない。

profiles 属性は、入力ソースの望ましい視覚表現と 振る舞いの両方を示す input profile namelist である。

input profile name は、スペースを含まず、別々の単語を ハイフン(-)文字で連結した ASCII 小文字の DOMString である。可能な場合はデバイスベンダーの好ましい表現を用いて、説明的な名前を選ぶべきである。プラットフォームが USB ベンダー ID および製品 ID などの適切な識別子を提供する場合、それを使用してもよい。シリアル番号など、 単一のデバイスを一意に識別する値は使用してはならない。input profile name は、デバイスの利き手を示す情報を 含んではならない。複数のユーザーエージェントが同じデバイスを公開する場合、それらは同じ input profile name を報告するよう努めるべきである。 WebXR Input Profiles Registry は、input profile name を管理するための推奨場所である。

プロファイルは具体性の降順で与えられる。リストの最初のエントリーの後に与えられる任意の input profile name は、デバイスの代替表現を表すフォールバック値を提供すべきである。これには、より汎用的または 以前のバージョンのデバイス、十分に類似したより広く認識されているデバイス、またはデバイス種別の広い説明 ("generic-trigger-touchpad" など)が含まれうる。複数のプロファイルが与えられる場合、それらが記述する レイアウトはすべて、リスト内の他のすべてのプロファイルの上位集合または下位集合を表さなければならない。

XRSessioninline session である場合、 profiles は空リストでなければならない。

ユーザーエージェントは、その裁量により、適切な汎用の input profile name のみ、または空リストのみを報告することを選んでもよい。これが適切なシナリオとしては、入力デバイスを 信頼性をもって識別できない場合、既知の入力プロファイルが入力デバイスに一致しない場合、またはユーザーエージェントが 使用されている入力デバイスを隠したい場合などがある。

たとえば、Samsung HMD Odyssey のコントローラーは、標準的な Windows Mixed Reality コントローラーの 設計バリエーションである。両方のコントローラーは同じ入力レイアウトを共有する。その結果、Samsung HMD Odyssey コントローラーの profiles は次のようになりうる: ["samsung-odyssey", "microsoft-mixed-reality", "generic-trigger-squeeze-touchpad-thumbstick"]. コントローラーの外観はリスト内の最初のプロファイルによって最も正確に伝えられ、2 番目のプロファイルは許容可能な 代替を記述し、最後のプロファイルはデバイスを最も大まかな意味で記述する汎用フォールバックである。 (これはトリガー、スクイーズボタン、タッチパッド、およびサムスティックを持つコントローラーである。)
同様に、Valve Index コントローラーは HTC Vive コントローラーと後方互換性があるが、Index コントローラーには 追加のボタンと軸がある。その結果、Valve Index コントローラーの profiles は次のようになりうる: ["valve-index", "htc-vive", "generic-trigger-squeeze-touchpad-thumbstick"]. この場合、 "valve-index" プロファイルによって記述される入力レイアウトは、"htc-vive" プロファイルによって記述されるレイアウトの上位集合である。また、"valve-index" プロファイルは コントローラーの正確な外観を示す一方、"htc-vive" コントローラーは大きく異なる外観を持つ。 この場合、UA はその差異を許容可能と判断したことになる。そして最初の例と同様に、最後のプロファイルは汎用の フォールバックである。
(正確な文字列は例にすぎない。実際のプロファイル名は WebXR Input Profiles Registry で管理される。)

注: XRSessioninputSources 配列内の XRInputSource は「ライブ」である。そのため、その内部の値はインプレースで更新される。これは、あるフレームで XRInputSource の属性への参照を保存し、状態変化を調べるために後続のフレームで同じ属性と比較しても機能しないことを意味する。 なぜなら、それらは同じオブジェクトになるためである。したがって、フレーム間で入力状態を比較したい開発者は、 問題となる状態の内容をコピーすべきである。

XR 入力ソースは、 primary action を サポートする場合、primary input source である。primary action は、開始されると selectstart, selectend, および select イベントを生成する、プラットフォーム固有のアクションである。可能な primary action の例は、トリガー、タッチパッド、またはボタンを押すこと、 コマンドを発話すること、または手のジェスチャーを行うことである。プラットフォームガイドラインが推奨される primary input を定義している場合、それを primary action として使用すべきであり、そうでなければユーザーエージェントは自由に 1 つを選択できる。 デバイスは少なくとも 1 つの primary input source をサポートしなければならない。

XR 入力ソースは、 primary action をサポートしない場合、tracked input source である。これらの入力は主にポーズデータを提供することを意図している。 注: tracked input source の例としては、ユーザーの脚または小道具のための トラッキングアタッチメントが挙げられる。primary action を検出するためのジェスチャー認識が行われていない場合、トラッキングされた手も tracked input source とみなされることがある。

XRSession sessionXR 入力 ソース source がその primary action を開始したとき、UA は次の手順を実行しなければならない:

  1. frame を、session関連するレルム内の 新しい XRFrame とし、sessionsession を、time にアクションが発生した時刻を持たせる。

  2. 名前 selectstart, frame frame, および source source入力ソースイベントを発火するよう タスクをキューに入れる

XRSession sessionXR 入力 ソース source がその primary action を終了したとき、UA は次の手順を実行しなければならない:

  1. frame を、session関連するレルム内の 新しい XRFrame とし、sessionsession を、time にアクションが発生した時刻を持たせる。

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

    1. 名前 select, frame frame, および source source入力ソースイベントを発火する。

    2. 名前 selectend, frame frame, および source source入力ソースイベントを発火する。

XR 入力ソースは、 primary squeeze action を定義してもよい。primary squeeze action は、開始されると squeezestart, squeezeend, および squeeze イベントを生成する、プラットフォーム固有のアクションである。primary squeeze action は、おおよそ握るまたはつかむことに対応する アクションに使用されるべきである。可能な primary squeeze action の例は、 グリップトリガーを押すこと、またはつかむ手のジェスチャーを行うことである。プラットフォームガイドラインが 推奨される primary squeeze action を定義している場合、それを primary squeeze action として使用すべきであり、そうでなければ ユーザーエージェントは 1 つを選択してもよい。

XRSession sessionXR 入力 ソース source がその primary squeeze action を開始したとき、UA は次の手順を 実行しなければならない:

  1. frame を、session関連するレルム内の 新しい XRFrame とし、sessionsession を、time にアクションが発生した時刻を持たせる。

  2. 名前 squeezestart, frame frame, および source source入力ソースイベントを発火するよう タスクをキューに入れる

XRSession sessionXR 入力 ソース source がその primary squeeze action を終了したとき、UA は次の手順を 実行しなければならない:

  1. frame を、session関連するレルム内の 新しい XRFrame とし、sessionsession を、time にアクションが発生した時刻を持たせる。

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

    1. 名前 squeeze, frame frame, および source source入力ソースイベントを発火する。

    2. 名前 squeezeend, frame frame, および source source入力ソースイベントを発火する。

プラットフォーム固有の振る舞いによって、primary action または primary squeeze action が 中断またはキャンセルされることがある。たとえば、primary action または primary squeeze action が開始された後、それが終了する前に、XR 入力ソースXR device から取り除かれることがある。

XRSession sessionXR 入力 ソース sourceprimary action がキャンセルされたとき、UA は次の手順を実行しなければならない:

  1. frame を、session関連するレルム内の 新しい XRFrame とし、sessionsession を、time にアクションが発生した時刻を持たせる。

  2. 名前 selectend, frame frame, および source sourceXRInputSourceEvent である 入力ソースイベントを発火するよう タスクをキューに入れる

XRSession sessionXR 入力 ソース sourceprimary squeeze action がキャンセルされたとき、UA は次の手順を 実行しなければならない:

  1. frame を、session関連するレルム内の 新しい XRFrame とし、sessionsession を、time にアクションが発生した時刻を持たせる。

  2. 名前 squeezeend, frame frame, および source sourceXRInputSourceEvent である 入力ソースイベントを発火するよう タスクをキューに入れる

10.2. 一時的入力

一部の XR device一時的入力ソースを サポートすることがある。そこでは、XR 入力ソースtransient action を 実行している間だけ意味を持つ。これは、primary input sourceprimary action であるか、tracked input source のためのデバイス固有の auxiliary action である。

一例として、inline session に対するマウス、タッチ、またはスタイラス入力があり、 これは targetRayModescreen に設定された一時的な XRInputSource を生成しなければならず、primary pointer については primary action として扱われ、非 primary pointer については非 primary の auxiliary action として扱われる。

別の例として、視線に基づくインタラクションなど、直接公開できない機微情報から得られる入力を伴う オペレーティングシステムからの意図がある。これらは targetRayModetransient-pointer に設定された一時的な XRInputSource を生成し、primary action として扱われる。

一時的入力ソースは、 transient action の継続時間中だけ、セッションの アクティブな XR 入力ソースのリストに存在する。

一時的入力ソースは、 非一時的な primary actions のための アルゴリズムの代わりに、transient actions を処理するとき、次のシーケンスに従う:

XRSession session一時的入力ソース source がその transient action を開始したとき、UA は次の手順を実行しなければならない:

  1. frame を、session関連するレルム内の 新しい XRFrame とし、sessionsession を持たせ、アクションが発生した時刻のためのものとする。

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

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

    2. XR 入力ソースを追加して、アクティブな XR 入力ソースのリストに入れる。

    3. transient actionprimary action である場合、 名前 selectstart, frame frame, および source source入力ソースイベントを発火する。

XRSession session一時的入力ソース source がその transient action を終了したとき、UA は次の手順を実行しなければならない:

  1. frame を、session関連するレルム内の 新しい XRFrame とし、sessionsession を持たせ、アクションが発生した時刻のためのものとする。

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

    1. transient actionprimary action である場合、 名前 select, frame frame, および source source入力ソースイベントを発火する。

    2. 必要に応じて、XR 入力ソースのアクションによって 生成される任意の "click" イベントを発火する。

    3. transient actionprimary action である場合、 名前 selectend, frame frame, および source source入力ソースイベントを発火する。

    4. XR 入力ソースを削除して、 アクティブな XR 入力ソースのリストから 取り除く。

    5. 必要に応じて、XR 入力ソースのアクションによって 生成される任意の "pointerup" イベントを発火する。

XRSession session一時的入力ソース sourcetransient action がキャンセルされたとき、UA は次の手順を実行しなければならない:

  1. frame を、session関連するレルム内の 新しい XRFrame とし、sessionsession を持たせ、アクションが発生した時刻のためのものとする。

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

    1. transient actionprimary action である場合、 名前 selectend, frame frame, および source source入力ソースイベントを発火する。

    2. XR 入力ソースを削除して、 アクティブな XR 入力ソースのリストから 取り除く。

    3. 必要に応じて、XR 入力ソースのアクションによって 生成される任意の "pointerup" イベントを発火する。

10.3. XRInputSourceArray

XRInputSourceArrayXRInputSourcelist を表す。 これは、XRSessioninputSources 属性のように、list の内容が時間とともに変化することが 期待される場合に、frozen array type に優先して使用される。

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

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

XRInputSourceArrayindexed property getter は、指定されたインデックスの XRInputSource を取得する。

11. レイヤー

注: この仕様は XRWebGLLayer レイヤーのみを定義するが、将来の仕様拡張では追加のレイヤー種別と、それらが描画元とする画像ソースが追加されることが 期待される。

11.1. XRLayer

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

XRLayer は、 XRWebGLLayer および将来の拡張によって導入されるその他のレイヤー種別の基底クラスである。

11.2. XRWebGLLayer

XRWebGLLayer は、レンダリング先となる WebGL フレームバッファを提供するレイヤーであり、ハードウェアアクセラレーションされた 3D グラフィックスのレンダリングを XR device 上に提示できるようにする。

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 は、最初は null である context オブジェクトを持ち、これは WebGLRenderingContext または WebGL2RenderingContext のいずれかのインスタンスである。

XRWebGLLayer は、関連付けられた session を持ち、これはそれが作成されたときの XRSession である。

XRWebGLLayer(session, context, layerInit) コンストラクターは、呼び出されたとき次の手順を実行しなければならない:

  1. layer を、session関連するレルム内の 新しい XRWebGLLayer とする。

  2. sessionended 値が true である場合、InvalidStateError を投げ、これらの手順を中止する。

  3. context が lost である場合、InvalidStateError を投げ、これらの手順を中止する。

  4. sessionimmersive session であり、contextXR compatible 真偽値が false である場合、InvalidStateError を投げ、これらの手順を中止する。

  5. layercontextcontext に初期化する。

  6. layersessionsession に初期化する。

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

    layerInitignoreDepthValues 値が false であり、XR Compositor が depth 値を使用する場合:

    layerignoreDepthValuesfalse に初期化する。

    そうでない場合:

    layerignoreDepthValuestrue に初期化する。

  8. layercomposition enabled 真偽値を次のように初期化する:

    sessioninline session である場合:

    layercomposition enabledfalse に初期化する。

    そうでない場合:

    layercomposition enabled 真偽値を true に初期化する。

  9. layercomposition enabled 真偽値が true である場合:
    1. layerantialiaslayerInitantialias 値に初期化する。

    2. scaleFactorlayerInitframebufferScaleFactor とする。

    3. ユーザーエージェントはここで、たとえば性能上の理由でバッファ寸法を 2 の累乗に収めたい場合など、 適切と考えるように scaleFactor をクランプまたは丸めることを選んでもよい。

    4. framebufferSize を、幅と高さにそれぞれ scaleFactor を掛けた recommended WebGL framebuffer resolution とする。

    5. layerframebuffer を、context関連するレルム内の 新しい WebGLFramebuffer に初期化する。これは context で作成された寸法 framebufferSizeopaque framebuffer であり、sessionsession に 初期化され、layerInitdepth, stencil, および alpha 値を持つ。

    6. layer の合成をサポートするために必要に応じて、GPU からアクセス可能な メモリバッファを含む、sessionXR device と互換性のあるリソースを 割り当て、初期化する。

    7. 何らかの理由で layer のリソースを作成できなかった場合、OperationError を投げ、これらの手順を中止する。

    そうでない場合:
    1. layerantialias を、layercontextactual context parametersantialias 値に初期化する。

    2. layerframebuffernull に初期化する。

  10. layer を返す。

注: XRWebGLLayercomposition enabled 真偽値が false に 設定されている場合、XRWebGLLayerInit オブジェクト上のすべての値は無視される。これは WebGLRenderingContext の デフォルトフレームバッファが、すでにそのコンテキストの actual context parameters を使用して割り当てられており、上書きできないためである。

context 属性は、XRWebGLLayer が作成されたときの WebGLRenderingContext である。

XRWebGLLayer は、最初 true に設定される composition enabled 真偽値を持つ。false に 設定されている場合、それは XRWebGLLayer が自身の WebGLFramebuffer を割り当ててはならず、framebuffer プロパティを反映する XRWebGLLayer のすべてのプロパティは、代わりに context のデフォルトフレームバッファのプロパティを反映しなければならないことを示す。

XRWebGLLayerframebuffer 属性は、 composition enabledtrue である場合は opaque としてマークされた WebGLFramebuffer のインスタンスであり、そうでない場合は null である。XRWebGLLayer が作成された後、開発者は framebuffer サイズを調整できない。

opaque framebuffer は標準的な WebGLFramebuffer と同一に機能するが、default framebuffer により近く振る舞わせる次の変更を伴う:

注: ユーザーエージェントは、depth および stenciltrue 値を尊重することを要求される。これは、drawing buffer を作成するときの WebGL の振る舞いに類似している。

opaque framebuffer にアタッチされたバッファは、最初に作成されたとき、 または各 XR animation frame の処理前に、下の表の値へ クリアされなければならない。これは WebGL コンテキストの default framebuffer の振る舞いと同一である。Opaque framebuffers は、関連付けられた WebGL コンテキストの preserveDrawingBuffer 値に関係なく常にクリアされる。

バッファ クリア値
(0, 0, 0, 0)
深度 1.0
ステンシル 0

注: 実装は、開発者が別プロセスからバッファ内容へアクセスできないことが 保証できる限り、opaque framebuffer に必要な暗黙のクリア操作を最適化で省略してもよい。 たとえば、開発者が明示的なクリアを行う場合、暗黙のクリアは不要である。

alphatrue に設定された状態で XRWebGLLayer が作成された場合、framebufferRGBA 色形式のテクスチャに裏付けられなければならない。 alphafalse に設定された状態で XRWebGLLayer が作成された場合、framebufferRGB 色形式のテクスチャに裏付けられなければならない。

しかし、XR Compositor は、 framebuffer の バッキングのピクセルを、SRGB8_ALPHA8 または SRGB8 colorFormat 内にあるかのように扱わなければならない。

注: これは、XR Compositorframebuffer を裏付けるテクスチャを処理するとき、線形 RGBA または RGB からのガンマ変換を行ってはならないことを意味する。そうしないと、最終レンダリングのピクセルが明るすぎて 見えることになり、通常の 2D WebGLRenderingContext コンテキスト上のレンダリングと一致しなくなる。

XRWebGLLayerimmersive sessionbaseLayer として設定された場合、opaque framebuffer の内容は、XR animation frame が完了した直後に immersive XR device に提示されるが、 前回の XR animation frame 以降に少なくとも次のいずれかが発生した場合に限られる:

opaque framebufferimmersive XR device に提示される前に、ユーザーエージェントは、 すべてのレンダリング操作が opaque framebuffer にフラッシュ済みであることを保証しなければならない。

XRWebGLLayertarget framebuffer を持ち、これは composition enabledtrue である場合は framebuffer であり、そうでない場合は context の デフォルトフレームバッファである。

framebufferWidth および framebufferHeight 属性は、それぞれ target framebuffer のアタッチメントの幅と高さを返す。

antialias 属性は、target framebuffer が UA の選択する技法を用いて アンチエイリアスをサポートする場合は true であり、アンチエイリアスが実行されない場合は false である。

ignoreDepthValues 属性は、 true である場合、XR Compositor がレンダリング時に深度バッファアタッチメント内の値を 使用してはならないことを示す。この属性が false である場合、深度バッファアタッチメントの内容が XR Compositor によって使用され、レイヤー内にレンダリングされたシーンを 表すことが期待されることを示す。

バッファに格納される深度値は、0.0 から 1.0 の間であることが期待され、 0.0depthNear の距離を表し、1.0depthFar の距離を表し、中間値は線形に補間される。これは WebGL のデフォルトの振る舞いである。(追加の詳細については depthRange 関数の文書を参照。)

注: シーンの深度バッファをコンポジターに利用可能にすることで、 一部のプラットフォームは改良された再投影など、品質と快適性の向上を提供できる。

fixedFoveation 属性は、XR Compositor によって使用される foveation の量を制御する。ユーザーエージェントまたはデバイスがこの属性を サポートしない場合、取得時には null を返すべきであり、設定は no-op であるべきである。 fixedFoveation0 未満の値に設定すると 0 に設定され、1 より大きい値に設定すると 1 に設定される。0 は foveation の最小量を設定し、1 は最大量を設定する。 XR Compositor がこれらの値をどのように解釈するかは ユーザーエージェント次第である。fixedFoveation レベルが変更された場合、それは次の XRFrame で効果を持つ。

注: Fixed foveation は、ユーザーの視野の端付近で コンテンツがレンダリングされる解像度を下げる技法である。GPU フィル性能によって制限される体験を大幅に改善できる。 電力消費を減らし、アプリケーションが目用テクスチャの解像度を上げることを可能にする。背景画像のような 低コントラストのテクスチャに最も有用であり、テキストや詳細画像のような高コントラストのものにはあまり有用ではない。 作者は、性能と視覚品質の最良のトレードオフを達成するため、フレームごとにレベルを調整できる。

XRWebGLLayerlist of full-sized viewports を持たなければならない。これは XRSession が 公開しうる各 view について 1 つの WebGL viewport を含む list であり、現在は active でないが現在のセッションで active になりうる secondary views も含む。ビューポートは width および height0 より大きくなければならず、target framebuffer の境界を超えない矩形を記述しなければならない。 ビューポートは重なり合ってはならない。

composition enabledfalse であり、 sessionlist of views が、eye"none" である単一の view を含む場合、 list of full-sized viewports は、 context の デフォルトフレームバッファ全体を覆う単一の WebGL viewport を含まなければならない。

composition enabledfalse であり、 sessionlist of views が 2 つの primary views、すなわち eye"left" であるものと、eye"right" であるものを含む場合、list of full-sized viewports は 2 つの WebGL viewport を含まなければならない。1 つは "left" view に関連付けられ、もう 1 つは "right" view に関連付けられる。ユーザーエージェントは、 上記の制約に従って、これらのビューポートのサイズと位置を決定する。

注: この仕様は、ステレオ inline ビューポートについて、 横並びなど特定の詰め方を要求しない。作者はレイアウトを仮定するのではなく、各 XRView について getViewport() を使用すべきである。

XRWebGLLayerlist of viewport objects を持たなければならない。これは、XRSession が 現在公開している各 activeview について 1 つの XRViewport を含む list である。

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 に関連付けられた XRViewport を、session について view に関連付けられた list of full-sized viewports から scaled viewport を取得する結果の XRViewport に設定する。

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

  8. viewport を、view に関連付けられた list of viewport objects からの XRViewport とする。

  9. viewport を返す。

注: viewport modifiable フラグは、 current viewport scale に変更がない場合でも、意図的に false に設定される。これにより、そのビューについて、アニメーションフレーム内の getViewport(view) 呼び出しは常に一貫した結果を返し、最初に取得された値がフレームの残りの間 固定されることが保証される。アプリケーションが getViewport() の後に requestViewportScale() を呼び出した場合、要求された値は、将来のフレームで getViewport() が再び呼び出されたときにのみ 後で適用される。

XRSessionnative WebGL framebuffer resolution を識別しなければならない。 これは、XR device の 物理ピクセル解像度に一致するために必要な WebGL フレームバッファのピクセル解像度である。

XRSession sessionnative WebGL framebuffer resolution は、 次の手順を実行することによって決定される:

  1. sessioninline session である場合、native WebGL framebuffer resolutionsessionrenderStateoutput canvas の物理ディスプレイピクセルでのサイズに 設定し、canvas のサイズが変化するたび、または output canvas が変更されるたびにこれらの手順を再評価し、これらの手順を中止する。

  2. native WebGL framebuffer resolution を、 セッションのすべての XRView を 含むのに十分な大きさのフレームバッファのピクセルと、最も高い拡大率の下にあるディスプレイ領域の 物理スクリーンピクセルとの間で 1:1 の比率を持つために必要な解像度に設定する。記述されたように ネイティブ解像度を決定する方法が存在しない場合、recommended WebGL framebuffer resolution を使用してもよい。

さらに、XRSessionrecommended WebGL framebuffer resolution を 識別しなければならない。これは、平均的なアプリケーションに性能と品質の良好なバランスを提供しつつ、セッションの すべての XRView を 含むのに十分な大きさの WebGL フレームバッファ解像度の最良推定を表す。これは native WebGL framebuffer resolution より小さくても、 大きくても、等しくてもよい。新しい opaque framebuffer はこの解像度で作成され、幅と高さはそれぞれ、提供された任意の XRWebGLLayerInitframebufferScaleFactor によってスケールされる。

注: ユーザーエージェントは、 recommended WebGL framebuffer resolution を 推定するために任意の方法を自由に使用できる。推奨サイズを問い合わせるためのプラットフォーム固有の方法がある場合、 それを使用することが推奨されるが、要求はされない。framebufferScaleFactor および getNativeFramebufferScaleFactor() によって使用されるスケール係数は幅と高さに別々に適用されるため、2 のスケール係数は全体のピクセル数を 4 倍にする。 プラットフォームがピクセル数に基づく面積ベースの render scale を公開する場合、ユーザーエージェントはそれを WebXR スケール係数へ変換するために平方根を取る必要がある。

getNativeFramebufferScaleFactor(session) メソッドは、呼び出されたとき次の手順を実行しなければならない:

  1. sessionthis とする。

  2. sessionended 値が true である場合、0.0 を返し、 これらの手順を中止する。

  3. sessionrecommended WebGL framebuffer resolution の幅と高さにそれぞれ掛けることで、sessionnative WebGL framebuffer resolution が 得られる値を返す。

11.3. WebGL 컨텍스트 호환성

WebGL 컨텍스트가 immersive XR imagery의 소스로 사용되려면, immersive XR device에 대한 호환 가능한 그래픽 어댑터에서 생성되어야 한다. 무엇이 compatible graphics adapter로 간주되는지는 플랫폼에 따라 다르지만, graphics adapter가 과도한 지연 없이 immersive XR device에 imagery를 제공할 수 있음을 의미하는 것으로 이해된다. WebGL 컨텍스트가 compatible graphics adapter에서 이미 생성되지 않았다면, 일반적으로 XRWebGLLayer와 함께 사용되기 전에 해당 adapter에서 다시 생성되어야 한다.

참고: 단일 GPU를 가진 XR 플랫폼에서는 GPU가 플랫폼이 알리는 immersive XR device와 호환된다고 안전하게 가정할 수 있으므로, 모든 hardware accelerated WebGL context 역시 호환된다. integrated GPU와 discrete GPU를 모두 가진 PC에서는 discrete GPU가 일반적으로 더 높은 성능의 chip이므로 compatible graphics adapter로 간주되는 경우가 많다. 여러 graphics adapter가 설치된 desktop PC에서는 immersive XR device가 물리적으로 연결된 adapter가 compatible graphics adapter로 간주될 가능성이 높다.

참고: Inline session은 canvas와 같은 graphics adapter를 사용하여 렌더링하므로, xrCompatible context가 필요하지 않다.

partial dictionary WebGLContextAttributes {
    boolean xrCompatible = false;
};

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

사용자 에이전트가 이 명세를 구현할 때, 모든 WebGLRenderingContextBase에 처음에는 false로 설정되는 XR compatible boolean을 설정해야 한다. XR compatible boolean이 true로 설정되면, 그 context는 현재 immersive XR device에서 요청된 모든 XRSession에 대한 layer와 함께 사용할 수 있다.

참고: 이 flag는 느린 synchronous behavior를 도입하므로 권장되지 않는다. asynchronous solution으로 대신 makeXRCompatible()을 호출하는 것을 고려하라.

XR compatible boolean은 context 생성 시점이나 context 생성 이후에 설정할 수 있으며, 잠재적으로 context loss가 발생할 수 있다. context 생성 시점에 XR compatible boolean을 설정하려면, WebGL context를 요청할 때 xrCompatible context creation attribute를 true로 설정해야 한다. 요청하는 document의 origin이 "xr-spatial-tracking" permissions policy를 사용할 수 없다면, xrCompatible은 효과가 없다.

xrCompatible flag가 true이면, WebGLContextAttributes에서 사용자 에이전트가 immersive XR device에 대한 compatible graphics adapter를 사용하여 WebGL context를 생성하도록 요청함으로써 context creation에 영향을 준다. 사용자 에이전트가 이에 성공하면, 생성된 context의 XR compatible boolean은 true로 설정된다. immersive XR device를 얻으려면, immersive XR device가 선택되도록 보장하는 것이 호출되어야 한다.

참고: Immersive XR device가 선택되도록 보장하는 작업은 in parallel로 실행되어야 하며, 이는 main thread에 느린 synchronous behavior를 도입한다. 사용자 에이전트는 대신 makeXRCompatible()을 사용하도록 요청하는 warning을 console에 출력해야 한다.

다음 코드는 immersive XR device와 호환되는 WebGL context를 생성한 다음, 이를 사용하여 XRWebGLLayer를 생성한다.
function onXRSessionStarted(xrSession) {
  const glCanvas = document.createElement("canvas");
  const gl = glCanvas.getContext("webgl", { xrCompatible: true });

  loadWebGLResources();

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

context가 생성된 후 XR compatible boolean을 설정하려면, makeXRCompatible() 메서드를 사용한다.

참고: 일부 시스템에서는 이 flag가 예를 들어 high powered discrete GPU를 켜거나 모든 command를 on-device GPU로 proxy할 수 있다. XR을 사용할 수도 있고 사용하지 않을 수도 있는 상황이라면, immersive session을 시작하려는 경우에만 makeXRCompatible()을 호출하는 것이 권장된다.

makeXRCompatible() 메서드는 WebGLRenderingContextBaseimmersive XR device에 대한 compatible graphics adapter에서 실행되도록 보장한다.

이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. 요청하는 document의 origin이 "xr-spatial-tracking" permissions policy를 사용할 수 없다면, promiseresolve하고 반환한다. XR permissions policy가 비활성화된 경우, 이 경우에는 XR device가 없는 것처럼 동작하기를 원한다. makeXRCompatible()은 set-and-forget method로 의도되었기 때문이다.

  2. promise를 이 WebGLRenderingContextBaseRealm에서 생성된 새 Promise로 둔다.

  3. contextthis로 둔다.

  4. 다음 단계를 in parallel로 실행한다:

    1. deviceimmersive XR device가 선택되도록 보장한 결과로 둔다.

    2. contextXR compatible boolean을 다음과 같이 설정한다:

      contextWebGL context lost flag가 설정된 경우:

      contextXR compatible boolean을 false로 설정하고, InvalidStateErrorpromisereject하도록 task를 queue한다.

      devicenull인 경우:

      contextXR compatible boolean을 false로 설정하고, InvalidStateErrorpromisereject하도록 task를 queue한다.

      contextXR compatible boolean이 true인 경우:

      promiseresolve하도록 task를 queue한다.

      contextdevice에 대한 compatible graphics adapter에서 생성된 경우:

      contextXR compatible boolean을 true로 설정하고 promiseresolve하도록 task를 queue한다.

      그렇지 않으면:

      다음 단계를 수행하도록 WebGL task sourcetask를 queue한다:

      1. context를 강제로 lost 상태로 만든다.

      2. WebGL 명세에 설명된 대로 context loss를 처리한다:

        1. canvascontextcanvas로 둔다.

        2. contextwebgl context lost flag가 설정되어 있으면, 이 단계를 중단한다.

        3. contextwebgl context lost flag를 설정한다.

        4. context가 생성한 각 WebGLObject instance의 invalidated flag를 설정한다.

        5. "WEBGL_lose_context"를 제외한 모든 extension을 비활성화한다.

        6. 다음 단계를 수행하도록 WebGL task sourcetask를 queue한다:

          1. canvas에서 "webglcontextlost"라는 이름을 가진 WebGL context event estatusMessage가 ""로 설정된 상태로 fire한다.

          2. ecanceled flag가 설정되어 있지 않으면, AbortErrorpromisereject하고 이 단계를 중단한다.

          3. 다음 단계를 in parallel로 실행한다.

            1. device에 대한 compatible graphics adapter에서 restorable drawing buffer를 기다린다.

            2. 다음 단계를 수행하도록 WebGL task sourcetask를 queue한다:

              1. device에 대한 compatible graphics adapter에서 context를 restore한다.

              2. contextXR compatible boolean을 true로 설정한다.

              3. promiseresolve한다.

  5. promise를 반환한다.

또한, WebGL context가 lost될 때마다 "webglcontextlost" event를 fire하기 전에 다음 단계를 실행한다:

  1. context의 XR compatible boolean을 false로 설정한다.

다음 코드는 기존 WebGL context에서 XRWebGLLayer를 생성한다.
const glCanvas = document.createElement("canvas");
const gl = glCanvas.getContext("webgl");

loadWebGLResources();

glCanvas.addEventListener("webglcontextlost", (event) => {
  // Indicates that the WebGL context can be restored.
  event.canceled = true;
});

glCanvas.addEventListener("webglcontextrestored", (event) => {
  // WebGL resources need to be re-created after a context loss.
  loadWebGLResources();
});

async function onXRSessionStarted(xrSession) {
  // Make sure the canvas context we want to use is compatible with the device.
  // May trigger a context loss.
  await gl.makeXRCompatible();
  xrSession.updateRenderState({ baseLayer: new XRWebGLLayer(xrSession, gl) });
}

12. 이벤트

별도로 지정되지 않는 한, 이 명세에서 queue된 모든 task sourceXR task source이다.

12.1. XRSessionEvent

XRSessionEventXRSession의 상태 변경을 나타내기 위해 fire된다.

[SecureContext, Exposed=Window]
interface XRSessionEvent : Event {
  constructor(DOMString type, XRSessionEventInit eventInitDict);
  [SameObject] readonly attribute XRSession session;
};

dictionary XRSessionEventInit : EventInit {
  required XRSession session;
};

session 속성은 event를 생성한 XRSession을 나타낸다.

12.2. XRInputSourceEvent

XRInputSourceEventXRInputSource의 상태 변경을 나타내기 위해 fire된다.

[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 속성은 이 event를 생성한 XRInputSource를 나타낸다.

frame 속성은 event가 발생한 시간에 대응하는 XRFrame이다. 이는 historical data를 나타낼 수 있다. getViewerPose()frame에서 호출될 때 exception을 throw해야 한다.

사용자 에이전트가 이름 name, XRFrame frame, 및 XRInputSource sourceinput source event를 fire해야 하는 경우, 다음 단계를 실행해야 한다:

  1. type name, frame frame, 및 inputSource source를 가진 XRInputSourceEvent event를 생성한다.

  2. frameactive boolean을 true로 설정한다.

  3. frame에 대해 frame update를 적용한다.

  4. framesession에서 eventdispatch한다.

  5. frameactive boolean을 false로 설정한다.

12.3. XRInputSourcesChangeEvent

XRInputSourcesChangeEventXRSession에서 사용할 수 있는 active XR input source 목록의 변경을 나타내기 위해 fire된다.

[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 속성은 event를 생성한 XRSession을 나타낸다.

added 속성은 event 시점에 XRSession에 추가된 XRInputSource들의 list이다.

removed 속성은 event 시점에 XRSession에서 제거된 XRInputSource들의 list이다.

12.4. XRReferenceSpaceEvent

XRReferenceSpaceEventXRReferenceSpace의 상태 변경을 나타내기 위해 fire된다.

[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 속성은 이 event를 생성한 XRReferenceSpace를 나타낸다.

선택적 transform 속성은 event 전 coordinate system에서 referenceSpacenative origin의 event 후 위치와 orientation을 설명한다. XRSystem이 old coordinate system과 new coordinate system 사이의 delta를 결정할 수 없는 경우, 이 속성은 null일 수 있다.

참고: referenceSpace 또는 referenceSpace가 될 수 있는 상황은 headset이 두 개의 서로 다른 위치 사이에서 벗겨졌다가 다시 착용된 경우이다. 이러한 경우 experience가 world-locked content에 의존한다면, 사용자에게 경고하고 scene을 reset해야 한다.

12.5. XRVisibilityMaskChangeEvent

frustum이 rectangular display와 정확히 교차하지 않기 때문에, XRLayer의 전체 영역이 표시되지 않을 수 있다. 이 event는 사용자에게 표시되는 XRView의 region에 대해 experience에 알린다.

XRVisibilityMaskChangeEvent event는 사용자 에이전트가 XRLayer의 표시되는 영역이 변경되었음을 experience에 알리고자 할 때 fire된다. experience는 해당 region만 draw하도록 선택할 수 있으며, 이는 performance에 도움이 될 수 있다.

참고: experience는 requestSession의 promise resolution 중에 이 event를 등록해야 한다. 그렇지 않으면 event가 fire되고 mask가 experience에 전달되지 않을 수 있다.

[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 속성은 event를 생성한 XRSession을 나타낸다.

eye 속성은 mask가 어떤 XREye에 적용되는지를 나타낸다.

index 속성은 이 mask가 적용되는 XRViewview 목록 안에서의 offset을 나타낸다.

vertices 속성은 X, Y coordinate의 list이다. experience는 Z coordinate가 -1이라고 가정해야 한다. 각 X, Y, Z coordinate는 하나의 vertex를 설명한다. 이 array가 비어 있으면, XRView의 전체 region을 draw해야 한다.

indices 속성은 vertices가 설명하는 vertex list 안의 index를 설명하는 index들의 list이다. 이러한 index는 draw해야 하는 eye의 XRView region을 설명한다. 이 array가 비어 있으면, XRView의 전체 region을 draw해야 한다.

그 영역은 eyeXRViewprojectionMatrix와 기본 XRRigidTransform을 사용하여 draw되어야 한다.

참고: 이는 그 영역이 eye의 현재 XRViewXRRigidTransform을 사용해서는 안 된다는 뜻이다.

12.6. 이벤트 유형

사용자 에이전트는 다음 새 event를 제공해야 한다. event의 registration과 firing은 DOM Events의 일반적인 동작을 따라야 한다.

사용자 에이전트는 document의 origin이 "xr-spatial-tracking" permissions policy를 사용할 수 없는 경우가 아니라면, immersive XR device의 availability가 변경되었음을 나타내기 위해 XRSystem object에서 devicechange라는 이름의 event를 fire해야 한다.

사용자 에이전트는 XRSessionvisibility state가 변경될 때마다, XRSessionEvent를 사용하여 XRSession에서 visibilitychange라는 이름의 event를 fire해야 한다.

사용자 에이전트는 application 또는 user agent에 의해 session이 종료될 때, XRSessionEvent를 사용하여 XRSession에서 end라는 이름의 event를 fire해야 한다.

사용자 에이전트는 session의 active XR input source 목록이 변경될 때, XRInputSourcesChangeEvent를 사용하여 XRSession에서 inputsourceschange라는 이름의 event를 fire해야 한다.

사용자 에이전트는 session의 active XR tracked source 목록이 변경될 때, XRInputSourcesChangeEvent를 사용하여 XRSession에서 trackedsourceschange라는 이름의 event를 fire해야 한다. 이 event는 session의 granted feature 집합tracked-sources가 포함되어 있는 경우에만 fire되어야 한다.

사용자 에이전트는 자신의 XRInputSource 중 하나가 자신의 primary action을 시작할 때, XRSession에서 XRInputSourceEvent를 사용하여 selectstart라는 이름의 이벤트를 fire해야 한다. 이벤트는 type . 이어야 한다.

사용자 에이전트는 자신의 XRInputSource 중 하나가 자신의 primary action을 끝내거나, primary action을 시작한 XRInputSource가 disconnected될 때, XRSession에서 XRInputSourceEvent를 사용하여 selectend라는 이름의 이벤트를 fire해야 한다.

사용자 에이전트는 자신의 XRInputSource 중 하나가 primary action을 완전히 완료했을 때, XRSession에서 XRInputSourceEvent를 사용하여 select라는 이름의 이벤트를 fire해야 한다.

사용자 에이전트는 자신의 XRInputSource 중 하나가 자신의 primary squeeze action을 시작할 때, XRSession에서 XRInputSourceEvent를 사용하여 squeezestart라는 이름의 이벤트를 fire해야 한다.

사용자 에이전트는 자신의 XRInputSource 중 하나가 자신의 primary squeeze action을 끝내거나, primary squeeze action을 시작한 XRInputSource가 disconnected될 때, XRSession에서 XRInputSourceEvent를 사용하여 squeezeend라는 이름의 이벤트를 fire해야 한다.

사용자 에이전트는 자신의 XRInputSource 중 하나가 primary squeeze action을 완전히 완료했을 때, XRSession에서 XRInputSourceEvent를 사용하여 squeeze라는 이름의 이벤트를 fire해야 한다.

사용자 에이전트는 XR CompositorXRSessioninternal nominal framerate를 변경할 때, XRSession에서 XRSessionEvent를 사용하여 frameratechange라는 이름의 이벤트를 fire해야 한다.

사용자 에이전트는 XRSystem이 사용자에게 표시되는 XRView의 visible region 변경을 signal하려는 경우, XRSession에서 XRVisibilityMaskChangeEvent를 사용하여 visibilitymaskchange라는 이름의 이벤트를 fire해야 한다.

사용자 에이전트는 사용자 환경에 상대적인 origin의 position 또는 orientation에 중대한 변경이 있는 경우, 즉 native origin 또는 effective origin의 discontinuity가 발생할 때, XRReferenceSpace에서 XRReferenceSpaceEvent를 사용하여 reset이라는 이름의 이벤트를 fire해야 한다. (예: 사용자의 XR device recalibration 이후 또는 XR device가 tracking을 잃었다가 되찾은 뒤 자동으로 origin을 shift한 경우.) XRBoundedReferenceSpaceboundsGeometry가 변경될 때에도 reset 이벤트가 dispatch되어야 한다. viewer의 pose가 discontinuity를 겪지만 XRReferenceSpace의 origin physical mapping은 안정적으로 유지되는 경우, 예를 들어 viewer가 같은 tracking area 안에서 잠시 tracking을 잃었다가 되찾는 경우에는 reset 이벤트가 dispatch되어서는 안 된다. 또한 unbounded reference space가 중대한 discontinuity가 발생하지 않은 경우, 사용자 근처의 space stability를 유지하기 위해 시간이 지남에 따라 native origin에 작은 조정을 하는 경우에도 reset 이벤트가 dispatch되어서는 안 된다. 이벤트는 새 origin을 사용하는 모든 XR animation frame이 실행되기 전에 dispatch되어야 한다. reset 이벤트는 reset 이벤트를 fire하는 reference space의 모든 offset reference space에서 dispatch되어야 하며, offset XRBoundedReferenceSpaceboundsGeometry도 다시 계산되어야 한다.

참고: 이는 session이 reset listener가 있는 모든 XRReferenceSpace에 대한 strong reference를 유지해야 함을 의미한다.

참고: viewer position의 jump는 애플리케이션이 emulatedPosition boolean을 관찰하여 처리할 수 있다. viewer position의 jump가 emulatedPositiontrue에서 false로 전환되는 것과 동시에 발생하면, 이는 viewer가 tracking을 되찾았고 그 새 position이 이전에 emulated된 값으로부터의 correction을 나타냄을 의미한다. viewer가 물리적으로 움직이지 않고도 virtual world를 이동할 수 있는 "teleportation" mechanic이 없는 experience의 경우, 이는 일반적으로 애플리케이션이 원하는 동작이다. 그러나 experience가 "teleportation" mechanic을 제공하는 경우, tracking recovery 후 viewer의 position을 되돌리는 jump는 불필요하게 불편할 수 있다. 대신, 이러한 애플리케이션은 tracking을 recovery할 때, position의 갑작스러운 jump를 teleportation offset에 흡수함으로써 virtual world에서 viewer의 현재 position에서 experience를 단순히 재개할 수 있다. 이를 위해 개발자는 getOffsetReferenceSpace()를 호출하여 이전 frame 이후 viewer의 position이 jump한 양만큼 effective origin이 조정된 replacement reference space를 생성한다.

13. 보안, 개인정보 보호 및 편안함 고려 사항

WebXR Device API는 사용자 에이전트가 완화 조치를 취해야 하는 몇 가지 고유한 개인정보 보호, 보안 및 편안함 위험을 동반하는 강력한 새 기능을 제공한다.

13.1. 민감한 정보

XR의 맥락에서 민감한 정보에는 interpupillary distance (IPD)와 같은 사용자 설정 가능 데이터 및 XRPose와 같은 sensor 기반 데이터가 포함되지만 이에 한정되지는 않는다. 모든 immersive session은 무엇이든 렌더링하려면 사용자의 pose가 필요하기 때문에 어느 정도의 민감한 데이터를 노출한다. 그러나 일부 경우에는 동일한 민감한 정보가 inline session을 통해서도 노출된다.

13.2. 사용자 의도

주어진 action에 대한 사용자 의도는 그러한 action이 의도적이었고 사용자의 consent를 가진다는 사용자로부터의 signal이다.

민감한 정보를 노출하거나 사용자 experience에 중대한 영향을 미치는 action을 허용하기 전에, user intent를 확실히 해야 하는 경우가 많다. 이 intent는 여러 방식으로 전달되거나 관찰될 수 있다.

참고: user intent를 판단하는 일반적인 방법은 UI control의 transient activation을 사용하는 것이며, 일반적으로 "enter VR" button이다. activation은 transient하므로, XR session을 요청하는 browsing context는 UI control을 포함하는 context의 ancestor이거나 same origin-domain descendant여야 하며, 최근에 browsing context의 active document였어야 한다.

13.2.1. 사용자 activation

Transient activation은 일부 scenario에서 user intent의 표시로 사용될 수 있다.

13.2.2. 웹 애플리케이션 실행

일부 환경에서는 page가 application으로 제시되어 immersive content를 실행하려는 명시적 intent로 설치될 수 있다. 이 경우 웹 애플리케이션 실행 역시 user intent의 표시로 사용될 수 있다.

묵시적 동의는 사용자 에이전트가 사용자에게 명시적으로 묻지 않고 사용자의 consent에 대한 판단을 내리는 경우이다. 예를 들어 web application의 install status, 방문 빈도와 최근성, 또는 사용자가 immersive experience에 들어가기를 원한다는 intent를 명확히 signal하는 user agent defined action을 기반으로 할 수 있다. XR data의 민감성을 고려할 때, implicit signal에 의존할 때는 강한 주의가 권장된다.

명시적 동의는 사용자 에이전트가 사용자에게 명시적으로 물어본 것을 기반으로 사용자의 consent에 대한 판단을 내리는 경우이다. explicit consent를 수집할 때, 사용자 에이전트는 요청되는 것이 무엇인지 설명을 제시하고 사용자가 거부할 수 있는 option을 제공한다. user consent 요청은 보호되는 기능 및 user agent 선택에 따라 여러 visual form으로 제시될 수 있다. web application의 install status는 설치 시 어떤 형태의 explicit consent가 요청된다면 explicit consent의 signal로 간주될 수 있다.

특정 origin에 대해 explicit consent가 부여되면, 이 consent는 browsing context가 종료될 때까지 지속되는 것이 권장된다. 사용자 에이전트는 user intent의 implicit 또는 explicit signal에 따라 이 consent duration을 늘리거나 줄일 수 있지만, 특히 implicit signal에 의존할 때는 이 권장 사항에서 벗어나는 경우 구현이 주의할 것을 권고한다. 예를 들어 immersive content를 실행하려는 명시적 intent로 설치된 web application에 대해서는 사용자의 consent를 지속시키는 것이 적절할 수 있지만, immersive content가 secondary feature인 설치된 web application에는 적절하지 않을 수 있다.

사용자 에이전트가 사용자의 consent를 얼마나 오래 지속시키기로 선택하든 관계없이, sensitive informationended되지 않은 XRSession에 의해서만 노출되어야 한다.

사용자 에이전트가 기능 사용을 위해 explicit consent를 요청하게 하는 non-XR API가 여러 개 있다. active immersive session이 있는 동안 사용자 에이전트가 사용자의 consent를 요청하려는 경우, 사용자 에이전트는 사용자에게 consent request를 표시하기 전에 session을 shut down해야 한다. 기능에 대한 사용자의 consent가 active immersive session이 생성되기 전에 이미 부여되었다면 session을 종료할 필요가 없다.

참고: 이 제한은 사용자 에이전트가 mid-session explicit consent를 어떻게 관리해야 하는지에 대한 합의가 이루어질 때까지 모든 사용자 에이전트 간의 behavioral parity를 보장하기 위한 것이다. 장기적 요구 사항일 것으로 예상되지는 않는다.

13.4. 데이터 조정

일부 경우 보안 및 개인정보 보호 위협은 throttling, quantizing, rounding, limiting 또는 XR device에서 보고되는 데이터를 그 외 방식으로 조작하는 것과 같은 data adjustment를 통해 완화될 수 있다. 이는 user intent가 확립된 상황에서도 fingerprinting을 피하기 위해 때때로 필요할 수 있다. 그러나 data adjustment 완화책은 사용자 discomfort를 초래하지 않는 상황에서만 사용되어야 한다.

13.4.1. Throttling

Throttlingsensitive information이 가능한 것보다 낮은 frequency로 보고되는 경우이다. 이 완화책은 site가 user intent를 추론하거나, location을 추론하거나, user profiling을 수행하는 능력을 줄일 가능성이 있다. 그러나 적절히 사용되지 않으면 throttling은 사용자 discomfort를 유발할 상당한 위험이 있다. 또한 많은 상황에서 완전한 완화책을 제공하기에 불충분할 수 있다.

13.4.2. Rounding, quantization 및 fuzzing

Rounding, quantization 및 fuzzing은 그렇지 않으면 개발자에게 반환될 raw data를 수정하는 세 가지 category의 완화책이다. Rounding은 데이터를 표현하는 데 사용되는 digit 수를 줄여 data의 precision을 낮춘다. Quantization은 continuous data를 discrete subset의 value로 보고하도록 제한한다. Fuzzing은 데이터에 작고 random한 error를 도입하는 것이다. 이러한 완화책들은 집합적으로 fingerprinting을 피하는 데 유용하며, 특히 그렇게 해도 user comfort에 noticeable impact를 일으키지 않는 경우 유용하다.

13.4.3. Limiting

Limiting은 데이터가 특정 range 안에 있을 때만 보고되는 경우이다. 예를 들어, 사용자가 승인된 location에서 특정 distance 이상 벗어났을 때 positional pose data 보고를 편안하게 제한할 수 있다. 이 완화책을 사용할 때 user experience가 부정적으로 영향을 받지 않도록 주의해야 한다. range 끝에서 'hard stop'을 피하는 것이 바람직한 경우가 많으며, 이는 disruptive user experience를 유발할 수 있기 때문이다.

13.5. 보호되는 기능

API가 노출하는 sensitive information은 threat profile과 그 threat에 대한 필요한 protection을 공유하는 category로 나눌 수 있다.

13.5.1. 몰입성

immersive session의 생성은 사용자 machine에 invasive change를 일으키기 때문에, 사용자는 immersive session이 언제 생성되는지 제어할 수 있어야 한다. 예를 들어 immersive session을 시작하면 XR device sensor가 작동하고, device display에 대한 access를 차지하며, XR hardware에 대한 다른 application의 access를 종료할 수 있는 immersive content를 presentation하기 시작한다. 또한 일부 system에서는 상당한 power 또는 performance overhead가 발생하거나 status tray 또는 storefront가 실행될 수 있다.

주어진 global object에 대해 immersive session request가 허용되는지 판단하려면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. 요청이 global objecttransient activation을 가진 동안 또는 web application을 실행할 때 이루어진 것이 아니면, false를 반환한다

  2. immersive session을 시작하려는 user intentexplicit consent 또는 implicit consent를 통해 잘 이해되지 않는다면, false를 반환한다

  3. true를 반환한다

inline session을 시작하는 것은 immersive session을 시작하는 것과 동일한 요구 사항을 implicit하게 수반하지 않는다. 다만 session의 requested features에 따라 추가 요구 사항이 부과될 수 있다.

주어진 global object에 대해 inline session request가 허용되는지 판단하려면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. session request가 inline-stereo 이외의 required features 또는 optional features를 포함하면 requiresUserIntenttrue로 두고, 그렇지 않으면 false로 둔다.

  2. requiresUserIntenttrue이고 요청이 global objecttransient activation을 가진 동안 또는 web application을 실행할 때 이루어진 것이 아니면, false를 반환한다.

  3. global objectWindow가 아니면, false를 반환한다.

  4. true를 반환한다.

13.5.2. Pose

sensor data를 기반으로 하는 경우, XRPoseXRViewerPose는 input sniffing, gaze tracking 또는 fingerprinting을 포함한 여러 방식으로 오용될 수 있는 sensitive information을 노출한다.

XRSession sessionpose가 보고될 수 있는지 판단하려면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. sessionrelevant global objectcurrent global object가 아니면, false를 반환한다.

  2. sessionvisibilityState"hidden"이면, false를 반환한다.

  3. pose data를 반환할 수 있는지 다음과 같이 판단한다:

    pose data가 user agent에 의해 fingerprint 가능한 sensor data를 노출하지 않는 것으로 알려진 경우

    true를 반환한다.

    fingerprinting 또는 profiling을 방지하기 위해 underlying sensor data에 data adjustment가 적용될 경우

    true를 반환한다.

    user intentexplicit consent 또는 implicit consent를 통해 잘 이해되는 경우

    true를 반환한다.

    그렇지 않으면

    false를 반환한다.

참고: pose가 fingerprint 가능한 data를 노출하지 않는다고 사용자 에이전트가 판단하는 방법은 사용자 에이전트의 재량에 맡겨진다.

XRViewerPoseXRPose의 주된 차이는 XRView information의 포함 여부이다. view가 둘 이상 존재하고 이 view들 사이의 physical relationship을 사용자가 구성할 수 있는 경우, 이 view들 사이의 relationship은 사용자를 fingerprint하거나 profile하는 데 사용될 수 있으므로 sensitive information으로 간주된다.

XRView들 사이의 relationship이 XR device를 고유하게 식별할 수 있다면, 사용자 에이전트는 fingerprinting을 방지하기 위해 XRView data를 anonymize해야 한다. anonymization 방법은 사용자 에이전트의 재량에 따른다.

참고: 또한 XRView들 사이의 relationship이 user-configured interpupillary distance (IPD)의 영향을 받는 경우, 사용자 에이전트가 session 생성 중, XRView data를 보고하기 전에 explicit consent를 요구하는 것이 강하게 권장된다.

13.5.3. Reference space

사용되는 reference space에 따라 여러 다른 유형의 sensitive information이 application에 노출될 수 있다.

그 결과 다양한 reference space type은 노출되는 sensitive information이 안전하게 처리되도록 하기 위해 생성에 제한이 부과된다:

대부분의 reference space는 reference space를 사용하려는 user intentexplicit consent 또는 implicit consent를 통해 잘 이해될 것을 요구한다. 자세한 내용은 feature requirements 표를 참조하라.

서로 관련될 수 있는 "local", "local-floor", 및 "bounded-floor" reference space의 모든 group은 공통 native origin을 공유해야 한다. 이 제한은 "unbounded" reference space의 생성이 restricted된 경우에만 적용된다.

두 space인 spacebaseSpace 사이에서 pose가 제한되어야 하는지 판단하려면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. space 또는 baseSpace 중 하나가 XRBoundedReferenceSpace이고 다른 space의 native origin이 사용자 에이전트가 결정한 reasonable distance보다 native bounds geometry의 바깥으로 더 멀리 떨어져 있으면, true를 반환한다.

  2. space 또는 baseSpace 중 하나가 XRReferenceSpace이고 그 type"local" 또는 "local-floor"이며, space들의 native origin 사이의 거리가 사용자 에이전트가 결정한 reasonable distance보다 크면, true를 반환한다.

  3. false를 반환한다.

참고: document visibility 요구 사항은 [DEVICE-ORIENTATION]에 기반한다.

참고: "local" 또는 "local-floor" reference space에 상대적으로 보고되는 pose는 XRReferenceSpacenative origin에서 15 meter 거리로 limited되는 것이 제안된다.

참고: XRBoundedReferenceSpace에 상대적으로 보고되는 pose는 XRBoundedReferenceSpacenative bounds geometry 바깥 1 meter 거리로 limited되는 것이 제안된다.

13.6. 신뢰할 수 있는 환경

Trusted UI는 사용자 에이전트가 제공하는 interface이며, 사용자는 상호작용할 수 있지만 page는 상호작용할 수 없다. 사용자 에이전트는 trusted UI 표시를 지원해야 한다.

trusted UI는 다음 property를 가져야 한다:

넓게 말하면, trusted UI를 지원하려는 사용자 에이전트에는 두 가지 option이 있다. 하나의 option은 trusted immersive UI이며, 이는 immersive mode를 종료하지 않는 trusted UI이다. trusted immersive UI를 구현하는 것은 어려울 수 있다. 이는 XRWebGLLayer buffer가 XR Device display를 채우고, User Agent가 일반적으로 자체 사용을 위해 pixel을 "reserve"하지 않기 때문이다. 사용자 에이전트는 trusted immersive UI를 지원할 필요는 없으며, 대신 immersive mode를 일시적으로 pause/exit하고 non-immersive trusted UI를 사용자에게 표시할 수 있다.

참고: trusted UI의 예에는 다음이 포함된다:

pose와 input information을 읽을 수 있는 능력은 trusted UI의 integrity에 위험을 초래한다. page가 이 정보를 사용하여 trusted UI와 상호작용하는 동안 사용자가 내린 선택을 snoop할 수 있으며, 여기에는 keyboard input을 추측하는 것도 포함된다. 이 위험을 방지하기 위해 사용자 에이전트는 URL bar 또는 system dialog와 같은 trusted UI (immersive 또는 non-immersive)와 사용자가 상호작용할 때 모든 XRSessionvisibility state"hidden" 또는 "visible-blurred"로 설정해야 한다. 또한 malicious page가 다른 page의 input을 monitor할 수 없도록 하기 위해, 사용자 에이전트는 currently focused areaXRSession을 생성한 document에 속하지 않는 경우, XRSessionvisibility state"hidden"으로 설정해야 한다.

특정 trusted UI instance에 대해 "hidden" 또는 "visible-blurred" 중 어느 것을 사용할지 선택할 때, 사용자 에이전트는 pose information이 security risk인지 고려해야 한다. 예를 들어 text input, 특히 password input을 포함하는 trusted UI는 사용자가 입력할 때의 움직임을 통해 typed text를 잠재적으로 leak할 수 있다. 사용자 에이전트는 이러한 경우 eye tracking 관련 information도 노출하지 않아야 한다.

사용자 에이전트는 permission prompt를 표시하기 위해 trusted UI를 사용해야 한다.

virtual environment가 사용자의 viewpoint를 낮은 latency와 높은 frame rate로 일관되게 update하지 않으면 사용자는 disoriented되거나 physically ill해질 수 있다. page가 일관되게 performant하고 correct한 content를 생성하도록 강제하는 것은 불가능하므로, 사용자 에이전트는 tracked, trusted environment와 page content와 비동기적으로 실행되는 XR Compositor를 제공해야 한다. compositor는 trusted content와 untrusted content를 compositing할 책임이 있다. content가 performant하지 않거나, frame을 submit하지 않거나, 예기치 않게 종료되는 경우에도 사용자 에이전트는 responsive한 trusted UI를 계속 표시할 수 있어야 한다.

또한 page content는 performance와 관련 없는 방식으로 사용자를 불편하게 만들 수 있다. 잘못 적용된 tracking, strobing color, 그리고 offend, frighten 또는 intimidate하려는 content는 사용자가 XR experience에서 빠르게 나가고 싶게 만들 수 있는 content의 예이다. 이런 경우 XR device를 제거하는 것이 항상 빠르거나 실용적인 option은 아닐 수 있다. 이를 수용하기 위해 사용자 에이전트는 reserved hardware button을 누르거나 gesture를 수행하는 것과 같이 WebXR content에서 벗어나 사용자 에이전트의 trusted UI를 표시하는 action을 사용자에게 제공해야 한다.

13.7. Context Isolation

trusted UI는 page가 사용하는 rendering context와 state가 isolated된 independent rendering context에 의해 그려져야 한다. (예: 모든 WebGL rendering context.) 이는 page가 trusted UI의 context state를 손상시켜 tracked environment를 제대로 렌더링하지 못하게 하는 것을 방지하기 위한 것이다. 또한 page가 trusted UI에서 imagery를 capture할 수 있는 가능성을 방지하며, 이는 private information이 leak되는 결과로 이어질 수 있다.

또한 CORS 관련 vulnerability를 방지하기 위해 각 browsing context는 API가 반환하는 object, 예를 들어 XRSession의 새 instance를 보게 된다. 한 relevant realm을 가진 XRWebGLLayer에 설정된 context와 같은 attribute는 same origin을 가지지 않는 relevant realm을 가진 XRWebGLLayer를 통해 읽을 수 없어야 한다. 마찬가지로, API에서 호출된 method는 다른 browsing context에 observable state change를 일으켜서는 안 된다. 예: system-level orientation reset을 가능하게 하는 method는 노출되지 않을 것이다. 이는 malicious page가 이를 반복적으로 호출하여 다른 page가 제대로 tracking하지 못하게 할 수 있기 때문이다. 그러나 사용자 에이전트는 user gesture 또는 system menu에 의해 trigger된 system-level orientation reset은 존중해야 한다.

참고: 이는 하나의 browsing context가 immersive mode에 들어가고, device에 대한 lock을 획득하며, 다른 browsing context에서 devicechange event를 잠재적으로 fire하여 발생하는 state change에는 적용되지 않는다.

13.8. Fingerprinting

API가 사용자가 이용할 수 있는 hardware와 그 capability를 설명한다는 점을 고려하면, fingerprinting을 위한 추가 surface area를 필연적으로 제공한다. 이를 완전히 피하는 것은 불가능하지만, 사용자 에이전트는 문제를 완화하기 위한 조치를 취해야 한다. 이 명세는 available hardware의 보고를 한 번에 단일 device로만 제한하며, 이는 여러 headset이 연결된 드문 경우를 fingerprinting signal로 사용하는 것을 방지한다. 또한 보고되는 device에는 string identifier가 없으며 XRSession이 생성되기 전까지 device capability에 대한 정보가 매우 적게 노출된다. XRSession 생성은 sensitive information이 노출될 때 추가 protection을 요구한다.

13.8.1. isSessionSupported()의 Fingerprinting 고려 사항

isSessionSupported()는 user activation 없이 호출될 수 있으므로 fingerprinting vector로 사용될 수 있다.

"xr-session-supported" powerful featureisSessionSupported() API에 대한 access를 gate한다.

"xr-session-supported"의 permission-related algorithm과 type은 다음과 같이 정의된다:

permission descriptor type
dictionary XRSessionSupportedPermissionDescriptor: PermissionDescriptor {
  XRSessionMode mode;
};

name for XRPermissionDescriptor is "xr-session-supported".

13.8.2. "xr-session-supported"를 자동으로 grant할 시점에 대한 고려 사항

Web에서는 privacy와 personalization 사이에 종종 긴장이 있다. 이 section은 그 tradeoff를 어디까지 제한할 수 있는지, 그리고 사용자 에이전트가 privacy reduction 없이 isSessionSupported()를 통해 browser의 WebXR capability를 site에 설명할 수 있는 시점에 대한 guidance를 제공한다.

"xr-session-supported"는 아래 criteria에 따라 일부 system에서 자동으로 grant될 수 있다. 이는 더 나은 user experience를 제공하고 permissions fatigue를 완화할 수 있다.

user agent들의 집합은 모두 동일한 userAgentappVersion을 보고하면 user agent string으로 구별할 수 없음이다. 이러한 class는 일반적으로 실행 중인 browser version 및 platform/device에 의해 식별되지만, 연결된 외부 device의 status로는 구별될 수 없다. 우리는 user agent string으로 구별할 수 없는 user agent concept를 사용하여 fingerprinting risk를 적절히 평가할 수 있다.

user agent string으로 구별할 수 없는 일부 user agent는 주어진 XRSessionMode의 session을 절대 지원하지 않을 것이다. 예: mobile AR support 요구 사항을 충족하지 않는 것으로 알려진 phone model에서 실행되는 user agent. 이런 경우 모든 그러한 device가 일관되게 같은 값을 보고하고 device type과 model은 userAgent와 같은 다른 방식으로 추론될 수 있다고 가정되므로, isSessionSupported()가 항상 해당 XRSessionMode가 지원되지 않는다고 보고하는 데 fingerprinting risk가 거의 없다. 따라서 그러한 system에서 사용자 에이전트는 관련 XRSessionMode에 대한 "xr-session-supported"를 자동으로 deny해야 한다.

user agent string으로 구별할 수 없는 다른 user agent는 주어진 XRSessionMode의 session을 대개 지원할 것이다. 예: VR headset 안에서만 실행되는, WebXR을 지원하는 것으로 알려진 user agent는 사용자가 특별히 block하지 않는 한 "immersive-vr" session을 지원할 가능성이 높다. 이런 경우 해당 XRSessionMode가 지원되지 않는다고 보고하는 것은 accurate하더라도 사용자에 대한 더 uniquely identifying information을 제공할 것이다. 따라서 해당 XRSessionMode가 항상 available하다고 보고하고 requestSession()이 fail하도록 허용하는 것이 더 privacy-preserving하며, 사용자에게 혼란의 source가 되지 않을 가능성이 높다. 그러한 system에서 사용자 에이전트는 관련 XRSessionMode에 대해 "xr-session-supported"를 자동으로 grant해야 한다.

XR peripheral을 지원하는 desktop system처럼 XR capability의 availability가 매우 variable한 user agent string으로 구별할 수 없는 user agent는 가장 높은 fingerprinting risk를 제시한다. 이러한 device의 사용자 에이전트는 isSessionSupported() API가 추가 fingerprinting bit를 제공할 수 있도록 하는 방식으로 "xr-session-supported"를 자동으로 grant해서는 안 된다.

참고: 이러한 경우를 처리하기 위한 허용 가능한 접근 방식의 예는 다음과 같다:
  • isSessionSupported()가 호출될 때 "xr-session-supported"에 대해 항상 explicit consent를 판단하는 것 (potentially cached permissions prompt 또는 유사한 방식 사용).

  • "xr-session-supported"를 자동으로 grant하지만, 적절한 hardware 또는 software가 존재하는지 여부와 관계없이 XR capability가 일관되게 available하지 않은 platform에서도 isSessionSupported()가 항상 true를 보고하도록 하는 것. 이는 XR content를 볼 수 없는 사용자에게 page가 XR content를 advertise하게 만들기 때문에 user ergonomics라는 cost를 수반한다.

  • 적절한 hardware가 있을 때 isSessionSupported()"xr-session-supported"에 대한 explicit consent를 요청하도록 하고, 그러한 hardware가 존재하지 않을 때는 적절히 random한 시간 이후 false를 반환하도록 하는 것. 그러한 구현에서 content는 사용자 에이전트가 XR hardware에 연결되어 있지 않은 경우와, 사용자 에이전트가 XR hardware에 연결되어 있었지만 사용자가 explicit consent 제공을 거부한 경우를 구별할 수 없어야 한다.

어떤 technique를 선택하든, explicit consent 없이 connected XR hardware에 대한 추가 knowledge를 드러내서는 안 된다.

14. 통합

14.1. Permissions Policy

이 명세는 spatial tracking 사용이 필요한 모든 XRSessionrequestSession()에 의해 반환될 수 있는지, 그리고 spatial tracking이 필요한 session mode 지원이 isSessionSupported() 또는 navigator.xr object의 devicechange event에 의해 indicated될 수 있는지를 제어하는 policy-controlled feature를 정의한다.

이 feature의 feature identifier는 "xr-spatial-tracking"이다.

이 feature의 default allowlist["self"]이다.

참고: document의 origin"xr-spatial-tracking" permissions policy를 사용할 수 없는 경우, 모든 immersive session은 block된다. 이는 모든 immersive session이 spatial tracking의 사용을 어느 정도 필요로 하기 때문이다. "inline" session은 여전히 허용되지만, "viewer" XRReferenceSpace만 사용하는 것으로 제한된다.

14.2. Permissions API 통합

[permissions] API는 website가 사용자에게 permission을 요청하고 어떤 permission이 granted되었는지 query하는 uniform한 방법을 제공한다.

"xr" powerful feature의 permission-related algorithm과 type은 다음과 같이 정의된다:

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
XRPermissionDescriptor descriptorXRPermissionStatus status로 "xr" permission을 query하려면, UA는 다음 단계를 실행해야 한다:
  1. statusstatedescriptorpermission state로 설정한다.

  2. statusstate"denied"이면, statusgranted를 빈 FrozenArray로 설정하고 이 단계를 중단한다.

  3. resultdescriptorrequiredFeatures, optionalFeatures, 및 mode가 주어졌을 때 requested feature를 resolve한 결과로 둔다.

  4. resultnull이면, 다음 단계를 실행한다:

    1. statusgranted를 빈 FrozenArray로 설정한다.

    2. statusstate"denied"로 설정한다.

    3. 이 단계를 중단한다.

  5. (consentRequired, consentOptional, granted)를 result의 field로 둔다.

  6. statusgrantedgranted로 설정한다.

  7. consentRequired비어 있고 consentOptional비어 있으면, statusstate"granted"로 설정하고 이 단계를 중단한다

  8. statusstate"prompt"로 설정한다.

permission request algorithm
XRPermissionDescriptor descriptorXRPermissionStatus status"xr" permission을 request하려면, UA는 다음 단계를 실행해야 한다:
  1. statusgranted를 빈 FrozenArray로 설정한다.

  2. requiredFeaturesdescriptorrequiredFeatures로 둔다.

  3. optionalFeaturesdescriptoroptionalFeatures로 둔다.

  4. devicemode, requiredFeatures, 및 optionalFeatures에 대해 current device를 obtain한 결과로 둔다.

  5. resultrequiredFeatures,optionalFeatures, 및 mode가 주어졌을 때 requested feature를 resolve한 결과로 둔다.

  6. resultnull이면, 다음 단계를 실행한다:

    1. statusstate"denied"로 설정한다.

    2. 이 단계를 중단한다.

  7. (consentRequired, consentOptional, granted)를 result의 field로 둔다.

  8. 사용자 에이전트는 이 시점에서 calling algorithm이 consentRequiredconsentOptional의 feature를 사용할 수 있도록 사용자 permission을 요청할 수 있다. 이러한 prompt의 결과는 이 feature를 enable하기 위한 user intent의 clear signal이 있는지 판단할 때 포함되어야 한다.

  9. consentRequired 안의 각 feature에 대해 다음 단계를 수행한다:

    1. 사용자 에이전트는 이 시점에서 calling algorithm이 feature를 사용할 수 있도록 사용자 permission을 요청할 수 있다. 이러한 prompt의 결과는 feature를 enable하기 위한 user intent의 clear signal이 있는지 판단할 때 포함되어야 한다.

    2. feature를 enable하기 위한 user intent의 clear signal이 판단되지 않은 경우, 다음 단계를 실행한다:

      1. statusstate"denied"로 설정하고 이 단계를 중단한다.

    3. featuregranted 안에 없으면, featuregranted에 append한다.

  10. consentOptional 안의 각 feature에 대해 다음 단계를 수행한다:

    1. 사용자 에이전트는 이 시점에서 calling algorithm이 feature를 사용할 수 있도록 사용자 permission을 요청할 수 있다. 이러한 prompt의 결과는 feature를 enable하기 위한 user intent의 clear signal이 있는지 판단할 때 포함되어야 한다.

    2. feature를 enable하기 위한 user intent의 clear signal이 판단되지 않은 경우, 다음 entry로 continue한다.

    3. featuregranted 안에 없으면, featuregranted에 append한다.

  11. statusgrantedgranted로 설정한다.

  12. granted의 모든 element를 mode에 대한 devicegranted feature 집합에 추가한다.

  13. statusstate"granted"로 설정한다.

참고: 사용자 에이전트는 user intent의 clear signal이 있는지 평가할 때, 요청된 모든 feature에 대한 permissions prompt를 batch로 묶을 자유가 있지만, 하나씩 표시하는 것도 허용된다.

참고: web application에 대한 user intent를 판단할 때, 사용자 에이전트는 그것이 web application으로서 사용자에 의해 명시적으로 launched 되었는지 확인해야 한다. 단지 origin이 설치된 web application의 origin과 일치하는지만 확인해서는 안 된다.

XRSessionMode mode에 대해 requiredFeaturesoptionalFeatures가 주어졌을 때 requested feature를 resolve하려면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. consentRequiredDOMString의 빈 list로 둔다.

  2. consentOptionalDOMString의 빈 list로 둔다.

  3. grantedDOMString의 빈 list로 둔다.

  4. devicemode, requiredFeatures, 및 optionalFeatures에 대해 current device를 obtain한 결과로 둔다.

  5. previouslyEnabledmode에 대한 devicegranted feature 집합으로 둔다.

  6. devicenull이거나 devicesupported mode 목록modecontain하지 않으면, 다음 단계를 실행한다:

    1. tuple (consentRequired, consentOptional, granted)를 반환한다

  7. mode와 연결된 default features table의 모든 feature descriptor를, 아직 존재하지 않는 경우 granted에 추가한다.

  8. requiredFeatures 안의 각 feature에 대해 다음 단계를 수행한다:

    1. featurenull이면, 다음 entry로 continue한다.

    2. feature가 valid feature descriptor가 아니면, null을 반환한다.

    3. feature가 이미 granted 안에 있으면, 다음 entry로 continue한다.

    4. requesting document의 originfeature requirements table에 표시된 대로 feature가 요구하는 어떤 permissions policy도 사용할 수 없다면, null을 반환한다.

    5. sessionXR devicefeature가 설명하는 기능을 support할 수 없거나 사용자 에이전트가 그 feature를 reject하기로 달리 판단한 경우, null을 반환한다.

    6. feature가 설명하는 기능이 explicit consent를 요구하고 featurepreviouslyEnabled 안에 없으면, 이를 consentRequired에 append한다.

    7. 그렇지 않으면 featuregranted에 append한다.

  9. optionalFeatures 안의 각 feature에 대해 다음 단계를 수행한다:

    1. featurenull이면, 다음 entry로 continue한다.

    2. feature가 valid feature descriptor가 아니면, 다음 entry로 continue한다.

    3. feature가 이미 granted 안에 있으면, 다음 entry로 continue한다.

    4. requesting document의 origin이 feature requirements table에 표시된 대로 feature가 요구하는 어떤 permissions policy도 사용할 수 없다면, 다음 entry로 continue한다.

    5. sessionXR devicefeature가 설명하는 기능을 support할 수 없거나 사용자 에이전트가 그 feature를 reject하기로 달리 판단한 경우, 다음 entry로 continue한다.

    6. feature가 설명하는 기능이 explicit consent를 요구하고 featurepreviouslyEnabled 안에 없으면, 이를 consentOptional에 append한다.

    7. 그렇지 않으면 featuregranted에 append한다.

  10. tuple (|consentRequired|, |consentOptional|, |granted|)를 반환한다

변경 사항

Candidate Recommendation Snapshot, 31 March 2022 이후 변경 사항

Working Draft 24 July 2020 이후 변경 사항

Working Draft 10 October 2019 이후 변경 사항

새 기능:

변경 사항:

First Public Working Draft 5 Feburary 2019 이후 변경 사항

새 기능:

제거된 기능:

변경 사항:

15. 감사의 말

WebXR Device API specification에 기여한 다음 개인들에게 감사한다:

그리고 이 모든 모험을 시작하게 해 준 Vladimir Vukicevic (Unity)에게 특별한 감사를 전한다!

적합성

문서 관례

적합성 요구 사항은 descriptive assertion과 RFC 2119 용어의 조합으로 표현된다. 이 문서의 normative 부분에서 사용하는 핵심 단어 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, 및 “OPTIONAL”은 RFC 2119에 설명된 대로 해석되어야 한다. 그러나 가독성을 위해, 이 명세에서는 이러한 단어가 모두 대문자로 나타나지는 않는다.

이 명세의 모든 text는 normative이다. 단, non-normative로 명시적으로 표시된 section, example, note는 예외이다. [RFC2119]

이 명세의 example은 “for example”이라는 말로 도입되거나, 다음과 같이 class="example"을 사용하여 normative text와 구분된다:

이는 informative example의 예이다.

Informative note는 “Note”라는 단어로 시작하며, 다음과 같이 class="note"를 사용하여 normative text와 구분된다:

참고, 이는 informative note이다.

적합한 알고리즘

algorithm의 일부로 imperative하게 표현된 요구 사항 (예: "strip any leading space characters" 또는 "return false and abort these steps")은 해당 algorithm을 도입할 때 사용된 핵심 단어 ("must", "should", "may" 등)의 의미로 해석되어야 한다.

algorithm 또는 특정 step으로 표현된 적합성 요구 사항은 최종 결과가 equivalent한 한, 어떤 방식으로든 구현될 수 있다. 특히 이 명세에 정의된 algorithm은 이해하기 쉽도록 의도된 것이며 performant하도록 의도된 것은 아니다. 구현자는 optimize하는 것이 권장된다.

색인

이 명세에서 정의하는 용어

참조에서 정의된 용어

참조

Normative References

[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[ECMASCRIPT]
ECMAScript Language Specification. URL: https://tc39.es/ecma262/multipage/
[GEOMETRY-1]
Sebastian Zartner; Yehonatan Daniv. Geometry Interfaces Module Level 1. 4 December 2025. CRD. URL: https://www.w3.org/TR/geometry-1/
[HR-TIME-3]
Yoav Weiss. High Resolution Time. 24 March 2026. WD. URL: https://www.w3.org/TR/hr-time-3/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[PERMISSIONS]
Marcos Caceres; Mike Taylor. Permissions. 6 October 2025. WD. URL: https://www.w3.org/TR/permissions/
[PERMISSIONS-POLICY-1]
Ian Clelland. Permissions Policy. 6 October 2025. WD. URL: https://www.w3.org/TR/permissions-policy-1/
[POINTEREVENTS4]
Patrick Lauke; Robert Flack. Pointer Events. 22 May 2026. WD. URL: https://www.w3.org/TR/pointerevents4/
[POINTERLOCK]
Mustaq Ahmed; Vincent Scheib. Pointer Lock 2.0. 25 February 2026. WD. URL: https://www.w3.org/TR/pointerlock-2/
[REQUESTIDLECALLBACK]
Scott Haseley. requestIdleCallback(). 21 May 2025. WD. URL: https://www.w3.org/TR/requestidlecallback/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBGL-2]
Dean Jackson; Jeff Gilbert. WebGL 2.0 Specification. 12 August 2017. URL: https://www.khronos.org/registry/webgl/specs/latest/2.0/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/
[WEBXRLAYERS-1]
Rik Cabanier. WebXR Layers API Level 1. 22 January 2026. WD. URL: https://www.w3.org/TR/webxrlayers-1/

Non-Normative References

[DEVICE-ORIENTATION]
Reilly Grant; Marcos Caceres. Device Orientation and Motion. 12 February 2025. CRD. URL: https://www.w3.org/TR/orientation-event/
[WEBXR-AR-MODULE-1]
Brandon Jones; Manish Goregaokar; Rik Cabanier. WebXR Augmented Reality Module - Level 1. 25 April 2025. 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