WebXR 深度感知模块

W3C 工作草案,

关于此文档的更多详细信息
此版本:
https://www.w3.org/TR/2025/WD-webxr-depth-sensing-1-20251210/
最新发布版本:
https://www.w3.org/TR/webxr-depth-sensing-1/
编辑草案:
https://immersive-web.github.io/depth-sensing/
先前版本:
历史:
https://www.w3.org/standards/history/webxr-depth-sensing-1/
反馈:
GitHub
编辑:
(Google)
前编辑:
(Google)
参与:
提交议题 (开放议题)
邮件列表归档
W3C 的 #immersive-web IRC

摘要

深度感知 API 是一个扩展 WebXR Device API 能力的模块。它使应用能够获取由受支持的 XR 设备 计算出的深度信息,以便提供更具沉浸感的体验。深度感知 API 的示例用例包括(但不限于) 模拟虚拟对象与真实世界的物理交互、遮挡,以及可利用对用户环境更高感知能力的非视觉应用。

本文档状态

本节描述本文档在发布时的状态。当前 W3C 出版物列表以及此 技术报告的最新修订版可在 W3C 标准和草案索引中找到。

Immersive Web Working Group 维护着该小组尚未处理的所有 bug 报告列表。此草案突出显示了一些仍有待工作组讨论的待处理议题。 对于这些议题的结果,包括它们是否有效,尚未作出任何决定。 强烈鼓励针对未解决议题提交带有拟议规范文本的 pull request。

本文档由 Immersive Web Working Group 作为工作草案发布,使用 推荐 标准轨道。本文档旨在成为 W3C 推荐标准。

作为工作草案发布并不意味着获得 W3C 及其成员的认可。这是一个草案文档,可能会在任何时候 被其他文档更新、替换或废弃。除作为进行中的工作外,不宜引用本文档。

本文档由一个在 W3C 专利政策下运作的小组制作。 W3C 维护着与该小组交付成果相关的任何 专利披露的公开列表; 该页面还包含披露专利的说明。实际知晓某项专利且个人认为该专利包含 必要 权利要求的个人,必须按照 W3C 专利政策第 6 节披露相关信息。

本文档受 2025 年 8 月 18 日 W3C 流程文档管辖。

1. 简介

随着虚拟现实和增强现实变得更加普及,原生 API 正在引入新的特性, 这些特性能够访问有关用户所在环境的更详细信息。深度感知 API 将这样一种能力带到 WebXR Device API 中,允许由 WebXR 驱动的体验的作者获取从用户设备到用户环境中真实 世界几何体的距离信息。

本文档假定读者熟悉 WebXR Device APIWebXR 增强 现实模块规范,因为本文档构建在它们之上,为 XRSessions 提供附加特性。

1.1. 术语

本文档使用缩写 AR 表示增强现实,使用 VR 表示虚拟现实。

本文档在指代包含深度信息的字节数组时,可互换地使用诸如 "depth buffer"、"depth buffer data" 和 "depth data" 等术语, 这些信息可以由 XR 设备返回,也可以由 API 本身返回。关于深度缓冲区具体内容的更多信息,可参见规范中的 datatexture 条目。

本文档使用术语 归一化视图坐标来指代一种坐标系, 其原点位于视图左上角,X 轴向右增长,Y 轴向下增长。

2. 初始化

2.1. 特性描述符

应用可以通过传入适当的 特性描述符,请求在 XRSession 上启用深度感知。此模块引入一个新的字符串 - depth-sensing, 作为深度感知特性的新有效特性描述符。

如果设备暴露原生深度 感知能力,则该设备能够支持深度感知特性。内联 XR 设备不得被视为能够 支持深度感知特性。

深度感知特性受特性策略约束,并且 要求在请求文档的源上允许 "xr-spatial-tracking" 策略。

2.2. 预期深度类型、数据用途和数据格式

enum XRDepthType {
  "raw",
  "smooth",
};
enum XRDepthUsage {
  "cpu-optimized",
  "gpu-optimized",
};
enum XRDepthDataFormat {
  "luminance-alpha",
  "float32",
  "unsigned-short",
};

下表总结了各种数据格式可以被使用的方式:

数据格式 GLenum 等价值 深度缓冲区条目的大小 CPU 上的使用 GPU 上的使用
"luminance-alpha" LUMINANCE_ALPHA 2 乘以 8 位 data 解释为 Uint16Array 检查 Luminance 和 Alpha 通道以重新组装单个值。
"float32" R32F 32 位 data 解释为 Float32Array 检查 Red 通道并使用该值。
"unsigned-short" R16UI 16 位 data 解释为 Uint16Array 检查 Red 通道并使用该值。

2.3. 会话配置

dictionary XRDepthStateInit {
  required sequence<XRDepthUsage> usagePreference;
  required sequence<XRDepthDataFormat> dataFormatPreference;
  sequence<XRDepthType> depthTypeRequest;
  boolean matchDepthView = true;
};

