使用SceneKit来添加真实3D物体到AR体验


概述

因为ARKit自动将SceneKit场景匹配到真实世界,所以要放置一个虚拟物体并保持其在真实世界的位置,只需要正确的设置该物体的SceneKit位置即可。举例来说,使用默认配置项,以下的示例代码完成了将一个10厘米的立方体放置在摄像头初始位置前20厘米的位置:

let cubeNode = SCNNode(geometry: SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0))
cubeNode.position = SCNVector3(0, 0, -0.2) // SceneKit/AR coordinates are in meters
sceneView.scene.rootNode.addChildNode(cubeNode)

上述代码在视图的SceneKit场景中直接放置了一个物体。该物体自动出现并追踪真实世界的位置,因为ARkit将SceneKit空间与真实世界空间匹配在了一起。

或者,可以使用ARAnchor 类来追踪真实世界位置。即可以通过自行创建锚点并添加到会话中,也可以通过观察ARKit自动创建的锚点。举例来说,当平面检测被开启后,ARKit为每一个检测到的平面添加并更新锚点。为了向这些锚点添加虚拟内容,可以采用如下方法来实现ARSCNViewDelegate 方法:

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    // This visualization covers only detected planes.
    // 当前可视化只针对检测到的平面
    guard let planeAnchor = anchor as? ARPlaneAnchor else { return }

    // Create a SceneKit plane to visualize the node using its position and extent.
    // 创建一个SceneKit平面并使用节点的位置和范围来可视化该节点
    let plane = SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(planeAnchor.extent.z))
    let planeNode = SCNNode(geometry: plane)
    planeNode.position = SCNVector3Make(planeAnchor.center.x, 0, planeAnchor.center.z)

    // SCNPlanes are vertically oriented in their local coordinate space.
    // SCNPlane在其坐标系中是垂直定向的
    // Rotate it to match the horizontal orientation of the ARPlaneAnchor.
    // 需要将其选装来符合ARPlaneAnchor的水平定向
    planeNode.transform = SCNMatrix4MakeRotation(-Float.pi / 2, 1, 0, 0)

    // ARKit owns the node corresponding to the anchor, so make the plane a child node.
    // ARKit拥有与锚点对应的节点,所以将此平面作为子节点
    node.addChildNode(planeNode)
}

遵循设计3D资源的最佳实践

  • 基于针对材质的光照模型来物理上的使用SceneKit,从而实现更加真实的展现。(参见SCNMaterial 类和Badger: Advanced Rendering in SceneKit 实例代码项目)
  • 添加环境光遮蔽阴影,使得物体在各种场景光照条件下都会被正确的照亮
  • 如果你想通过AR放置一个你创建的虚拟物体在真实世界平坦表面上,在你的3D资源下方引入一个带有软阴影纹理的透明平面。