ARKit介绍

2018-08-14  本文已影响31人  iOSDevLog

Apple在WWDC17上宣布了一个名为ARKit的新iOS框架。它是一个“允许您轻松为iPhone和iPad创建无与伦比的增强现实体验”的框架。该框架随iOS 11一起发布(目前处于测试阶段),并且仅由Apple的A9或A10芯片驱动的iOS设备支持。这意味着它不适用于iPhone 5S或iPad Mini等旧设备。此外,您无法在模拟器中使用它,因此您必须使用最新的测试版更新您的iPhone / iPad(iOS 11 SDK仅适用于Xcode 9)。

AR - 使用相机创建虚拟对象放置在物理世界中的错觉。

我们知道增强现实并不是新的,但由于Apple的新框架,AR现在正受到很多关注。Pokemon Go是第一个也许是最着名的应用程序之一,它向我们展示了应用程序中AR的强大功能。实现与Pokemon Go具有相同交互性的应用程序并不容易,这就是为什么我认为ARKit会有所作为。

通过这个新框架,通过为iOS提供本机AR支持,开发人员可以更方便地访问AR。它使用相机传感器进行照明估算,它可以分析相机视图所呈现的内容,并找到像桌子和地板一样的水平平面,它可以在锚点上放置和跟踪物体。您甚至可以使用Metal,SceneKit和Unity和虚幻引擎等第三方工具渲染3D对象。ARKit以卓越的性能完成所有这一切,并且有很好的文档记录。

需要一些想法才能使用ARKit?您可以查看madewitharkit,并通过在您的应用上加入此框架来了解可能实现的目标。

使用ARKit测量对象

我真正喜欢的项目之一是“AR Measure App Demo”:

他们创造了一个精确的虚拟标尺,与真实标尺相比,我惊呆了。我心想:“我需要试试这个!”,所以我决定使用ARKit创建自己的测量应用程序。

我开始观看介绍ARKit:来自WWDC17的iOS增强现实视频。然后我阅读文档并使用演示应用程序(在增强现实中放置对象)。在那之后,我了解了我可以使用什么以及如何工作。从演示中,我了解到场景单元映射到ARKit中的米,所以这是一个很好的提示。

两个节点之间的距离

我想要一个基本的应用程序,只需点击屏幕选择点并计算最后一个点击与前一个点的距离。所以,我使用Swift和SceneKit创建了一个新项目:

创建项目步骤1

创建项目步骤1

创建项目步骤2

创建项目步骤2

“增强现实应用程序”模板为我们提供了一个基本代码。有一个ViewController实现AR场景视图delegate(ARSCNViewDelegate),它已经有一个ARSCNView很好的IB出口,因为这是用于使用相机显示带有3D SceneKit内容的AR的视图。

