追踪光标的实现—VR及AR开发高级教程(10)

发表于:2017-3-30 10:23

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:吴亚峰、刘亚志、于复    来源:51Testing软件测试网原创

  7.5.4 追踪光标的实现
  上面小节介绍了使用UGUI在场景中开发的主菜单以及侧面返回菜单,为了提示用户在头部姿态发生变化时双眼中间位置注视在什么地方,以便于更好地拾取菜单按钮,使用追踪光标来实时更新并指示眼睛注视的位置,具体代码如下。
  代码位置:见随书源代码/第7章/GearVR_Demo/Assets/Scripts目录下的GazePointer.cs。
1     public override void Process() {  //该脚本继承自BaseInputModual类,该方法每一帧刷新
2      CastRayFromGaze();                                  //向注视方向发射线
3      UpdateCurrentObject();                              //更新当前拾取到的对象
4      PlaceCursor();                                      //将光标移至注视位置
5      HandlePendingClick();                               //处理单击期间事件
6      HandleTrigger();}                                   //处理触发事件
7     private void CastRayFromGaze() {
8      if (pointerData == null) {                          //指针数据若为空
9       pointerData = new PointerEventData(eventSystem);}  //实例化指针事件数据对象
10     pointerData.Reset();                                //重新设置事件到默认状态
11     pointerData.position = new Vector2(hotspot.x * Screen.width, hotspot.y *
Screen.height);                              //当前指针位置
12     eventSystem.RaycastAll(pointerData, m_RaycastResultCache);
//使用所有配置好的RayCasters发射线
13     pointerData.pointerCurrentRaycast = FindFirstRaycast(m_RaycastResultCache);
//当前射线返回结果
14     m_RaycastResultCache.Clear();}
15    private void UpdateCurrentObject() {
16     var go = pointerData.pointerCurrentRaycast.gameObject; //获取当前射线拾取到的对象
17     HandlePointerExitAndEnter(pointerData, go);            //处理指针离开和进入事件
18     var selected = ExecuteEvents.GetEventHandler<ISelectHandler>(go);
19     if (selected == eventSystem.currentSelectedGameObject) {
20      ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, GetBaseEventData(),
21      ExecuteEvents.updateSelectedHandler);}    //执行对象上的事件
22     else {
23      eventSystem.SetSelectedGameObject(null, pointerData);}} //设置该对象为被选中对象
24    private void PlaceCursor() {
25     if (cursor == null)                        //判断光标是否为空
26      return;
27     var go = pointerData.pointerCurrentRaycast.gameObject;    //获取当前拾取到的对象
28     if(go==null){
29      return;}
30     Constraints.RayCasterObjName = go.name;    //记录下当前获取对象的名称,方便索引
31     cursor.SetActive(go != null);              //拾取对象为空就将光标设置为未激活状态
32     if (cursor.activeInHierarchy) {                     //如果光标处在激活状态
33      Camera cam = pointerData.enterEventCamera;         //获取发射线的相机引用
34      float dist = pointerData.pointerCurrentRaycast.distance + cam.nearClipPlane;
//计算相机距拾取点距离
35      cursor.transform.position = cam.transform.position + cam.transform.forward *        dist;}}              //设置光标位置
  第1~6行为重写基类BaseInputModual的每一帧刷新方法Process,该方法中调用了用于实现确定光标位置以及失去对象的重要方法,这也是对于UI事件系统的高级应用,需要对EventSystem、PointerEventData、BaseInputModual以及BaseRayCaster类详细了解。
  第7~23行为CastRayFromGaze和UpdateCurrentObject方法的代码实现,前者用于使用场景中相机发射射线并返回结果存储在pointerEventData(PointerEventData类型)中,后者用于实时更新射线拾取到的当前对象。
  第24~35行为PlaceCursor方法的代码实现,该方法用于设置光标位置,使其随相机发射射线方向的改变而不断改变位置,能够辅助用户清楚目前正在注视的点,以便更好地对目标进行拾取操作等。
  7.5.5 触摸板事件监听
  该案例当中用于触发事件的外部输入方式是侧面触摸板,在满足某种特定的条件时单击侧面触摸板,会触发相应的事件,比如OVRPlayerController左右旋转、发射"炮弹"击打Box和Cylinder等。对Oculus Mobile SDK中的OVRTouch.cs脚本稍作改动就可以实现相应功能,具体代码如下。
  代码位置:见随书源代码/第7章/GearVR_Demo/Assets/OVR/Moonlight/Scripts目录下的OVRTouchpad.cs。
