当前位置: 首页 > article >正文

[PICO VR眼镜]眼动追踪串流Unity开发与使用方法,眼动追踪打包报错问题解决(Eye Tracking)

前言

最近在做一个工作需要用到PICO4 Enterprise VR头盔里的眼动追踪功能,但是遇到了如下问题:

  1. 在Unity里面没法串流调试眼动追踪功能,根本获取不到Device,只能将整个场景build成APK,安装到头盔里,才能在代码里调用眼动追踪功能。这使得每次修改代码都要打包一次apk安装到头盔里,十分不方便,难以调试。
  2. PICO VR 官方提供的Eye Tracking教程里,获取到的眼睛朝向和位置是相对于Head这个位置的,而不是相对于XR Origin下的Camera的位置,这使得API不能直接拿来使用。
  3. Unity在引入PICO VR眼动跟踪代码后,编译时点击"build and run"后,会报错“NullReferenceException: Object reference not set to an instance of an object

鉴于以上问题网络上均没有人进行解答,以及个人没能得到PICO官方的技术支持情况下(三周内发了2封技术工单邮件+2次催线上客服),遂打算自己捣鼓一下写篇教程。

(点名批评PICO官方的技术支持不回复邮件的问题,明明就几个特别简单的问题,但是官方承诺的3-5个工作日内回复并没有做到,等了三周一封邮件也没回,这个过程还问了客服,客服表示会催技术人员回复,但等了一周半也没看到,放弃了orz)

更新补充:据说在PICO企业版官网提交企业版工单能得到官方较快的回复。

1. 如何在代码里使用眼动跟踪,并转换成世界坐标 或 摄像机坐标系

首先,检查眼动追踪是否能正常工作:

void Start()
{
	CheckEyeTracking();

}
private void CheckEyeTracking()
{
    //Start PICO Eye Tracking Service
    TrackingStateCode trackingState;
    trackingState = (TrackingStateCode)PXR_MotionTracking.WantEyeTrackingService();
    Debug.Log("告知PICO想要眼动跟踪服务 trackingState: " + trackingState.ToString());

    //Check Eye Tracking able or not
    EyeTrackingMode eyeTrackingMode = EyeTrackingMode.PXR_ETM_NONE;
    bool supported = false;
    int supportedModesCount = 0;
    trackingState = (TrackingStateCode)PXR_MotionTracking.GetEyeTrackingSupported(ref supported, ref supportedModesCount, ref eyeTrackingMode);
    Debug.Log("检查是否有眼动跟踪功能 trackingState: "+ trackingState.ToString()+"  code  "+ supported);

    // Get Eye Tracking State
    bool tracking = true;
    EyeTrackingState eyeTrackingState = new EyeTrackingState();
    trackingState = (TrackingStateCode)PXR_MotionTracking.GetEyeTrackingState(ref tracking, ref eyeTrackingState);
    Debug.Log("获取当前眼动跟踪状态 trackingState: " + trackingState.ToString());

    // Start Eye Tracking
    //这里要严谨点的话,应该要加上if条件判断是否有眼动跟踪功能,再选择开启该功能
    EyeTrackingStartInfo info = new EyeTrackingStartInfo();
    info.needCalibration = 1;
    info.mode = eyeTrackingMode;
    trackingState = (TrackingStateCode)PXR_MotionTracking.StartEyeTracking(ref info);
    Debug.Log("开始眼动跟踪状态 trackingState: " + trackingState.ToString());

    //Get Eye Tracking Data
    //获取眼动跟踪数据
    EyeTrackingDataGetInfo eyeData = new EyeTrackingDataGetInfo();
    eyeData.displayTime = 0;
    eyeData.flags = EyeTrackingDataGetFlags.PXR_EYE_DEFAULT
    | EyeTrackingDataGetFlags.PXR_EYE_POSITION
    | EyeTrackingDataGetFlags.PXR_EYE_ORIENTATION;
    EyeTrackingData eyeTrackingData = new EyeTrackingData();
    trackingState = (TrackingStateCode)PXR_MotionTracking.GetEyeTrackingData(ref eyeData, ref eyeTrackingData);
    Debug.Log("eyeData:  "+ eyeData.ToString() + " TrackingData:  " + eyeTrackingData.ToString());

  
}

接下来,每帧都获取眼动数据,并将眼睛位置和眼睛朝向数据转换成世界坐标

public Transform origin;//在Unity主界面把XR Origin拖进来即可
private Matrix4x4 headPoseMatrix,originPoseMatrix;
private Vector3 combineEyeGazeVector, combineEyeGazeOriginOffset, combineEyeGazeOrigin;
private Vector3 combineEyeGazeVectorInWorldSpace, combineEyeGazeOriginInWorldSpace;
void Update()
{
	GetEyeTrackingData();
}

