ARCore之路-环境理解之交互

版权声明:David Wang原创ARCore文章,仅供学习研究之用,不得用于任何商业目的,未经授权不得转载! https://blog.csdn.net/yolon3000/article/details/82810021

  我们已经利用ARCore提供的功能检测了特征点和平面,更精细的物体检测现在还是非常困难的事情(如果不能检测出物体,那么MR就不能实现,精细的物体检测是MR中基础的急待突破的技术难点),但技术发展是有一个过程的,随着技术的成熟,物体检测也在慢慢的完善中。对现在来讲,我们能检测到平面,这对我们目前的AR应用来说就提供了一个能够与实际相符的展示虚拟与实现融合的平台。
  ARCore为我们提供的这些识别的点或平面,我们可以附加虚拟对象。ARCore能实时的踪这些点和平面,当用户移动时,连接到这些特征点或者平面上的对象仍然是固定的。
  不能交互的虚拟场景就是电影,就不是AR,AR是要能在场景中与周边环境进行交户才能提供足够的吸引力,也才能真正显示出AR的强大活力。本节我们就主要对AR中的交互相关技术进行学习。

一、ray casting

  在前面我们知道,射线检测(Raycast)的基本思路是在三维世界中从一个点沿一个方向发射出一条无限长的射线,在射线的方向上,一旦与添加了碰撞器的模型发生碰撞,则产生一个碰撞检测到的对象,这个返回的碰撞对象包含了位置、方向及该对象的相关属性。

这里写图片描述

  如上图所示,对AR来说,用户操作的是其手机设备,Raycast的做法是检测到用户的点击屏幕的操作,以点击的位置为准,连接该位置与摄像机就构成一条直线,从摄像机位置,通过点击点就可以构建一条射线,利用该射线,与场景中的物体进行碰撞检测,如果发生碰撞则返回碰撞对象,这就是在AR中的射线检测(Raycast)。
  其实不只是AR应用,几乎所有3D应用程序都使用射线检测(Raycast)来进行对象交互和碰撞检测。现在我们已经了解了光线投射是如何工作的,让我们看看在之前讲解过的代码:

TrackableHit hit;
        TrackableHitFlags raycastFilter = TrackableHitFlags.PlaneWithinPolygon | TrackableHitFlags.PlaneWithinBounds;

        if (Frame.Raycast(touch.position.x, touch.position.y, raycastFilter, out hit))
        {
            if ((hit.Trackable is DetectedPlane) && Vector3.Dot(FirstPersonCamera.transform.position - hit.Pose.position, hit.Pose.rotation * Vector3.up) < 0)
            {
                Debug.Log("射线击中了DetectedPlane的背面!");
            }
            else
            {
                var FoxObject = Instantiate(prefab, hit.Pose.position, hit.Pose.rotation);
                FoxObject.transform.Rotate(0, mModelRotation, 0, Space.Self);
                var anchor = hit.Trackable.CreateAnchor(hit.Pose);
                FoxObject.transform.parent = anchor.transform;
            }
        }

  在上面的代码中,我们利用Frame.Raycast来构建了一条摄像机到点击点的射线,并对场景中的虚拟对象进行碰撞检测,如果有命中就检测命中点的姿态,然后创建一个锚点并将虚拟对象挂载在这个锚点上。在上面的代码中,我们使用了Unity内置的touch,这是手机屏幕的touch事件检测类,也就是Unity的手势检测类。

二、手势检测

  上面我们讲解了在AR中最基本最简单的交互。我们这里讲的手势检测是指用户在手机屏幕上的手指操作检测,不是指利用图像技术检测到用户手部运动的检测。

1、定义

  检测用户在手机屏幕上的手指触控运动来判断用户的操作意图。如单击、双击、缩放、滑动等等。

这里写图片描述

2、Unity中的手势检测

  Unity内置了手势检测,其包括最基本的触摸检测支持,还支持压力检测。其最主要的是Input类和Touch结构体。
  Input类
  Unity能够同时跟踪多根手指触摸屏幕的检测。可以通过访问input.touch属性数组来访问每个手指触摸屏幕在最后一帧中的状态数据。

