1. 先搞清楚框架怎么分工Interactor、Interactable 与 Input Action 的三角关系刚开始做 Unity XR Interaction Toolkit后面统一叫 XRI手柄交互的人最容易犯的一个错误是装好包、拖好预设体就开始找抓取按钮在哪。实际上 XRI 把一次完整的交互拆成了三层每一层各管一摊你只改某一层另外两层没配合好结果就是白忙活。第一层是 Interactor可以理解成手的抽象。XRI 里有三类XR Ray Interactor射线手负责隔空指、XR Direct Interactor直接手负责贴脸碰、XR Socket Interactor槽位手负责接住东西。它们的共同点是都挂在玩家身上靠手柄输入驱动。第二层是 Interactable也就是能被交互的物体。XRI 里最常见的是 XR Grab Interactable挂在物体上之后这个物体才可被捡起。脚本里还会管理它是可以抓取、可以远程抓取还是只能被放到指定的槽位里。这一步很容易被忽略因为交互器默认能看到场景里所有带 Collider 的物体但物体没有 Interactable 组件时射线穿过去也不会触发任何反馈。第三层才是 Input Action也就是手柄按钮输入。XRI 默认提供了一套 XRI Default Input Actions里面预设了瞬移、抓取、旋转、转向等常用的输入映射。你需要在 XR Controller 组件的字段里把 Select Action、Activate Action、UI 点击等槽位指到这个 .inputactions 文件里对应的 Action 上。这三层的关系可以类比成现实里的场景你的手是 Interactor杯子是 Interactable而大脑发出的伸手去拿指令就是 Input Action。手到了杯子旁边大脑也下了指令这个动作才完整。如果手到了但大脑没指令Input Action 没配对或者大脑指令到了但手不在Interactor 没激活交互一定失败。我在给项目排查手柄没反应的时候第一步永远是去检查 Input Action 是否配对第二步检查 Interactor 的 Interaction Layer Mask第三步才看物体上的 Interactable 配置。顺序不要反因为大部分手柄能转但按钮无效的问题都出在 Input Action 没有被正确驱动上。1.1 Interaction Layer Mask 是看不见的过滤器XRI 里有一个很容易踩坑的设计Interaction Layer Mask。它和 Unity 自带的 Layer 不是一回事是 XRI 自己维护的一套掩码用来决定 Interactor 能看见哪些 Interactable。默认情况下这个掩码是 Everything也就是所有交互器能抓所有可交互物体这在 Demo 里无所谓但项目一复杂就出问题射线想抓远处的遥控器结果半路把桌上的打火机先吸附过来了Socket 想接住电池却把整个武器都吞了进去。正确做法是在 Project Settings 的 XR Interaction Toolkit 分区里自定义几层比如 Player、Interactable、UI、SocketOnly。然后每个 Grab Interactable 勾选它属于哪一层每个 Interactor 勾选它能够与哪一层发生交互。注意这里有个双向匹配的规则交互器和物体的掩码必须互相包含两边都满足才能交互。这个细节很容易被忽略我见过不少明明都配好了但手指穿过去了没反应的案例最后查出来就是掩码不匹配。1.2 版本差异2.x 和 3.x 的配置位置完全不一样还有一个经常让老项目翻车的地方XRI 2.x 和 3.x现在 Unity 6 里默认会拉到的版本在配置方式上有比较大的变化。2.x 时代很多组件字段是直接挂在 Interactor 上的3.x 开始XRI 把输入相关的入口收拢到了 XR Controller 和 Input Action Manager 里。如果你是从老项目升级过来会发现原来的 Ray Interactor Inspector 面板上少了很多输入字段比如 Select Action、Activate Action 这些都被挪到了 Controller 脚本里。这个变化本身不算坏事它让输入设备和交互算法解耦了但升级时必须手动重新把 Action 拖到对应槽位上否则手柄按键静悄悄。另外3.x 里 Interaction Manager 也变成了一个显式引用的组件如果场景里的多个交互器没有共享同一个 Interaction Manager它们之间是互相看不见的。特别是把两个预制体拼进一个场景时最容易出现这种射线各自为政的诡异现象。2. 射线交互从瞬移、点按钮到隔空抓取一条射线能做的三件事射线交互是 VR 里手感最直观、也是使用频率最高的一类交互。很多人以为射线就是一条线加一个圆点实际上 XRI 的射线交互能分成三种完全不同的应用场景瞬移定位、UI 操作、隔空抓取。三条腿缺一不可而且它们的配置细节各不相同。2.1 先分清三种 Line Type再谈手感在 XR Ray Interactor 的 Inspector 里有一个 Line Type 下拉框里面有三个选项Straight Line、Projectile Curve、Bezier Curve。这个选项直接决定射线的形态。Straight Line 就是笔直一条线适合瞬移瞄准、UI 点击这类需要精确指哪打哪的操作。Projectile Curve 是一条抛物线适合模拟扔出去的感觉比如往远处扔一个球、给某个区域投掷一个物体也可以应用到瞬移上让你能看到落点轨迹。Bezier Curve 可以做得更自由它可以绕开中间的遮挡物但这通常需要额外的控制点计算普通项目里用得不多。我之前在 Pico 4 上做了一个远程抓取的功能玩家要隔空把一个零件从架子上取下来。如果只用 Straight Line需要精确地瞄准一个很小的目标点人的手稍微抖一下就偏了。后来改成 Projectile Curve 加一条宽松的抛物线末端圆环Reticle跟着落点走玩家扔一条线过去碰到零件就能抓手感一下就好了很多。还有个很容易被忽视的细节Reticle就是射线末端那个小圆环或者十字光标。如果 Ray Interactor 的 Reticle 字段是空的玩家就不知道自己的焦点落在哪里这在 UI 交互和瞬移里都很难受。正确做法是做一个带 XR Reticle 脚本的小圆标拖到 Ray Interactor 的 Reticle 槽位上射线末端就会跟着目标点移动。2.2 瞬移不是传送而是整个 XR Origin 在移动很多第一次做瞬移的人会想着去移动 Main Camera这是错的。XRI 的标准做法是在 XR Origin 下挂一个 Teleportation Area玩家用射线指到地面上手柄按下瞬移键系统会移动整个 XR Origin包括地面、左右手柄和相机而不是单独移动相机。这样做的原因是单独移动相机会导致 Wrist 坐标系错乱手柄视角和身体实际位置对不上玩起来就晕。如果你明确要让玩家瞬移到某个固定位置比如一个椅子前、一扇门旁边应该用 Teleportation Anchor而不是 Area。Area 是面可以随便传Anchor 是点固定落位。我一般的大厅场景里两者混用大厅本身是 Area但每个展台前放一个 Anchor保证玩家传到展台时朝向和距离是对的。瞬移还有一个常见问题玩家传送后朝向飘了。这通常是因为右手摇杆同时驱动了移动和转向瞬移触发的瞬间又碰了一下转向。XRI 在 Teleportation Area 上提供了 Teleport Direction 相关选项可以选择传送时是否带方向以及方向参考哪里。一般建议把方向参考设置为射线起点到落点的方向或头部朝向不要用手柄朝向否则视角会非常不稳定。注意瞬移时移动的是 XR Origin不是 Main Camera。如果你在 Main Camera 上额外挂了一个摄像机跟随脚本让它去追 XR Origin那必然会出现抖动和视角漂移。XRI 的场景结构里Main Camera 本来就挂在 Camera Offset 下面跟着 XR Origin 一起移动不需要你再写任何跟随逻辑。2.3 用射线点 UIWorld Space UI 不被遮挡的设置手柄射线点按钮和鼠标点按钮完全是两码事。鼠标是屏幕坐标的精确点击手柄射线则是一个物理碰撞检测它需要先决定射线碰到的是哪一层然后再把点击事件发到 UI 上。这套流程在 XRI 里的实现是场景里放一个 EventSystem挂上 XR UI Input Module然后把 XR Ray Interactor 的 Enable UI Interaction 勾上同时把 Tracked Device 指向对应手柄的 XR Controller。这里有一个非常常见的坑如果 Ray Interactor 没有勾选 Enable UI Interaction它就只能和 3D 物体交互UI 怎么点都没反应。但更隐蔽的问题是 World Space UI 被 3D 物体挡住。比如你在场景里放了一块世界空间面板World Space Canvas面板前面正好有一根柱子手柄射线从柱子后面穿过结果事件被柱子截断了UI 按钮点不到。解决办法是在 Canvas 的 Inspector 里调整 Blocking Objects 和 Blocking Mask。Blocking Objects 设成 AllBlocking Mask 设成需要挡射线的那个层一般把柱子等 3D 物体单独放一层这样 UI 就不会被无关物体抢走焦点。还有一个小技巧如果按钮的点击范围太小手柄射线很难精准点中不要在 UI 上到处放大按钮本身而是给按钮的子物体加一个透明的 Image 组件来扩展点击热区。射线按到透明区域同样算点击UI 视觉上还是一个精致的按钮。2.4 隔空抓取射线抓取什么情况下用、怎么调隔空抓取用射线拿起远处的物体是 VR 里很实用的能力但手感和近处直接抓完全不同。实现上就是给物体挂上 XR Grab Interactable然后让 Ray Interactor 的 Interaction Layer Mask 包含这个物体所在的层射线指到物体上按抓取键就能吸附过来。这里有个细节要注意当一个物体同时可被 Direct Interactor近处和 Ray Interactor远处抓取时玩家在靠近后经常会发现距离很近却用不了直接抓取因为射线优先把物体锁定了。解决办法有两个一是在射线接近物体一定距离时主动禁用 Ray Interactor二是在 Grab Interactable 上配置 Preferred Interactor 优先级让它优先响应直接抓取。两种方案我都在项目里用过建议先试试方案二改配置比改逻辑简单得多。3. 直接交互为什么抓取总穿模、抛出像甩出去近处抓取是所有手柄交互里最考验手感的部分。你伸手过去握住一个杯子拿起来放下看起来简单但实际调起来会发现要么手指还没碰到杯子杯子就瞬移到手心要么抓住杯子之后一晃杯子就飞了要么把杯子放到桌上时它直接穿进桌子。这些问题大多可以归结到三个点Attach Transform 没配、Movement Type 选错、刚体上的阻尼参数不合适。3.1 抓取点Attach Transform决定物体贴在手的位置先想象一个现实里的场景你伸手去拿桌上的马克杯手指是环住杯身握住它的握点大概在杯身中间偏上。但在默认情况下XRI 抓取物体时是拿物体的中心点贴向手柄的握持点所以如果你想抓杯身结果可能是杯子中心对着手心杯口和杯底各露出一半看起来很别扭。解决办法是给每个 Grab Interactable 创建一个空的子物体把它放到你期望的握持位置然后把这个子物体拖到 Attach Transform 槽位上。建议在制作物体时就按一个物体一个抓取点空物体的约定来管理毕竟枪支、瓶子、刀具这些物品的握持点各有不同等你摆了一桌子物品再回头补工作量很大。还有一个容易被忽略的版本差异在 XRI 3.x 的配置里Attach Transform 的位置可以自动计算也可以手动指定。如果选择自动计算物体的 Transform 中心就会被当作抓取点等于没配。手动指定后抓取时物体会平滑地把 Attach Transform 和手柄的 Attach Transform 对齐。3.2 Movement Type三种模式相当于三种手的材质Grab Interactable 上的 Movement Type 有三个选项初学者经常选默认值就不管了但往往就是这里决定了物体是死是活。Instantaneous 是瞬时改变物体位置让它直接跳到抓取点。适合钥匙、遥控器、武器这类需要到手即用、不太在意惯性的物体。上手感就是一按就吸附但太重的物体用这个模式会显得假。Velocity Tracking 是最接近物理跟手的模式。它把手柄运动速度、角速度记录下来然后通过刚体驱动物体跟随手柄。这个模式的好处是物体可以抛出并且在快速移动时不会卡顿缺点是如果刚体质量、拖拽参数没调好物体可能会抖动或者在空中乱飘。Kinematic 模式下物体会被设置为 kinematic 刚体也就是不参与物理模拟然后跟随手柄运动。它的优点是拿在手里非常稳定不会因为碰撞抖动缺点是抛出时需要用额外代码在释放瞬间把刚体切回非 kinematic 并手动赋予速度不然物体就像被冻结在半空中。这里给出我在 Pico 4 项目里的初始参数建议物品类型Movement TypeMassDragAngular Drag钥匙/小零件Instantaneous0.510.1瓶子/球Velocity Tracking1.00.50.05家具/大件Kinematic5.020.2这些值不是标准答案只是起点。最终还是要以拿起、转动、放下是否自然为判断标准去微调。3.3 抛出效果为什么扔出去像甩而不是扔用 Velocity Tracking 模式抓一个球伸出手快速一甩球飞出去后应该获得一个和手部运动近似的速度。但默认情况下你会发现两种情况要么球飞得很近几乎像是掉出去要么球脱手瞬间突然加速飞得不可控。问题出在 Velocity Damping 和 Angular Velocity Damping 这两个参数上。它们的作用是抑制速度的继承阻尼越大物体抛出后继承的手柄速度就越小阻尼越小继承的速度就越完整。如果要实现扔飞镖那种轻快的抛出建议把 Velocity Damping 调到 0.1~0.2Angular Velocity Damping 调到 0.2 左右如果要实现放杯子到桌上这种缓慢的放置动作反而需要把阻尼调高一些让物体在释放后不突然获得很大速度。你可以这样理解阻尼本质上是一个速度衰减器它决定物体在离开手的瞬间还保留了多少手的动能。3.4 Socket 槽位让物体精准放到位而不是掉在附近Socket 在 XRI 里的作用是给场景里提供一个指定位置接住物体的交互器。经典用法是把盾牌放到背上的卡槽、把螺丝刀放回工具架、把弹夹装进枪里。Socket Interactor 挂在空物体上设置它的 Interaction Layer Mask只接收特定层的物体。挂好之后物体进入 Socket 的有效范围只要满足掩码条件它就会被吸附过去。关于 Socket 有两个高频问题。第一个是物体放进去后旋转不对比如钉子横着放进去了。解决办法依旧是给 Socket 设置一个 Attach Transform调整它的旋转让物体吸附时对齐到这个方向。第二个是 Socket 要在 Hover 的时候显示这个位置可以放的提示Socket 的 Show Interactable Hover Meshes 字段默认是勾上的会把当前悬停物体的网格显示出来当预览如果项目里面有成百上千个可交互物体建议把 Socket 的 Hover Mesh 显示关掉可以明显降低每帧的绘制开销。3.5 Interaction Layer Mask 的双向匹配规则前面多次提到 Interaction Layer Mask这里再说透一点。在 XRI 里一个物体要能被抓取必须满足两个条件同时成立一是 Interactor 的 Interaction Layer Mask 里要包含物体所在的 Interactable 层二是 Interactable 的 Interaction Layer Mask 里要包含 Interactor 所在的层。两边都达成交互才会建立。这个规则导致的一个常见 bug 是你创建了一个Interactable层把物体都扔进去了并在物件的 Grab Interactable 上勾选了这个层但忘了检查手柄的 Ray Interactor 是不是也勾选了 Interactable 层。结果就是——手碰不到东西因为两边的掩码不闭合。调这种问题的时候建议养成一个习惯选中交互器再看物体的 Inspector把两个 Interaction Layer Mask 都点上确认一下只盯一边永远看不出问题。4. 手感补齐震动反馈、手柄模型与自定义按钮当你能抓起物体、能瞬移、能点 UI这套手柄交互算能用了。但距离像样还差两件事反馈和外观。VR 里玩家看不见自己的真实手腕想要有我真摸到了的感觉震动反馈至关重要而手柄模型如果不替换举起来看到的是一个方块沉浸感瞬间没了。4.1 震动反馈短而有力的脉冲比持续震动更有效XRI 里做震动的方式很简单在 XR Base ControllerXR Controller 的父类上调用 Send HapticImpulse 方法传入振幅和时间即可。通常的做法是通过 Grab Interactable 的 Select Entered 事件当物体被抓起来的时候触发一个脉冲。下面是一个最简实现挂在 Grab Interactable 物体上让它在被抓取时触发震动using UnityEngine; using UnityEngine.XR.Interaction.Toolkit; public class GrabHapticFeedback : MonoBehaviour { [SerializeField] private XRBaseController leftController; [SerializeField] private XRBaseController rightController; [SerializeField] private float hapticAmplitude 0.5f; [SerializeField] private float hapticDuration 0.1f; private XRGrabInteractable grabInteractable; private void Start() { grabInteractable GetComponentXRGrabInteractable(); grabInteractable.selectEntered.AddListener(OnGrabbed); } private void OnGrabbed(SelectEnterEventArgs args) { var interactor args.interactorObject.transform; // 判断是哪只手抓的然后触发对应控制器的震动 var controller GetControllerByInteractor(interactor); if (controller ! null) { controller.SendHapticImpulse(hapticAmplitude, hapticDuration); } } private XRBaseController GetControllerByInteractor(Transform interactor) { // 在这里用交互器的位置或其他标记判断左右手返回对应控制器 return null; // 需要按项目实际结构实现 } }在真正开发时判断左右手建议用 XR Input Device 的 characteristics 来区分或者把左右手柄分别命名然后从交互器反查。这个细节不处理好就会出现左手抓东西右手在震的情况。震动的参数也很有讲究。我的经验是拿取物体时振幅 0.3~0.5、时长 0.05~0.1 秒比较合适既能让玩家明显感知又不会震得发麻。持续震动的效果反而不好手柄电机长时间高频率震动会让手很快疲劳尽量只在碰触、拿起、放下这几个关键节点发短脉冲。另外很多 SDK 自带的手柄模型默认会抢占震动权限比如 PICO 的控制器在某些模式下会自动处理震动。如果你发现代码里 SendHapticImpulse 调了没反应先检查 XR Controller 上 Haptics 相关的初始化设置再检查是不是 SDK 覆盖了震动事件。4.2 手柄模型替换让玩家在虚拟世界里看见自己的设备如果没有做任何模型替换XRI 默认的手柄会显示成一个简单的几何体。在 Pico 4 上开发时玩家戴上头盔看到的是一对圆柱形手柄而不是实际的 Pico 手柄形状这会非常出戏。替换模型的做法不复杂准备一个包含正确手柄外观的预制体可以用设备 SDK 自带模型或者下载对应型号的 glTF把它挂在 XR Controller 的 Model Prefab 字段下XRI 会自动在运行时实例化这个模型并跟随手柄的运动。真正比较复杂的是骨骼绑定和动作驱动。比如 Pico 手柄在按下扳机键时模型上的扳机部分应该有对应的动画。XRI 的 XR Controller Model 脚本可以监听手柄的 activate、select、uiPress 等输入动作然后驱动模型上指定的骨骼节点。你需要确认模型资源里有对应的握持骨骼节点然后在 Inspector 里把 Model 组件下方的手指/扳机映射槽位指向它们。这里有个提醒替换手柄模型后一定要重新检查射线的起点。很多时候射线是从手柄模型头部发出的模型换了之后如果锚点没对准射线会从错误的位置射出玩家看到射线从手指缝里穿出去很奇怪。通常做法是保留一个名为 Attach/Anchor 的空子物体放在模型前端作为射线起点。4.3 自定义按钮把抓取从手柄按键改成扳机键XRI 默认的方案是抓取用握持键Grip激活/点击用扳机键Trigger。但实际项目里经常要重新映射。比如有的游戏想把抓取放到扳机上把瞬移放到 A 键或者反过来做成按住扳机瞄准松开扳机释放。要改这个是在 .inputactions 文件里改绑定。打开 XRI Default Input Actions找到 Grab 这个 Action选中它在 Binding 区域把绑定改成右手柄的 Trigger 按钮然后保存并重新加载一次。改完之后要确认 XR Controller 上对应的 Select Action 变量引用的正是这个 Action。这里最容易踩的坑是很多人改了 .inputactions 文件但忘了场景里正在引用的还是旧缓存运行起来毫无变化。XRI 3.x 里同一个 Action 可以有不同的 Binding你得确认当前设备实际触发的是哪条 Binding。最简单的调试方法是在 Inspector 里打开 Input Debugger按下手柄按键看对应 Action 有没有数值变化这样很快就能定位是绑定问题还是组件配置问题。4.4 手柄和手势共存从手柄玩法切到 MR 手势玩法自从 Quest、Pico 这类一体机陆续开放手势追踪很多项目都面临一个需求玩家在菜单界面用手势操作进入主玩法时切回手柄。这个切换在 XRI 里的本质就是启用/禁用 Hand Interactor 和 XR Controller 对应的 Interactor。我常用的做法很简单在场景里同时保留手柄射线和手势射线设置一个交互模式枚举切换时把当前不需要的 Interactor 组件 Disable 掉同时把 Input Action Manager 里的默认 Action Map 切到相应的映射。比如手势模式下把 Teleport 相关 Action 停用否则玩家空手一挥就会瞬移很难受。这也解释了一个很多人问的问题unity mr切换vr到底怎么实现。其实虚拟现实和设备 MR 模式的切换更多是 XR 插件管理器层面的开关但手柄和手势的切换是 XRI 交互层的事情两者分开处理别混在一起。5. Pico 4 等设备上的适配与排查从能跑到能交付最后这部分我想围绕 Pico 4 这种国内一体机设备上跑 XRI 的实战问题聊一聊我踩过的坑和现在的排查习惯。这些经验不限于 PicoQuest 等设备也基本适用。5.1 先定输入方案OpenXR 还是设备 SDK二选一别混用现在在 Pico 4 上开发 XR 项目主流方案有两种一是用 Unity 的 OpenXR 插件加 XR Interaction Toolkit配合 XR Plugin Management 来做二是直接用 PICO Unity Integration SDK。两种方案各有适用场景但千万不要两个混用。混用的典型症状是手柄模型出现两份、手柄坐标偏移、按钮事件被重复触发按一次键场景里响应了两次。这是因为两套输入系统都在监听手柄。如果你只需要基础手柄追踪、瞬移、抓取、UI 点击这些 XRI 原生能力推荐直接用 OpenXR 方案干净省事只有当项目需要用到 PICO 平台专属能力比如头戴、面部追踪、特定平台商店接入时再引入 PICO SDK。我现在的习惯是能不开 PICO SDK 就不开先纯 OpenXR XRI 跑通核心玩法等需要平台能力时再增量接入。这样调试的输入源少一个出问题的时候好排查很多。5.2 手柄交互失灵我的标准排查链路遇到手柄能追踪但交互全没反应这类问题不要乱改配置按照下面的顺序一条条排查至少能解决九成的情况。排查步骤检查点验证方法1Input Action 是否绑定打开 Input Debugger按对应按钮看 Action 是否跳动2XR Controller 是否驱动检查 Select Action / Activate Action 字段是否引用了正确的 Action3Interactor 是否启用确认 XR Ray Interactor 或 XR Direct Interactor 组件是 Enable 状态4Interaction Layer Mask 是否闭合同时检查交互器和物体的掩码是否互相包含5物体刚体是否缺失Grippable 物体必须要有 Rigidbody且不要勾选错误的 Is Kinematic这套顺序是从输入源头到最终物体的链路来的。先保证手柄输入确实产生了 Action 值再保证控制器把它转发给了交互器然后保证交互器能看见物体最后检查物体本身的物理状态。跳过任何一步都可能白忙。举个例子有个项目里抓取物体时偶尔失灵排查发现是物体上的 Rigidbody 在启动时被代码设成了 Is Kinematic导致 Grab Interactable 无法驱动刚体移动。这种问题在 Inspector 上看是看不出来的必须打断点或者写日志才能定位。5.3 射线断断续续、UI 点不到、传送线消失射线交互的问题通常有三个现象射线一会儿有一会儿没有、UI 点了没反应、瞬移的蓝色指示线不显示。射线断断续续多半是 Line Renderer 没有正确跟随射线末端。XRI 的 Ray Interactor 自带 Line Renderer 组件但如果你手动加了一个新的 Line Renderer两者会冲突。优先检查 Interaction Manager 里这个交互器是否被正确注册以及 Reticle 有没有拖指定对象。UI 点不到先别急着改 UI 代码按这个顺序看射线有没有勾 Enable UI Interaction场景里有没有 EventSystem 和 XR UI Input ModuleCanvas 的 Event Camera 是不是指向玩家相机Canvas 的 Blocking Mask 是不是设得太宽把不该挡的东西也挡住了。尤其是第四个问题很多人会把 Blocking Mask 设成 Everything结果面板自带的一个小碰撞体把射线全部拦截了。传送线不显示的问题最常见的是 Teleportation Area 上面的 Interactable 层没被 Ray Interactor 的 Interaction Layer Mask 覆盖。瞬移是 XRI 内置的一种交互它同样遵循掩码规则。如果射线能看到普通物体但看不到地面八成就是地面所在的层没勾上。5.4 性能与稳定性不为一时的手感埋性能的雷手柄交互在性能上的开销主要来自两个地方Interactor 每帧对所有可达 Interactable 做 hover 检测以及 Socket 的 Hover Mesh 预览。在 XRI 里每个 Interaction Manager 都会遍历场景中的可交互物体去判断它们是否进入交互器的 hover 范围。物体数量多、又没有按层区分时这个计算量会上升得很明显。建议把场景里当前不需要交互的物体所在的层从交互器的掩码里剔除等需要用的时候再动态开启。Socket 的 Hover Mesh 也一样它会在物体进入范围时动态生成预览网格。如果场景里有几十个 Socket每个都在做预览性能压力不小。实际交付时如果不需要预览提示直接关掉这个开关就行非要保留提示建议只给关键交互点的 Socket 开。我之前做过一个场景墙上有 20 个武器槽位每个槽位都是一个 Socket每帧都在生成武器的预览网格帧率掉了接近 15%。把这些 Socket 的 Show Interactable Hover Meshes 关掉之后帧率马上回来了。交互逻辑没有任何改动只是去掉了一部分实时视觉效果。在手柄交互这件事上我的经验是别贪多把手上的那一两件交互做到顺手比把所有组件都摆上去更实用。你在项目里排查手柄问题时如果能养成先看 Input Action再看 Interaction Layer Mask最后看 Attach Transform的习惯很多诡异的问题从一开始就不会缠上你。