private void GetEyeTrackingData()
{
		//获取head的局部转世界矩阵,该矩阵点乘head局部坐标系下坐标,则能转换为世界坐标系下的坐标
        PXR_EyeTracking.GetHeadPosMatrix(out headPoseMatrix);	
        //获取双眼(取中间位置)位于Head坐标系下的朝向信息GazeVector
        PXR_EyeTracking.GetCombineEyeGazeVector(out combineEyeGazeVector);
        //获取双眼(取中间位置)位于Head坐标系下的位置信息GazePoint
        PXR_EyeTracking.GetCombineEyeGazePoint(out combineEyeGazeOrigin);
        
        //获取眼睛的世界坐标
        combineEyeGazeOriginInWorldSpace = originPoseMatrix.MultiplyPoint(headPoseMatrix.MultiplyPoint(combineEyeGazeOrigin));
        //获取眼睛的朝向信息
        combineEyeGazeVectorInWorldSpace = originPoseMatrix.MultiplyVector(headPoseMatrix.MultiplyVector(combineEyeGazeVector));
		
		//highlighArea是我添加的一个手电筒高亮区域,能让用户更直观地查看眼睛看向位置
        highlighArea.transform.position = combineEyeGazeOriginInWorldSpace ;
        //LookRotation默认是以z轴旋转,如果要以y轴旋转的话可以在后面加上 ,Vector3.up
        highlighArea.transform.rotation = Quaternion.LookRotation(combineEyeGazeVectorInWorldSpace);
/*        RaycastHit hit;
        if (Physics.Raycast(highlighArea.transform.position, combineEyeGazeVectorInWorldSpace, out hit, 1000f))
        {
            highlighArea.transform.LookAt(hit.point);
        }*/
}

简易效果图(透明圈处是一个作为highlighArea的圆锥区域):
在这里插入图片描述

至此,便已经能获取到PICO VR里眼动追踪的位置和朝向信息。

2. "Build and Run"报错

引入EyeTracking代码后,发现Build and Run时会报以下错误:
在这里插入图片描述

在这里插入图片描述
这是因为run的话会导致Unity找不到可供眼动追踪的设备,导致编译报错。

解决方法,只点击Build,而不是Build and Run:
在这里插入图片描述
Build完后,打开Pico Developer Center,依次点击"应用管理"->“安装包”->“安装本地应用”:
在这里插入图片描述
选择build好的apk即可,后续便能直接在眼镜里运行:
在这里插入图片描述

3.眼镜内调试的Trick

对于这种要build到眼镜里才能调试的功能,可以利用Unity提高的UI->Text组件进行调试。

即,在Unity场景下创建一个UI->Text对象,然后把对象拖到下面脚本的GazeDebugText变量上,便能在眼镜里看到相应数据输出了

public TMP_Text GazeDebugText;
private void GetEyeTrackingData()
{
	GazeDebugText.text = combineEyeGazeOrigin.ToString("F3");//F3是指精确到小数点后3位
}

效果:
在这里插入图片描述

4.如何在Unity里串流调用眼动追踪功能

B站视频:使用PICO头显在VR串流环境下进行眼动追踪

我个人是在看了这个视频后才知道PICO VR也能在Unity下串流使用眼动跟踪功能,但我没有进一步深入探究,据该视频UP主表示,PICO neo3 pro eye是可以串流的,该方法理应也适用于其他头盔。

在此处也表达下对UP主的感谢,在后台私信耐心细致替我解答问题。

原理:串流使用pico的眼动追踪功能,需要下载特定的串流软件和PICO系统版本,电脑端上用的是PICO企业版串流工具(普通版的串流工具不知道可不可以):在这里插入图片描述

在PICO端上则是自动保持串流软件更新到最新版本。

build成apk安装包之后,调用的SDK是正常使用的;串流时候的SDK会随business streaming一起安装,和apk的SDK不一样

business streaming安装后,sdk里会有一个用qt写的测试程序,可以试试看串流后眼动跟踪是否正常,测试程序不需要用steam;但是对头显的固件版本有要求:
在这里插入图片描述

在这里插入图片描述

如果经过测试后,eye tracking data什么的没有问题,后续可以串流Unity基于OpenXR进行开发。


http://www.kler.cn/news/304007.html

相关文章:

  • HTML5中Checkbox标签的深入全面解析
  • 位段、枚举、联合
  • Hazel 2024
  • 24.9.14学习笔记
  • 构造函数与析构函数的执行顺序
  • 多个系统运维压力大?统一运维管理为IT轻松解忧
  • 计算机网络八股总结
  • 使用vscode上传git远程仓库流程(Gitee)
  • uniapp点击跳转到对应位置
  • 写在OceanBase开源三周年
  • [项目][WebServer][日志设计]详细讲解
  • 【JVM 工具命令】JAVA程序线上问题诊断,JVM工具命令的使用,jstat, jstack,jmap命令的使用
  • 【机器学习】使用Numpy实现神经网络训练全流程
  • 关于若依flowable的安装
  • 76-mysql的聚集索引和非聚集索引区别
  • 为什么网站加载速度总是那么不尽如人意呢?(网站优化篇)
  • 2024.9.14(RC和RS)
  • Docker操作MySQL
  • 互联网环境下CentOS7部署K8S
  • LNMP的简单安装(ubuntu)
  • Artec Leo协助定制维修管道,让石油和天然气炼油厂不停产
  • vue3开发uniapp转字节小程序注意事项
  • 《C++PrimerPlus》第10章:类和对象
  • go语言开发windows抓包工具
  • 在centos上搭建syslog服务端
  • 详情攻略来了!浏览网站记录怎么查?一文读懂这3种实用方法
  • Vue3 响应式工具函数isRef()、unref()、isReactive()、isReadonly()、isProxy()
  • 火焰检测算法、明烟明火检测、烟火检测算法
  • dirty pages , swapiness 查看SWAP占用进程
  • 线性代数 第六讲 特征值和特征向量_相似对角化_实对称矩阵_重点题型总结详细解析