我正在测试 ARKit 的实现,我的部分实验只是导入一个动画模型,让它像 Apple 示例项目中包含的其他静态模型一样跟随 AR 场景的运动。
我从 Apple 的 SceneKit 示例 https://developer.apple.com/library/content/samplecode/SceneKitAnimations/Introduction/Intro.html中抓取了一个动画 3D 模型 ,并将其放入简单的 ARKit 测试项目中。 https://viewar.com/apple-augmented-reality-arkit-for-ios/
结果是:它显示了模型,并且是动画的,但是模型一直“跟随”我,而不是停留在 AR 空间中的相同位置。奇怪的是,它不仅停留在屏幕上的同一位置,而且在 AR 空间中一直漂浮在我的头顶。
我对 3D 事物太陌生,无法弄清楚发生了什么。你们有什么想法吗?
代码是这样的。
class ViewController: UIViewController, ARSCNViewDelegate {
@IBOutlet var sceneView: ARSCNView!
var _animations = [CAAnimation]()
var charNode : SCNNode!
override func viewDidLoad() {
super.viewDidLoad()
// Set the view's delegate
sceneView.delegate = self
// Show statistics such as fps and timing information
sceneView.showsStatistics = true
// Create a new scene (Keep this ship just as a reference)
let scene = SCNScene(named: "art.scnassets/ship.scn")!
// Set the scene to the view
sceneView.scene = scene
// Load the DAE file and the associated animations
loadSceneAndAnimations();
// Be idle by default
playAnimation(ASCAnimation.Walk);
}
// MARK: Playing animations
func playAnimation(_ animation: ASCAnimation) {
// Use the same animation key for all the animations except "idle".
// When we will add an animation it will replace the animation currently
// playing (if any) but the idle animation will remain active for ever.
let key:String = animation == .Idle ? "idleAnimation" : "otherAnimation";
// Add the animation - it will start playing right away
sceneView.scene.rootNode.addAnimation(_animations[animation.rawValue], forKey: key);
}
// MARK: Animation loading
func loadSceneAndAnimations () {
// Load the character from one of our dae documents, for instance "idle.dae"
let idleURL = Bundle.main.url(forResource: "art.scnassets/idle", withExtension: "dae");
let idleScene = try! SCNScene(url: idleURL!, options: nil);
// Merge the loaded scene into our main scene in order to
// place the character in our own scene
for child in idleScene.rootNode.childNodes {
sceneView.scene.rootNode.addChildNode(child)
}
// Load all the animations from their respective dae document
// The animation identifier can be found in the Node Properties inspector of the Scene Kit editor integrated into Xcode
loadAnimation(animation: .Attack, sceneName: "art.scnassets/attack", animationIdentifier: "attackID");
loadAnimation(animation: .Die, sceneName: "art.scnassets/die", animationIdentifier: "DeathID");
loadAnimation(animation: .Idle, sceneName: "art.scnassets/idle", animationIdentifier: "idleAnimationID");
loadAnimation(animation: .Run, sceneName: "art.scnassets/run", animationIdentifier: "RunID");
loadAnimation(animation: .Walk, sceneName: "art.scnassets/walk", animationIdentifier: "WalkID");
}
func loadAnimation(animation:ASCAnimation, sceneName:String, animationIdentifier:String) {
let sceneURL = Bundle.main.url(forResource: sceneName, withExtension: "dae");
let sceneSource = SCNSceneSource(url: sceneURL!, options: nil);
let animationObject = sceneSource?.entryWithIdentifier(animationIdentifier, withClass: CAAnimation.self)
// Store the animation for later use
_animations.append(animationObject!);
// Whether or not the animation should loop
if animation == .Idle || animation == .Run || animation == .Walk {
animationObject?.repeatCount = MAXFLOAT;
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
let configuration = ARWorldTrackingSessionConfiguration()
// Run the view's session
sceneView.session.run(configuration)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Pause the view's session
sceneView.session.pause()
}
func session(_ session: ARSession, didFailWithError error: Error) {
// Present an error message to the user
}
func sessionWasInterrupted(_ session: ARSession) {
// Inform the user that the session has been interrupted, for example, by presenting an overlay
}
func sessionInterruptionEnded(_ session: ARSession) {
// Reset tracking and/or remove existing anchors if consistent tracking is required
}
}