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

标签 ios swift 3d scenekit arkit

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

我从 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        
    }
}

最佳答案

我自己解决了。 太傻了,但这只是因为模型被渲染成非常巨大的尺寸,就像一个数百米的巨人。因为它太大了,我几米左右的移动根本没有影响。糟糕的是它还漂浮得很高,所以从某种意义上说它的尺寸看起来还不错。通过提供大约 1/100 的比例转换,它变得正常。

关于ios - 动画 3D 模型以错误的方式跟随 ARKit Scene 的运动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44799148/

相关文章:

android - 如何在支持图层的 Android 上显示 Collada (.dae) 文件?

math - 原点变化前后基于相机旋转/平移确定点位置

iOS:以编程方式更改选项卡 - Storyboard

ios - 如何从 iOS 项目中删除启动屏幕?

ios-防止滚动时重新加载 UITableView 中的单元格

ios - children count 总是返回0 ,无法正确到达

ios - 是什么导致 UIToolbar 中出现重影 UIBarButtonItems?

ios - 我想要导航栏中后退按钮的自定义图像,但有 2 个后退按钮

ios - 如何使用 swift 显示带有进度条的 AVAudioPlayer?

math - 没有欧拉角的四元数旋转