1. 简介
随着虚拟现实和增强现实变得更加普及,原生 API 正在引入新的特性, 这些特性能够访问有关用户所在环境的更详细信息。深度感知 API 将这样一种能力带到 WebXR Device API 中,允许由 WebXR 驱动的体验的作者获取从用户设备到用户环境中真实 世界几何体的距离信息。
本文档假定读者熟悉 WebXR Device API 和
WebXR 增强
现实模块规范,因为本文档构建在它们之上,为
XRSessions
提供附加特性。
1.1. 术语
本文档使用缩写 AR 表示增强现实,使用 VR 表示虚拟现实。
本文档在指代包含深度信息的字节数组时,会交替使用“深度缓冲区”、“深度缓冲区数据”和“深度数据”等术语,
这些数据既可能由 XR 设备返回,也可能由 API 本身返回。有关深度缓冲区具体内容的更多信息,请参阅规范中 data、
texture
和 texture
条目。
本文档使用术语 归一化视图坐标 来指代一种坐标系, 其原点位于视图左上角,X 轴向右增大,Y 轴向 下增大。
原生深度
缓冲区 是由原生深度感知产生的、由实现定义的存储,其中包含
原始深度值。它可以是 CPU 可访问的分配区,也可以是原生 API 纹理,并且不会直接暴露
给作者。它具有宽度、高度和数据格式,并由单个二维层或
多个大小相同的二维数组层组成。为特定 XRView
返回的非分层原生深度缓冲区包含该视图的深度值。分层原生深度缓冲区必须为
XRSession
获取时的
视图列表中的每个条目包含一个数组层,并且这些层
按相同顺序与这些视图相对应。
原生深度
信息 是查询原生深度感知所得的、由实现定义的结果。它包含一个
原生深度
缓冲区、用于将其中的值转换为米的缩放因子、一个 深度坐标
变换矩阵,以及产生该缓冲区的传感器的投影矩阵和 transform。
2. 初始化
2.1. 特性描述符
应用可以通过传入适当的 特性描述符,请求在 XRSession 上启用深度感知。此模块引入一个新的字符串 - depth-sensing, 作为深度感知特性的新有效特性描述符。
如果设备暴露原生深度 感知能力,则该设备能够支持深度感知特性。内联 XR 设备不得被视为能够 支持深度感知特性。
深度感知特性受特性策略约束,并且
要求在请求文档的源上允许 "xr-spatial-tracking" 策略。
2.2. 预期深度类型、数据用途和数据格式
enum {XRDepthType "raw" ,"smooth" , };
-
"raw"的使用表示不应对深度数据进行额外 处理。 -
"smooth"的使用表示运行时 应该对深度纹理执行额外处理,以移除潜在噪声。
enum {XRDepthUsage "cpu-optimized" ,"gpu-optimized" , };
-
使用
"cpu-optimized"表示 深度数据旨在通过与XRCPUDepthInformation接口交互,在 CPU 上使用。 -
使用
"gpu-optimized"表示 深度数据旨在通过与XRWebGLDepthInformation接口交互,在 GPU 上使用;或者,对于兼容 WebGPU 的会话,通过与XRGPUDepthInformation接口交互来使用。
enum {XRDepthDataFormat "luminance-alpha" ,"float32" ,"unsigned-short" , };
-
"luminance-alpha"或"unsigned-short"的数据格式表示从 API 获取的深度数据缓冲区中的项是 16 位无符号整数 值。 -
"float32"数据格式表示从 API 获取的 深度数据缓冲区中的项是 32 位浮点值。
下表总结了各种数据格式可以被使用的方式:
| 数据格式 | WebGL 格式 | WebGPU 格式 | 深度缓冲区条目的大小 | 在 CPU 上的使用方式 | 在 GPU 上的使用方式 |
|---|---|---|---|---|---|
"luminance-alpha"
| LUMINANCE_ALPHA | 不支持 | 2 个 8 位 | 将 data
解释为 Uint16Array
| 检查 WebGL 中的亮度通道和 Alpha 通道,以重新组合成单个值。亮度 通道包含最低有效字节。 |
"float32"
| R32F | "r32float"
| 32 位 | 将 data
解释为 Float32Array
| 检查红色通道并使用该值。 |
"unsigned-short"
| R16UI | "r16uint"
| 16 位 | 将 data
解释为 Uint16Array
| 检查红色通道并使用该值。 |
"luminance-alpha"
数据格式不得与 XRGPUDepthInformation
一起使用。
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
可以返回在更早时间点捕获的深度信息。
注: 如果 matchDepthView
为 false,作者应该使用来自 XRDepthInformation
的 view
来进行重投影。
通过添加新的 depthSensing
键,扩展了 XRSessionInit
字典。该键在 XRSessionInit
中是可选的,但当 depth-sensing 被包含在
requiredFeatures
或 optionalFeatures
中时,必须提供该键。
partial dictionary XRSessionInit {XRDepthStateInit ; };depthSensing
如果深度感知特性是必需特性,但应用没有提供 depthSensing
键,则用户代理必须将其视为未解决的必需特性,并用 NotSupportedError
拒绝 requestSession(mode, options)
promise。
如果它是作为可选特性请求的,则用户代理必须忽略该特性请求,并且不得在新创建的会话上启用
深度感知。
如果深度感知特性是必需特性,但使用 XRDepthStateInit
调用查找受支持配置组合算法的结果
为 null,则用户代理必须将其视为未解决的必需特性,并用 NotSupportedError
拒绝 requestSession(mode, options)
promise。
如果它是作为可选特性请求的,则用户代理必须忽略该特性请求,并且不得在新创建的会话上启用
深度感知。
当 XRSession
在启用深度感知的情况下创建时,depthUsage、
depthDataFormat
和 depthType
属性必须设置为使用 XRDepthStateInit
调用查找受支持配置组合算法的结果。
depthActive
必须默认为 true。
注: 该算法的意图是按从最严格到最不严格的顺序处理 偏好。因此,我们首先处理只指示单个项的项目,然后处理多个项,最后处理未指示偏好的情况。
-
如果在 depthStateInit 中设置了
depthTypeRequest键,则令 depthTypeRequest 为该键包含的值,否则为空序列。 -
令 selectedType 为
null -
令 usagePreference 为 depthStateInit 中
usagePreference键包含的值 -
令 selectedUsage 为
null。 -
令 dataFormatPreference 为 depthStateInit 中
dataFormatPreference键包含的值 -
令 selectedDataFormat 为
null。 -
令 processingOrder 为 (preferences, selection) 对的序列,其中 selection 是对前面步骤中引入的某个变量的引用: [(depthTypeRequest, selectedType), (usagePreference,selectedUsage),(dataFormatPreference,selectedDataFormat)]
-
对于 processingOrder 中的每个 (preferences, selection),执行以下 步骤
-
如果 preferences 只包含单个值,则将 selection 设置为该 值。
-
-
对于 processingOrder 中的每个 (preferences, selection),执行以下 步骤:
-
如果 selection 不是
null,则继续到下一个条目。 -
如果 preferences 序列为空,则继续到下一个条目。
-
对于 preferences 中的每个 preference,执行以下步骤:
-
如果 preference 与 selectedType、selectedUsage、selectedDataFormat 的其他值一起, 未被设备的原生深度感知能力视为受支持的深度感知 配置,则继续到下一个条目。
-
将 selection 设置为 preference 并中止这些嵌套步骤。
-
-
对于 processingOrder 中的每个 (preferences, selection),执行以下 步骤:
-
如果 selection 不是
null,则继续到下一个条目。 -
将 selection 设置为由具有 selectedType、selectedUsage、selectedDataFormat 其他值的首选原生深度 感知能力所确定的值。
-
-
如果 selectedType、selectedUsage、selectedDataFormat 中任何一个为
null,则返回null并中止这些步骤。 -
如果 selectedType、selectedUsage、selectedDataFormat 被设备的 原生深度感知能力视为受支持的深度感知 配置, 则返回 selectedType、selectedUsage、selectedDataFormat 的深度感知配置并中止这些 步骤。
-
如果 depthTypeRequest 不是空列表,则将其设置为空列表并重复这些 步骤。
-
返回
null并中止这些步骤。
当为查找受支持的配置组合
兼容 WebGPU 的会话时,将 "gpu-optimized"
使用方式与 "luminance-alpha"
数据格式组合的配置不得被视为受支持的深度感知配置。
注:用户代理不需要支持所有 现有的使用方式和数据格式组合。这样做旨在使它们能够以 高效的方式提供数据,并且具体取决于底层平台。这一决定给 应用开发者带来了额外负担——可以通过创建隐藏 API 复杂性的库来缓解这种负担,但可能会 牺牲性能。
能够支持深度感知 API 的用户代理必须至少支持
一种 XRDepthUsage
模式。能够支持深度感知 API 的用户代理必须支持 "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()
时,用户代理必须运行以下步骤:
-
如果 session 的
ended值为true,则抛出InvalidStateError并中止这些步骤。 -
令 frame 为 session 的动画帧。
-
如果 frame 的活动布尔值为
false,则抛出InvalidStateError并中止这些步骤。 -
如果 depth-sensing 功能描述符未包含在 session 的XR 设备的、针对 session 的模式的已启用功能列表中,则抛出
NotSupportedError并中止这些步骤。 -
如果深度感知活动状态为
true,则中止这些步骤。 -
将深度感知活动状态设置为
true。
XRSession
session 上调用 pauseDepthSensing()
时,用户代理必须运行以下步骤:
-
如果 session 的
ended值为true,则抛出InvalidStateError并中止这些步骤。 -
令 frame 为 session 的动画帧。
-
如果 frame 的活动布尔值为
false,则抛出InvalidStateError并中止这些步骤。 -
如果 depth-sensing 功能描述符未包含在 session 的XR 设备的、针对 session 的模式的已启用功能列表中,则抛出
NotSupportedError并中止这些步骤。 -
如果深度感知活动状态为
false,则中止这些步骤。 -
将深度感知活动状态设置为
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 ;
normDepthBufferFromNormView
属性包含一个 XRRigidTransform,
在索引到深度缓冲区中时需要应用它。
该矩阵表示的变换会将坐标系从归一化视图坐标更改为归一化深度缓冲区坐标,
然后可以用深度缓冲区的 width
和 height
对其进行缩放,以获得绝对深度缓冲区坐标。
注: 如果应用打算将得到的 深度缓冲区用于给网格贴图,则必须注意确保网格顶点的纹理坐标以归一化视图坐标表示,或在着色器中执行适当的 坐标系变换。
rawValueToMeters
属性包含一个比例因子,来自深度缓冲区的原始深度值
必须乘以该因子才能得到以米为单位的深度。
如果sensor
与关联的 view
对齐,则从 XRViewGeometry
包含的所有值,必须返回与关联 view 相同的值。
每个 XRDepthInformation
都有一个关联的 view,它是距离 sensor 最近的 XRView,
并用于检索 XRDepthInformation。
每个 XRDepthInformation
都有一个关联的 sensor,它是从中获得深度信息的 XRViewGeometry
的包含对象。
每个 XRDepthInformation
都有一个关联的 深度缓冲区,其中包含深度缓冲区数据。
不同的 XRDepthInformation
可以在深度缓冲区中存储不同具体类型的对象。
当尝试访问 XRDepthInformation
或继承自它的任何接口的深度缓冲区时,用户代理必须运行以下步骤:
-
令 depthInformation 为其成员被访问的实例。
-
令 view 为 depthInformation 的 view。
-
令 frame 为 view 的 frame。
-
如果 frame 不是活动的, 则抛出
InvalidStateError并中止这些步骤。 -
如果 frame 不是 animationFrame,则抛出
InvalidStateError并中止这些步骤。 -
继续执行访问 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 上使用 x、y 调用 getDepthInMeters(x, y)
方法时,用户代理必须通过运行以下步骤获取坐标
处的深度:
-
令 view 为 depthInformation 的 view, frame 为 view 的 frame,并且 session 为 frame 的
session。 -
如果 x 大于
1.0或小于0.0,则抛出RangeError并中止这些步骤。 -
如果 y 大于
1.0或小于0.0,则抛出RangeError并中止这些步骤。 -
令 normalizedViewCoordinates 为一个表示空间中三维点的向量, 其中
x坐标设置为 x,y坐标设置为 y,z坐标设置为0.0,并且w坐标 设置为1.0。 -
令 normalizedDepthCoordinates 为从左侧将 normalizedViewCoordinates 向量预乘以 depthInformation 的
normDepthBufferFromNormView的结果。 -
令 depthCoordinates 为对 normalizedDepthCoordinates 进行缩放的结果, 其中
x坐标乘以 depthInformation 的width且y坐标乘以 depthInformation 的height。 -
令 column 为 depthCoordinates 的
x坐标的值, 截断为整数,并钳制到[0, width-1]整数范围内。 -
令 row 为 depthCoordinates 的
y坐标的值, 截断为整数,并钳制到[0, height-1]整数范围内。 -
令 index 等于 row 乘以
width并加上 column。 -
令 byteIndex 等于 index 乘以深度数据格式的大小。
-
令 rawDepth 等于在
data中索引 byteIndex 处找到的值,并根据 session 的depthDataFormat将其解释为数字。 -
令 rawValueToMeters 等于 depthInformation 的
rawValueToMeters。 -
返回 rawDepth 乘以 rawValueToMeters。
partial interface XRFrame {XRCPUDepthInformation ?getDepthInformation (XRView ); };view
getDepthInformation(view) 方法在 XRFrame
上调用时,表示应用想要获取与该帧相关的 CPU 深度信息。
当在 getDepthInformation(view)
方法在 XRFrame
frame 上以 XRView
view 为参数调用时,用户代理必须通过运行以下步骤获取 CPU 深度信息:
-
令 session 为 frame 的
session。 -
如果 depth-sensing 功能描述符未包含 在 session 的XR 设备的、针对 session 的已启用功能列表中,且该列表对应 session 的模式,则抛出一个
NotSupportedError并中止这些步骤。 -
如果 frame 的活动布尔值为
false,则抛出一个InvalidStateError并中止这些步骤。 -
如果 frame 的animationFrame 布尔值为
false,则抛出 一个InvalidStateError并中止这些步骤。 -
如果 frame 与 view 的帧不匹配,则抛出一个
InvalidStateError并中止这些步骤。 -
如果 session 的
depthUsage不是"cpu-optimized", 则抛出一个InvalidStateError并中止这些步骤。 -
令 depthInformation 为给定 frame 和 view 时创建 CPU 深度信息 实例的结果。
-
返回 depthInformation。
为了在给定
XRFrame
frame 和 XRView
view 时创建 CPU 深度信息实例,用户代理必须运行以下步骤:
-
令 result 为
XRCPUDepthInformation的新实例。 -
令 time 为 frame 的时间。
-
令 session 为 frame 的
session。 -
令 device 为 session 的XR 设备。
-
如果
depthActive为false,则返回null并中止这些步骤。 -
令 nativeDepthInformation 为通过查询 device,获得针对指定 view、在 time 时有效的原生深度 信息,并考虑 session 的
depthType、depthUsage和depthDataFormat。 -
如果 nativeDepthInformation 为
null,则返回null并中止 这些步骤。 -
令 nativeDepthBuffer 为 nativeDepthInformation 的原生深度缓冲区。
-
如果 nativeDepthBuffer 满足用户代理阻止访问深度数据的条件,则返回
null并中止这些步骤。 -
如果 nativeDepthBuffer 满足用户代理限制 信息量的条件,以限制深度缓冲区中可用的信息量,则相应地调整 nativeDepthBuffer。
-
将 result 的
width初始化为 nativeDepthBuffer 的宽度。 -
将 result 的
height初始化为 nativeDepthBuffer 的高度。 -
将 result 的
normDepthBufferFromNormView初始化为一个新的XRRigidTransform, 其基于 nativeDepthInformation 的深度坐标变换 矩阵。 -
将 result 的
rawValueToMeters初始化为 nativeDepthInformation 提供的缩放因子。 -
将 result 的
data初始化为从 nativeDepthBuffer 中取得的 view 原始深度值的副本。 -
将 result 的视图初始化为 view。
-
返回 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 viewof 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 深度信息:
-
令 session 为 binding 的 session。
-
令 frame 为 view 的 frame。
-
如果 session 与 frame 的
session不匹配,则抛出InvalidStateError并中止这些步骤。 -
如果 depth-sensing 特性描述符未包含 在 session 的 XR 设备针对 session 的mode 的启用特性列表中,则抛出
NotSupportedError并中止这些步骤。 -
如果 session 的
depthUsage不是"gpu-optimized", 则抛出InvalidStateError并中止这些步骤。 -
如果 frame 的 active 布尔值为
false,则抛出InvalidStateError并中止这些步骤。 -
如果 frame 的 animationFrame 布尔值为
false,则抛出InvalidStateError并中止这些步骤。 -
令 depthInformation 为给定 frame 和 view 创建 WebGL 深度信息 实例的结果。
-
返回 depthInformation。
为了在给定 XRFrame
frame 和 XRView
view 的情况下创建 WebGL 深度信息实例,用户代理必须运行以下步骤:
-
令 result 为
XRWebGLDepthInformation的新实例。 -
按如下方式初始化 time:
- 如果
XRSession是在将matchDepthView设置为true的情况下创建的: - 令 time 为 frame 的时间。
- 否则
- 令 time 为 device 捕获深度信息的时间。
- 如果
-
令 session 为 frame 的
session。 -
令 device 为 session 的XR 设备。
-
如果
depthActive为false,则返回null并中止这些步骤。 -
令 nativeDepthInformation 为通过查询 device 的原生深度感知所获得的原生深度 信息,该深度信息对于指定的 view 在 time 时有效,并考虑 session 的
depthType、depthUsage和depthDataFormat。 -
如果 nativeDepthInformation 为
null,则返回null并中止 这些步骤。 -
令 nativeDepthBuffer 为 nativeDepthInformation 的原生深度缓冲区。
-
如果 nativeDepthBuffer 满足用户代理阻止访问深度数据的条件,则返回
null并中止这些步骤。 -
如果 nativeDepthBuffer 满足用户代理限制 信息量的条件,以限制深度缓冲区中可用的信息量,则相应地调整 nativeDepthBuffer。
-
将 result 的
width初始化为 nativeDepthBuffer 的宽度。 -
将 result 的
height初始化为 nativeDepthBuffer 的高度。 -
将 result 的
normDepthBufferFromNormView初始化为一个新的XRRigidTransform, 其基于 nativeDepthInformation 的深度坐标变换 矩阵。 -
将 result 的
rawValueToMeters初始化为 nativeDepthInformation 提供的缩放因子。 -
将 result 的视图初始化为 view。
-
按如下方式初始化 result 的
textureType:- 如果 result 的
texture是使用 textureType 为 texture-array 创建的: - 将 result 的
textureType初始化为 "texture-array"。 - 否则
- 将 result 的
textureType初始化为 "texture"。
- 如果 result 的
-
按如下方式初始化 result 的
imageIndex:- 如果
textureType为 texture - 将 result 的
imageIndex初始化为null。 - 否则,如果 view 的
eye为"right" - 将 result 的
imageIndex初始化为1。 - 否则
- 将 result 的
imageIndex初始化为0。
- 如果
-
返回 result。
XRFrameRequestCallback
中获取深度数据。
假定该会话已启用深度感知,使用方式设置为 "gpu-optimized",数据
格式设置为 "luminance-alpha":
const session= ...; // 使用启用了深度感知的会话创建。 const referenceSpace= ...; // 从会话创建的参考空间。 const glBinding= ...; // 从会话创建的 XRWebGLBinding。 function requestAnimationFrameCallback( t, frame) { session. requestAnimationFrame( requestAnimationFrameCallback); const pose= frame. getViewerPose( referenceSpace); if ( pose) { for ( const viewof pose. views) { const depthInformation= glBinding. getDepthInformation( view); if ( depthInformation) { useWebGLDepthInformation( view, depthInformation); } } } }
获得 XRWebGLDepthInformation
后,可以使用它确定从视图平面到用户环境的距离(有关详细信息,请参阅§ 4 解释结果一节)。下面的代码
演示了如何将数据传递给着色器:
const gl= ...; // 要使用的 GL 上下文。 const shaderProgram= ...; // 已链接的 WebGLProgram。 const programInfo= { uniformLocations: { depthTexture: gl. getUniformLocation( shaderProgram, 'uDepthTexture' ), uvTransform: gl. getUniformLocation( shaderProgram, 'uUvTransform' ), rawValueToMeters: gl. getUniformLocation( shaderProgram, 'uRawValueToMeters' ), } }; function useWebGLDepthInformation( 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 , depthInformation. normDepthBufferFromNormView. matrix); gl. uniform1f( programInfo. uniformLocations. rawValueToMeters, depthInformation. 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 ) { // 深度被打包到其纹理的亮度和 Alpha 分量中。 // 该纹理采用归一化格式,以毫米为单位存储。 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= ...; }
3.4. XRGPUDepthInformation
对于兼容 WebGPU 的会话,GPU 优化的深度信息
必须通过 XRGPUBinding
以 XRGPUDepthInformation
的形式暴露,而不是通过 XRWebGLBinding
以 XRWebGLDepthInformation
的形式暴露。
每个 XRGPUDepthInformation
都有一个关联的非负整数 数组层索引,
用于标识其 texture
中包含关联视图的深度信息的数组层。
[Exposed =Window ]interface :XRGPUDepthInformation XRDepthInformation { [SameObject ]readonly attribute GPUTexture ;texture GPUTextureViewDescriptor getViewDescriptor (); };
texture
属性以使用 XRGPUBinding
的
device 创建的 GPUTexture
的形式包含深度缓冲区信息。每个纹素对应从传感器近裁剪平面到用户环境的距离,单位
未指定。通过将这些值乘以 rawValueToMeters,
可以将其从未指定单位转换为米。normDepthBufferFromNormView
可用于从归一化视图坐标转换到深度缓冲区的
坐标系。访问此属性时,必须运行用于尝试访问深度缓冲区的 XRDepthInformation
算法。
返回的纹理具有以下属性:
-
**dimension**:
"2d"。 -
**format**:与会话的
depthDataFormat在§ 2.2 预期的深度类型、数据使用方式和数据格式 表中相对应的GPUTextureFormat。 -
**width**:此
XRGPUDepthInformation的width。 -
**height**:此
XRGPUDepthInformation的height。 -
**usage**:
TEXTURE_BINDING。 -
**mipLevelCount**:`1`。
-
**sampleCount**:`1`。
在 texture
上调用 destroy()
必须终止通过该 GPUTexture
进行的访问,但不得销毁或更改其底层的原生深度缓冲区。
getViewDescriptor()
方法返回一个 GPUTextureViewDescriptor,
其配置用于创建 texture
中包含此对象深度信息部分的二维视图。
当在 XRGPUDepthInformation
depthInformation 上调用时,用户代理必须运行以下步骤:
-
使用 depthInformation 运行尝试访问深度缓冲区的算法。
-
令 descriptor 为一个新的
GPUTextureViewDescriptor。 -
将 descriptor 的
baseMipLevel设置为 `0`。 -
将 descriptor 的
mipLevelCount设置为 `1`。 -
将 descriptor 的
baseArrayLayer设置为 depthInformation 的数组层索引。 -
将 descriptor 的
arrayLayerCount设置为 `1`。 -
返回 descriptor。
每个 XRFrame
都有一个关联的 WebGPU 深度纹理列表,初始为空列表。
XR 动画帧算法扩展如下:在将 XRFrame
的
active 布尔值设置为 false 之前,用户代理必须立即运行
以下步骤:
-
对于
XRFrame的 WebGPU 深度纹理列表中的每个 texture: -
将
XRFrame的 WebGPU 深度纹理列表设置为空 列表。
注:作者必须在获取 XRGPUDepthInformation
的那个 XRFrameRequestCallback
期间,对使用 texture
的所有工作进行编码并提交。保留 XRGPUDepthInformation
或其纹理不会延长该纹理的生命周期。
partial interface XRGPUBinding {XRGPUDepthInformation ?getDepthInformation (XRView ); };view
getDepthInformation(view) 方法在
XRGPUBinding
上调用时,表示应用程序希望获取与该帧相关的 WebGPU 深度信息。
当在 XRGPUBinding
binding 上以 XRView
view 为参数调用 getDepthInformation(view)
时,用户代理必须通过运行以下
步骤获取
WebGPU 深度信息:
-
令 session 为 binding 的会话。
-
令 device 为 binding 的设备。
-
令 frame 为 view 的帧。
-
如果 session 与 frame 的
session不匹配,则抛出一个InvalidStateError并中止这些步骤。 -
如果 depth-sensing 功能描述符未包含 在 session 的XR 设备的、针对 session 的模式的已启用功能列表中,则抛出一个
NotSupportedError并中止这些步骤。 -
如果 session 的
depthUsage不是"gpu-optimized", 则抛出一个InvalidStateError并中止这些步骤。 -
如果 device 已被销毁, 则抛出一个
InvalidStateError并中止这些步骤。 -
如果 frame 的active 布尔值为
false,则抛出一个InvalidStateError并中止这些步骤。 -
如果 frame 的animationFrame 布尔值为
false,则抛出 一个InvalidStateError并中止这些步骤。 -
令 depthInformation 为给定 binding、frame 和 view 时创建 WebGPU 深度信息 实例的结果。
-
返回 depthInformation。
为了在给定 XRGPUBinding
binding、XRFrame
frame 和 XRView
view 的情况下创建 WebGPU 深度信息实例,
用户代理必须运行以下步骤:
-
令 result 为
XRGPUDepthInformation的新实例。 -
令 session 为 frame 的
session。 -
令 xrDevice 为 session 的XR 设备。
-
令 gpuDevice 为 binding 的设备。
-
按如下方式初始化 time:
- 如果 session 是在将
matchDepthView设置为true的情况下创建的: - 令 time 为 frame 的时间。
- 否则:
- 令 time 为 xrDevice 捕获深度信息的时间。
- 如果 session 是在将
-
如果
depthActive为false,则返回null并中止这些步骤。 -
令 nativeDepthInformation 为通过查询 xrDevice 的原生深度感知所获得的原生深度 信息,该深度信息对于指定的 view 在 time 时有效,并 考虑 session 的
depthType、depthUsage和depthDataFormat。 -
如果 nativeDepthInformation 为
null,则返回null并中止 这些步骤。 -
令 nativeDepthBuffer 为 nativeDepthInformation 的原生深度缓冲区。
-
如果 nativeDepthBuffer 满足用户代理阻止访问深度数据的条件,则返回
null并中止这些步骤。 -
如果 nativeDepthBuffer 满足用户代理限制 信息量的条件,以限制深度缓冲区中可用的信息量,则相应地调整 nativeDepthBuffer。
-
将 result 的
width初始化为 nativeDepthBuffer 的宽度。 -
将 result 的
height初始化为 nativeDepthBuffer 的高度。 -
将 result 的
normDepthBufferFromNormView初始化为一个新的XRRigidTransform, 其基于 nativeDepthInformation 的深度坐标变换 矩阵。 -
将 result 的
rawValueToMeters初始化为 nativeDepthInformation 提供的缩放因子。 -
令 format 为与 session 的
depthDataFormat在§ 2.2 预期的深度类型、数据使用方式和数据格式 表中相对应的GPUTextureFormat。 -
令 arrayLayerCount 为 nativeDepthBuffer 中的数组层数;如果 nativeDepthBuffer 不是分层的,则为 `1`。
-
如果 arrayLayerCount 为 `1`,则令 arrayLayerIndex 为 `0`;否则,令其为 view 的
index。 -
断言 arrayLayerIndex 小于 arrayLayerCount。
-
令 descriptor 为一个新的
GPUTextureDescriptor, 其具有以下成员:-
size设置为一个GPUExtent3D, 其宽度为 result 的width, 高度为 result 的height, 深度或数组层数为 arrayLayerCount。 -
mipLevelCount设置为 `1`。 -
sampleCount设置为 `1`。 -
format设置为 format。 -
usage设置为TEXTURE_BINDING。 -
viewFormats设置为空序列。
-
-
将 result 的
texture初始化为使用 descriptor 调用 gpuDevice.createTexture()的结果,但使该GPUTexture的底层存储指向 nativeDepthBuffer。 -
将 result 的数组层索引初始化为 arrayLayerIndex。
-
将 result 的
texture追加到 frame 的WebGPU 深度纹理列表中。 -
将 result 的视图初始化为 view。
-
返回 result。
"gpu-optimized"
使用方式和 "unsigned-short"
数据格式的兼容 WebGPU 的会话中获取深度数据:
const adapter= await navigator. gpu. requestAdapter({ xrCompatible: true }); const device= await adapter. requestDevice(); const session= await navigator. xr. requestSession( "immersive-ar" , { requiredFeatures: [ "depth-sensing" , "webgpu" ], depthSensing: { usagePreference: [ "gpu-optimized" ], dataFormatPreference: [ "unsigned-short" ], }, }); const referenceSpace= await session. requestReferenceSpace( "local" ); const gpuBinding= new XRGPUBinding( session, device); const projectionLayer= gpuBinding. createProjectionLayer({ colorFormat: gpuBinding. getPreferredColorFormat(), }); session. updateRenderState({ layers: [ projectionLayer] }); function requestAnimationFrameCallback( time, frame) { session. requestAnimationFrame( requestAnimationFrameCallback); const pose= frame. getViewerPose( referenceSpace); if ( ! pose) return ; for ( const viewof pose. views) { const depthInformation= gpuBinding. getDepthInformation( view); if ( ! depthInformation) continue ; const depthTextureView= depthInformation. texture. createView( depthInformation. getViewDescriptor()); // 在此回调期间提交的 WebGPU 工作中使用 depthTextureView。 } } session. requestAnimationFrame( requestAnimationFrameCallback);
4. 解释结果
如果确定给定像素具有无效深度数据,或者无法通过其他方式确定深度数据,则 用户代理必须返回深度值 0。
存储在 data、
texture
和 texture
中的值表示从相机平面到现实世界几何体(由 XR 系统所理解)的距离。在
下面的示例中,点 a = (x, y) 处的深度值对应于点
A 到相机平面的距离。具体而言,该深度值并不表示 aA
向量的长度。

上图对应于以下代码:
// depthInfo 的类型为 XRCPUDepthInformation: const depthInMeters= depthInfo. getDepthInMeters( x, y);
5. 原生设备概念
5.1. 原生深度感知
深度感知规范假定,实现深度感知 API 所基于的原生设备
提供了一种查询设备原生深度感知能力的方式。如果设备公开了一种获取原生
深度信息的方式,则称该设备支持
查询设备的原生深度感知能力。原生深度信息中的深度坐标变换矩阵
执行从归一化视图
坐标到归一化深度缓冲区坐标的坐标系变换,并且不应影响变换后的 3D 向量的 z
坐标。
设备可以通过 2 种方式支持深度感知类型。如果设备只是
返回经过最少后处理的估算深度值,则称其支持 "raw"
深度类型。如果设备或运行时可以对这些数据应用额外处理以“平滑”其中的噪声
(例如,将其处理为具有相同深度值的更大区域),则称其支持 "smooth"
深度类型。
注:“原始”深度数据通常伴随 置信度值。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 所需的数据。
对于 depthTypeRequest、
usagePreference
和 dataFormatPreference
中的每一个,设备都必须具有一个首选原生深度感知
能力,当相应数组为空时必须使用该能力。类型、使用方式和格式
应反映设备中效率最高的选项,不过它们可能彼此依赖。
设备可以被认为具有一个深度感知活动状态,它是一个表示
深度感知能力是否正在活动运行的布尔值。此状态必须初始为 true。当此状态
为 false 时,用户代理应采取措施减轻启用此功能所带来的性能影响。
6. 隐私与安全考量
深度感知 API 以深度缓冲区的形式向网站提供有关用户环境的附加信息。 给定具有足够高分辨率和足够高精度的深度缓冲区,网站可能会了解到比用户感到舒适的程度更加详细的信息。 根据所使用的底层技术,深度数据可能基于相机图像和 IMU 传感器创建。
为了缓解用户的隐私风险,用户代理应该在会话上启用深度感知 API 之前寻求用户同意。 此外,随着深度感知技术和硬件的改进,用户代理应该考虑限制通过 API 暴露的信息量, 或者如果引入此类限制不可行,则阻止访问 API 返回的数据。为了限制信息量,用户代理例如可以 降低所得深度缓冲区的分辨率,或降低深度缓冲区中存在的值的精度(例如通过量化)。 决定以这种方式限制数据量的用户代理仍将被视为实现了本规范。
如果用户代理能够提供详细到等同于设备相机所提供信息的深度缓冲区, 则它必须首先获得等同于获取相机访问权限所需同意的用户同意。
变更
自 2021 年 8 月 31 日第一份公开 工作草案以来的变更
7. 致谢
以下个人为 WebXR 深度感知规范的设计作出了贡献: