Microtube 文档
EN中文
开发者 / Unity / SDK 架构与 API

SDK 架构与 API

了解 HEXR Unity SDK 的组成结构、手套如何连接、交互如何转化为触觉反馈,以及如何在你自己的代码中驱动手套。

SDK 版本

本页介绍 com.microtube.hexr 0.9.4 版本,发布于 2026 年 10 月 11 日。早期版本请参阅更新日志。

插件包结构

插件包采用分层结构:你的场景与最上层交互,手套位于最底层。两个后端层只有在安装了对应的 XR SDK 时才会编译,核心层从不依赖它们。

程序集命名空间包含内容编译条件
HaptGlove.RuntimeHaptGloveHaptGloveHandler、蓝牙传输层、Haptics 命令构建器始终
HexR.RuntimeHexR管理器、手部追踪、Pressure Controller(压力控制器)、触点、场景组件、HexR 菜单始终
HexR.Runtime.MetaOVRHexR.MetaOVRMeta 抓取与戳按检测、可交互对象事件、透视已安装 Meta Interaction SDK
HexR.Runtime.OpenXRHexR.OpenXRXR Interaction Toolkit 集成(OpenXR 头显,包括 PICO)已安装 XR Interaction Toolkit
HexR.EditorHexRHexR 菜单、Auto Setup、验证器、HexR Tools 窗口仅限编辑器

后端在加载时会自动向核心层注册。碰撞体可视化工具、HexRUsable 和 HexR 菜单保留在全局命名空间中,以便旧场景仍可正常运行。

HEXR 场景

HexR → Create HexR Rig 会添加前两项,第三项由你的 XR SDK 提供。

对象组件作用
HexR MainHexRManager管理两只手套、处理连接,并在场景切换后重新关联双手。可通过 HexRManager.Instance 访问
Left / Right Hand PhysicsHaptGloveHandler、HexRTrackedHand、FingerUseTracking每只手一个:负责蓝牙连接、指定跟随哪只被追踪的手,以及记录每根手指的弯曲程度
HexR Floating MenuHexRFloatingMenu头显中的 HexR 菜单:连接手套、显示触点、查看每根手指的触觉反馈、切换场景和演示。用指尖按压操作
Left / Right Pressure ControllerPressureTrackerMain该手的触觉控制器
每个场景都需要一对处于激活状态的 Pressure Controller(压力控制器)

场景启动时,触点会按名称查找它们。没有 Pressure Controller 的手不会产生任何触觉反馈。使用 HexR → Add Pressure Controller 即可添加。

被追踪的手

HexRTrackedHand.handRoot 指向你的 SDK 提供的手。HEXR 按名称查找各个关节:

XR SDK手部根节点关节
Meta Interaction SDKOpenXRLeftHand / OpenXRRightHandXRHand_IndexTip、XRHand_Palm、…
XR Interaction Toolkit + XR HandsLeft / Right Hand Interaction Visual 下的 L_Wrist / R_WristL_IndexTip、L_Palm、…

每个触点由一个小型触发碰撞体、一个运动学(kinematic)Rigidbody(Unity 需要它来产生触发事件)和一个标明所属手和手指的 HapticFingerTrigger 组成。HEXR 没有自己的手模型:自 0.9 起,在所有后端上,触点都直接位于被追踪的手上。仍带有「幽灵」手的旧项目可以通过 HexR → Migration → Remove Ghost Hand 将其移除。

连接手套

蓝牙连接由你的应用自行建立,无需在系统设置中配对,也无需配套应用。每只手套都有各自的 HaptGloveHandler。

应用运行平台蓝牙
Android 头显(Meta Quest、PICO)支持;装置(rig)的默认设置
Windows(Unity 编辑器和 64 位构建)支持。在构建版本中,将每个 HaptGloveHandler 上的 Build Platform 设置为 Window。在编辑器中,请通过 HexR Haptics Tester 连接,它会为 Play 模式自动完成此设置
macOS、iOS、Linux、HoloLens(UWP)插件包不支持。包内虽附带一个 macOS 蓝牙库,但目前尚无任何代码调用它

包括头显在内的完整列表,请参阅平台与头显支持。

事件

这些是 HaptGloveHandler 上的公共 UnityAction 字段。使用 += 订阅,使用 -= 取消订阅。切勿使用 = 赋值:这会移除 HexRManager 所依赖的处理函数。它们不是 UnityEvent,因此不会显示在 Inspector 中。

事件触发时机
onBluetoothConnected(HandType)手套已连接
onBluetoothConnectionFailed(HandType)连接尝试失败
onBluetoothDisconnected(HandType)连接已关闭:手套掉线、你主动断开连接,或应用正在关闭
onPumpAction(HandType, bool)供气已启动或停止
onBatteryStateChange(BatteryState)Full、Medium 或 Low
onDeviceFound(id, name)扫描发现了设备
HexRManager.ConnectAttemptEnded静态事件。连接尝试结束但未能建立连接时触发:权限被拒绝,或某次尝试失败(包括随后会重试的尝试)。连接成功时不会触发;成功连接请使用 onBluetoothConnected

触觉如何触发

触发用途示例
XR 交互事件在抓取或悬停时感受物体HexRInteractableHaptics
物理接触感受表面、液体、心跳SpecialHaptics
你的代码游戏事件、序列、测试PressureTrackerMain

延迟

从应用中发生事件到用户产生触感,所需时间是三段延迟之和。之所以分开列出,是因为只有最后一段由手套决定,另外两段取决于你的设置。

阶段过程耗时
1 · 从应用到蓝牙射频在 Quest 和 PICO 构建中,包内的两个预置装置都开启了 Quest BLE Buffering:命令会先被收集起来,每 100 ms 最多合并为一次蓝牙写入发送,并在 Unity 的固定更新中进行检查。在 Windows 上以及在 Python 中,每条命令在你发送时都会立即写入在开启缓冲的 Quest 和 PICO 上最多约 100 ms
2 · 蓝牙手套请求 7.5 ms 的连接间隔;实际使用的间隔由手机、头显或 PC 决定。Android 和 Python 使用带响应的写入方式,需等待手套响应由主机决定;未经测量
3 · 手套压力命令到达后,气泵会在一个 20 ms 控制周期内开始驱动,然后逐渐升至目标压力。在最快的 speed(1)下,每升高 10 kPa 约需 60 ms:达到最轻强度约需 90 ms,达到最强约需 300 ms;speed 为 0.1 时,耗时为其十倍。5 Hz 及以上的振动会在控制循环的下一轮开始。释放命令会立即停止气泵依据固件源代码得出;非实测数据

当前手套的端到端延迟(从你的事件发生到用户感受到触感的时间)尚未经过测量,本文也不提供相关数值。如果你的应用依赖这一指标,请在你自己的环境中进行测量。

Quest BLE Buffering 是一种取舍

开启缓冲后,蓝牙写入次数更少、每次写入的数据更多,代价是最多需等待 100 ms。关闭缓冲(HexRManager 上的 Quest BLE Buffering 设置)后,每条命令都会立即写入,但在 Android 上连续发送的命令可能会丢失。该设置仅在 Quest 上测试过;如果 PICO 构建能够连接,但触感迟滞或没有反应,请分别尝试开启和关闭。

手部靠近检测

Pressure Controller(压力控制器)只有在 IsHandNear() 为 true 时才会发送大部分触觉反馈。满足以下任一条件即为 true:

信号设置来源
正在抓取,或悬停准备抓取你的 SDK 的抓取交互器:Meta 的 HandGrabInteractor,或 XRI 的 XRDirectInteractor 或 NearFarInteractor(自 0.9.4 起)。由 Auto Setup 以及每次场景加载时自动连接。对于 Near-Far Interactor,只有近距离抓取才算数,其悬停也仅在关闭远距离投射(far casting)时才算数:沿射线从房间另一头抓取的物体不会让手套施压
正在戳按,或即将戳按你的 SDK 的戳按交互器:Meta 的 PokeInteractor 或 XRI 的 XRPokeInteractor,连接方式相同
指尖位于 ProximityCheck 区域内你添加到交互器未覆盖的对象上的 ProximityCheck。指尖离开后,该状态会保持 0.5 s(即 clearDelay 的默认值)

这三项结果是每个 PressureTrackerMain 上的公共字段:HandGrabbing、PokeHovering 和 CollisionNearHand。检测方法本身 IsHandNear() 是私有的。该检测按手进行:任意位置出现一个信号,就会为该手上所有受检测限制的调用放行。

受检测不受检测
Single…Haptic、TriggerAll…、TriggerCustom…、TriggerPinchPressureHapticFingerTrigger.TriggerFixPressure、所有 SpecialHaptics 效果、将 ByPassHandCheck 设为 true 的 CustomSingleHaptics / CustomSingleVibrations、RemoveAllHaptics、RemoveAllVibrations 以及各个 Remove…Haptics 调用

通过受检测调用执行的释放操作同样会受到检测:如果手已经离开,RemovePinchPressure() 以及最后一个参数为 false 的 CustomSingleHaptics 都会被丢弃。请使用 RemoveAllHaptics()、Remove…Haptics() 调用,或将最后一个参数设为 true 来释放。

如果你的调用没有任何效果,请选中 Pressure Controller(压力控制器),将 Inspector 切换到 Debug 模式并观察它的三个标志;或者在测试时为 ByPassHandCheck 传入 true。

通道与参数

共有六个通道:Haptics.Finger.Thumb、Index、Middle、Ring、Pinky、Palm。每个通道同一时间只播放一种模式。超出范围的数值会被限制在范围内。

模式手感参数
压力持续稳定的按压intensity 0.1–1(约 15–50 kPa);speed 0.1–1,表示压力上升的速度
振动通断交替的压力脉冲frequency 0.1–40 Hz;intensity 0.1–1。低于 5 Hz 时,强度决定脉冲压力;从 5 Hz 起,强度决定脉冲时长
慢脉冲波形可调的缓慢节奏frequency 0.1–2 Hz;intensity;peakRatio 0.2–0.8;speed;endIntensity(低于 0.1 时释放)
计数脉冲指定次数的脉冲frequency;intensity;pulseCount 1–1000

场景组件以 10–60 的刻度表示强度(10 几乎感觉不到,60 则很有力),并将其换算为上文 0.1–1 的强度值。在你自己的代码中,可使用 PressureTrackerMain.StrengthToIntensity(strength) 进行同样的换算。

释放手套

手套会一直保持最后一条命令,直到收到新的指令;手套本身不会自动释放。插件包对此的处理方式如下:

触发时机过程
组件被禁用或销毁HexRInteractableHaptics、HexRPhysicalButton、HexRGrabbable 和 SpecialHaptics 会释放它们施压的通道。后两者自 0.9.4 起支持;SpecialHaptics 区域只释放自己的通道,不会释放其他组件的通道
应用退出,包括在编辑器中停止 Play 模式先释放两只手套上的所有通道,再关闭连接。自 0.9.4 起
应用暂停:摘下头显,或应用切换到后台在 HaptGloveHandler.releaseWhenPaused 开启时(默认开启),释放所有通道。恢复运行后效果不会自动恢复,下一次发生变化时才会重新施加。自 0.9.4 起
你主动断开连接:调用 Disconnect(hand),或使用菜单中的开关先释放手套,再关闭连接。自 0.9.4 起
应用崩溃或被强制关闭无法发送任何命令,手套会持续施压
蓝牙连接中断无法发送任何命令。手套会持续施压,并且在 Android 上处理器重连时不会释放。请参阅重连时释放
如果手套持续施压

请关闭手臂模块电源。断连时自动释放只能由手套固件实现,而目前的固件并不具备这一功能。在你自己的代码中,施加了什么就要释放什么(在 OnDisable 中也要释放),或者在手套处理器上调用 ReleaseAllChannels()。

场景组件

大多数项目根本不需要调用 API,这些组件会自行触发触觉反馈。

