01_ARKit平面检测原理

  1. 点云和平面检测

  ARKit是基于特征点实现环境理解,完成对平面的检测的。而识别出的多个特征点,就构建成了点云,通过三角测量算法,可以让三个点构成一个平面,经过多次计算以后,就可以得到这个平面在现实中的位置。

总结:ARKit通过识别空间中的多个特征点,将这些特征点进行计算,通过空间中任意的三个不在一条直线上的点确定一个平面(即两个空间坐标不相同的点可以构成一条直线,一条直线和线外一点可以确定一个平面),通过无数个特征点计算可以得到N个平面,将这些平面根据尺度、方向和位置,找到最匹配的作为空间平面。

  1. 点云的可视化

  Create Empty并命名为PointCloud,添加一个新的脚本[PointCloudParticleExample],选择需要的特征点样式并填写自己需要显示的最大特征点数量及特征点大小。
脚本配置
编译运行,得到效果:

点云可视化效果

02_ARKit阴影和遮罩

阴影(Shadow)

  在AR应用里,阴影扮演着一个非常重要的角色,通过阴影我们可以直观的感受到当前场景的光源位置、光线强弱、物体的轮廓等,通过将虚拟物体的阴影和现实世界的光照条件统一,我们可以获得更加真实的、符合视觉规律的增强现实体验。

如何在项目中创建阴影?

  1. 将主摄像头[Main Camera]设置为深感摄像头[Depth only]。
    Depth only

  2. 添加Unity AR Camera Manager脚本,并将主摄像头[Main Camera]拖拽入Camera项。
    添加Unity AR Camera Manager脚本

  3. 添加Hit Result Controller脚本,并将下载的AR模型拖入Obj项
    Hit Result Controller脚本
    脚本内容如下:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.XR.iOS;
    
    public class HitResultController : MonoBehaviour
    {
        //private Text text;
    
        public GameObject currentObj;
    
        public GameObject obj;
    
        // Start is called before the first frame update
        void Start()
        {
        
        }
    
        // Update is called once per frame
        void Update()
        {
            if (Input.touchCount > 0)
            {
                var touch = Input.GetTouch(0);
                if(touch.phase == TouchPhase.Began || touch.phase == TouchPhase.Moved)
                {
                    Vector3 screenPos = Camera.main.ScreenToViewportPoint(touch.position);
                    ARPoint point = new ARPoint
                    {
                        x = screenPos.x,
                        y = screenPos.y,
                    };
                    ARHitTestResultType[] resultTypes =
                    {
                        ARHitTestResultType.ARHitTestResultTypeFeaturePoint,
                        ARHitTestResultType.ARHitTestResultTypeEstimatedHorizontalPlane,
                        ARHitTestResultType.ARHitTestResultTypeExistingPlane,
                        ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingExtent,
                    };
    
                    foreach (ARHitTestResultType type in resultTypes)
                    {
                        List<ARHitTestResult> hitTestResults = UnityARSessionNativeInterface.GetARSessionNativeInterface().HitTest(point, type);
                        //text.text = hitTestResults[0].worldTransform.ToString();
                        if(currentObj == None)
                        {
                            currentObj = Instantiate(obj);
                        }
                        currentObj.transform.position = UnityARMatrixOps.GetPosition(hitTestResults[0].worldTransform);
                        //currentObj.transform.rotation = UnityARMatrixOps.GetRotation(hitTestResults[0].worldTransform);
                    }
    
                }
            }
        }
    }
    
    

    脚本内容大致为点击后在点击位置显示模型。
    模型下载链接:https://www.mixamo.com/

  4. 添加平面检测对象及添加Unity AR Generate Plane脚本,其中Plane Prefab项选择 shadowPlanePrefab
    添加平面检测对象

  5. 添加点云对象并进行相关配置
    添加点云对象

  6. 选择Build Settings并进行项目配置,run。

  7. 运行效果
    运行效果

  8. 阴影优化,点击[Directional Light],进行相关配置
    阴影优化_1
    打开Project Settings,选择Quality,进行相关配置
    阴影优化_2

  9. 重新编译运行。得到阴影优化过的效果。
    阴影优化效果

    可以看的阴影效果稍微暗淡一点(可以调整),但是显得更加真实。