usagePreference 是一个有序的 XRDepthUsage 序列, 用于描述会话所需的深度感知用途。

dataFormatPreference 是一个有序的 XRDepthDataFormat 序列, 用于描述会话所需的深度感知数据格式。

depthTypeRequest 是一个有序的 XRDepthType 序列, 用于描述会话所需的深度感知类型。用户代理可以忽略此请求。

matchDepthView 请求深度信息的view 必须与 XRView 对齐。 如果其值为 true,则 XRSystem 应该返回反映当前帧的深度信息。如果其值为 false,则 XRSystem 可以返回在更早时间点捕获的深度信息。

注: 如果 matchDepthViewfalse,作者应该使用来自 XRDepthInformationview 来进行重投影。

通过添加新的 depthSensing 键,扩展了 XRSessionInit 字典。该键在 XRSessionInit 中是可选的,但当 depth-sensing 被包含在 requiredFeaturesoptionalFeatures 中时,必须提供该键。

partial dictionary XRSessionInit {
  XRDepthStateInit depthSensing;
};

如果深度感知特性是必需特性,但应用没有提供 depthSensing 键,则用户代理必须将其视为未解决的必需特性,并用 NotSupportedError 拒绝 requestSession(mode, options) promise。 如果它是作为可选特性请求的,则用户代理必须忽略该特性请求,并且不得在新创建的会话上启用 深度感知。

如果深度感知特性是必需特性,但使用 XRDepthStateInit 调用查找受支持配置组合算法的结果 为 null,则用户代理必须将其视为未解决的必需特性,并用 NotSupportedError 拒绝 requestSession(mode, options) promise。 如果它是作为可选特性请求的,则用户代理必须忽略该特性请求,并且不得在新创建的会话上启用 深度感知。

XRSession 在启用深度感知的情况下创建时,depthUsagedepthDataFormatdepthType 属性必须设置为使用 XRDepthStateInit 调用查找受支持配置组合算法的结果。 depthActive 必须默认为 true

注: 该算法的意图是按从最严格到最不严格的顺序处理 偏好。因此,我们首先处理只指示单个项的项目,然后处理多个项,最后处理未指示偏好的情况。

为了给定 depthStateInit 字典,为深度 感知 API 查找受支持配置组合,用户代理必须运行以下算法:
  1. 如果在 depthStateInit 中设置了 depthTypeRequest 键,则令 depthTypeRequest 为该键包含的值,否则为空序列。

  2. selectedTypenull

  3. usagePreferencedepthStateInitusagePreference 键包含的值

  4. selectedUsagenull

  5. dataFormatPreferencedepthStateInitdataFormatPreference 键包含的值

  6. selectedDataFormatnull

  7. processingOrder 为 (preferences, selection) 对的序列,其中 selection 是对前面步骤中引入的某个变量的引用: [(depthTypeRequest, selectedType), (usagePreference,selectedUsage),(dataFormatPreference,selectedDataFormat)]

  8. 对于 processingOrder 中的每个 (preferences, selection),执行以下 步骤

    1. 如果 preferences 只包含单个值,则将 selection 设置为该 值。

  9. 对于 processingOrder 中的每个 (preferences, selection),执行以下 步骤:

    1. 如果 selection 不是 null,则继续到下一个条目。

    2. 如果 preferences 序列为空,则继续到下一个条目。

    3. 对于 preferences 中的每个 preference,执行以下步骤:

    4. 如果 preferenceselectedTypeselectedUsageselectedDataFormat 的其他值一起, 未被设备的原生深度感知能力视为受支持的深度感知 配置,则继续到下一个条目。

    5. selection 设置为 preference 并中止这些嵌套步骤。

  10. 对于 processingOrder 中的每个 (preferences, selection),执行以下 步骤:

    1. 如果 selection 不是 null,则继续到下一个条目。

    2. selection 设置为由具有 selectedTypeselectedUsageselectedDataFormat 其他值的首选原生深度 感知能力所确定的值。

  11. 如果 selectedTypeselectedUsageselectedDataFormat 中任何一个为 null,则返回 null 并中止这些步骤。

  12. 如果 selectedTypeselectedUsageselectedDataFormat 被设备的 原生深度感知能力视为受支持的深度感知 配置, 则返回 selectedTypeselectedUsageselectedDataFormat深度感知配置并中止这些 步骤。

  13. 如果 depthTypeRequest 不是空列表,则将其设置为空列表并重复这些 步骤。

  14. 返回 null 并中止这些步骤。

注: 用户代理不需要支持所有 现有的用途和数据格式组合。这旨在允许它们以高效方式提供数据,并取决于底层平台。 此决定会给应用开发者带来额外负担——这可以通过创建隐藏 API 复杂性的库来缓解,但可能会 牺牲性能。

能够支持深度感知 API 的用户代理必须至少支持一种 XRDepthUsage 模式。能够支持深度感知 API 的用户代理必须支持 "luminance-alpha" 数据格式,并可以支持其他格式。