组件用途关键字段
HexRInteractableHaptics — 从这里开始在抓取或悬停时感受你的 SDK 自带的可交互对象(XRI 或 Meta)。后端会自动选择。禁用时释放其通道fireOn Select / Hover / SelectAndHover;各手指开关;strength 10–60;followGrip,根据手指的闭合程度在 minStrength 和 strength 之间缩放强度(两者均在 0.9.4 中修复);backend
SpecialHaptics被触碰时播放预设效果的触发碰撞体。不受手部靠近检测限制RPressureTracker 和 LPressureTracker(必填:可由 Auto Find Hand Physics 自动填充)、TypeOfHaptics(见下表)、HapticPressure、VibrationsFrequencyValue、InTimer / OutTimer
ProximityCheck告知 Pressure Controller(压力控制器)手正靠近一个不属于 SDK 可交互对象的物体Auto Set Up 按钮会自动连接两个 Pressure Controller
HexRPhysicalButton由真实指尖按压的按钮,无需任何 SDK。HexR 菜单就是用它构建的onPressed;可触发的手指(默认为食指)
HexRUsable扳机、把手、握把:所选手指弯曲时触发事件。自 0.9.4 起支持两种后端,之前仅支持 OpenXRUseThreshold;WhenUseTriggerEvents / WhenStopUsingTriggerEvents
HapticFingerTrigger即触点本身。在你自己的 OnTriggerEnter 中读取它,即可得知是哪只手的哪根手指发生了触碰handType、fingertype;TriggerFixPressure、TriggerVibrationPressure、RemoveHaptics
HexRGrabbableHEXR 自带的抓取功能,无需交互 SDK,手套的手即可拾取。直接发送到手套,不经过手部靠近检测。在 0.9.4 之前,没有父对象时它会在启动时抛出异常,其触觉反馈也会在抓取时抛出异常PinchGrab / PalmGrab;HapticStrength 10–60;需要 Rigidbody 和触发碰撞体
SpecialHaptics 效果手感
CustomHaptics触碰期间持续施加压力
CustomVibrations以设定的频率和强度振动
FountainEffect流水
RainDropEffect雨滴落在手掌上
HeartBeatEffect心跳,规律或不规律
HandSqueezeEffect当手在该区域内握拢时触发 OnSqueezeEventTrigger。需要在装置(rig)的手上添加 FingerUseTracking

我需要哪个组件?

你想要……应用补充说明
在 XR SDK 抓取、戳按或悬停于物体时感受该物体在 SDK 的可交互对象旁添加 HexRInteractableHaptics物体本身或其子对象上必须有 XRI 或 Meta 可交互对象,否则不起作用。将 Backend 保持为 Auto
让某个表面或区域带来特定触感,例如水、雨、心跳、嗡嗡振动在触发碰撞体上添加 SpecialHaptics仅凭接触即可触发,不受手部靠近检测限制,因此无需 ProximityCheck
无需 SDK,用指尖按下的按钮HexRPhysicalButton需要触发碰撞体
手指弯曲时执行某个动作HexRUsable自 0.9.4 起支持 Meta 和 OpenXR。更早的版本通过 L_ / R_ 关节名区分左右手,而 Meta 的骨骼并不使用这些名称
在装置的抓取和戳按交互器覆盖不到的物体上,使用受手部靠近检测约束的触觉添加 ProximityCheck点击它的 Auto Set Up。它本身不会触发任何触觉
在你自己的代码中精确控制PressureTrackerMain 方法施加的触觉记得释放——参见触发反馈

组合使用组件

组合结果
HexRInteractableHaptics + ProximityCheck可行。仅当装置的交互器不向手部靠近检测提供输入时才需要,例如在开启远距投射(far casting)的 Near-Far 装置上由悬停触发的触觉,或 0.9.4 之前的任何 OpenXR 装置;其他情况下属于多余
可抓取物体上的 SpecialHaptics 区域可行。PICO 教程中的心跳就是这样实现的
SpecialHaptics + ProximityCheck可行但没有必要。该区域本身不受检测限制;而当手位于区域内时,ProximityCheck 还会为该手的其他所有受检测约束的调用放行
HexRInteractableHaptics + 同一可交互对象上调用 Pressure Controller(压力控制器)的 UnityEvent避免。两者驱动相同的通道,以最后运行的为准;Inspector 会对此发出警告
HexRInteractableHaptics + HexRGrabbable避免。两套独立的抓取系统都会移动物体,并且都会发送触觉

手部靠近检测按手计算,而不是按物体计算:任何位置上的一次抓取、悬停或 ProximityCheck,都会为该手上所有受此检测约束的调用放行。

C# API

如果你想用自己的逻辑驱动触觉,请调用这些方法。

PressureTrackerMain — 位于每个 Pressure Controller(压力控制器)上