总结:

  1、这里使用Unity内置阴影实现,优点是美观、效果好,缺点是性能消耗比较大。
  2、内置可以满足学习阶段的开发,在后续的项目实战中,将会采用一些插件来实现阴影,降低性能开销,并且基于环境理解实现动态阴影。

遮罩(Occlution)

  现阶段,大部分的AR技术都会遇到遮罩问题,主要体现在真实物体和虚拟对象的前后位置关系,如果不能实现巧妙的遮挡效果,这个问题将会
影响用户使用时的体验。

如何在项目中加入遮罩?
加入遮罩

在开发中,我测试的遮罩效果不太好,就不演示效果了。

03_ARKit图片识别

1. ARKit图片识别的条件

  借助ARKit中的图像识别功能,我们可以构建识别平面图像(如海报或产品包装)的AR应用。
  只需要提供一组图片,在用户的相机摄像头检测到图像时,ARKit会创建一个图片锚点[Image Anchor],告诉我们这些图像在AR绘画中的物理位置。我们可以基于图片锚点,加载自定义模型、动画、文字、视频等内容。
  在AR应用中,图片识别是非常重要、十分常见的形式,我们可以使用ARKit的图片识别开发AR书籍、AR名片、AR卡牌游戏等应用。

ARKit图片的建议:

  1. 检测仅基于高对比度的点,所以彩色和黑白图像都会被检测到,无论是使用彩色还是黑白参考图像都可以;
  2. 避免使用具有稀疏特征的图像;
  3. 避免使用具有重复特征的图像;
  4. 在Build的时候Xcode会对不符合要求的图像进行提示。
    图片

图片来源于腾讯课堂: ARKit视觉风暴https://ke.qq.com/course/575145


技术选型考虑的因素:

  1. 用户设备需要支持ARKit:设备需要A9处理器以上(iphone 6s/SE以上);
  2. ARKit 1.5版本开始支持图片识别;
  3. ARKit 3.0版本支持同时追踪最多100张以上的图片;
  4. ARKit的图片识别主要针对平面图片识别,不规则形状图片偶尔会识别失败(如可乐瓶包装);
  5. 图片识别时也要考虑光照条件,光线暗、反光的情况可能会识别不出。

2. 如何实现ARKit的图片识别

  1. 创建unity项目,倒入ARKit插件;

  2. 在MainCamera中添加脚本并进行相关配置
    脚本配置

  3. 新建ARReferenceImagesSet,新建ARReferenceImage并导入照片。
    新建ARReferenceImagesSet

    ARReferenceImage配置

    ARReferenceImagesSet配置

    需要将ARReferenceImagesSet、ARReferenceImage和项目场景放在同一路径下。

  4. 与MainCamera关联
    MainCamera Unity AR Camera Manager配置

  5. 新建EmptyObject,添加脚本并进行相关配置
    GenerateImageAnchor配置

  6. 编译运行,得到效果
    IMG_1535.png


04_第一个可交互的AR项目

AR交互

为了增加用户体验,我们往往会在项目中加入可以交互的元素,例如:按钮,选择框等等,用于用户和程序之间的互动。

在项目中添加按钮

添加按钮

修改Canvas

修改按钮属性

可以选中元素后,在右侧对元素属性进行修改。

为按钮添加点击事件

在合适的脚本中添加点击时的事件,本案例中,是需要改变识别后出现的Cube的颜色,所以,选择在上一节中的GenerateImageAnchor脚本中添加方法,方法如下:

public void setRedColor()
{
    print("改变前: " + imageAnchorGO.GetComponent<Renderer>().material.color);
    imageAnchorGO.GetComponent<Renderer>().material.color = Color.red;
    Debug.Log("点击红色按钮易以后颜色为: " + imageAnchorGO.GetComponent<Renderer>().material.color);
}

public void setBlueColor()
{
    print("改变前: " + imageAnchorGO.GetComponent<Renderer>().material.color);
    imageAnchorGO.GetComponent<Renderer>().material.color = Color.blue;
    Debug.Log("点击红色按钮易以后颜色为: " + imageAnchorGO.GetComponent<Renderer>().material.color);
}

