0

我正在测试 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        
    }
}
4

2 回答 2

1

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

于 2017-07-10T06:23:22.417 回答
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

于 2017-06-28T13:01:13.137 回答