1     public sealed class OVRTouchpadHelper : MonoBehaviour{
2      private GameObject ObjShooting;                            //炮弹预制体引用
3      private Transform ObjShootingPos;                          //实例化子弹初始位置
4      private bool IsShooting=false;                             //是否发射炮弹
5      void Awake(){
6       UnityEngine.Object go = Resources.Load ("Sphere",typeof(GameObject));
//获取炮弹预制体
7       ObjShooting = go as GameObject;             //转换成游戏对象
8       ObjShootingPos = GameObject.Find ("CenterEyeAnchor").transform;
//获取CenterEyeAnchor位置
9       DontDestroyOnLoad(gameObject);}             //加载时不删除该对象
10     void Start(){
11      OVRTouchpad.TouchHandler += LocalTouchEventCallback;}
//将触摸事件监听回调方法加入事件列表
12     void Update(){
13      OVRTouchpad.Update();}                               //更新OVRTouchpad
14     public void OnDisable(){
15      OVRTouchpad.OnDisable();}
16     void LocalTouchEventCallback(object sender, EventArgs args){ //触摸事件监听方法
17      var touchArgs = (OVRTouchpad.TouchArgs)args;         //强制类型转换:基类-继承类
18      OVRTouchpad.TouchEvent touchEvent = touchArgs.TouchType;    //获取触摸事件
19      switch(touchEvent){
20       case OVRTouchpad.TouchEvent.SingleTap:    //单击事件
21        Debug.Log("SINGLE CLICK\n");{            //打印调试信息
22      if(Constraints.IsRaycaster_Right==true){   //当射线离开"右转菜单",此变量置为false
23       Constraints.RotateToRight=true;           //当转向完成此变量置为false}
24      if(Constraints.IsRaycaster_Left==true){    //当射线离开"左转菜单",此变量置为false
25       Constraints.RotateToLeft=true;}           //当转向完成此变量置为false
26      if(Constraints.IsRayCaster_BoxBack==true){ //当射线离开Box返回图片时置为false
27       Constraints.RotateToLeft=true;}        //当转向完成此变量置为false
28      if(Constraints.IsRayCaster_CylinderBack==true){
//当射线离开Cylinder返回图片时置为false
29       Constraints.RotateToRight=true;}       //当转向完成此变量置为false
30      if(Constraints.Shooting==true&&Constraints.IsRaycaster_Right==false
//左转变量为false
31      &&Constraints.IsRaycaster_Left==false&&Constraints.IsRayCaster_BoxBack==false&&
32      Constraints.IsRayCaster_CylinderBack==false){
//左转变量为false,Box和Cylinder返回变量为false
33      Shooting();}}                                        //发射"炮弹"
34      break;
35      case OVRTouchpad.TouchEvent.Left:                    //左滑事件
36       Debug.Log("LEFT SWIPE\n");                          //打印调试信息
37       break;
38      case OVRTouchpad.TouchEvent.Right:                   //右滑事件
39       Debug.Log("RIGHT SWIPE\n");                         //打印调试信息
40       break;
41      case OVRTouchpad.TouchEvent.Up:                      //上滑事件
42       Debug.Log("UP SWIPE\n");                            //打印调试信息
43       break;
44      case OVRTouchpad.TouchEvent.Down:                    //下滑事件
45       Debug.Log("DOWN SWIPE\n");                          //打印调试信息
46       break;}}
47     void Shooting(){                                      //发射炮弹方法
48      GameObject go = Instantiate(ObjShooting,new Vector3(ObjShootingPos.transform.
position.x,
49      ObjShootingPos.transform.position.y,ObjShootingPos.transform.position.z),
//初始化炮弹预制体
50      Quaternion.identity)as GameObject;
51      go.GetComponent<Rigidbody>().AddForce(ObjShootingPos.forward*2000);//向前发射
52    }}
  第1~15为获取炮弹预制体、炮弹初始化位置,以及在场景加载后在Assets/Resources文件夹中加载炮弹资源和在Start方法中添加触摸事件处理方法到事件列表中。其中在Update和OnDestory方法中调用的OVRTouchpad中的方法没有具体功能,可以注释。
  第16~46行为LocalTouchEventCallback处理触摸事件的回调方法,其中包括SingleTap、Left、Right、Up以及Down 5个触摸事件,本案例中只用到了SingleTap单击触摸事件,单击侧面触摸板后根据具体条件不同分别会发生向右旋转、向左旋转、左返回主菜单、右返回主菜单和发射炮弹几种操作。
  第47~52行为用于炮弹发射的方法,使用预制体根据CenterEyeAnchor的位置实例化炮弹,然后获取该物体的刚体组件,添加一个沿CenterEyeAnchor正方向的力,使其"炮弹"飞出去击打Box和Cylinder。
  7.5.6 部署运行APK的步骤
  上面小节讲解了虚拟现实场景的开发过程,从场景中打包的APK安装到手机上,将Gear VR头盔插上手机之后在Oculus Home找不到该应用,手机桌面也找不到图标,但实际上已经安装好了,接下来介绍如何将已经制作好的APK配合Gear VR头盔及手机运行出来,具体步骤如下。
  (1)Gear VR应用或者游戏就是Android游戏或者应用,除了从三星手机上Oculus Home商店运行软件之外,还可以自己创建游戏及应用,因为根据设备ID绑定过签名文件,所以在Oculus Home中找不到已经安装的应用。
  (2)通过下载并安装"ES文件浏览器"应用,可以运行提取版(免费/破解版)Gear VR游戏以及可以在三星手机上找到已经安装好的应用图标,如图7-40所示,ES文件浏览器下载地址:http://pan.baidu.com/s/1i5tXEFr。
  (3)已经确保安装了Gear VR应用之后,在手机桌面打开"ES文件管理器",单击"应用"查找已经安装的应用,如图7-33所示。找到应用之后单击会弹出"属性"提示框,如图7-41所示,单击"打开"会提示"请插入Gear VR设备",如图7-42所示,这时将手机插入Gear VR头戴设备中并带上头盔即可。
  
  7.6  本章小结
  本章对Gear VR硬件以及Oculus Mobile SDK进行了详细介绍,尤其着重介绍了如何在Unity中使用Oculus提供的SDK开发移动平台的Gear VR应用。通过对本章内容的学习,相信读者能够系统全面地掌握Gear VR的开发过程,增强了在开发中解决实际问题的能力。
  7.7  习题
  1.简要介绍Gear VR的硬件组成。
  2.下载Oculus Mobile SDK,并利用手机的ID在Oculus官网获取签名文件。
  3.试述开发Gear VR项目的软硬件要求。
  4.列举SDK中的脚本,并试述每个脚本的具体功能。
  5.列举影响游戏性能的几个因素。
  6.开发一个基于Gear VR SDK的简单案例。
本文选自《VR及AR开发高级教程—基于Unity》第七章,本站经人民邮电出版社和作者的授权。
版权声明:51Testing软件测试网获清华大学出版社和作者授权连载本书部分章节。任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。
一个简单的案例—VR及AR开发高级教程(9)
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号