public void setYellowColor()
{
    print("改变前: " + imageAnchorGO.GetComponent<Renderer>().material.color);
    imageAnchorGO.GetComponent<Renderer>().material.color = Color.yellow;
    Debug.Log("点击红色按钮易以后颜色为: " + imageAnchorGO.GetComponent<Renderer>().material.color);
}

此处学习使用两种方法打印日志


在按钮事件出点击添加,并选在上步骤中添加的对应的操作对象和方法。
为按钮添加点击事件

同理,多个ImageAnchor需要使用共同的方法,只需要进一步在onclick处添加对应的对象和方法:
为按钮添加点击事件

编译运行,得到效果

您的浏览器不支持播放该视频!

并且可以在Xcode控制台看到日志
控制台日志

修复空对象的Bug

在变换颜色之前,加入判断,判断当前对象是否不为空

public void setRedColor()
{
    // 判断当前对象不为空
    if (imageAnchorGO != None)
    {
        print("改变前: " + imageAnchorGO.GetComponent<Renderer>().material.color);
        imageAnchorGO.GetComponent<Renderer>().material.color = Color.red;
        Debug.Log("点击红色按钮易以后颜色为: " + imageAnchorGO.GetComponent<Renderer>().material.color);
    }
    else
    {
        Debug.Log("当前imageAnchorGO为空");
    }

}

public void setBlueColor()
{
    if (imageAnchorGO != None)
    {
        print("改变前: " + imageAnchorGO.GetComponent<Renderer>().material.color);
        imageAnchorGO.GetComponent<Renderer>().material.color = Color.blue;
        Debug.Log("点击红色按钮易以后颜色为: " + imageAnchorGO.GetComponent<Renderer>().material.color);
    }
    else
    {
        Debug.Log("当前imageAnchorGO为空");
    }
}

public void setYellowColor()
{
    if (imageAnchorGO != None)
    {
        print("改变前: " + imageAnchorGO.GetComponent<Renderer>().material.color);
        imageAnchorGO.GetComponent<Renderer>().material.color = Color.yellow;
        Debug.Log("点击红色按钮易以后颜色为: " + imageAnchorGO.GetComponent<Renderer>().material.color);
    }
    else
    {
        Debug.Log("当前imageAnchorGO为空");
    }
}

加入手机日志显示

在插件商店中找到Log Viewer插件,下载并导入。
Log Viewer

点击Report -> Create,使用该插件

image.png

重新打包该项目,然后在屏幕上画圆圈,即出现日志系统。
日志显示


05_使用自定义的3D模型

为什么要使用自定义的3D模型

  ARKit以及Unity自带的3D模型往往是不能够满足日常开发使用的,但是对于新手小白来说,制作一个3D模型又比较困难,因此,我们往往通过一些3D模型资源网站下载,并加入到我们的项目中。

如何下载免费的3D模型

资源网站:

网站名称 网址 描述
CG模型网 https://www.cgmodel.com/ 部分免费 不可商用
爱给网 http://www.aigei.com/ 完全免费 部分商用
Unity资源商店 https://assetstore.unity.com/ 部分免费 模型和账号绑定
Free 3D https://free3d.com/ 免费区免费 网站打开慢
mixamo https://www.mixamo.com/ 完全免费 动画绑定 推荐
Unity Chan https://unity-chan.com/ 完全免费 开源 推荐

导入自定义3D模型

在当前Assets中新建文件夹Model,通过 Import New Asset 将下载好的模型导入进来。
导入自定义模型

默认导入后的自定义3D模型是没有贴图的,需要选中该模型,在Inspector中选择Materials,点击Textures的选择菜单,选择模型所在目录,点击Choose,如果提弹出Fix提示框,选择Ignore。

导入模型贴图

将模型放入场景,如出现没有头发或者衣物材质异常的问题,在Model路径下新建Material,进行相关配置,将配置好的材质拖到场景中的模型上。
Material

效果展示:
3D模型展示

