探究 HelloAR 示例应用代码

深入探究 ARCore SDK for Unity 示例应用代码,以了解 SDK 组件在 AR 场景中的工作方式。

先决条件

本指南假定您已下载和安装 ARCore SDK for Unity。 如果您是第一次使用该 SDK,请先参阅 ARCore SDK for Unity 快速入门指南

浏览示例应用

看一看 HelloAR 示例场景中的 SDK 组件。

  1. 在 Unity Project 窗口中,导航至 Assets > Examples > HelloAR > Scenes > HelloAR

  2. 双击 HelloAR 场景将其打开。

  3. 使用 Hierarchy 窗口开始在示例场景中导航。 您将找到下列 ARCore 游戏对象:

    游戏对象 说明
    ARCore 设备 管理 ARCore 会话的预制件

    容纳第一人称摄像头 游戏对象,该对象利用您设备的后置摄像头采集现实图像并将它们用作 AR 场景的背景。
    环境光 通过预估您的相机采集的图像平均像素亮度来调整 AR 场景光照的预制件。 要执行此操作,在每一帧中:
    点云 适用于在当前帧中检测到的特征预制件
    示例控制器 控制器脚本管理 AR 场景的游戏对象。
    控制器脚本包含对下列游戏对象的引用:
    • 第一人称摄像头
    • 用于动态创建游戏对象的预制件:
      • 检测到的平面: 用于显示检测到的平面的预制件。
      • Andy Android:用户可置于 AR 场景内的预制件。
      • 查找平面:平面检测期间显示的界面文本元素。

    请参阅下文,对 Example Controller 代码进行单步调试。

探究代码

既然您对示例场景中的主要 ARCore 游戏对象已有大概了解,请单步调试使它们协同工作的代码。

ExampleController 脚本实现了 ARCore 示例应用体验的关键层面。

访问代码

  1. HelloAR 场景中,点击 Example Controller 游戏对象。

  2. Inspector 窗口中,双击 HelloARController 脚本以在编辑器中打开它。

单步调试代码

看一下代码。 在 HelloARController 脚本中,Update() 函数处理每个帧中的关键任务:

检查有无运动跟踪

  • 运动跟踪提供平面检测。 Update() 函数会调用 _UpdateApplicationLifecycle() 函数来检查运动跟踪。 以下代码位于 _UpdateApplicationLifecycle()
  // Check that motion tracking is tracking.
  if (Session.Status != SessionStatus.Tracking)
  {
      Screen.sleepTimeout = SleepTimeout.SystemSetting;
  }
  else
  {
      Screen.sleepTimeout = SleepTimeout.NeverSleep;
  }

检测现实场景中的新平面和现有平面

  • ARCore 寻找要在现实场景中跟踪的新平面

  • 尚未检测到新平面和现有平面时,将一直显示“Seaching for Planes”界面文本元素。 一旦对至少一个平面进行了跟踪,文本元素就会隐藏起来。

 // Hide snackbar when currently tracking at least one plane.
    Session.GetTrackables<DetectedPlane>(m_AllPlanes);
            bool showSearchingUI = true;
            for (int i = 0; i < m_AllPlanes.Count; i++)
            {
                if (m_AllPlanes[i].TrackingState == TrackingState.Tracking)
                {
                    showSearchingUI = false;
                    break;
                }
            }

            SearchingForPlaneUI.SetActive(showSearchingUI);

处理放置虚拟物体的用户输入

跟踪平面后,Update() 函数会处理在平面上放置 Andy Android 对象的用户输入。

  • 当用户点按界面时,Frame.Raycast() 使用来自点按位置的光线投射来检测用户点按了平面还是定向点

  • 如果用户点按平面或定向点表面,则在用户点按的 TrackableHit 姿态处实例化 Andy Android 对象。

  • 命中姿态用于创建锚点

    • 锚点可让 Andy 游戏对象保持在相同的实境相对位置。

    • 当您不再需要锚点时,请对其调用 Unity GameObject Destroy() 函数。 它会指示 ARCore 停止跟踪锚点。

  • 摄像头位置用于调整 Andy 对象的转换,使得从他的位置来看,Andy 正对着摄像头。

  • Andy 对象的转换继承了命中的锚点,这样一来,用户四处移动手机时,Andy 对象始终位于用户放置它的位置。

   // Raycast against the location the player touched to search for planes.
            TrackableHit hit;
            TrackableHitFlags raycastFilter = TrackableHitFlags.PlaneWithinPolygon |
                TrackableHitFlags.FeaturePointWithSurfaceNormal;

            if (Frame.Raycast(touch.position.x, touch.position.y, raycastFilter, out hit))
            {
                // Use hit pose and camera pose to check if hittest is from the
                // back of the plane, if it is, no need to create the anchor.
                if ((hit.Trackable is DetectedPlane) &&
                    Vector3.Dot(FirstPersonCamera.transform.position - hit.Pose.position,
                        hit.Pose.rotation * Vector3.up) < 0)
                {
                    Debug.Log("Hit at back of the current DetectedPlane");
                }
                else
                {
                    // Instantiate Andy model at the hit pose.
                    var andyObject = Instantiate(AndyAndroidPrefab, hit.Pose.position, hit.Pose.rotation);

                    // Compensate for the hitPose rotation facing away from the raycast (i.e. camera).
                    andyObject.transform.Rotate(0, k_ModelRotation, 0, Space.Self);

                    // Create an anchor to allow ARCore to track the hitpoint as understanding of the physical
                    // world evolves.
                    var anchor = hit.Trackable.CreateAnchor(hit.Pose);

                    // Make Andy model a child of the anchor.
                    andyObject.transform.parent = anchor.transform;
                }
            }