方式作用
CustomSingleHaptics(finger, States, TargetPressure, Speed, ByPassHandCheck)对单个通道施加压力。States 为 true 时施加,为 false 时释放;TargetPressure 和 Speed 取值 0.1–1。使用命名参数时,必须与这些名称完全一致
CustomSingleVibrations(finger, States, TargetPressure, frequency, ByPassHandCheck)单个通道振动;frequency 取值 0.1–40 Hz
SingleThumbHaptic(float) … SinglePalmHaptic(float)对单个通道施加 0.1–1 的压力。只有一个 float 参数,因此可以连接到 UnityEvent
RemoveThumbHaptics() … RemovePalmHaptics()释放单个通道
TriggerAllHapticsIncrease(float) / TriggerAllVibrations(frequency)同时作用于所有通道
TriggerCustomHapticsIncrease(bool[6], pressure, speed) / TriggerCustomlVibrations(bool[6], intensity, frequency)选定的一组通道,按 Thumb…Palm 的顺序排列
TriggerPinchPressure(float) / RemovePinchPressure()拇指与食指捏合。释放操作同样受检测约束,因此如果手可能已经离开,请配合 RemoveAllHaptics() 使用
RemoveAllHaptics() / RemoveAllVibrations()全部释放。永远不会被手部靠近检测拦截;两者都发送,以确保所有通道均已关闭
HandGrabbing, PokeHovering, CollisionNearHand手部靠近检测的三个输入。你只需读取它们;它们由 Auto Setup 和场景组件负责设置
StrengthToIntensity(strength)静态方法。将组件使用的 10–60 强度刻度转换为这些方法所接受的 0.1–1 强度。自 0.9.4 起
TrackedHandRoot装置这一侧所跟随的被追踪的手;找到之前为 null。自 0.9.4 起

HexRManager — HexRManager.Instance

成员作用
Connect(hand)连接该手套,包含权限请求,并遵循一次只连接一只手的规则。如果已连接或正在连接,则不执行任何操作;不需要 HexR 菜单。hand 为 HaptGloveHandler.HandType.Left 或 Right。自 0.9.4 起
Disconnect(hand)先释放该手套,再断开连接。未连接时不执行任何操作。自 0.9.4 起
IsConnected(hand), IsConnecting(hand)当前是否已连接;是否正在连接(包括等待权限或重试)。自 0.9.4 起
ConnectLeftBT() / ConnectRightBT()菜单按钮所调用的方法。作用为切换:对已连接的手套会断开连接,在重试期间则会取消。在代码中请优先使用 Connect(hand)。0.9.4 之前,如果场景中没有 HexR 菜单,调用这些方法会抛出异常
leftHand / rightHand每只手套的 HaptGloveHandler
XRFrameworkOpenXR 或 MetaOVR
RebindHandsToCurrentScene()将触点重新挂接到当前场景的手上。每次加载场景时都会自动运行
碰撞体设置Auto Setup 所添加触点的尺寸和位置,按骨骼分别设置
ConnectAttemptEnded静态事件:一次连接尝试已结束,但未能建立连接。参见事件

HaptGloveHandler — 每只手套一个,命名空间为 HaptGlove

成员作用
whichHandLeft 或 Right
BTConnection()连接;如果已连接则断开连接。建议优先使用管理器的 Connect(hand),它会额外处理权限请求,并遵循一次只连接一只的规则
IsConnecting正在连接中,包括两次重试之间的等待。自 0.9.4 起
ReleaseAllChannels(), ReleaseChannels(params Haptics.Finger[])一次写入即可关闭通道,振动和压力都会关闭。手套未连接时不会发送任何内容。自 0.9.4 起
releaseWhenPaused应用暂停时释放所有通道。默认开启。自 0.9.4 起
bleConnected当前是否已连接?
UseCustomDeviceName, OptionalCustomDeviceName按你指定的名称查找手套
RememberDevice(id), ForgetDevice(), ConnectToDevice(id)直接连接到哪只手套
haptics构建命令:HEXRPressure、HEXRVibration、HEXRPulse。GetChannelState(finger) 返回上一条命令对某个通道的设置,类型为 ChannelState(HapticMode、强度、频率)
BTSend(byte[])直接向手套发送命令。跳过手部靠近检测
GetBatteryLevel(), GetAirPressure()最新的电量和压力读数

HexRTrackedHand 和 FingerUseTracking — 位于每只手上

成员作用
HexRTrackedHand.handType, handRoot哪只手,以及它所跟随的被追踪的手
ResolveRawFingerJoint(finger), ResolveRawPalmJoint()指尖或手掌关节,两种骨骼均适用
FingerUseTracking.ThumbUse … LittleUse0 = 完全弯曲,1 = 完全伸直。自动校准:手张开并握拢一次后即趋于稳定
FingerUseTracking.isHandOpen()是否所有手指都已伸直?

场景切换与编辑器工具

SDK 的手会随所在场景一起销毁,而装置会一直保留。因此每次加载场景后,管理器都会重新挂接:

随后日志会显示 [HexR] Rebound Left hand … 6 haptic trigger(s):即五个指尖和手掌。

