跳到主要内容

自然交互

自然交互是指让用户跟空间中的软件界面和虚拟内容交互时,就像跟现实世界的真实物体互动,不使用任何控制设备(比如 XR 手柄),只靠手和眼就做直观高效的交互。

这种自然交互有两种模式:

  1. 直接交互:采用最符合直觉的方式,用单手或双手直接接触虚拟内容元素。
  2. 间接交互:更高效,不用抬手接触,先用眼睛注视的方式在虚拟内容元素中做「选择」,然后捏合手指触发「确认」操作,捏住不放还可以进一步做拖拽、旋转、缩放等手势操作。

2D 内容交互

这两种自然交互模式在 2D 内容上产生的效果是等价的,都相当于在传统屏幕设备上做触屏交互的结果:在一个 HTML 元素上做直接交互(手指直接触控元素)或间接交互(先注视元素,再捏合手指),都会触发 Touch Events、Pointer Events,为了兼容旧网页代码,也会触发 Mouse Events 和 click 事件,这些 Web API 的行为完全等价于在传统屏幕设备上对网页做触屏交互。

以间接交互为例:

  1. 在手指捏合之前,眼睛注视位置的移动,不触发任何 JS 事件,也不触发 CSS 的 hover 状态,相当于在触屏交互中,手指还没接触到屏幕前的状态,网页代码完全不知道用户在做什么
  2. 在手指捏合然后立刻松开的过程中,会按顺序触发以下 JS 事件:
    1. 捏合瞬间,同时触发「接触」事件(pointerover)、「进入」事件(pointerenter)、「按下」事件(pointerdown)事件。只有在手指捏合的瞬间,网页才能通过这些事件获取交互对象和交互位置信息(知道眼睛在注视哪里)
    2. 接下来会触发「触摸开始」事件(touchstart
    3. 手指松开的瞬间,会同时触发「脱离」事件(pointerout)、「离开」事件(pointerleave)、「松开」事件(pointerup
    4. 接下来会触发「触摸结束」事件(touchend
    5. 为了保持对旧网页代码的兼容,接下来会模拟触发一系列鼠标事件,包括「接触」事件(mouseover)、「进入」事件(mouseenter)、「移动」事件(mousemove)、「按下」事件(mousedown)、「松开」事件(mouseup)。还会触发 CSS 的 hover 状态,这种状态由于是模拟出来的,要在跟其他元素交互后才会被解除
    6. 最后触发「点击」事件(click
  3. 如果手指捏合后未松开,这对手指的移动行为会在 touchstart 事件后持续触发以下事件,直到手指松开
    1. 「移动」事件(pointermove,手指移动对应初始交互位置的移动)
    2. 「触摸移动」事件(touchmove

Hover Effect

在间接交互模式下,在手指捏合之前,由于网页不知道眼睛在注视哪里,不会触发任何 JS 事件,也不会改变 CSS 状态,因此无法用网页代码实现 Hover Effect,需要由 Spatial Runtime 统一负责在被注视的 HTML 元素上自动渲染 Hover Effect。

为此,Spatial Runtime 需要知道网页当前可见区域中有哪些「Interactive Region」。

凡是在桌面浏览器里会让鼠标指针变成 pointer 形状的 HTML 元素,都会被自动识别为 Interactive Region,包括:

  1. 链接元素(<a>
  2. 表单交互元素(<button><input><select> 等)
  3. 用 Web 标准里的可访问性 API(ARIA)设置成跟上述元素语义等价的元素(比如 <div role="button">
  4. 通过 CSS 样式 cursor: pointer 主动把鼠标指针设置为 pointer 形状的 HTML 元素

空间交互

不同于平面内的 2D 内容,空间化 HTML 元素都被视作悬浮在空间中的 2D 面片,可以在 3D 空间的 X/Y/Z 三个方向上定位和移动,可以在空间中旋转,交互命中的范围也从平面上的点变成了空间中 2D 面片和 3D 网格上的点。

Web 标准中现有的 JS 交互事件只能命中这些空间对象或 3D 内容投影到 2D 平面上的点,只能获取 X/Y 轴位置,无法实现 3D 空间范围中的交互。

因此,Spatial Runtime 统一定义和实现了新的空间手势,WebSpatial SDK 目前支持单击、拖拽、旋转、缩放这四种空间手势:

TypeEvent NameReact APIEvent Results
Spatial TapspatialtaponSpatialTapSpatialTapEvent
Spatial Dragspatialdragstart
spatialdrag
spatialdragend
onSpatialDragStart
onSpatialDrag
onSpatialDragEnd
SpatialDragStartEvent
SpatialDragEvent
SpatialDragEndEvent
Spatial Rotatespatialrotate
spatialrotateend
onSpatialRotate
onSpatialRotateEnd
SpatialRotateEvent
SpatialRotateEndEvent
Spatial Magnifyspatialmagnify
spatialmagnifyend
onSpatialMagnify
onSpatialMagnifyEnd
SpatialMagnifyEvent
SpatialMagnifyEndEvent