前语

2019年苹果推出了一个新的ARKit版别(ARKit3)和专门为AR场景研制的RealityKit。从WWDC视频和官网介绍上能够看出新的ARKit3 + RealityKit组合带来了很多新的运用场景以及明显提高了开发体会和运用体会。

所有这些功用基本上都需求最新体系(iOS13)和较新的设备(A12芯片以上),别的,RealityKit需求Swift开发,关于已转Swift开发的同学十分友好。

Reality是全新的结构,为AR量身定制,能够供给逼真的图像烘托、相机特效、动画、物理特效等等。凭借原生ARKit整合供给物理的超逼真烘托、变换和骨骼动画、空间音频和刚体物理等。再结合Reality Composer东西,就能构建出一个体会十分杰出的AR APP。下面咱们就是用ARKit3 + RealityKit结构,结合Reality Composer东西,开发一个简略的AR运用。

Reality Composer

Reality Composer在MAC、iPhone、iPad三个渠道都能够运用,一起能够进行无缝切换。它内建AR资源库,也能够自己导入一些新的第三方资源。惯例的动画或者物理特性现已完整内嵌在东西里,只需挑选想运用的动画或者动作,比如旋转或者摇摆等等,还能够以导出为轻量级 AR Quick Look 体会,以便用户放置和预览内容。所以,不管你是开发者仍是产品仍是设计师都能够无门槛的创造属于你自己的AR场景。

AR场景实践(2 ) - RealityKit探究
如上图(图1 – 3)所以,咱们能够挑选一个Reality Composer内建的AR模型没入场景,这儿咱们能够看到,Reality Composer内建的模型是十分多的,开发者尝试AR开发时,再也不用为寻觅模型发愁了。模型搭建十分简略,模型拖入场景,就算完结了。

导出usdz文件,这就是xcode需求的文件,咱们将该文件导入xcode工程,此刻,咱们就能够进行coding了。不过在开端coding前,咱们需求先把握最基本的结构知识,RealityKit。

RealityKit

介绍一下要完结一个最基本的AR场景,需求把握的Api。

ARView

ARView是能够运用 RealityKit 显现 AR 体会的视图,

Entity

RealityKit 中所有的虚拟目标都承继自 Entity ,RealityKit 界说了 Entity 的一些详细子类,它们供给常用的功用。

  • Entity – RealityKit 场景的一个元素,能够将供给实体外观和行为特征的组件附加到该元素。
  • Anchor entity – 将实体捆绑到场景的锚点。
  • Model entity – RealityKit烘托的物理目标

AR场景实践(2 ) - RealityKit探究

BodyTrackedEntity

BodyTrackedEntity和ModelEntity相同,都是承继Entity,这儿为什么会把BodyTrackedEntity独自拎出来讲,BodyTrackedEntity相对比较特别,ModelEntity用来烘托物理目标,而BodyTrackedEntity是用于经过盯梢真人来为 AR 场景中的虚拟人物设置动画的实体:

  • 它代表了一个人体
  • 包括骨骼和方位
  • 每帧都会更新
  • 将骨骼体系运用到.usdz 模型上

这提到能够将骨骼体系运用到模型上,那怎样运用呢?

AR场景实践(2 ) - RealityKit探究
看上图(图7),3D骨骼关节,包括的关节点共有 91 个,只要你的模型中包括这些场景称号,RealityKit 就会主动运用,再建立模型,RealityKit 就会主动驱动模型。

ARBodyAnchor

ARBodyAnchor就是在后置摄像头中盯梢人体方位和运动的锚点,它包括了本身的 Transform和内部的骨骼体系Skeleton。整个骨骼体系中髋关节Hip joint就是根节点Root,如下图(图8)所示:

AR场景实践(2 ) - RealityKit探究
每一个节点包括内部的父子关系及关节称号Joint Name。其间绿色节点是被追寻出来的,而黄色节点,如手指,则是固定在离它最近的绿色节点上,跟随运动的。如下图(图9)箭头所示,