在当前场景目录下,新建Prefabs文件夹,并将场景中的3D模型放入Prefabs作为预制,并删除当前场景中的模型
预制模型

因为模型与现实是等比例大小,所以需要将模型等比例缩小。
缩小模型

把前两节项目中的cube更换为配置好的3D模型。
更换模型

效果展示

image.png

播放模型动画

在当前场景目录下,新建Scripts文件夹,并在文件夹中创建Animator Controller,点击该文件,并自定义3D模型的动画拖拽到场景中。
image.png
进行相关配置
动画配置

参数说明:
    loap time: 循环播放
    loap pose: 原地播放

将动画脚本加入到模型
将动画脚本加入到模型

编译运行,得到效果

您的浏览器不支持播放该视频!

模型脱卡

脱卡,即卡片消失后模型依然存在。编辑GenerateImageAnchor脚本

void UpdateImageAnchor(ARImageAnchor arImageAnchor)
{
    // Debug.LogFormat("image anchor updated[{0}] : tracked => {1}", arImageAnchor.identifier, arImageAnchor.isTracked);
    if (arImageAnchor.referenceImageName == referenceImage.imageName)
    {
        if (arImageAnchor.isTracked)
        {
            if (!imageAnchorGO.activeSelf)
            {
                imageAnchorGO.SetActive(true);
            }
            imageAnchorGO.transform.position = UnityARMatrixOps.GetPosition(arImageAnchor.transform);
            imageAnchorGO.transform.rotation = UnityARMatrixOps.GetRotation(arImageAnchor.transform);
        }
        else if (imageAnchorGO.activeSelf)
        {
            // 脱卡. 取消找不到识别对象时让模型消失
            // imageAnchorGO.SetActive(False);
        }
    }

}

效果展示

您的浏览器不支持播放该视频!

本章总结

注意事项

  1. 关掉平面检测
  2. 设置识别图、调整识别图的大小
  3. 设置相对目录
  4. 设置相机相关
  5. 设置模型大小和距离图片的位置,模型太大可能会出现看不到的情况
  6. 绑定模型动画
  7. 设置按钮点击事件
  8. 模型脱卡

06_ARKit之ARFoundation入门

什么是ARFoundation

ARFoundation是Unity于2018年推出的跨平台AR开发工具,致力于建成一个统一、开放的AR平台,ARFoundation并不直接提供AR底层技术,而是通过对底层API的进一步封装,ARFoundation提供独立于平台的API,降低开发者对安卓平台ARCore、iOS平台ARKit等技术的开发时间成本。

因此,使用ARFoundation进行开发的好处在于可以通过ARFoundation同时使用ARCore和ARKit的核心功能,只需开发一次应用,就可以部署到安卓、iOS等不同系统的设备上,让开发变得更加便捷。

ARFoundation 与 ARKit 和 ARCore 的关系

ARFoundation与ARKit和ARCore的关系

ARFoundation 生态

ARFoundation生态

ARFoundation 架构与术语

支持功能 ARFoundation ARCore ARKit
垂直平面检测
水平平面检测
特征点检测
✔ + 支持特征点姿态
光照估计
✔ + Color Correction
✔ + Color Temperature
射线测试(Hit Testing,对特征点与平面的射线碰撞测试)
图像跟踪
3D物体检测与跟踪
-
环境光探头(Environment Probes)
-
世界地图
-
人脸跟踪(识别、姿态、网格和形状混合)
✔(iphoneX 及更高型号)
云锚点(Cloud Anchors)
-
远程调试(Editor Remoting)
开发中
✔-Instant Preview
✔-ARKit Remote
模拟器(Editor Simulation)
-
-
LWRP支持(支持使用ShaderGraph)
开发中
开发中
摄像机图像API
-
人体动作捕捉(Motion capture)
-
✔(iphoneX 及更高型号)
人形遮挡(People Cclusion)
-
✔(iphoneX 及更高型号)
多人脸检测
-
✔(iphoneX 及更高型号)
多人协作(Collaborative session)
-
✔(iphoneX 及更高型号)
多图像识别
✔(iphoneX 及更高型号)