Auto Setup 会在编辑器中完成同样的工作,结果随场景一起保存。它只添加缺少的部分,绝不会移动你调整过的碰撞体。你可以通过 Create HexR Rig、HexR → Troubleshoot → Re-run Auto Setup 或管理器上的 Auto Set Up HexR 按钮运行它。之后,Validate Scene Setup 会报告仍未连接好的部分。

菜单作用
HexR → HexR Tools工具窗口,包含三个标签页:HexR Haptics Tester(在播放模式下连接手套、触发任意通道、查看实时压力,以及 All OFF)、HexR Setup(以检查清单形式呈现的验证器,带有 Fix all)、Project Setup(选择 OpenXR、Meta OVR 或 PICO,并安装对应的包)
HexR → Create Demo Scene装置、Pressure Controller(压力控制器)、一个可抓取物体和一个触觉区域
HexR → Create HexR Rig为你的后端创建装置和 Pressure Controller(压力控制器),然后运行 Auto Setup
HexR → Add Pressure Controller一对 Pressure Controller(压力控制器)
HexR → Add HexR Menu在你自己的场景中添加 HexR 菜单
HexR → TroubleshootRe-run Auto Setup、Validate Scene Setup
HexR → Migration一次性升级操作,例如 Remove Ghost Hand
HexR 菜单 → Show Colliders在被追踪的手上绘制所有触点
HexR 菜单 → HAPTICS每只手套各手指和手掌最近一次收到的数值(已限制在有效范围内):开启时高亮,结束后变暗。可通过 showHapticsReadout 关闭

类型索引

com.microtube.hexr 中的所有公共类型,便于按名称查找。如果上文已有章节介绍,链接会指向该章节。

组件

类型说明
HexRManager装置(rig):两只手套、连接、重新挂接手部。成员
HaptGloveHandler单只手套的蓝牙连接与命令发送器。成员
PressureTrackerMainPressure Controller(压力控制器):一只手的所有触觉都经由它发送。方法
HexRTrackedHand, FingerUseTracking手套跟随哪只被追踪的手,以及每根手指的弯曲程度。成员
HapticFingerTrigger每个指尖和手掌上的触点。场景组件
HexRInteractableHaptics为你所用 SDK 自带的可交互对象添加触觉。场景组件
HexRGrabbableHEXR 自带的抓取功能,无需交互 SDK,直接由戴手套的手完成。场景组件
SpecialHaptics, ProximityCheck, HexRPhysicalButton, HexRUsable预设效果、手部靠近检测区域、指尖按钮、弯曲手指即可使用。场景组件
HexRFloatingMenu头显内的面板。HEXR 场景
HaptGloveCollidersVisualizer绘制触点;菜单中的 Show Colliders 使用的就是它。SetVisible(bool)、IsShowing
HaptGloveUI位于 HexR Main 上:将 Connect 按钮的点击转发给管理器的 ConnectLeftBT() / ConnectRightBT()。为兼容旧版面板而保留;它本身不更新任何文本
SceneLoader应用的场景切换。与 HexRManager 位于同一个常驻对象上
HexRGripByHandOpenXR:在不替换原生 XRGrabInteractable 的前提下,为它提供每只手各自的握持点,以及捏合或握拳两种抓握方式。GripMode 用于选择抓握方式
OpenXRHandNearSource, MetaOVRHandNearSource根据抓取和戳按交互器为手部靠近检测提供输入。由 Auto Setup 自动添加
OpenXRBackendSetup, MetaOVRBackendSetup在编辑器中和运行时,将这些输入源连接到 Pressure Controller(压力控制器)上。无需你自己添加任何内容
MetaOVRPassthrough, IHexRPassthroughMeta 上的透视功能,以及菜单在场景加载后用于刷新任意后端透视的接口

枚举与取值