以下代码演示了如何请求一个需要深度感知 API 的会话。该示例假定调用者能够处理 CPU 和 GPU 优化的用途, 以及 "luminance-alpha" 和 "float32" 两种格式,并偏好 CPU 和 "luminance-alpha":
const session = await navigator.xr.requestSession("immersive-ar", {
  requiredFeatures: ["depth-sensing"],
  depthSensing: {
    usagePreference: ["cpu-optimized", "gpu-optimized"],
    dataFormatPreference: ["luminance-alpha", "float32"],
  },
});
partial interface XRSession {
  readonly attribute XRDepthUsage depthUsage;
  readonly attribute XRDepthDataFormat depthDataFormat;
  readonly attribute XRDepthType? depthType;
  readonly attribute boolean? depthActive;

  undefined pauseDepthSensing();
  undefined resumeDepthSensing();
};

depthUsage 描述会话配置时使用的深度感知用途。如果在未启用深度感知的会话上访问此属性, 用户代理必须抛出 InvalidStateError

depthDataFormat 描述会话配置时使用的深度感知数据格式。如果在未启用深度感知的会话上访问此属性, 用户代理必须抛出 InvalidStateError

depthType 描述会话配置时使用的深度感知类型。如果在未启用深度感知的会话上访问此属性, 用户代理必须抛出 InvalidStateError。 如果运行时只支持单个 XRDepthType 或以其他方式忽略了 depthTypeRequest, 则此属性可以返回 null

depthActive 返回当前的深度感知活动状态。如果在未启用深度感知的会话上访问此属性, 用户代理必须抛出 InvalidStateError。 当该值为 false 时,用户代理必须拒绝获取深度数据的尝试。当该值为 true 时, 用户代理可以返回有效的深度数据或 null

当在 XRSession session 上调用 resumeDepthSensing() 时,用户代理必须运行以下步骤:

  1. 如果 sessionended 值为 true,则抛出 InvalidStateError 并中止这些步骤。

  2. framesession动画帧

  3. 如果 frameactive 布尔值为 false,则抛出 InvalidStateError 并中止这些步骤。

  4. 如果 depth-sensing 特性描述符未包含sessionXR 设备针对 sessionmode启用特性列表中,则抛出 NotSupportedError 并中止这些步骤。

  5. 如果深度感知活动状态true,则中止这些步骤。

  6. 深度感知活动状态设置为 true

当在 XRSession session 上调用 pauseDepthSensing() 时,用户代理必须运行以下步骤:
  1. 如果 sessionended 值为 true,则抛出 InvalidStateError 并中止这些步骤。

  2. framesession动画帧

  3. 如果 frameactive 布尔值为 false,则抛出 InvalidStateError 并中止这些步骤。

  4. 如果 depth-sensing 特性描述符未包含sessionXR 设备针对 sessionmode启用特性列表中,则抛出 NotSupportedError 并中止这些步骤。

  5. 如果深度感知活动状态false,则中止这些步骤。

  6. 深度感知活动状态设置为 false

3. 获取深度数据

3.1. XRDepthInformation

[SecureContext, Exposed=Window]
interface XRDepthInformation {
  readonly attribute unsigned long width;
  readonly attribute unsigned long height;

  [SameObject] readonly attribute XRRigidTransform normDepthBufferFromNormView;
  readonly attribute float rawValueToMeters;
};

XRDepthInformation includes XRViewGeometry;

width 属性包含深度缓冲区的宽度(即列数)。

height 属性包含深度缓冲区的高度(即行数)。

normDepthBufferFromNormView 属性包含一个 XRRigidTransform, 在索引到深度缓冲区中时需要应用它。 该矩阵表示的变换会将坐标系从归一化视图坐标更改为归一化深度缓冲区坐标, 然后可以用深度缓冲区的 widthheight 对其进行缩放,以获得绝对深度缓冲区坐标。

注: 如果应用打算将得到的 深度缓冲区用于给网格贴图,则必须注意确保网格顶点的纹理坐标以归一化视图坐标表示,或在着色器中执行适当的 坐标系变换。

rawValueToMeters 属性包含一个比例因子,来自深度缓冲区的原始深度值 必须乘以该因子才能得到以米为单位的深度。

transform 在关联view参考 空间中给出。

如果sensor 与关联的 view 对齐,则从 XRViewGeometry 包含的所有值,必须返回与关联 view 相同的值。

每个 XRDepthInformation 都有一个关联的 view,它是距离 sensor 最近的 XRView, 并用于检索 XRDepthInformation

每个 XRDepthInformation 都有一个关联的 sensor,它是从中获得深度信息的 XRViewGeometry包含对象

每个 XRDepthInformation 都有一个关联的 深度缓冲区,其中包含深度缓冲区数据。 不同的 XRDepthInformation 可以在深度缓冲区中存储不同具体类型的对象。

