pico4 支持眼动模块,但是官方文档不够清晰,且不存在演示demo。记录以下流程和坑点。
1.首先在场景中的XR Origin物体上的PXR_Manager脚本,勾选Eye tracking(注意只有pico4 pro和Neo 3支持眼动)。此时,便可以通过脚本获取到眼动的数据了。
2.在创建的脚本中,输入如下代码
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using Unity.XR.PXR;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class EyeTrackingManager : MonoBehaviour
{
public TMP_Text ui_text;
public Slider slider;
public float zCoordinate =14;
private bool trackingSupported = false;
private bool tracking = false;
private EyeTrackingData eyeTrackingData;
public Transform ray;
public Transform point_gaze;
public Transform root;
// Start is called before the first frame update
void Start()
{
var trackingState = (TrackingStateCode)PXR_MotionTracking.WantEyeTrackingService();
if (trackingState == TrackingStateCode.PXR_MT_SUCCESS)
{
ui_text.text = "Want Success";
EyeTrackingMode eyeTrackingMode = EyeTrackingMode.PXR_ETM_NONE;
int supportedModesCount = 0;
trackingState = (TrackingStateCode)PXR_MotionTracking.GetEyeTrackingSupported(ref trackingSupported, ref supportedModesCount, ref eyeTrackingMode);
if (trackingSupported)
{
ui_text.text = "Supported!!";
EyeTrackingStartInfo info = new EyeTrackingStartInfo();
info.needCalibration = 1;
info.mode = EyeTrackingMode.PXR_ETM_BOTH;
trackingState = (TrackingStateCode)PXR_MotionTracking.StartEyeTracking(ref info);
}
else
{
ui_text.text = "Not Supported!!";
}
}
else
{
ui_text.text = "Want Fail";
}
}
void Update()
{
if (trackingSupported)
{
EyeTrackingState eyeTrackingState = new EyeTrackingState();
var trackingState = (TrackingStateCode)PXR_MotionTracking.GetEyeTrackingState(ref tracking, ref eyeTrackingState);
if (tracking)
{
EyeTrackingDataGetInfo getInfo = new EyeTrackingDataGetInfo();
getInfo.displayTime = 0;
getInfo.flags = EyeTrackingDataGetFlags.PXR_EYE_DEFAULT
| EyeTrackingDataGetFlags.PXR_EYE_POSITION
| EyeTrackingDataGetFlags.PXR_EYE_ORIENTATION;
trackingState = (TrackingStateCode)PXR_MotionTracking.GetEyeTrackingData(ref getInfo, ref eyeTrackingData);
var eyeData = eyeTrackingData.eyeDatas[2].pose;
var localorigin = new Vector3(eyeData.orientation.y, eyeData.orientation.z, -eyeData.orientation.w) + root.localPosition;
var origin = root.TransformPoint(localorigin);
Quaternion direction = new Quaternion(-eyeData.position.x, -eyeData.position.y, eyeData.position.z, eyeData.orientation.x) ;
var point = origin + (root.rotation * direction * Vector3.forward* zCoordinate);
point_gaze.position = point;
ray.position = origin;
ray.rotation = root.rotation*direction ;
ui_text.text = eyeTrackingData.ToString();
}
}
} 代码来自 https://zhuanlan.zhihu.com/p/678956811
PICO4 pro眼动追踪开发实战 - 知乎 (zhihu.com)
坑点1:结构体 EyeTrackingData中存放Pico运行时的眼动数据。eyeDatas[0],eyeDatas[1]分别是左眼和右眼单独的数据,只有企业版能够读取,故数据为空。eyeDatas[2]则为两者混合后的数据
var eyeData = eyeTrackingData.eyeDatas[2].pose;
var localorigin = new Vector3(eyeData.orientation.y, eyeData.orientation.z, -eyeData.orientation.w) + root.localPosition;
var origin = root.TransformPoint(localorigin);
Quaternion direction = new Quaternion(-eyeData.position.x, -eyeData.position.y, eyeData.position.z, eyeData.orientation.x) ; 比较逆天的是,其中position和rotation的数据是乱的。

Pico官网论坛
坑点二:Pico获取的position以XR Origin 或者 Camera offset物体为参考系。然而Unity
pico 执行旋转时会直接对Xr Origin进行旋转操作,总而言之,需要先使用本地坐标系确定眼动原点位置,再转换为世界坐标。

UNity XR tookit 提供的预制体
var localorigin = new Vector3(eyeData.orientation.y, eyeData.orientation.z, -eyeData.orientation.w) + root.localPosition;
var origin = root.TransformPoint(localorigin); 对于rotation数据,类似的,需要再加上XR Origin的旋转,注意旋转的叠加应该使用四元数的乘法,在四元数中,乘法顺序是从右到左的,
var point = origin + (root.rotation * direction * Vector3.forward* zCoordinate);