1. 简介
随着虚拟现实和增强现实变得更加普及,原生 API 正在引入新的特性, 这些特性能够访问有关用户所在环境的更详细信息。深度感知 API 将这样一种能力带到 WebXR Device API 中,允许由 WebXR 驱动的体验的作者获取从用户设备到用户环境中真实 世界几何体的距离信息。
本文档假定读者熟悉 WebXR Device API 和
WebXR 增强
现实模块规范,因为本文档构建在它们之上,为
XRSessions
提供附加特性。
1.1. 术语
本文档使用缩写 AR 表示增强现实,使用 VR 表示虚拟现实。
本文档在指代包含深度信息的字节数组时,可互换地使用诸如 "depth buffer"、"depth buffer data" 和 "depth data" 等术语,
这些信息可以由 XR 设备返回,也可以由 API 本身返回。关于深度缓冲区具体内容的更多信息,可参见规范中的 data
和 texture
条目。
本文档使用术语 归一化视图坐标来指代一种坐标系, 其原点位于视图左上角,X 轴向右增长,Y 轴向下增长。
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 上使用。
enum {XRDepthDataFormat "luminance-alpha" ,"float32" ,"unsigned-short" , };
-
"luminance-alpha"或"unsigned-short"的数据格式表示从 API 获取的深度数据缓冲区中的项是 16 位无符号整数 值。 -
"float32"数据格式表示从 API 获取的 深度数据缓冲区中的项是 32 位浮点值。
下表总结了各种数据格式可以被使用的方式:
| 数据格式 | 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
可以返回在更早时间点捕获的深度信息。
注: 如果 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并中止这些步骤。
注: 用户代理不需要支持所有 现有的用途和数据格式组合。这旨在允许它们以高效方式提供数据,并取决于底层平台。 此决定会给应用开发者带来额外负担——这可以通过创建隐藏 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 的 active 布尔值为
false,则抛出InvalidStateError并中止这些步骤。 -
如果 depth-sensing 特性描述符未包含 在 session 的 XR 设备针对 session 的mode 的启用特性列表中,则抛出
NotSupportedError并中止这些步骤。 -
如果深度感知活动状态为
true,则中止这些步骤。 -
将深度感知活动状态设置为
true。
XRSession
session 上调用 pauseDepthSensing()
时,用户代理必须运行以下步骤:
-
如果 session 的
ended值为true,则抛出InvalidStateError并中止这些步骤。 -
令 frame 为 session 的动画帧。
-
如果 frame 的 active 布尔值为
false,则抛出InvalidStateError并中止这些步骤。 -
如果 depth-sensing 特性描述符未包含 在 session 的 XR 设备针对 session 的mode 的启用特性列表中,则抛出
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 深度信息。
当在 XRFrame
frame 上使用一个 XRView
view 调用 getDepthInformation(view)
方法时,用户代理必须通过运行以下步骤获取 CPU 深度信息:
-
令 session 为 frame 的
session。 -
如果 depth-sensing 特性描述符未包含 在 session 的 XR 设备针对 session 的mode 的启用特性列表中,则抛出
NotSupportedError并中止这些步骤。 -
如果 frame 的 active 布尔值为
false,则抛出InvalidStateError并中止这些步骤。 -
如果 frame 的 animationFrame 布尔值为
false,则抛出InvalidStateError并中止这些步骤。 -
如果 frame 与 view 的 frame 不匹配,则抛出
InvalidStateError并中止这些步骤。 -
如果 session 的
depthUsage不是"cpu-optimized", 则抛出InvalidStateError并中止这些步骤。 -
令 depthInformation 为给定 frame 和 view 创建 CPU 深度信息 实例的结果。
-
返回 depthInformation。
为了给定
XRFrame
frame 和 XRView
view 创建 CPU 深度信息实例,用户代理必须运行以下步骤:
-
令 result 为
XRCPUDepthInformation的一个新实例。 -
令 time 为 frame 的 time。
-
令 session 为 frame 的
session。 -
令 device 为 session 的 XR 设备。
-
如果
depthActive为false,则返回null并中止这些步骤。 -
令 nativeDepthInformation 为查询 device 得到的深度信息结果, 该信息在 time 时有效,针对指定的 view,并考虑 session 的
depthType、depthUsage和depthDataFormat。 -
如果 nativeDepthInformation 为
null,则返回null并中止 这些步骤。 -
如果 nativeDepthInformation 中存在的深度缓冲区符合用户代理阻止访问深度数据的条件, 则返回
null并中止这些步骤。 -
如果 nativeDepthInformation 中存在的深度缓冲区符合用户代理限制深度缓冲区中可用信息量的条件, 则相应地调整深度缓冲区。
-
将 result 的
width初始化为 nativeDepthInformation 中返回的深度缓冲区宽度。 -
将 result 的
height初始化为 nativeDepthInformation 中返回的深度缓冲区高度。 -
将 result 的
normDepthBufferFromNormView初始化为一个新的XRRigidTransform, 基于 nativeDepthInformation 的深度坐标变换 矩阵。 -
将 result 的
data初始化为 nativeDepthInformation 中返回的原始深度缓冲区。 -
将 result 的 view 初始化为 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。
- 否则
- 令 time 为 device 捕获深度信息的时间。
- 如果
-
令 session 为 frame 的
session。 -
令 device 为 session 的 XR 设备。
-
如果
depthActive为false,则返回null并中止这些步骤。 -
令 nativeDepthInformation 为查询 device 的原生 深度感知得到的深度信息结果, 该信息在 time 时有效,针对指定的 view,并考虑 session 的
depthType、depthUsage和depthDataFormat。 -
如果 nativeDepthInformation 为
null,则返回null并中止 这些步骤。 -
如果 nativeDepthInformation 中存在的深度缓冲区符合用户代理阻止访问深度数据的条件, 则返回
null并中止这些步骤。 -
如果 nativeDepthInformation 中存在的深度缓冲区符合用户代理限制深度缓冲区中可用信息量的条件, 则相应地调整深度缓冲区。
-
将 result 的
width初始化为 nativeDepthInformation 中返回的深度缓冲区宽度。 -
将 result 的
height初始化为 nativeDepthInformation 中返回的深度缓冲区高度。 -
将 result 的
normDepthBufferFromNormView初始化为一个新的XRRigidTransform, 基于 nativeDepthInformation 的深度坐标变换 矩阵。 -
将 result 的
texture初始化为一个包含 nativeDepthInformation 中返回的深度缓冲区的不透明纹理。 -
将 result 的 view 初始化为 view。
-
按如下方式初始化 result 的
textureType:- 如果 result 的
texture是使用 texture-array 的 textureType 创建的: - 将 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
中获取深度数据。
假定会话已启用深度感知,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 viewof 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。
存储在 data
和 texture
中的值表示从相机平面到真实世界几何体(由 XR 系统理解)的距离。在下面的示例中,
点 a = (x, y) 处的深度值对应于点
A 到相机平面的距离。具体来说,该深度值不表示 aA
向量的长度。

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