尝试访问 XRDepthInformation 或继承自它的任何接口的深度缓冲区时,用户代理必须运行以下步骤:

  1. depthInformation 为其成员被访问的实例。

  2. viewdepthInformationview

  3. frameviewframe

  4. 如果 frame 不是活动的, 则抛出 InvalidStateError 并中止这些步骤。

  5. 如果 frame 不是 animationFrame,则抛出 InvalidStateError 并中止这些步骤。

  6. 继续执行访问 depthInformation 成员所需的正常步骤。

3.2. XRCPUDepthInformation

[Exposed=Window]
interface XRCPUDepthInformation : XRDepthInformation {
  [SameObject] readonly attribute ArrayBuffer data;

  float getDepthInMeters(float x, float y);
};

data 属性以原始格式包含深度缓冲区信息,必要时适合上传到 WebGL 纹理。 数据以行优先格式存储,没有填充,每个条目对应从sensor 的近裁剪平面到用户环境的距离,单位未指定。 每个数据条目的大小和类型由 depthDataFormat 确定。 这些值可以通过乘以 rawValueToMeters 从未指定单位转换为米。 normDepthBufferFromNormView 可用于从归一化视图坐标变换到深度缓冲区的坐标 系统。访问时,必须运行访问 深度缓冲区的算法。

注: 应用不应尝试更改 data 数组的内容,因为这可能导致 getDepthInMeters(x, y) 方法返回不正确的结果。

getDepthInMeters(x, y) 方法可用于获取坐标处的深度。调用时,必须运行访问深度缓冲区的算法。

当在 XRCPUDepthInformation depthInformation 上使用 xy 调用 getDepthInMeters(x, y) 方法时,用户代理必须通过运行以下步骤获取坐标 处的深度

  1. viewdepthInformationviewframeviewframe,并且 sessionframesession

  2. 如果 x 大于 1.0 或小于 0.0,则抛出 RangeError 并中止这些步骤。

  3. 如果 y 大于 1.0 或小于 0.0,则抛出 RangeError 并中止这些步骤。

  4. normalizedViewCoordinates 为一个表示空间中三维点的向量, 其中 x 坐标设置为 xy 坐标设置为 yz 坐标设置为 0.0,并且 w 坐标 设置为 1.0

  5. normalizedDepthCoordinates 为从左侧将 normalizedViewCoordinates 向量预乘以 depthInformationnormDepthBufferFromNormView 的结果。

  6. depthCoordinates 为对 normalizedDepthCoordinates 进行缩放的结果, 其中 x 坐标乘以 depthInformationwidthy 坐标乘以 depthInformationheight

  7. columndepthCoordinatesx 坐标的值, 截断为整数,并钳制到 [0, width-1] 整数范围内。

  8. rowdepthCoordinatesy 坐标的值, 截断为整数,并钳制到 [0, height-1] 整数范围内。

  9. index 等于 row 乘以 width 并加上 column

  10. byteIndex 等于 index 乘以深度数据格式的大小。

  11. rawDepth 等于在 data 中索引 byteIndex 处找到的值,并根据 sessiondepthDataFormat 将其解释为数字。

  12. rawValueToMeters 等于 depthInformationrawValueToMeters

  13. 返回 rawDepth 乘以 rawValueToMeters

partial interface XRFrame {
  XRCPUDepthInformation? getDepthInformation(XRView view);
};

getDepthInformation(view) 方法在 XRFrame 上调用时,表示应用想要获取与该帧相关的 CPU 深度信息

当在 XRFrame frame 上使用一个 XRView view 调用 getDepthInformation(view) 方法时,用户代理必须通过运行以下步骤获取 CPU 深度信息

  1. sessionframesession

  2. 如果 depth-sensing 特性描述符未包含sessionXR 设备针对 sessionmode启用特性列表中,则抛出 NotSupportedError 并中止这些步骤。

  3. 如果 frameactive 布尔值为 false,则抛出 InvalidStateError 并中止这些步骤。

  4. 如果 frameanimationFrame 布尔值为 false,则抛出 InvalidStateError 并中止这些步骤。

  5. 如果 frameviewframe 不匹配,则抛出 InvalidStateError 并中止这些步骤。

  6. 如果 sessiondepthUsage 不是 "cpu-optimized", 则抛出 InvalidStateError 并中止这些步骤。

  7. depthInformation 为给定 frameview 创建 CPU 深度信息 实例的结果。

  8. 返回 depthInformation