功能 描述
世界跟踪(World tracking) 在物理空间中跟踪用户设备的位置和方向(姿态)
平面检测(Plane detection) 对水平与垂直平面进行检测
参考点(Reference points) 对特定点的姿态跟踪,ARCore中称为Anchor
光照估计(Light estimation) 对物理环境中的光照强弱及方向进行估计
人脸跟踪(Face tracking) 检测并跟踪人脸
图像跟踪(Image tracking) 跟踪物理空间中的2D图像
人脸跟踪(Face tracking) 检测并跟踪人脸
物体跟踪(Object tracking) 跟踪物理空间中的物体对象,目前只支持ARKit
Seesion分享 支持多人共享场景,在ARKit中称为多人协作(Collaborative session),在ARCore中称为Cloud Anchor
人体动作捕捉(Motion capture) 简称动捕,检测物理空间中的人体及动作,用- -个由17根骨骼组成的层次关节来表达人体动作
人形遮挡(People occlusion) 利用计算机视觉判断人体在场景中的位置,获取人体形状及在场景中的位置实现虚拟物体遮挡
摄像机图像API 提供摄像机图像底层支持,方便开发人员开发计算机视觉应用

ARFoundation 只是提供了跨平台开发的方案, 但实际开发中仍需要ARCore 和 ARKit的支持,例如即便 ARFoundation 提供了人体动作捕捉(Motion capture),但因为只有ARKit提供了这一技术,所以只能在iOS设备上使用。

ARFoundation ARKit注意事项

1、由于 ARFoundation 是再次封装,主要侧重于便捷性和开发效率,程序运行效率和兼容性与原生SDK相比会有所差距;
2、ARFoundation 并不提供底层开发API,平台相关的API均由第三方如ARKit、ARCore提供,因此ARFoundation无法在第一时间使用ARKit SDK的最新功能,因为对新版本的集成需要时间。

ARFoundation 开发环境搭建

1、建议安装Unity2019.1以上版本(为了能够使用 ARKit3 及以上版本功能)
2、XCode10以上版本

新建Unity项目,选择 Window -> Package Manaager
Package Manaager

选择ARFoundation,并点击 install
ARFoundation安装

选择ARKit XR Plugin,并点击install
ARKit XR Plugin安装

如果需要用到人脸追踪,选择ARKit Face Tracking, 并点击install
ARKit Face Tracking安装

如果需要用到ARCore相关功能,选择ARCore XR Plugin, 并点击install
ARCore XR Plugin安装

Hello ARFoundation

删除原有 Main Camera,并新增AR会话,并添加AR Plan Manager脚本
新增AR会话并添加脚本

新增AR Default Plane,并制成预制件,放入创建好的Prefabs文件夹中,然后删除场景里的AR Default Plane,将制作好的预制件拖拽到 AR Plan Manager 脚本中。
制作预制件
将预制件添加到脚本

在AR Session Origin组件中添加 AR Raycast Manager脚本
image.png

在新创建的Scripts文件夹中,新建C#脚本命名为DetectionController.cs,并写入以下代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

// 强制必须加载此类
[RequireComponent(typeof(ARRaycastManager))]
public class Controller : MonoBehaviour
{
    // 需要加载的模型
    public GameObject model;
    // 射线检测管理器
    public ARRaycastManager aRRaycastManager;
    // 当前场景中是否已经加载模型
    public GameObject currentModel;


    void Start()
    {

    }

    void Update()
    {
        // 判断当前屏幕上是否有点击
        if (Input.touchCount > 0)
        {
            // 获取当前屏幕点击
            var touch = Input.GetTouch(0);

            List<ARRaycastHit> hits = new List<ARRaycastHit>();

            // 通过aRRaycastManager进行射线检测
            if (aRRaycastManager.Raycast(touch.position, hits, TrackableType.All))
            {
                // 获取射线检测的结果
                var hitPose = hits[0].pose;
                // 判断当前场景是否有模型
                if (currentModel == None)
                {
                    // 在点击位置加载模型
                    currentModel = Instantiate(model, hitPose.position, hitPose.rotation);

                    // 第二种写法
                    //currentModel = Instantiate(model);
                    //currentModel.transform.position = hitPose.position;
                    //currentModel.transform.rotation = hitPose.rotation;
                }
                else
                {
                    // 改变当前模型的位置
                    currentModel.transform.position = hitPose.position;
                    currentModel.transform.rotation = hitPose.rotation;
                }
            }
        }
    }
}