AR场景实践(2 ) - RealityKit探究
假如要获取右手处的方位(图10),有两种办法: 相关于父节点的 localTransform 和相关于根节点的 modleTransform

func localTransform(for jointName: ARSkeleton.JointName) -> simd_float4x4?
func modelTransform(for jointName: ARSkeleton.JointName) -> simd_float4x4?

ModelEntity完结简略AR场景

咱们经过RealityKit完结一个AR场景时,加载一个AR模型,一般首要创建 AnchorEntity 的实例来锚定咱们的内容,并将锚点增加到场景的锚点集合中。 然后,实例化一个 ModelEntity 来表明场景中的物理目标,并将其作为子实体增加到锚点。 这样就完结了实体的实例化,详细的代码量不多,如下:

private func loadModelEntity() {
    do {
        let plane = try ModelEntity.load(named: "character/car")
        // 将模型放置在水平面上
        let anchor = AnchorEntity(plane: .horizontal, minimumBounds: [0.15, 0.15])
        arView.scene.anchors.append(anchor) //锚点
        anchor.children.append(car) //场景
    } catch {
        fatalError("加载失利")
    }
}

实例化ARView,用以承载实体场景

private lazy var arView: ARView = {
    let arView = ARView(frame: self.view.bounds)
    return arView
}()
override func viewDidLoad() {
    super.viewDidLoad()
    view.addSubview(arView)
}

至此,一个简略的AR模型实景展现的比如咱们现已完结了,咱们跑起来看看作用,此刻,玩具汽车出现在了我的办公桌上。

AR场景实践(2 ) - RealityKit探究

ARCoachingOverlayView

这个视图是引导用户去寻觅适宜的AR场景,整个进程都进行了杰出的封装,悉数主动识别和判定。引导视图也比较直接明晰,是能够直接接入到咱们的运用中的,咱们先看看引导作用

AR场景实践(2 ) - RealityKit探究
完结调用的代码不多

    private let guidanceOverlay = ARCoachingOverlayView()
    /// 增加ARCoachingOverlayView,引导用户调整设备姿势
    func setOverlay(automatically: Bool, forDetectionType goal: ARCoachingOverlayView.Goal) {
        //1. 将 GuidanceOverlay 链接到咱们当前的会话
        self.guidanceOverlay.session = self.arView.session
        self.guidanceOverlay.delegate = self
        self.arView.addSubview(self.guidanceOverlay)
        //2. 设置约束
        NSLayoutConstraint.activate([
          NSLayoutConstraint(item:  guidanceOverlay, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1, constant: 0),
          NSLayoutConstraint(item:  guidanceOverlay, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1, constant: 0),
          NSLayoutConstraint(item:  guidanceOverlay, attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leading, multiplier: 1, constant: 0),
          NSLayoutConstraint(item:  guidanceOverlay, attribute: .trailing, relatedBy: .equal, toItem: self.view, attribute: .trailing, multiplier: 1, constant: 0)
          ])
        guidanceOverlay.translatesAutoresizingMaskIntoConstraints = false
        //3. 启用叠加层,依据用户偏好主动激活
        self.guidanceOverlay.activatesAutomatically = automatically
        //4. 依据用户偏好设置叠加层的用途
        self.guidanceOverlay.goal = goal
    }
    .......
    ///调用setOverlay即可完结引导视图

咱们再看看完结引导视图后的运用体会(图14 – 17)

AR场景实践(2 ) - RealityKit探究

能够看到,ARCoachingOverlayView引导视图的参加,能够让用户更容易的调整设备到锚点的场景,也就更容易展现出咱们预设的AR场景内容,所以,这个仍是比较引荐运用的。

AR交互场景实践

上面咱们现现已过Reality Composer东西和RealityKit结构完结了一个基本的AR模型展现作用,假如咱们想进一步完结有交互的AR场景,咱们该怎样做?

咱们接着来看Reality Composer东西,它能够给咱们供给这些能力支撑,咱们给刚才的小汽车场景,再增加一个同样的小汽车,而且给这个小汽车,增加一个自界说的行为。如下图18所示