为了给定 XRFrame frameXRView view 创建 CPU 深度信息实例,用户代理必须运行以下步骤:

  1. resultXRCPUDepthInformation 的一个新实例。

  2. timeframetime

  3. sessionframesession

  4. devicesessionXR 设备

  5. 如果 depthActivefalse,则返回 null 并中止这些步骤。

  6. nativeDepthInformation 为查询 device 得到的深度信息结果, 该信息在 time 时有效,针对指定的 view,并考虑 sessiondepthTypedepthUsagedepthDataFormat

  7. 如果 nativeDepthInformationnull,则返回 null 并中止 这些步骤。

  8. 如果 nativeDepthInformation 中存在的深度缓冲区符合用户代理阻止访问深度数据的条件, 则返回 null 并中止这些步骤。

  9. 如果 nativeDepthInformation 中存在的深度缓冲区符合用户代理限制深度缓冲区中可用信息量的条件, 则相应地调整深度缓冲区。

  10. resultwidth 初始化为 nativeDepthInformation 中返回的深度缓冲区宽度。

  11. resultheight 初始化为 nativeDepthInformation 中返回的深度缓冲区高度。

  12. resultnormDepthBufferFromNormView 初始化为一个新的 XRRigidTransform, 基于 nativeDepthInformation深度坐标变换 矩阵

  13. resultdata 初始化为 nativeDepthInformation 中返回的原始深度缓冲区。

  14. resultview 初始化为 view

  15. resulttransform 初始化为 sensortime 时于 view参考空间中的姿态。

  16. 返回 result

以下代码演示了如何在 XRFrameRequestCallback 中获取深度数据。 假定会话已启用深度感知,usage 设置为 "cpu-optimized",数据 格式设置为 "luminance-alpha":
const session = ...;          // Session created with depth sensing enabled.
const referenceSpace = ...;   // Reference space created from the session.

function requestAnimationFrameCallback(t, frame) {
  session.requestAnimationFrame(requestAnimationFrameCallback);

  const pose = frame.getViewerPose(referenceSpace);
  if (pose) {
    for (const view of pose.views) {
      const depthInformation = frame.getDepthInformation(view);
      if (depthInformation) {
        useCpuDepthInformation(view, depthInformation);
      }
    }
  }
}

一旦获得 XRCPUDepthInformation, 就可以用它来发现从视图平面到用户环境的距离(详见 § 4 解释结果章节)。下面的代码 演示了如何获取归一化视图坐标 (0.25, 0.75) 处的深度:

function useCpuDepthInformation(view, depthInformation) {
  const depthInMeters = depthInformation.getDepthInMeters(0.25, 0.75);
  console.log("Depth at normalized view coordinates (0.25, 0.75) is:",
    depthInMeters);
}

3.3. XRWebGLDepthInformation

[Exposed=Window]
interface XRWebGLDepthInformation : XRDepthInformation {
  [SameObject] readonly attribute WebGLTexture texture;

  readonly attribute XRTextureType textureType;
  readonly attribute unsigned long? imageIndex;
};

texture 属性包含作为不透明 纹理的深度缓冲区信息。每个纹素对应从sensor的近平面到 用户环境的距离,单位未指定。每个数据条目的大小和类型由 depthDataFormat 确定。 这些值可以通过乘以 rawValueToMeters 从未指定单位转换为米。 normDepthBufferFromNormView 可用于从归一化视图坐标变换到深度缓冲区的坐标 系统。访问时,必须运行访问 深度缓冲区的算法,该深度缓冲区属于 XRDepthInformation

textureType 属性描述纹理是 TEXTURE_2D 类型,还是 TEXTURE_2D_ARRAY 类型。

imageIndex 属性返回纹理数组中的偏移量。当 textureType 等于 TEXTURE_2D_ARRAY 时,它必须被定义;如果它是 TEXTURE_2D, 则它必须为 undefined。

partial interface XRWebGLBinding {
  XRWebGLDepthInformation? getDepthInformation(XRView view);
};

getDepthInformation(view) 方法在 XRWebGLBinding 上调用时,表示应用想要获取与该帧相关的 WebGL 深度信息

当在 XRWebGLBinding binding 上使用一个 XRView view 调用 getDepthInformation(view) 方法时,用户代理必须通过运行以下步骤获取 WebGL 深度信息

  1. sessionbindingsession

  2. frameviewframe

  3. 如果 sessionframesession 不匹配,则抛出 InvalidStateError 并中止这些步骤。

  4. 如果 depth-sensing 特性描述符未包含sessionXR 设备针对 sessionmode启用特性列表中,则抛出 NotSupportedError 并中止这些步骤。

  5. 如果 sessiondepthUsage 不是 "gpu-optimized", 则抛出 InvalidStateError 并中止这些步骤。

  6. 如果 frameactive 布尔值为 false,则抛出 InvalidStateError 并中止这些步骤。

  7. 如果 frameanimationFrame 布尔值为 false,则抛出 InvalidStateError 并中止这些步骤。

  8. depthInformation 为给定 frameview 创建 WebGL 深度信息 实例的结果。

  9. 返回 depthInformation