将脚本挂载到AR Session Origin
将脚本挂载到AR Session Origin

添加自定义模型预制件,并挂载到脚本上。
挂载自定义模型

效果展示

效果展示1
效果展示2

本次实验中,平面检测效果不理想。

07_ARKit1.5之面部增强入门

什么是面部增强

  面部增强是近年来比较流行的AR应用形式,主要应用方式是通过AR的面部追踪技术实现对人脸检测,根据特征结构识别出人脸后,将业务模型加载到用户面部的指定位置。
  ARKit的面部追踪功能于2017年上线,主要基于iPhone手机的前置TrueDepth深度摄像头。检测相机画面中的人脸,然后覆盖匹配的虚拟内容并实时动态匹配人脸表情动画。

面部追踪[Face Tracking]技术原理

  ARKit以每秒60帧的速度,基于关键特征点和欧拉角估计每一帧中人脸的位置和方向,由此提供人脸拟合三角网络[Face Mesh Geometry],构成ARFaceGeometry对象,ARFaceGeometry包含渲染这个面部网络所需的所有信息,并且通过顶点、三角形、检测坐标来进行表示。

  通过ARFaceGeometry,可以得到面部追踪锚点[FaceAnchor],其中包含了执行面部追踪所需的所有信息。

  为了逼真的渲染这样的面部几何模型,ARKit 以脸部作为 Light Probe,使用当前场景的光照进行调整光强、光照方向和色温,这足以满足绝大部分的AR应用的需求。

如果开发者追求更逼真的效果,也可以通过 ARKit 提供的二次球谐系数[Spherical harmonics cofficients]收集当前场景对光照条件进一步对面部增强AR应用进行优化。

  ARKit提供了实时表情追踪,基于实时表情追踪,可以让我们添加的AR虚拟内容跟随我们的面部表情进行变化。

实时表情追踪原理: 混合形状[Blend Shapes]
表情其实是由混合形状[Blend Shapes]构成的,ARKit可以识别出50多种不同的混合形状。
混合形状
假定一个0和1之间的值,1意味着完全激活,0则说明没有激活,例如当我们张开嘴时,下颚打开系数值将接近1,如果合上嘴,值接近0。


实时表情追踪原理: 凝视跟踪
FaceAnchor的成员变量:
leftEyeTransform 左眼
rightEyeTransform 右眼
lookAtPoint 两个凝视方向的交叉点
ARKit 可以在 6 自由度跟踪左眼和右眼。
凝视追踪


实时表情追踪原理: 舌头跟踪
舌头追踪以新的混合形状出现,当用户伸出舌头时,这个混合形状,假设值则为1,反之则为0。
舌头跟踪

ARKit Face Tracking 注意事项

  1. 运行环境
      运行面部追踪项目,要求带有前置TrueDepth摄像头的iOS设备:iPhone X,iPhone XS,iPhone XS Max 或 iPhone XR,iPad Pro (11英寸) 或 iPad Pro(12.9英寸,第三代),iOS 11.0 或更高版本。
      开发工具 Xcode 10.0 或更高版本,ARKit在iOS Simulator中不可用。

  2. 版本问题
      如果没有找到想要的AR Foundation 版本,打开预览版本。
    AR Foundation预览版本

  3. 模型位置
      基于位置偏移的AR展示可能会出现不同人群体验效果不同,比如儿童的眼睛离中心点的距离小于成人,如果以儿童为参照调调整眼镜类AR试穿物品,成人使用的时候位置就会有偏差,反过来也是一样。

体验 AR Foundation 示例

  1. 下载示例
    https://github.com/Unity-Technologies/arfoundation-samples

  2. 打开示例项目
    image.png

注:首先我使用了导入项目的形式,但是反复报错,各种错误,于是采用了直接打开AR Foundation的项目,经测试,成功。

  1. 运行效果
    FacePose

FaceMesh

ARKitFaceBlendShapes

EyeLasers

EyePoses

以上图片均进行处理,只为显示面部增强和表情追踪效果。

ARFoundation ARKit核心API

库(类) 说明
ARSession 管理生命周期,如决定开始、暂停和结束
ARInputManager 管理输入相关信息
ARSession Origin 原点,用于实现Transform转换
ARCamera 自带相机
     
ARFaceManager   
FacePrefab 模型的预制件
Maxinum Face Count 最多同时追踪人脸数量

08_ARKit1.5之面部增强实战

新建项目并配置环境

1、新建项目FaceTracking
2、安装ARFoundation及FaceTracking的相关插件

配置当前场景

在当前场景中新建 AR Session和 AR Session Orgin,将 AR Session Orgin 设置为 Main Camera后删除当前场景中的原有 Main Camera。
配置当前场景

准备Mask模型

可以在Assert Store里搜索并下载喜欢的mask模型
搜索并下载模型

导入模型

加入模型

添加ARFaceManager脚本,并将下载的模型添加到脚本中
加入模型

注:经测试,如果直接添加模型,将模型y轴旋转180度,在显示时,面具方向会反向,所以需要包裹在GameObject对象中。

效果展示

未包裹在GameObject对象中:

未包裹在GameObject对象

包裹在GameObject对象中:

包裹在GameObject对象中

以上图片均进行处理,只为显示面部增强和表情追踪效果。

眼睛追踪

需要单独加入眼睛追踪的脚本
image.png!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
#if UNITY_IOS && !UNITY_EDITOR
using UnityEngine.XR.ARKit;
#endif

/// <summary>
/// Visualizes the eye poses for an <see cref="ARFace"/>.
/// </summary>
/// <remarks>
/// Face space is the space where the origin is the transform of an <see cref="ARFace"/>.
/// </remarks>
[RequireComponent(typeof(ARFace))]
public class EyePoseVisualizer : MonoBehaviour
{
    [SerializeField]
    GameObject m_EyePrefab;

    public GameObject eyePrefab
    {
        get => m_EyePrefab;
        set => m_EyePrefab = value;
    }

    GameObject m_LeftEyeGameObject;
    //GameObject m_RightEyeGameObject;

    ARFace m_Face;
    XRFaceSubsystem m_FaceSubsystem;

    void Awake()
    {
        m_Face = GetComponent<ARFace>();
    }

    void CreateEyeGameObjectsIfNecessary()
    {
        if (m_Face.leftEye != None && m_LeftEyeGameObject == None)
        {
            m_LeftEyeGameObject = Instantiate(m_EyePrefab, m_Face.leftEye);
            m_LeftEyeGameObject.SetActive(False);
        }

        //if (m_Face.rightEye != None && m_RightEyeGameObject == None)
        //{
        //    m_RightEyeGameObject = Instantiate(m_EyePrefab, m_Face.rightEye);
        //    m_RightEyeGameObject.SetActive(False);
        //}
    }

    void SetVisible(bool visible)
    {
        if (m_LeftEyeGameObject != None) //&& m_RightEyeGameObject != None
        {
            m_LeftEyeGameObject.SetActive(visible);
            //m_RightEyeGameObject.SetActive(visible);
        }
    }

    void OnEnable()
    {
        var faceManager = FindObjectOfType<ARFaceManager>();
        if (faceManager != None && faceManager.subsystem != None && faceManager.subsystem.SubsystemDescriptor.supportsEyeTracking)
        {
            m_FaceSubsystem = (XRFaceSubsystem)faceManager.subsystem;
            SetVisible((m_Face.trackingState == TrackingState.Tracking) && (ARSession.state > ARSessionState.Ready));
            m_Face.updated += OnUpdated;
        }
        else
        {
            enabled = False;
        }
    }

    void OnDisable()
    {
        m_Face.updated -= OnUpdated;
        SetVisible(False);
    }

    void OnUpdated(ARFaceUpdatedEventArgs eventArgs)
    {
        CreateEyeGameObjectsIfNecessary();
        SetVisible((m_Face.trackingState == TrackingState.Tracking) && (ARSession.state > ARSessionState.Ready));
    }
}