AR场景实践(2 ) - RealityKit探究
接着 咱们给小汽车增加一个轻点的触发行为,而且给这个轻点触发,增加一个施力操作,咱们挑选对向另一个小汽车,调整力度到5公里/时,至于为什么是5公里,这儿我试了更大的速度,力度太大,撞飞了,力度太小,作用不明显。咱们能够运转下看看实际的磕碰作用,如下图(图20),咱们能够看到磕碰行为正常,咱们将场景保存为.rcproject,导出到Xcode中,运用RealityKit加载出现看看是否能够正常出现作用。

AR场景实践(2 ) - RealityKit探究

如上图21所示,当咱们点击下方小汽车时,它依照咱们指定的方向和力度运动,而且撞到了另一个小汽车,当咱们继续点击的时候他继续依照指定的方向和力度运动。

至此,咱们运用Reality Composer东西制造的AR场景功用现已完结,Reality Composer东西+RealityKit结构完结AR场景十分的轻松和快捷。

AR动画&运动轨迹

上面一节内容咱们介绍了如何用Reality Composer完结AR行为交互,本节咱们来探究下,如何运用代码定制AR模型行为动画。

首要,咱们经过Reality Composer导出带动画的.usdz模型文件,假如Reality Composer没有你心仪的动画模型,也能够经过导入外部模型文件来完结主意,此处咱们运用Reality Composer自带的两个模型来完结咱们的主意

AR场景实践(2 ) - RealityKit探究
接下来,咱们来完结详细的作用

private func loadBody() {
    do {
        let gushou = try ModelEntity.load(named: "character/gushou")
        // 将模型放置在水平面上
        let anchor = AnchorEntity(plane: .horizontal, minimumBounds: [0.15, 0.15])
        arView.scene.anchors.append(anchor) //锚点
        anchor.children.append(gushou) //场景
        // 履行动画
        gushou.playAnimation(gushou.availableAnimations[0].repeat(count: 10), transitionDuration: 0.5, startsPaused: false)
    } catch {
        fatalError("加载失利")
    }
}

咱们将demo运转,咱们看看实际作用(图25),咱们能够看到gushou模型开端打鼓。

这就是在实体上播映给定的动画,完结的中心就是实体 ModelEntityplayAnimation办法

/// 实体上播映给定的动画  
/// Parameter animation:要播映的动画   
/// Parameter transitionDuration:动画的继续时间
/// Parameter startsPaused:控制动画播映的bool值
/// Return AnimationPlaybackController:用于发动的动画播映控制器, 并中止动画
public func playAnimation(_ animation: AnimationResource, transitionDuration: TimeInterval, startsPaused: Bool) -> AnimationPlaybackController

别的,还有一个playAnimation办法,是用来运用指定选项来播映动画, 比较上面方面,这个方案增加了几个选项参数

/// 运用指定选项来播映动画 
/// Parameter animation:要播映的动画   
/// Parameter transitionDuration:动画的继续时间
/// Parameter blendLayerOffset:当播映多个动画时运用动画,指定混合层的顺序
/// Parameter separateAnimatedValue:动画完结时动画进展是否重置
/// Parameter clock:运用自界说时间刻度驱动动画
/// Return AnimationPlaybackController:用于发动的动画播映控制器, 并中止动画
public func playAnimation(_ animation: AnimationResource, transitionDuration: TimeInterval = 0, blendLayerOffset: Int = 0, separateAnimatedValue: Bool = false, startsPaused: Bool = false, clock: CMClockOrTimebase? = nil) -> AnimationPlaybackController

那咱们用上面所列的动画办法来完结模型AutoRobot按轨迹移动的动画,模型加载的代码能够参阅上面的事例,此处咱们直接来看动画完结部分的代码

// 履行位移动画
robot.move(to: Transform(translation: [0,0,20]), relativeTo: robot, duration: 4, timingFunction: .easeInOut)