为了给定 XRFrame frameXRView view 创建 WebGL 深度信息实例,用户代理必须运行以下步骤:

  1. resultXRWebGLDepthInformation 的一个新实例。

  2. 按如下方式初始化 time

    如果 XRSession 是在 matchDepthView 设置为 true 的情况下创建的:
    timeframetime
    否则
    timedevice 捕获深度信息的时间。
  3. sessionframesession

  4. devicesessionXR 设备

  5. 如果 depthActivefalse,则返回 null 并中止这些步骤。

  6. nativeDepthInformation 为查询 device原生 深度感知得到的深度信息结果, 该信息在 time 时有效,针对指定的 view,并考虑 sessiondepthTypedepthUsagedepthDataFormat

  7. 如果 nativeDepthInformationnull,则返回 null 并中止 这些步骤。

  8. 如果 nativeDepthInformation 中存在的深度缓冲区符合用户代理阻止访问深度数据的条件, 则返回 null 并中止这些步骤。

  9. 如果 nativeDepthInformation 中存在的深度缓冲区符合用户代理限制深度缓冲区中可用信息量的条件, 则相应地调整深度缓冲区。

  10. resultwidth 初始化为 nativeDepthInformation 中返回的深度缓冲区宽度。

  11. resultheight 初始化为 nativeDepthInformation 中返回的深度缓冲区高度。

  12. resultnormDepthBufferFromNormView 初始化为一个新的 XRRigidTransform, 基于 nativeDepthInformation深度坐标变换 矩阵

  13. resulttexture 初始化为一个包含 nativeDepthInformation 中返回的深度缓冲区的不透明纹理

  14. resultview 初始化为 view

  15. resulttransform 初始化为 sensortime 时于 view参考空间中的姿态。

  16. 按如下方式初始化 resulttextureType

    如果 resulttexture 是使用 texture-array 的 textureType 创建的:
    resulttextureType 初始化为 "texture-array"。
    否则
    resulttextureType 初始化为 "texture"。
  17. 按如下方式初始化 resultimageIndex

    如果 textureTypetexture
    resultimageIndex 初始化为 null
    否则,如果 vieweye"right"
    resultimageIndex 初始化为 1
    否则
    resultimageIndex 初始化为 0
  18. 返回 result

以下代码演示了如何在 XRFrameRequestCallback 中获取深度数据。 假定会话已启用深度感知,usage 设置为 "gpu-optimized",数据 格式设置为 "luminance-alpha":
const session = ...;          // Session created with depth sensing enabled.
const referenceSpace = ...;   // Reference space created from the session.
const glBinding = ...;        // XRWebGLBinding created from the session.

function requestAnimationFrameCallback(t, frame) {
  session.requestAnimationFrame(requestAnimationFrameCallback);

  const pose = frame.getViewerPose(referenceSpace);
  if (pose) {
    for (const view of pose.views) {
      const depthInformation = glBinding.getDepthInformation(view);
      if (depthInformation) {
        useGpuDepthInformation(view, depthInformation);
      }
    }
  }
}

一旦获得 XRWebGLDepthInformation, 就可以用它来发现从视图平面到用户环境的距离(详见 § 4 解释结果章节)。下面的代码 演示了如何将数据传输到着色器:

const gl = ...;             // GL context to use.
const shaderProgram = ...;  // Linked WebGLProgram.
const programInfo = {
  uniformLocations: {
    depthTexture: gl.getUniformLocation(shaderProgram, 'uDepthTexture'),
    uvTransform: gl.getUniformLocation(shaderProgram, 'uUvTransform'),
    rawValueToMeters: gl.getUniformLocation(shaderProgram, 'uRawValueToMeters'),
  }
};

function useGpuDepthInformation(view, depthInformation) {
  // ...

  gl.bindTexture(gl.TEXTURE_2D, depthInformation.texture);
  gl.activeTexture(gl.TEXTURE0);
  gl.uniform1i(programInfo.uniformLocations.depthTexture, 0);

  gl.uniformMatrix4fv(
    programInfo.uniformLocations.uvTransform, false,
    depthData.normDepthBufferFromNormView.matrix);

  gl.uniform1f(
    programInfo.uniformLocations.rawValueToMeters,
    depthData.rawValueToMeters);

  // ...
}

使用深度缓冲区的片段着色器可以例如是:

precision mediump float;

uniform sampler2D uDepthTexture;
uniform mat4 uUvTransform;
uniform float uRawValueToMeters;

varying vec2 vTexCoord;

float DepthGetMeters(in sampler2D depth_texture, in vec2 depth_uv) {
  // Depth is packed into the luminance and alpha components of its texture.
  // The texture is a normalized format, storing millimeters.
  vec2 packedDepth = texture2D(depth_texture, depth_uv).ra;
  return dot(packedDepth, vec2(255.0, 256.0 * 255.0)) * uRawValueToMeters;
}

void main(void) {
  vec2 texCoord = (uUvTransform * vec4(vTexCoord.xy, 0, 1)).xy;

  float depthInMeters = DepthGetMeters(uDepthTexture, texCoord);

  gl_FragColor = ...;
}

4. 解释结果