Input类常见与手势检测相关的方法属性 属性说明
Input.GetTouch(int index) 返回特定触摸状态的对象。gettouch返回Touch结构体。
Input.touchCount 接触触摸屏的手指数量。这是个只读属性
Input.touches 返回上一帧中所有触摸状态的对象List,每个List表示手指触摸的状态。
touchPressureSupported Bool值,检测用户手机设备是否支持触摸压力特性。
touchSupported Bool值,返回应用程序当前运行的设备是否支持触摸输入。

  Touch结构体
  Touch结构体描述手指触摸屏幕的状态。Unity可以跟踪与触摸屏上的触摸有关的许多不同的数据,包括它的阶段(开始、移动、结束)、它的位置以及该触摸是一个单一的接触还是几个触点。此外,Unity还可以检测到帧更新之间的触摸的连续性,因此可以检测到一致的fingerId并用来确定手指是如何移动的。Touch结构体被Unity用来存储与单个触摸实例相关的数据,并由Input.GetTouch方法查询和返回。在Unity内部,每次帧更新都需要对GetTouch进行新的调用,以便从设备获得最新的触摸信息,但是可以使用该手指fingerId来识别帧间的相同触摸。

Touch结构体 属性说明
altitudeAngle 触控时的角度,0值表示触头与屏幕表面平行,π/2表示其垂直。
azimuthAngle 手写笔的角度,0值表示手写笔是沿着设备的x轴指向的。
deltaPosition 上次变化后的位置增量,delta值。
deltaTime 自上一次记录的触点值变化以来已过去的时间,delta值。
fingerId 触摸的唯一索引值。
maximumPossiblePressure 屏幕触摸的最大压力值。如果Input.touchPressureSupported返回false,则此属性的值将始终为1.0F。
phase 描述触摸的阶段。
position 以像素坐标表示的触摸位置。
pressure 施加在屏幕上的当前压力量。1.0F被认为是平均触点的压力。如果Input.touchPressureSupported返回false,则此属性的值将始终为1.0F。
radius 一个触点半径的估计值。加上radiusVariance得到最大触摸尺寸,减去它得到最小触摸尺寸
radiusVariance radiusVariance这个值决定了触控半径的准确性。把这个值加到半径中,得到最大的触控大小,减去它得到最小的触控尺寸。
rawPosition 用于触摸的原始位置。
tapCount 触点的数量。
type 指示触摸是直接、间接(或远程)还是手写笔类型的值。

  TouchPhase枚举
  TouchPhase是一种枚举类型,它包含可能的手指触点的状态。这些状态代表了手指在最近的帧中可能的每一个动作。由于触摸是通过设备在其“生命周期”内跟踪的,所以触摸的开始和结束以及其间的运动可以在它们发生的帧上检测。

TouchPhase 属性说明
Began 一根手指触到了屏幕,开始跟踪。
Moved 一根手指在屏幕上移动。
Stationary 一根手指触摸着屏幕,但没有移动。
Ended 一个手指从屏幕上被抬起。跟踪结束。
Canceled 系统取消了对触摸的跟踪。

3、常用手势检测插件

  Unity提供了最基础的手势检测支持,为更方便操作使用,当前有很多简单易用的手势检测插件可供选择,如:

  1. FingerGuesture
      FingerGestures插件。监听Unity中的各种手势事件:上下左右四方向的滑动、按下、抬起、移动、连击、长按等等。FingerGestures同时支持触摸屏操作与鼠标操作,其通过C#代理(delegete)形式来实现手势操作的。FingerGestures Unity插件通过预设来监听触摸与鼠标的手势事件。包括:单手触摸事件、双手触摸事件、鼠标事件、触摸事件。
  2. EasyTouch
      EasyTouch插件。EasyTouch插件也能检测常见的触摸屏操作,EasyTouch插件还支持摇杆(Joystick)、Dpad。也是常用的手势检测插件。

猜你喜欢

转载自blog.csdn.net/yolon3000/article/details/82810021