1. 简介
WebXR Anchors 模块使应用能够请求底层 XR 系统跟踪某个特定三维姿态(位置和方向)随着系统对世界的理解 变化而发生的改变。这允许应用调整它放置在场景中的虚拟对象的位置, 以有助于维持这些被放置对象真实存在于用户环境中的错觉。
1.1. 术语
在本文档中,姿态表示 3D 空间中的位置和方向。
在本文档中,锚点是一个跟踪相对于真实世界固定的姿态的实体,并由应用创建。
2. 初始化
2.1. 特性描述符
为了让应用在会话期间表示其有意使用锚点,必须使用适当的特性描述符来请求会话。字符串 anchors 由本模块作为锚点特性的新有效 特性描述符引入。
如果设备的跟踪系统暴露原生锚点能力,则设备能够支持锚点特性。内联 XR 设备不得被视为能够
支持锚点特性。用户代理应该尝试为
模式等于 "immersive-ar"
的会话支持锚点特性。
注:尽管不要求支持锚点特性,
但锚点是支持 AR 的应用提供良好用户体验所需的基本特性之一。
因此,*强烈*建议用户代理为
"immersive-ar" 会话支持锚点。
3. 锚点
3.1. XRAnchor
[SecureContext ,Exposed =Window ]interface {XRAnchor readonly attribute XRSpace ;anchorSpace Promise <DOMString >();requestPersistentHandle undefined (); };delete
XRAnchor
包含 anchorSpace,
可用于相对于其他 XRSpaces
定位锚点。
如果在 已删除设为
true 时访问此属性,用户代理必须抛出
InvalidStateError。
每个 XRAnchor
都有一个关联的 已删除布尔值,其初始设置为 false。
每个 XRAnchor
都有一个关联的 原生原点。
每个 XRAnchor
都有一个关联的 会话。
-
令 anchor 为一个新的
XRAnchor。 -
将 anchor 的原生原点设为 native origin。
-
将 anchor 的会话设为 session。
-
将 anchor 的已删除设为
false。 -
将 anchor 的
anchorSpace设为一个新的XRSpace对象,该对象以 session 设为 anchor 的会话、native origin 设为原生原点来创建。 -
返回 anchor。
XRAnchor
anchor 上调用 requestPersistentHandle()
方法时,必须运行以下步骤:
注:当 XRSystem
创建唯一 ID 时,它必须是唯一的,并且只为当前源所知。
4. 锚点创建
XRSession
被扩展为包含一个关联的 被跟踪锚点集。
XRSession
被扩展为包含一个关联的 持久
锚点映射,该映射以 UUID 字符串为键,并映射到一个 XRAnchor。
此映射由 XR
设备填充和存储,并且仅限于由
源上的任何 XRSession
创建且尚未销毁的持久锚点集合。
此映射的大小由用户代理决定。用户代理可以出于任何原因删除此映射中的条目。
例如,如果所有源的所有映射已达到系统锚点的最大数量,
用户代理可以释放一个条目以便为新请求的锚点腾出空间。
XRSession
被扩展为包含一个关联的 新锚点映射,该映射以 XRAnchor 对象
为键,并映射到
对象。
Promise<XRAnchor>
partial interface XRFrame {Promise <XRAnchor >(createAnchor XRRigidTransform ,pose XRSpace ); };space partial interface XRSession {readonly attribute FrozenArray <DOMString >;persistentAnchors Promise <XRAnchor >(restorePersistentAnchor DOMString );uuid Promise <undefined >(deletePersistentAnchor DOMString ); };uuid partial interface XRHitTestResult {Promise <XRAnchor >(); };createAnchor
XRHitTestResult
被扩展为包含一个关联的 原生实体。如果
底层系统未提供有关导致计算该结果的原生实体的信息,则将假定
原生实体设为 null。
应用可以通过以下 2 种方式之一创建锚点:
-
通过从帧创建锚点——创建的锚点将不会 附加到任何特定真实世界对象。
-
通过从命中测试结果创建锚点—— 如果底层 XR 设备支持, 创建的锚点将附加到真实世界对象。
为了从帧创建锚点,应用可以调用 XRFrame
的
createAnchor(pose, space)
方法。
XRFrame
frame 上以 pose 和 space 调用 createAnchor(pose, space)
方法时,必须运行以下步骤:
-
令 promise 为一个新的 Promise。
-
如果 frame 的 active 布尔值为
false,则用InvalidStateError拒绝 promise, 返回 promise,并中止这些步骤。 -
令 session 为 frame 的 session。
-
令 device 为 session 的 XR 设备。
-
令 effective origin 为 space 的有效原点。
-
令 anchor native origin 为从 device 调用以使用 pose 创建新锚点所返回的一个新原生原点,该 pose 被解释为在 frame 的时间相对于 effective origin 表达。
-
使用 anchor native origin 和 session 创建新锚点对象 anchor。
-
将 anchor 添加到 session 的被跟踪 锚点集。
-
将从 anchor 到 promise 的映射添加到 session 的新锚点映射。
-
返回 promise。
注:用户代理有责任确保
每次 createAnchor(pose, space)
调用返回的锚点所跟踪的物理原点,尽可能接近调用该方法的帧所表示的时间点上
space 中 pose 的物理位置。具体而言,这意味着对于
动态变化的空间,用户代理应尝试在应用指定的时间捕获此类空间的原生原点。
本文本是非规范性的,但表达了规范作者及贡献者的意图,因此强烈建议
实现遵循它,以确保不同厂商之间的行为一致。
persistentAnchors
返回已知持久锚点的列表。此列表必须反映持久锚点映射的键。
XRSession
session 上以 uuid 调用 restorePersistentAnchor(uuid)
方法时,必须运行以下步骤:
-
令 promise 为在此
XRSystem的相关领域中新建的 Promise。 -
如果 session 的持久锚点映射不包含 从 uuid 到
XRAnchor的映射, 则用InvalidStateError拒绝 promise, 返回 promise,并中止这些步骤。 -
如果 session 的
ended值为 `true`,则用InvalidStateError拒绝 promise, 返回 promise,并中止这些步骤。 -
令 anchor 为 session 的持久锚点映射上 来自 uuid 的映射的值。
-
如果 session 的新锚点映射包含从 anchor 到 promise 的映射,则用
InvalidStateError拒绝该 promise, 返回 promise,并中止这些步骤。 -
如果 session 的新锚点映射已达到用户代理 最大大小,则用
InvalidStateError拒绝 promise, 返回 promise,并中止这些步骤。 -
将 anchor 添加到 session 的被跟踪 锚点集。
-
将从 anchor 到 promise 的映射添加到 session 的新锚点映射。
-
返回 promise。
XRSession
session 上以 uuid 调用 deletePersistentAnchor()
方法时,必须运行以下步骤:
-
令 promise 为在此
XRSystem的相关领域中新建的 Promise。 -
如果 session 的持久锚点映射不包含 到 anchor 的映射,则用
InvalidStateError拒绝 promise, 返回 promise,并中止这些步骤。 -
令 anchor 为 session 的持久锚点映射上 来自 uuid 的映射的值。
-
从 session 的持久锚点映射中移除该映射。
-
在 anchor 上调用
delete()。 -
返回 promise。
为了从命中测试结果创建锚点,应用
可以调用 XRHitTestResult
的
createAnchor()
方法。
XRHitTestResult
hitTestResult 上调用 createAnchor()
方法时,必须运行以下步骤:
-
令 promise 为一个新的 Promise。
-
令 frame 为 hitTestResult 的 frame。
-
如果 frame 的 active 布尔值为
false,则用InvalidStateError拒绝 promise, 返回 promise,并中止这些步骤。 -
令 session 为 frame 的 session。
-
令 device 为 session 的 XR 设备。
-
令 nativeEntity 为 hitTestResult 的原生 实体。
-
令 anchor native origin 为从 device 调用以创建新锚点所返回的新原生原点, 该新锚点位于 hitTestResult 的原生原点,并在 frame 的时间附加到 nativeEntity。
-
使用 anchor native origin 和 session 创建新锚点对象 anchor。
-
将 anchor 添加到 session 的被跟踪 锚点集。
-
将从 anchor 到 promise 的映射添加到 session 的新锚点映射。
-
返回 promise。
注:存在于 createAnchor(pose, space)
方法上的相同说明同样适用于此处。
Session 的“帧更新列表” 可能需要一种指定顺序的方式——某些算法可能依赖其他算法。
5. 锚点更新
[Exposed =Window ]interface {XRAnchorSet readonly setlike <XRAnchor >; };partial interface XRFrame { [SameObject ]readonly attribute XRAnchorSet ; };trackedAnchors
XRAnchorSet
接口被引入,用作暴露锚点集合的一种方式。
XRFrame
被扩展为包含 trackedAnchors
属性,该属性包含帧中仍被跟踪的所有锚点。在 XRFrame
创建时,该集合初始为空,并将由更新锚点算法填充。
6. 锚点移除
当应用不再有兴趣接收某个锚点的更新时,它可以通过调用 delete()
来删除锚点。
7. 原生设备概念
为了使用户代理能够实现锚点 API,底层 XR 设备应对此特性提供原生支持。 本节描述对底层 XR 系统提出的要求,并且为使锚点 API 能够在各种 框架/设备之上实现,必然规定得不够详细。
7.1. 原生锚点
如果底层 XR 设备支持以下与锚点相关的能力,则它能够 支持anchors 特性:
-
可以创建原生锚点,并满足以下要求:
-
原生锚点由底层 XR 系统持续跟踪,并且通常可以查询其最新状态。 然而,可能存在其位置未知的帧,因此用户代理可以在一段时间内报告该姿态不可定位。 当底层系统认为原生锚点的位置再也不会被获知时,它应该报告该原生锚点 不再被跟踪。
-
可选地,原生锚点可以被附加到原生实体。附加到原生 实体的原生锚点会尝试将其位置保持为相对于所附加实体固定 (与自由浮动锚点相对于真实世界固定的情况相反)。当设备检测到锚点所附加对象的 姿态发生变化时,锚点也会相应更新。这并不意味着对象本身移动了—— 也可能是系统对其位置的理解发生了变化。如果底层系统能够跟踪移动对象, 附加到移动对象的原生锚点也应被更新。
如果底层设备不支持原生锚点,用户代理可以决定通过仿真原生锚点来实现
锚点 API。此方法假定锚点一经创建便永远不会改变其姿态,并且其姿态就是应用传入锚点
创建方法的姿态,例如 XRFrame
的
createAnchor(pose, space)
或 XRHitTestResult
的
createAnchor()。
注:仿真原生锚点
方法等价于应用自行仿真锚点特性,并且可以帮助减少应用需要处理的不同情况数量。
它还可能允许应用为 "immersive-ar"
和 "immersive-vr"
会话复用相同代码。
8. 隐私与安全考量
锚点 API 不会直接暴露对用户环境信息的访问。如果会话创建时启用了 hit-test 支持, 并且设备支持跟踪移动对象,则应用可能能够通过观察对象(例如被携带移动的对象)的 锚点姿态变化来推断用户环境的布局。这提供的信息级别与 命中测试 API 关于用户环境的信息类似。锚点特性在创建 XR 会话时必须声明, 这将允许用户代理通知用户允许网站使用锚点 API 的潜在隐私影响。
我不知道有支持跟踪 移动的一般对象的设备——规范是否应该考虑它们?是否有这类设备的示例?
9. 致谢
以下个人为 WebXR Anchors 规范的设计做出了贡献: