Unity PICO4 学习记录9:进场景时朝向不对

进场景后,头显朝向和编辑器里摆的 Main Camera 对不上,需要手动用home键重置。所以写了一个进场自动重置的脚本。

原因

运行时 Main Camera 的位姿由头显追踪驱动(TrackedPoseDriver),并不是在 Scene 里摆的那个 Transform。根据Unity官方对XR Origin的说明XR Origin | XR 核心工具 | 2.6.0 --- XR Origin | XR Core Utilities | 2.6.0

  • XR Origin 代表追踪空间的中心(0, 0, 0)
  • XR Origin 在 Session 启动时由 XR 系统决定
  • HMD Reset 时,XR Origin 本身不会移动; Camera 相对 Origin 的偏移会改变

解决

场景设置

使用BuildingBlock创建相机相关结构,或确保如下结构

复制代码
XR Origin (XROrigin 组件)
└── Camera Offset
    └── Main Camera (TrackedPoseDriver 组件+ Camera组件)

Tracking Origin Mode设置

  • Device:以Session启动时设备位置为原点,不含用户身高
  • Floor:以地面为原点,含用户身高,站立VR更推荐

脚本

思路:

XRInputSubsystem.TryRecenter()重定位,XROrigin.MatchOriginUpCameraForward() 旋转 XR Origin,让相机朝向场景期望方向

cs 复制代码
using System.Collections;
using UnityEngine;
using UnityEngine.XR;
using Unity.XR.CoreUtils;

/// <summary>
/// 进场景时把 HMD 朝向对齐到场景期望方向。
/// 编辑器里 Main Camera 的旋转不会在真机上生效------运行时位姿由头显追踪驱动。
/// </summary>
public class PicoRecenter : MonoBehaviour
{
    [SerializeField] XROrigin xrOrigin;
    [Tooltip("期望的"正前方"。留空则使用世界 +Z。")]
    [SerializeField] Transform sceneForwardReference;
    [Tooltip("启动后先调用系统 Recenter,把当前头显朝向当作 forward=0°。")]
    [SerializeField] bool recenterOnStart = true;
    [Tooltip("Recenter 后是否旋转 XR Origin,使相机朝向 sceneForwardReference。")]
    [SerializeField] bool alignToSceneForward = true;
    [Tooltip("等待追踪就绪的帧数,避免过早 Recenter 无效。")]
    [SerializeField] int waitFrames = 2;

    void Start()
    {
        if (xrOrigin == null)
            xrOrigin = FindFirstObjectByType<XROrigin>();

        if (xrOrigin != null)
            StartCoroutine(RecenterWhenReady());
    }

    IEnumerator RecenterWhenReady()
    {
        for (var i = 0; i < waitFrames; i++)
            yield return null;

        if (recenterOnStart)
            TryRecenter();

        yield return null;

        if (alignToSceneForward)
            AlignCameraToSceneForward();
    }

    /// <summary>等价于 Quest 长按 Home / Pico 长按 Home 的系统重定位。</summary>
    public void TryRecenter()
    {
        var subsystems = new System.Collections.Generic.List<XRInputSubsystem>();
        SubsystemManager.GetSubsystems(subsystems);
        foreach (var subsystem in subsystems)
            subsystem.TryRecenter();
    }

    /// <summary>旋转 XR Origin,使相机水平朝向与场景参考一致。</summary>
    public void AlignCameraToSceneForward()
    {
        if (xrOrigin == null)
            return;

        var desiredForward = sceneForwardReference != null
            ? sceneForwardReference.forward
            : Vector3.forward;

        xrOrigin.MatchOriginUpCameraForward(Vector3.up, desiredForward);
    }
}