更新 ARFoundation 4.0.2

更新4.0.2后不能直接启动相机,需要配置以下服务:

更新 ARFoundation 4.0.2
更新 ARFoundation 4.0.2
更新 ARFoundation 4.0.2 文档

09_ARKit UI可视化界面优化

用户引导优化

浅谈人机交互

用户界面(User Interface)

用户界面(User Interface,简称UI )是指对软件的人机交互、操作逻辑、界面美观的整体设计。好的UI设计不仅是让软件变得有个性有品味,还要让软件的操作变得舒适、简单、自由、充分体现软件的定位和特点。

用户体验(User Experience)

用户体验(User Experience,简称UX或UE)是一种纯主观的在用户使用一个产品(服务)的过程中建立起来的心理感受。它是指用户使用一个产品时的全部体验。他们的印象和感觉,是否成功,是否享受,是否还想再来使用。

举例:如何描述平面检测

平面检测

ARKit 提供的 UX 方案

AR 引导视图 [AR Coaching View] 遮罩 [Overlays]

官方引导

官方AR应用示例:
官方AR应用示例

注:遗憾的是,该AR动画引导流程内置在 iOS 12+ 系统中,因此ARFoundation作为跨平台AR开发框架,目前未集成在框架中。

ARFoundation 提供的 UX 方案

将 ARFoundation 官方示例导入项目,并将 ScreenSpaceUI 复制到自己项目的场景中即可。
ARFoundation UX方案
ARFoundation引导

AR经典的交互场景

  1. 放大缩小场景中的模型
  2. AR测量
  3. 平面交互升级为3维交互

人机交互准则

1. 使用引导动画帮助用户入门

当用户需要扫描地面或者是垂直的墙面的时候,最好先暂时隐藏其他不必要的操作界面,先帮助用户定位平面并且放置虚拟物体。

引导动画

2. 设备不可用提示

当用户使用不支持ARKit的苹果设备打开应用时,应该及时提示,否则会给用户带来困惑,严重影响体验。

3. 适度使用持久按钮和菜单

当需要为用户提供功能菜单的时候,可以考虑在屏幕上使用间接控件,这样用户可以直接使用,无需移动设备在场景里到处寻找按钮。
另外,一些控件的颜色可以考虑设置为半透明,避免遮挡场景。

适度使用按钮和菜单

4. 引导用户找到虚拟物体

当用户找不到场景中的虚拟物体,又不想重新开始的的时候,可以提供箭头、指南针等虚拟引导工具,帮助用户找到当前场景中的AR物体。

引导用户找到虚拟物体

5. 允许用户重置场景、初始化平面

当用户想要重新开始扫描平面或放置虚拟物体的时候,我们需要给用户提供重新开始的按钮。

允许用户重置场景、初始化平面

6. 允许用户直接操作物体

简单的放大、缩小、平移和旋转,都可以直接用屏幕手势来实现,这样操作起来更加灵活便利,并且最好在用户操作的时候给出适当的响应动画,让用户意识到这样操作是正确的。

允许用户直接操作物体

7. 使用三维提示

在AR应用中,绝大多数情况下,生动的三维提示会比传统的二维提示方式带来更好的用户体验。

使用三维提示

8. 在支持AR的选择界面中使用AR标记

当想要在选择界面告诉用户可以使用AR模式的时候,可以通过AR标记来表达。

在支持AR的选择界面中使用AR标记

9. 创造舒适的增强现实体验

  1. 稳定60fps (帧率),保证画面中的物体不会出现跳跃或者闪烁
  2. 实现光照估计
  3. 为有光滑表面的虚拟物体添加环境纹理实现反光效果
  4. 正确的遮挡关系,呈现合理的视觉效果
  5. 添加刚体物理效果
  6. 尽可能的让相机/视场角覆盖整个设备可见的画面

创造舒适的增强显示体验

10. 优秀AR应用展示

优秀AR应用展示:优秀AR应用展示

注:本ARKit系列博客是根据 【子羽老师】发布在腾讯课堂的ARKit视觉风暴课程学习整理总结:https://ke.qq.com/course/575145