- ARKit 三大基础能力
ARKit 整合了 SLAM、计算机视觉、机器学习、传感器融合、表面估计、光学校准、特征匹配、非线性优化等大量低层技术,提供给开发者简洁易用的程序界面。
ARKit 提供的功能总体可以分为3个部分:运动跟踪、场景理解、渲染,
1.运动跟踪
运动跟踪可以实时跟踪用户设备在现实世界中的运动,是 ARKit 的核心功能之一,利用该功能可以实时获取用户设备的姿态信息。在运动跟踪精度与消除设差积累方面,ARKit 控制得非常好,表现在使用层面就是加载的虚拟元素不会出现漂移、抖动、闪烁。ARKi的运动跟踪整合了 VIO 和 IMU,即图像视觉跟踪与运动传感器跟踪,提供 6DOF(Degree Of Freedom,自由度)跟踪能力,不仅能跟踪设备位移,还能跟踪设备旋转。
更重要的是,ARKit运动跟踪没有任何前置要求,不需要对环境的先验知识,也没有额外的传感器要求,仅凭现有的移动设备就能满足 ARKit运动跟踪的所有要求。
2. 场景理解
场景理解建立在运动跟踪、计算机视觉、机器学习等技术之上。场景理解提供了关于设备周边现实五境的属性相关信息,如平面检测功能,提供了在现实环境中物体表面(如地面、桌面等)检测平面的能力,从技术上讲,ARKit 通过检测特征点和平面不断改进它又现实世界环境的理解。ARKit 可以检测看起来位于常见水平或垂直面(例如桌子或墙)上的成簇特征点,并允许将这些表面用作应用程序的工作平面,ARKit也可以确定平面的边界,并将该信息提供给应用,使用此信息可以将虚拟物体放置于平坦的表面上而不超出平面的边界。场景理解是一个渐进的过程,随着设备探索的环境不断拓展而不断加深,并可随着探索的进展不断修正误差。
ARKit 通过VIO 检测特征点识别平面,因此它无法正确检测像白墙一样没有纹理的平坦表面。当加
入LiDAR传感器后,ARKit 对环境的感知能力得到大幅度提高,不仅可以检测平坦表面,也可以检测非平坦有起伏的表面,由于 LiDAR 的特性,其对弱纹理、光照不敏感,可以构建现实环境的高精度几何网格。
场景理解还提供了射线检测功能,利用该功能可以与场景中的虚拟对象、检测到的平面、特征点交互,如放置虚拟元素到指定位置、旋转移动虚拟物体等。场景理解还对现实环境中的光照信息进行评估,并利用这些光照估计信息修正场景中的虚拟元素光照。除此之外,场景理解还实现了反射现实物理环境功能以提供更具沉浸性的虚实融合体验。
3. 渲染
严格意义上讲,ARKit 并不包含渲染功能,AR 的渲染由第三方框架提供。但除提供场景理解能力2外,ARKit 还提供连续的摄像头图像流,这些图像流可以方便地融合任何第三方渲染框架,如 RealityKit、SceneKit、SpriteKit、Metal 或者是自定义的渲染器。
运动追踪,场景理解、渲染紧密协作,形成了稳定、健壮、智能的 ARKit,在这三大基础功能之上,ARKit还提供了诸如2D 图像识别跟踪、3D物体识别跟踪、物理仿真等实用功能。
在苹果公司的强力推动下,ARKit 正处于快速发展中,更好的硬件和新算法的加人,提供了更好更快的检测速度(如平面检测、人脸检测、3D物体检测等),更多更强的功能特性(如人形遮挡、人体运动捕提、人量SlendShapes、场最几何等)。ARKit适用的硬件范圈也在拓展,可以预见,ARKit适用的硬件已经拓展到平果公司的新产品MR眼镜产品中,是Vision OS的重要组成部分
- ARKit 事例-检测平面并添加纹理渲染显示平面
import SwiftUI
import RealityKit
import ARKit
import Combine
struct CheckingsPlaneShowView: View {
var body: some View {
return ARViewContainer4().edgesIgnoringSafeArea(.all)
}
}
struct ARViewContainer4: UIViewRepresentable {
let arView = ARView(frame: .zero)
let dele = ARViewDelegate()
func makeUIView(context: Context) -> ARView {
let config = ARWorldTrackingConfiguration()
//检测水平平面
config.planeDetection = .horizontal
arView.session.run(config, options:[ ])
arView.session.delegate = dele
createPlane()
return arView
}
func createPlane(){
let planeAnchor = AnchorEntity(plane:.horizontal)
do {
//texture(.load(named: "Surface_DIFFUSE.png")
dele.planeMaterial.color = try SimpleMaterial.BaseColor(tint:UIColor.yellow.withAlphaComponent(0.9999), texture: MaterialParameters.Texture(TextureResource.load(named: "Surface_DIFFUSE.png")))
dele.planeEntity = ModelEntity(mesh:dele.planeMesh,materials:[dele.planeMaterial])
dele.planeAnchor.addChild(dele.planeEntity!)
arView.scene.addAnchor(planeAnchor)
} catch {
print("找不到文件")
}
}
func updateUIView(_ uiView: ARView, context: Context) {
}
}
class ARViewDelegate :NSObject, ARSessionDelegate{
var planeMesh = MeshResource.generatePlane(width: 0.15, depth: 0.15)
var planeMaterial = SimpleMaterial(color:.white,isMetallic: false)
var planeEntity: ModelEntity?
var planeAnchor = AnchorEntity()
public func session(_ session: ARSession, didAdd anchors: [ARAnchor]){
guard let pAnchor = anchors[0] as? ARPlaneAnchor else {
return
}
DispatchQueue.main.async {
self.planeEntity!.model?.mesh = MeshResource.generatePlane(
width: pAnchor.planeExtent.width,
depth: pAnchor.planeExtent.height
)
self.planeEntity!.setTransformMatrix(pAnchor.transform, relativeTo: nil)
}
}
public func session(_ session: ARSession, didUpdate anchors: [ARAnchor]){
guard let pAnchor = anchors[0] as? ARPlaneAnchor else {
return
}
DispatchQueue.main.async {
self.planeEntity!.model?.mesh = MeshResource.generatePlane(
width: pAnchor.planeExtent.width,
depth: pAnchor.planeExtent.height
)
self.planeEntity!.setTransformMatrix(pAnchor.transform, relativeTo: nil)
}
}
}