前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ARKit介绍

ARKit介绍

作者头像
iOSDevLog
发布2018-08-22 14:13:19
2.3K0
发布2018-08-22 14:13:19
举报
文章被收录于专栏: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,对象位置将位于当前相机框架的正前方。

代码语言:javascript
复制
@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的距离。

代码语言:javascript
复制
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:)。此方法在摄像机图像中搜索视图坐标中指定点的有效曲面,并返回一个列表,其中命中测试结果的排序距离最近(距离摄像机的距离)。

代码语言:javascript
复制
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:) 可以观察设备位置跟踪状态的方法。

代码语言:javascript
复制
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/
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.08.14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用ARKit测量对象
    • 两个节点之间的距离
    • 增强测量
      • 作者:Ricardo Pereira 2017-07-19
        • 原文:https://www.whitesmith.co/blog/arkit-introduction/
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档