使用 ARKit 显示 DAE 文件并跟踪场景中的锚点
Displaying a DAE file with ARKit and tracking an Anchor in the scene
我正在试用 ARKit,我使用 this tutorial.
设置了一个 ARSCNView
的第二部分设置跟踪水平3D平面
我创建了一个单视图应用程序,然后使用 ViewController
.
的出口将 ARSCNView
刷新到根视图
这是ViewController
中的代码:
import UIKit
import ARKit
class ViewController: UIViewController {
//MARK: Properties
@IBOutlet weak var arScene: ARSCNView!
//MARK: ARKit variables
var realityConfiguration: ARWorldTrackingSessionConfiguration?
//MARK: Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.prepare()
}
//MARK: Actions
//MARK: Overrides
}
extension ViewController {
func prepare() {
//Check to see if active reality is supported
guard ARSessionConfiguration.isSupported else {
//Custom alert function that just quickly displays a UIAlertController
AppDelegate.alert(title: "Not Supported", message: "Active Reality is not supported on this device")
return
}
//Set up the ARSessionConfiguration
self.realityConfiguration = ARWorldTrackingSessionConfiguration()
//Set up the ARSCNView
guard let config = self.realityConfiguration else {
return
}
//Run the ARSCNView and set its delegate
self.arScene.session.run(config)
self.arScene.delegate = self
}
}
extension ViewController: ARSCNViewDelegate {
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
return nil
}
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
guard let planAnchor = anchor as? ARPlaneAnchor else {
return
}
let plane = SCNPlane(width: CGFloat(planAnchor.extent.x), height: CGFloat(planAnchor.extent.z))
let planeNode = SCNNode(geometry: plane)
planeNode.position = SCNVector3Make(planAnchor.center.x, 0, planAnchor.center.z)
planeNode.transform = SCNMatrix4MakeRotation(-Float.pi / 2, 1, 0, 0)
node.addChildNode(planeNode)
}
func renderer(_ renderer: SCNSceneRenderer, willUpdate node: SCNNode, for anchor: ARAnchor) {
print("Will updated Node on Anchor: \(anchor.identifier)")
}
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
print("Did updated Node on Anchor: \(anchor.identifier)")
}
func renderer(_ renderer: SCNSceneRenderer, didRemove node: SCNNode, for anchor: ARAnchor) {
print("Removed Node on Anchor: \(anchor.identifier)")
}
}
我下载了 Xcode 9 beta,按照 Apple 的教程进行操作,发现我的 iPhone 6 没有 ARWorldTrackingSessionConfiguration
对象所需的 A9 芯片。
在我链接的第一个教程的大约一半处,Apple 表示您仍然可以在没有 A9 芯片的情况下创建 AR 体验。但是,他们没有进一步详细说明。有没有其他人找到一个起点,并愿意提供一个使用 .dae 文件的代码示例和
- 选择一个锚点来显示它
- 追踪那个锚点
- 实际显示 .dae 文件
使用您的代码并没有什么可看的——只是一个实时摄像头视图。
您在现实中看不到任何增强的主要原因是您的代码仅在将锚点添加到 ARSession
时才将 SceneKit 内容添加到场景...但您没有手动添加任何锚点,并且您还没有启用平面检测,因此 ARKit 不会自动添加锚点。如果启用平面检测,您将开始到达某个地方...
self.realityConfiguration = ARWorldTrackingSessionConfiguration()
realityConfiguration?.planeDetection = .horizontal
但是你还是什么都看不到。那是因为您的 ARSCNViewDelegate
实现有冲突的指令。这部分:
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
return nil
}
...意味着不会为您的锚点创建任何 SceneKit 节点。因为没有节点,您的 renderer(_:didAdd:for:)
函数永远不会被调用,所以您在该方法中的代码永远不会创建任何 SceneKit 内容。
如果你打开平面检测并删除/注释掉 renderer(_: nodeFor:)
方法,你的代码的其余部分应该是这样的:
(纯白色区域是你的 SCNPlane
。我不得不在白色上展开我的 iPad 封面 table 获得足够的场景细节以进行平面检测以找到任何东西。另外,查看背景...实际上在今天的 WWDC 上有一个时刻商品商店并没有挤满人。)
至于你是否需要A9,Apple的消息在这里有点不清楚。当他们说 ARKit 需要 A9 或更好时,他们真正的意思是 ARWorldTrackingSessionConfiguration 需要。这就是所有最好的 AR 魔法所在。 (甚至还有一个 arkit
的 UIRequiredDeviceCapabilities
键,它实际上涵盖了具有世界跟踪支持的设备,因此您可以将 App Store 上的应用程序限制为仅提供给这些设备。)
尽管如此,仍然有 一些 没有世界跟踪的 ARKit。 运行 与基地 class ARSessionConfiguration
的会话,您将获得仅限方向的跟踪。 (没有位置跟踪,没有平面检测,没有命中测试。)
这让你得到了什么?嗯,如果你玩过当前版本的 Pokémon GO,它的工作原理是这样的:因为它只跟踪设备方向,而不是位置,你不能靠近皮卡丘或在他身后走来走去——他占据真实世界的错觉只要您只倾斜或转动您的设备而不移动它,世界就会保持不变。
您可以使用 SceneKit 加载 3D 内容并将其放置在 AR 中,就像您将其加载并放置在任何其他 SceneKit 中一样 app/game。有很多资源可以做到这一点,也有很多方法可以做到这一点。当您创建一个新的 AR 项目并选择 SceneKit 时,您会在 Xcode 模板中找到其中之一。加载部分是这样的:
let scene = SCNScene(named: "ship.scn" inDirectory: "assets.scnassets")
let ship = scene.rootNode.childNode(withName: "ship", recursively: true)
然后放置它:
ship.simdPosition = float3(0, 0, -0.5)
// half a meter in front of the *initial* camera position
myARSCNView.scene.rootNode.addChildNode(ship)
要记住在 AR 中放置东西的主要区别是位置是以米为单位测量的(并且您的内容需要设计成以米为单位合理调整大小)。
我正在试用 ARKit,我使用 this tutorial.
设置了一个ARSCNView
的第二部分设置跟踪水平3D平面
我创建了一个单视图应用程序,然后使用 ViewController
.
ARSCNView
刷新到根视图
这是ViewController
中的代码:
import UIKit
import ARKit
class ViewController: UIViewController {
//MARK: Properties
@IBOutlet weak var arScene: ARSCNView!
//MARK: ARKit variables
var realityConfiguration: ARWorldTrackingSessionConfiguration?
//MARK: Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.prepare()
}
//MARK: Actions
//MARK: Overrides
}
extension ViewController {
func prepare() {
//Check to see if active reality is supported
guard ARSessionConfiguration.isSupported else {
//Custom alert function that just quickly displays a UIAlertController
AppDelegate.alert(title: "Not Supported", message: "Active Reality is not supported on this device")
return
}
//Set up the ARSessionConfiguration
self.realityConfiguration = ARWorldTrackingSessionConfiguration()
//Set up the ARSCNView
guard let config = self.realityConfiguration else {
return
}
//Run the ARSCNView and set its delegate
self.arScene.session.run(config)
self.arScene.delegate = self
}
}
extension ViewController: ARSCNViewDelegate {
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
return nil
}
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
guard let planAnchor = anchor as? ARPlaneAnchor else {
return
}
let plane = SCNPlane(width: CGFloat(planAnchor.extent.x), height: CGFloat(planAnchor.extent.z))
let planeNode = SCNNode(geometry: plane)
planeNode.position = SCNVector3Make(planAnchor.center.x, 0, planAnchor.center.z)
planeNode.transform = SCNMatrix4MakeRotation(-Float.pi / 2, 1, 0, 0)
node.addChildNode(planeNode)
}
func renderer(_ renderer: SCNSceneRenderer, willUpdate node: SCNNode, for anchor: ARAnchor) {
print("Will updated Node on Anchor: \(anchor.identifier)")
}
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
print("Did updated Node on Anchor: \(anchor.identifier)")
}
func renderer(_ renderer: SCNSceneRenderer, didRemove node: SCNNode, for anchor: ARAnchor) {
print("Removed Node on Anchor: \(anchor.identifier)")
}
}
我下载了 Xcode 9 beta,按照 Apple 的教程进行操作,发现我的 iPhone 6 没有 ARWorldTrackingSessionConfiguration
对象所需的 A9 芯片。
在我链接的第一个教程的大约一半处,Apple 表示您仍然可以在没有 A9 芯片的情况下创建 AR 体验。但是,他们没有进一步详细说明。有没有其他人找到一个起点,并愿意提供一个使用 .dae 文件的代码示例和
- 选择一个锚点来显示它
- 追踪那个锚点
- 实际显示 .dae 文件
使用您的代码并没有什么可看的——只是一个实时摄像头视图。
您在现实中看不到任何增强的主要原因是您的代码仅在将锚点添加到 ARSession
时才将 SceneKit 内容添加到场景...但您没有手动添加任何锚点,并且您还没有启用平面检测,因此 ARKit 不会自动添加锚点。如果启用平面检测,您将开始到达某个地方...
self.realityConfiguration = ARWorldTrackingSessionConfiguration()
realityConfiguration?.planeDetection = .horizontal
但是你还是什么都看不到。那是因为您的 ARSCNViewDelegate
实现有冲突的指令。这部分:
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
return nil
}
...意味着不会为您的锚点创建任何 SceneKit 节点。因为没有节点,您的 renderer(_:didAdd:for:)
函数永远不会被调用,所以您在该方法中的代码永远不会创建任何 SceneKit 内容。
如果你打开平面检测并删除/注释掉 renderer(_: nodeFor:)
方法,你的代码的其余部分应该是这样的:
(纯白色区域是你的 SCNPlane
。我不得不在白色上展开我的 iPad 封面 table 获得足够的场景细节以进行平面检测以找到任何东西。另外,查看背景...实际上在今天的 WWDC 上有一个时刻商品商店并没有挤满人。)
至于你是否需要A9,Apple的消息在这里有点不清楚。当他们说 ARKit 需要 A9 或更好时,他们真正的意思是 ARWorldTrackingSessionConfiguration 需要。这就是所有最好的 AR 魔法所在。 (甚至还有一个 arkit
的 UIRequiredDeviceCapabilities
键,它实际上涵盖了具有世界跟踪支持的设备,因此您可以将 App Store 上的应用程序限制为仅提供给这些设备。)
尽管如此,仍然有 一些 没有世界跟踪的 ARKit。 运行 与基地 class ARSessionConfiguration
的会话,您将获得仅限方向的跟踪。 (没有位置跟踪,没有平面检测,没有命中测试。)
这让你得到了什么?嗯,如果你玩过当前版本的 Pokémon GO,它的工作原理是这样的:因为它只跟踪设备方向,而不是位置,你不能靠近皮卡丘或在他身后走来走去——他占据真实世界的错觉只要您只倾斜或转动您的设备而不移动它,世界就会保持不变。
您可以使用 SceneKit 加载 3D 内容并将其放置在 AR 中,就像您将其加载并放置在任何其他 SceneKit 中一样 app/game。有很多资源可以做到这一点,也有很多方法可以做到这一点。当您创建一个新的 AR 项目并选择 SceneKit 时,您会在 Xcode 模板中找到其中之一。加载部分是这样的:
let scene = SCNScene(named: "ship.scn" inDirectory: "assets.scnassets")
let ship = scene.rootNode.childNode(withName: "ship", recursively: true)
然后放置它:
ship.simdPosition = float3(0, 0, -0.5)
// half a meter in front of the *initial* camera position
myARSCNView.scene.rootNode.addChildNode(ship)
要记住在 AR 中放置东西的主要区别是位置是以米为单位测量的(并且您的内容需要设计成以米为单位合理调整大小)。