类型取值及使用位置
Haptics命令构建器,位于 HaptGloveHandler.haptics 上。通道与参数
Haptics.FingerThumb, Index, Middle, Ring, Pinky, Palm
Haptics.HapticMode, Haptics.ChannelState上一条命令对某个通道的设置:Off、Pressure、Vibration 或 Pulse,以及强度和频率。通过 GetChannelState(finger) 获取
HandTypeLeft / Right,用于 HaptGloveHandler 和 HapticFingerTrigger
FingerTypeHapticFingerTrigger 对应哪根手指,见 fingertype
BatteryStateFull、Medium、Low。事件
TargetPlatform手套处理器的 Build Platform:Android 或 Window(拼写末尾没有 s)。连接手套
FireOnHexRInteractableHaptics.fireOn:Select、Hover、SelectAndHover
HexRBackendChoice由哪个交互 SDK 驱动组件:Auto 或指定名称的后端
HexRHandSide某次交互来自哪只手(以后端报告的为准)
HeartBeatSpecialHaptics 心跳:Regular 或 Irregular
Options, OptionHexRGrabbable.Options PinchGrab / PalmGrab;HexRGrabbable.Option 重力 On / Off;HexRManager.Options 即 XRFramework
FingertipCenters管理器碰撞体设置中各手指触点的偏移量

后端底层、编辑器与内部实现

类型说明
IHexRInteractionBackend, IHexRInteractionBinding, IHexRInteractionSink, HexRInteractionBackends, HexRHandSideResolverXR SDK 接入 HEXR 的方式。仅在添加你自己的后端时才需要
HexRCompat为在 2022.3 与 Unity 6 之间改名的 Unity API 提供的替代实现。参见Unity 版本支持
HexRMenu, HexRAutoSetup, HexRSetupValidator, SetupCheck, HexRToolsWindow编辑器:HexR 菜单、Auto Setup、Validate Scene Setup 和 HexR Tools 窗口。编辑器工具
HexRSettingEditorGUI, HexRInteractableHapticsEditor, HapticEffectControllerEditor, ProximityCheckEditor, FingerUseTrackingEditorSetting编辑器:HexRManager、HexRInteractableHaptics、SpecialHaptics、ProximityCheck 和 FingerUseTracking 的 Inspector
BLE, BLEScan, BLEData, Characteristic, Service, DeviceUpdate, ErrorMessage, ScanStatus, Encode, Decode, FunIndex, AndroidUiThread内部:HaptGloveHandler 底层的蓝牙层。不应直接使用;请通过手套处理器或 Pressure Controller(压力控制器)调用

Python

在 Unity 之外,HaptGlovePython 可以构建同样的命令,再由你用 bleak 写入手套。它需要 Python 3.8 至 3.13。安装设置和经过测试的示例请见Python 指南。

方式作用
hexr_pressure(finger, state, intensity, speed)对单个通道施加压力。state 为 True 时施加;为 False 且强度为 0 时释放
hexr_pressure_multiple(fingers, states, intensities, speeds)一次写入即可对多个通道施加压力;intensities 和 speeds 取值 0.1–1。所有状态均为 False 且强度均为 0 时释放这些通道
hexr_vibrations(finger, state, frequency, intensity, peakRatio, speed, endIntensity)慢速脉冲,0.1–2 Hz。hexr_vibrations_multiple 接受列表参数
AddressDiscovery.py, CharacteristicDiscovery.py, ExampleHaptics.py查找你的手套,列出它公开的特征,运行现成的示例
手指是枚举成员

请使用 Haptics.Finger.Index,而不是 "Index"。传入字符串会引发 AttributeError。

复制即用的示例

针对最常见需求的完整脚本。每个脚本都可以基于 com.microtube.hexr 0.9.4 编译通过。如果只是想在抓取物体时感受到它,完全不需要写代码:给物体添加 HexRInteractableHaptics 即可。

通过代码连接两只手套

无需 HexR 菜单。将它放在场景中的任意对象上即可。在编辑器中,请改用 HexR Haptics Tester 进行连接——参见连接手套。

csharp
using UnityEngine;
using HaptGlove;
using HexR;

// Connects both gloves when the scene starts -- no HexR menu needed --
// and logs each one as it comes up or drops.
public class ConnectGloves : MonoBehaviour
{
    void Start()
    {
        HexRManager rig = HexRManager.Instance;
        rig.leftHand.onBluetoothConnected += OnConnected;
        rig.rightHand.onBluetoothConnected += OnConnected;
        rig.leftHand.onBluetoothDisconnected += OnDisconnected;
        rig.rightHand.onBluetoothDisconnected += OnDisconnected;

        // Does nothing for a glove that is already connected or connecting.
        rig.Connect(HaptGloveHandler.HandType.Left);
        rig.Connect(HaptGloveHandler.HandType.Right);
    }