如果确定给定像素具有无效深度数据,或者无法以其他方式确定深度数据,则 用户代理必须返回深度值 0。

存储在 datatexture 中的值表示从相机平面到真实世界几何体(由 XR 系统理解)的距离。在下面的示例中, 点 a = (x, y) 处的深度值对应于点 A 到相机平面的距离。具体来说,该深度值不表示 aA 向量的长度。

Depth API 数据说明

上图对应于以下代码:

// depthInfo is of type XRCPUDepthInformation:
const depthInMeters = depthInfo.getDepthInMeters(x, y);

5. 原生设备概念

5.1. 原生深度感知

深度感知规范假定实现深度感知 API 所基于的原生设备提供了一种查询设备 原生深度感知能力的方式。如果设备暴露了获取深度缓冲区数据的方式, 则称该设备支持查询设备的原生深度感知能力。 深度缓冲区数据必须包含缓冲区尺寸、关于缓冲区中存储值所使用单位的信息、一个 深度坐标变换矩阵, 该矩阵执行从归一化视图坐标到归一化深度缓冲区坐标的坐标系变换。 该变换应该使被变换 3D 向量的 z 坐标不受影响。 设备还必须提供某种机制来暴露 投影矩阵以及 sensortransform

设备可以通过 2 种方式支持深度感知类型。如果设备只是返回经过最少后处理的估计深度值, 则称其支持 "raw" 深度类型。如果设备或运行时可以对这些数据应用额外处理以“平滑”掉噪声(例如处理成具有相同深度值的更大区域), 则称其支持 "smooth" 深度类型。

注: "Raw" 深度数据通常伴随置信度值。 UA 可以选择在向页面返回此类数据时,将置信度值较低的深度数据视为无效深度 数据

设备可以通过 2 种方式支持深度感知用途。如果设备主要能够通过 CPU 可访问内存返回深度数据, 则称其支持 "cpu-optimized" 用途。如果设备主要能够通过 GPU 可访问内存返回深度数据,则称其支持 "gpu-optimized" 用途。

注: 用户代理可以选择同时支持两种 用途模式(例如,当设备能够同时提供 CPU 和 GPU 可访问数据时,或通过手动执行 CPU 和 GPU 可访问数据之间的传输)。

给定深度感知用途和类型,设备可以通过以下方式支持深度感知数据格式。 如果在给定深度感知用途和类型的情况下,设备能够以包含 16 位无符号整数的缓冲区形式返回深度数据, 则称其支持 "luminance-alpha""unsigned-short" 数据格式。如果在给定深度感知用途和类型的情况下,设备能够以包含 32 位浮点值的缓冲区形式返回深度数据, 则称其支持 "float32" 数据格式。

深度 感知配置由一个 XRDepthType、 一个 XRDepthUsage 和一个 XRDepthDataFormat 的组合表示。

如果给定指定配置,设备支持深度感知类型支持深度感知 用途并且支持深度感知数据格式,则称该设备支持深度感知配置

注: 对深度感知 API 的支持并不 仅限于被分类为具备 AR 能力的硬件,尽管预计该特性会在此类设备中更为常见。 包含适当传感器和/或使用其他技术来提供深度缓冲区的 VR 设备,也应该能够提供实现深度感知 API 所需的数据。

对于 depthTypeRequestusagePreferencedataFormatPreference 中的每一个, 设备都必须具有一个首选原生深度感知 能力,当对应数组为空时必须使用该能力。类型、用途和格式 应该反映设备最高效的那些能力,尽管它们可能相互依赖。

设备可以说具有一个深度感知活动状态,这是一个表示深度感知能力是否正在主动运行的布尔值。 此状态必须以 true 开始。当此状态为 false 时, 用户代理应该采取措施来缓解启用此特性带来的性能影响。

6. 隐私与安全考量

深度感知 API 以深度缓冲区的形式向网站提供有关用户环境的附加信息。 给定具有足够高分辨率和足够高精度的深度缓冲区,网站可能会了解到比用户感到舒适的程度更加详细的信息。 根据所使用的底层技术,深度数据可能基于相机图像和 IMU 传感器创建。

为了缓解用户的隐私风险,用户代理应该在会话上启用深度感知 API 之前寻求用户同意。 此外,随着深度感知技术和硬件的改进,用户代理应该考虑限制通过 API 暴露的信息量, 或者如果引入此类限制不可行,则阻止访问 API 返回的数据。为了限制信息量,用户代理例如可以 降低所得深度缓冲区的分辨率,或降低深度缓冲区中存在的值的精度(例如通过量化)。 决定以这种方式限制数据量的用户代理仍将被视为实现了本规范。

如果用户代理能够提供详细到等同于设备相机所提供信息的深度缓冲区, 则它必须首先获得等同于获取相机访问权限所需同意的用户同意。

变更

2021 年 8 月 31 日第一份公开 工作草案以来的变更

7. 致谢

以下个人为 WebXR 深度感知规范的设计作出了贡献:

一致性

