动画3D模型以错误的方式跟随ARKit Scene的运动

时间:2017-06-28 09:50:22

标签: ios swift 3d scenekit arkit

我正在测试ARKit实现,我的一部分实验只是导入动画模型,让它像Apple场景示例中包含的其他静态模型一样遵循AR Scene的运动。

我从Apple的SceneKit示例中抓取了一个动画3D模型 https://developer.apple.com/library/content/samplecode/SceneKitAnimations/Introduction/Intro.html 并将其放入简单的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        
    }
}

2 个答案:

答案 0 :(得分:1)

我自己解决了。 它太傻了,但这只是因为模型呈现出非常巨大的尺寸,就像一个数百米的巨人。因为它太大了我几米左右的运动根本没有影响。糟糕的是它也漂浮得很高,所以它在某种程度上看起来不错。通过给出大约1/100的比例变换,它变得正常。

答案 1 :(得分:0)

看看ARSceneViewDelegate,有方法

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor)

当ARKit检测到曲面时,它会将一个节点添加到您可以放置​​3D模型的场景中。您还需要适当地设置会话:

let configuration = ARWorldTrackingSessionConfiguration()
configuration.planeDetection = .horizontal

有关更多信息,请查看Apple提供的ARKit示例代码: https://github.com/gao0122/ARKit-Example-by-Apple/tree/master/ARKitExample