    void OnDestroy()
    {
        HexRManager rig = HexRManager.Instance;
        if (rig == null) return;
        rig.leftHand.onBluetoothConnected -= OnConnected;
        rig.rightHand.onBluetoothConnected -= OnConnected;
        rig.leftHand.onBluetoothDisconnected -= OnDisconnected;
        rig.rightHand.onBluetoothDisconnected -= OnDisconnected;
    }

    void OnConnected(HaptGloveHandler.HandType hand) { Debug.Log(hand + " glove connected"); }
    void OnDisconnected(HaptGloveHandler.HandType hand) { Debug.Log(hand + " glove disconnected"); }
}

在你自己的事件中按压手指

将一个 Pressure Controller(压力控制器)拖入 Hand,然后将 Press 和 Release 连接到任意 UnityEvent。

csharp
using UnityEngine;
using HaptGlove;
using HexR;

// Wire Press() and Release() to any UnityEvent: a button, a trigger, an
// animation event. Strength is on the same 10-60 scale as the components'.
public class PressOnEvent : MonoBehaviour
{
    public PressureTrackerMain hand;                  // a Pressure Controller
    public Haptics.Finger finger = Haptics.Finger.Index;
    [Range(10f, 60f)] public float strength = 30f;

    bool pressing;

    public void Press()
    {
        float intensity = PressureTrackerMain.StrengthToIntensity(strength);
        // true skips the hand-near check: this press answers your event, not a touch.
        hand.CustomSingleHaptics(finger, true, intensity, 1f, true);
        pressing = true;
    }

    public void Release()
    {
        if (!pressing) return;
        hand.CustomSingleHaptics(finger, false, 0f, 1f, true);
        pressing = false;
    }

    // Disabled, or the scene changes, mid-press: let go as well.
    void OnDisable() { Release(); }
}

按压触碰到物体的手指

适用于任何带有触发碰撞体的物体。触点上的 HapticFingerTrigger 会告知是哪只手的哪根手指发生了触碰,因此该脚本无需单独配置 Pressure Controller(压力控制器)。

csharp
using System.Collections.Generic;
using UnityEngine;
using HexR;

// On a trigger collider: presses exactly the finger or palm that touches it,
// on the hand it belongs to, and releases it when it leaves.
[RequireComponent(typeof(Collider))]
public class PressWhereTouched : MonoBehaviour
{
    [Range(0.1f, 1f)] public float intensity = 0.5f;

    readonly HashSet<HapticFingerTrigger> touching = new HashSet<HapticFingerTrigger>();

    void OnTriggerEnter(Collider other)
    {
        if (!other.TryGetComponent(out HapticFingerTrigger touch)) return;
        touch.TriggerFixPressure(intensity);   // 0.1-1, skips the hand-near check
        touching.Add(touch);
    }

    void OnTriggerExit(Collider other)
    {
        if (!other.TryGetComponent(out HapticFingerTrigger touch)) return;
        touch.RemoveHaptics();
        touching.Remove(touch);
    }

    // Disabled while a finger is inside: release what is still pressed.
    void OnDisable()
    {
        foreach (HapticFingerTrigger touch in touching)
        {
            if (touch != null) touch.RemoveHaptics();
        }
        touching.Clear();
    }
}

重新连接时释放

连接中断的手套仍会保持最后一条命令所设定的按压。此脚本会在手套重新连接后立即将其释放。

csharp
using UnityEngine;
using HaptGlove;
using HexR;

// A glove whose Bluetooth link dropped keeps its last pressure. When it
// reconnects, release everything before anything else is sent.
public class ReleaseOnReconnect : MonoBehaviour
{
    void Start()
    {
        HexRManager.Instance.leftHand.onBluetoothConnected += ReleaseAll;
        HexRManager.Instance.rightHand.onBluetoothConnected += ReleaseAll;
    }

    void OnDestroy()
    {
        if (HexRManager.Instance == null) return;
        HexRManager.Instance.leftHand.onBluetoothConnected -= ReleaseAll;
        HexRManager.Instance.rightHand.onBluetoothConnected -= ReleaseAll;
    }

    void ReleaseAll(HaptGloveHandler.HandType hand)
    {
        HaptGloveHandler glove = hand == HaptGloveHandler.HandType.Left
            ? HexRManager.Instance.leftHand
            : HexRManager.Instance.rightHand;
        glove.ReleaseAllChannels();
    }
}

下一步

要集成到现有应用中?请先从 HexRInteractableHaptics 入手,再考虑更底层的 PressureTrackerMain 或 HaptGloveHandler。