咱们能够看到robot向着新的方位移动,并在到达给定的方位后不再移动,依照上面的动画办法,咱们还能够给模型设置旋转,那么咱们能够给他设置先左90度的旋转,那么这样的位移+方向旋转,继续下来,会让 AutoRobot走出一个圈,这就好玩多了,咱们来完结试试,咱们现将动画分解:

  • AutoRobot 朝指定的方位移动
  • AutoRobot中止位移,此刻对AutoRobot进行旋转动画
  • 向左旋转90度后,中止旋转,此刻对AutoRobot进行位移动画
  • 以上的无论旋转,仍是位移,其实都是重复的,咱们最要害的就是要get动画完结的机遇

这些咱们能够经过监听scene来完结

// 订阅动画播映完结事件
animationEnd = arView.scene.subscribe(to: AnimationEvents.PlaybackCompleted.self, { [self] event in
    moveFoward.toggle()
    if moveFoward {
        // 履行位移动画
        robot.move(to: Transform(translation: [0,0,20]), relativeTo: robot, duration: 4, timingFunction: .easeInOut)
    } else {
        // 履行旋转动画
        robot.move(to: Transform(rotation: simd_quatf(angle: 90 * .pi / 180, axis: [0,1,0]) ), relativeTo: robot, duration: 3, timingFunction: .easeInOut)
    }
})

至此,关于模型的位移、旋转、重复动画,咱们先介绍到这儿,至于愈加杂乱的动画,其实是能够经过组合以上三类动画来完结的。

AR场景实践(2 ) - RealityKit探究

AR追寻人体运动

上面章节咱们现已介绍了ARBodyAnchor和BodyTrackedEntity,这是完结追寻人体的要害类。ARBodyAnchor是 ARAnchor 的子类,负责盯梢单个人的运动。相关的装备装备就是ARbodyTrackingConfiguration

当 ARKit 识别出后置摄像头画面中的人物时,它会运用 ARBodyAnchor 调用委托的 session(_:didAdd:) 函数。 身体锚点的变换方位界说了身体髋关节的方位。

原理和相关的类咱们现已搞清楚了,现在咱们来完结,首要咱们初始化相关的类

/// 要显现的的3D人物
var character: BodyTrackedEntity?
/// 骨骼方位
let characterOffset: SIMD3<Float> = [-1, 0, 0]
let characterAnchor = AnchorEntity()

接下来咱们进行相关视图、署理和装备的设置

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    arView.session.delegate = self
    // 设备是否支撑
    guard ARBodyTrackingConfiguration.isSupported else {
        fatalError("需求A12芯片以上的iOS设备")
    }
    // run身体盯梢装备
    let configuration = ARBodyTrackingConfiguration()
    arView.session.run(configuration)
    arView.scene.addAnchor(characterAnchor)
    // 异步加载3D人物
    loadBody()
}

加载骨骼模型的部分,前面现已有相关的代码示例了,这儿再不罗列

剩余的功用逻辑,咱们只需求在署理办法内部完结就好:

/// ARSession署理,当目标方位更新时调用
func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
    for anchor in anchors {
        guard let bodyAnchor = anchor as? ARBodyAnchor else { continue }
        // 更新人物锚点方位
        let bodyPosition = simd_make_float3(bodyAnchor.transform.columns.3)
        characterAnchor.position = bodyPosition + characterOffset
        // 身体锚点旋转
        characterAnchor.orientation = Transform(matrix: bodyAnchor.transform).rotation
        // 检测主体锚点而且人物已加载
        if let character = character, character.parent == nil {
            //将人物附加到其锚点
            characterAnchor.addChild(character)
        }
    }
}

现在运转看看作用(图28)

AR场景实践(2 ) - RealityKit探究

总结

本节内容,简略介绍了Reality Composer东西的运用和RealityKit结构的根底运用,简略的场景实践,或许并不能运用到业务场景,可是咱们看到了苹果AR生态晋级后,更好的AR场景实践的或许性,这仍是很让人等待的。

今年的WWDC23苹果发布了头显体系Vision OS,而Reality Composer东西的迭代版别Reality Composer Pro 和RealityKit以及ARKit3,都是Vision OS的重要技能栈,所以,这块技能的深入研究仍是很有运用空间的。