免责声明:我使用SceneKit玩过一次,所以我对它有一些基本的了解。如果您没有这些知识或任何3D渲染,如Metal,OpenGL或Unity,那么我建议您在使用ARKit之前查看其中一个,因为它将帮助您理解我将呈现的代码(例如,矢量和矩阵等3D概念以及可以对它们执行的一般操作。

我删除了加载ship.scn资源的当前场景,viewDidLoad因为我想从干净的环境开始(在摄像机视图中没有任何内容)。

然后我UITapGestureRecognizer在主视图中添加了一个以识别用于添加节点的轻击手势。A SCNNode是“场景图的结构元素,表示3D坐标空间中的位置和变换”,其中可以附加几何图形,灯光,相机或其他可显示内容。我决定使用球体作为几何体。我希望节点位于摄像机前方10厘米处,因此我需要当前帧才能访问摄像机在世界坐标空间中的位置和方向。

红色是“x”轴,绿色是“y”轴,蓝色是“z”轴。

红色是“x”轴,绿色是“y”轴,蓝色是“z”轴。

为了实现10厘米的平移,我需要在第四列上应用转换z。正值定义为更接近相机,负值更远。因此,如果使用0,对象位置将位于当前相机框架的正前方。

@objc func handleTapGesture(sender: UITapGestureRecognizer) {
    if sender.state != .ended {
        return
    }
    guard let currentFrame = sceneView.session.currentFrame else {
        return
    }
    // Create a transform with a translation of 0.1 meters (10 cm) in front of the camera
    var translation = matrix_identity_float4x4
    translation.columns.3.z = -0.1
    // Add a node to the session
    let sphere = SCNSphere(radius: 0.005)
    sphere.firstMaterial?.diffuse.contents = UIColor.red
    sphere.firstMaterial?.lightingModel = .constant
    sphere.firstMaterial?.isDoubleSided = true
    let sphereNode = SCNNode(geometry: sphere)
    sphereNode.simdTransform = matrix_multiply(currentFrame.camera.transform, translation)
    sceneView.scene.rootNode.addChildNode(sphereNode)
}

translation是一个包含4行和4列的矩阵。这就是3D点的表示方式,可以应用平移,缩放,旋转,反射,倾斜等变换(通过搜索可以更好地理解OpenGL Matrices)。

最后一步是计算两个节点之间的距离。使用三维欧氏距离公式可以实现两点的距离

image.png

3D中的欧几里德距离公式

我用结束节点位置(两个3D矢量)减去起始节点位置,得到一个新的矢量,然后我应用了公式|a| = sqrt((ax * ax) + (ay * ay) + (az * az))。这将给出结果向量的长度,它与说明相同:距节点A和节点B的距离。

func distance(startNode: SCNNode, endNode: SCNNode) -> Float {  
    let vector = SCNVector3Make(startNode.position.x - endNode.position.x, startNode.position.y - endNode.position.y, startNode.position.z - endNode.position.z)
    // Scene units map to meters in ARKit.
    return sqrtf(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z)
}

self.distanceLabel.text = String(format: "%.2f", distance(startNode: nodeA, endNode: nodeB)) + "m"  

您可以在此处查看此实施。

增强测量

在第一次实现之后,我注意到测量不准确,因为您不能保证节点A和节点B在同一表面中。在那种情况下,我需要平面检测功能。垂直平面检测不是一个特征(但是),但可以用一行代码激活水平平面检测configuration.planeDetection = .horizontal然后ARKit将自动添加,更改或删除当前会话中的平面锚点。您可以观察通过实施这些变化session(_:didAdd:)session(_:didUpdate:)并且session(_:didRemove:)方法从ARSessionDelegate委托(请确保您验证是否锚参数是ARPlaneAnchor)。用户应该知道水平面何时可用,以便开始添加测量点。在苹果公司的ARKit演示实现了一个方形指示器,我认为它可以使用该sceneView.debugOptions属性,但事实并非如此。

平面检测在行动中

平面检测在行动中

所以,我FocusSquare从Apple的演示中借用了这个课程。

最后,最后一个问题:如何将节点放在最近的平面上?我已经知道如何将节点放置在摄像机所在的位置,但我如何获得距离最近的平面的距离。答案是:hitTest(_:types:)。此方法在摄像机图像中搜索视图坐标中指定点的有效曲面,并返回一个列表,其中命中测试结果的排序距离最近(距离摄像机的距离)。

let planeHitTestResults = sceneView.hitTest(view.center, types: .existingPlaneUsingExtent)  
if let result = planeHitTestResults.first {  
    let hitPosition = SCNVector3.positionFromTransform(result.worldTransform)
    let sphere = SCNSphere(radius: 0.005)
    sphere.firstMaterial?.diffuse.contents = UIColor.red
    sphere.firstMaterial?.lightingModel = .constant
    sphere.firstMaterial?.isDoubleSided = true
    let node = SCNNode(geometry: sphere)
    node.position = hitPosition //<--
    sceneView.scene.rootNode.addChildNode(node)
}

我假设主视图的中心作为目标,并且作为默认平面,我使用了列表的第一项(最近的平面)。

最后,我实现了session(_:cameraDidChangeTrackingState:) 可以观察设备位置跟踪状态的方法。

func session(_ session: ARSession, cameraDidChangeTrackingState camera: ARCamera) {  
    switch camera.trackingState {
    case .notAvailable:
        trackingStateLabel.text = "Tracking not available"
        trackingStateLabel.textColor = .red
    case .normal:
        trackingStateLabel.text = "Tracking normal"
        trackingStateLabel.textColor = .green
    case .limited(let reason):
        switch reason {
        case .excessiveMotion:
            trackingStateLabel.text = "Tracking limited: excessive motion"
        case .insufficientFeatures:
            trackingStateLabel.text = "Tracking limited: insufficient features"
        case .none:
            trackingStateLabel.text = "Tracking limited"
        case .initializing:
            trackingStateLabel.text = "Tracking limited: initializing"
        }
        trackingStateLabel.textColor = .yellow
    }
}

您可以检查整个项目并在您的设备上进行测试。

我对AR的力量印象深刻。有很多用例可以探索。如果您有任何我们可以帮助您使用AR的项目,请不要犹豫,并与我们联系。

作者:Ricardo Pereira 2017-07-19

原文:https://www.whitesmith.co/blog/arkit-introduction/

上一篇 下一篇

猜你喜欢

热点阅读