文档 约定

一致性要求通过 描述性断言 与 RFC 2119 术语的组合来表达。 本文档规范性部分中的关键字 “MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、 “MAY” 和 “OPTIONAL” 应按 RFC 2119 中的描述来解释。 但是,为了可读性, 这些词在本规范中并不全都以大写字母出现。

本规范的所有文本均为规范性内容, 但明确标记为非规范性的章节、示例和注释除外。 [RFC2119]

本规范中的示例以 “for example” 等词引入,或通过 class="example" 与规范性文本分隔开, 如下所示:

这是一个资料性示例。

资料性注释以 “Note” 开头,并通过 class="note" 与规范性文本分隔开, 如下所示:

注,这是一个资料性注释。

一致性 算法

作为算法一部分以祈使语气表述的要求 (例如 "strip any leading space characters" 或 "return false and abort these steps") 应按引入该算法时所使用的关键字 ("must"、"should"、"may" 等) 的含义来解释。

以算法或具体步骤表述的一致性要求 可以以任何方式实现, 只要最终结果等价即可。 特别是,本规范中定义的算法 旨在易于理解, 并不旨在具有高性能。 鼓励实现者进行优化。

索引

由本 规范定义的术语

由引用定义的术语

参考文献

规范性参考文献

[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. 现行标准. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997 年 3 月. 最佳当前实践. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBGL-2]
Dean Jackson; Jeff Gilbert. WebGL 2.0 Specification. 2017 年 8 月 12 日. URL: https://www.khronos.org/registry/webgl/specs/latest/2.0/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. 现行标准. URL: https://webidl.spec.whatwg.org/
[WEBXR]
Brandon Jones; Manish Goregaokar; Rik Cabanier. WebXR Device API. 2025 年 10 月 1 日. CRD. URL: https://www.w3.org/TR/webxr/
[WEBXRLAYERS-1]
Rik Cabanier. WebXR Layers API Level 1. 2025 年 11 月 24 日. WD. URL: https://www.w3.org/TR/webxrlayers-1/

资料性参考文献

[WEBXR-AR-MODULE-1]
Brandon Jones; Manish Goregaokar; Rik Cabanier. WebXR Augmented Reality Module - Level 1. 2025 年 4 月 25 日. CRD. URL: https://www.w3.org/TR/webxr-ar-module-1/

IDL 索引

enum XRDepthType {
  "raw",
  "smooth",
};

enum XRDepthUsage {
  "cpu-optimized",
  "gpu-optimized",
};

enum XRDepthDataFormat {
  "luminance-alpha",
  "float32",
  "unsigned-short",
};

dictionary XRDepthStateInit {
  required sequence<XRDepthUsage> usagePreference;
  required sequence<XRDepthDataFormat> dataFormatPreference;
  sequence<XRDepthType> depthTypeRequest;
  boolean matchDepthView = true;
};

partial dictionary XRSessionInit {
  XRDepthStateInit depthSensing;
};

partial interface XRSession {
  readonly attribute XRDepthUsage depthUsage;
  readonly attribute XRDepthDataFormat depthDataFormat;
  readonly attribute XRDepthType? depthType;
  readonly attribute boolean? depthActive;

  undefined pauseDepthSensing();
  undefined resumeDepthSensing();
};

[SecureContext, Exposed=Window]
interface XRDepthInformation {
  readonly attribute unsigned long width;
  readonly attribute unsigned long height;

  [SameObject] readonly attribute XRRigidTransform normDepthBufferFromNormView;
  readonly attribute float rawValueToMeters;
};

XRDepthInformation includes XRViewGeometry;

[Exposed=Window]
interface XRCPUDepthInformation : XRDepthInformation {
  [SameObject] readonly attribute ArrayBuffer data;

  float getDepthInMeters(float x, float y);
};

partial interface XRFrame {
  XRCPUDepthInformation? getDepthInformation(XRView view);
};

[Exposed=Window]
interface XRWebGLDepthInformation : XRDepthInformation {
  [SameObject] readonly attribute WebGLTexture texture;

  readonly attribute XRTextureType textureType;
  readonly attribute unsigned long? imageIndex;
};

partial interface XRWebGLBinding {
  XRWebGLDepthInformation? getDepthInformation(XRView view);
};

MDN

XRCPUDepthInformation/data

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

XRCPUDepthInformation/getDepthInMeters

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

XRCPUDepthInformation

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

XRDepthInformation/height

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

XRDepthInformation/normDepthBufferFromNormView

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

XRDepthInformation/rawValueToMeters

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

XRDepthInformation/width

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

XRDepthInformation

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

XRFrame/getDepthInformation

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

XRSession/depthDataFormat

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

XRSession/depthUsage

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

XRWebGLBinding/getDepthInformation

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

XRWebGLDepthInformation/texture

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

XRWebGLDepthInformation

In only one current engine.

FirefoxNoneSafariNoneChrome90+
Opera?Edge90+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?