swiftaugmented-realityscenekitarkitarscnview

ARKit Stereo – Is it possible to run two ARSCNView at the same time?


I was thinking to do some modification to my existing AR app, and I wanted to split the view and add inside 2 ARSCNView in this way users can use the VR Card Box and have a different experience but Xcode is always returning me:

Session (0x102617d10): did fail with error: Error Domain=com.apple.arkit.error Code=102 "Required sensor failed."

So, I'm supposing that I can't run 2 ARSCNView sessions at the same time, or am I wrong?


Solution

  • The answer is: Yes, it's possible.

    Use the following code to accomplish it:

    import UIKit
    import SceneKit
    import ARKit
    
    class ViewController: UIViewController, ARSCNViewDelegate {
    
        @IBOutlet weak var sceneView: ARSCNView!
        @IBOutlet weak var sceneView2: ARSCNView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            sceneView.delegate = self
            sceneView.showsStatistics = true
            let scene = SCNScene(named: "art.scnassets/ship.scn")!
            sceneView.scene = scene
            sceneView.isPlaying = true
    
            // Setup for sceneView2
            sceneView2.scene = scene
            sceneView2.showsStatistics = sceneView.showsStatistics
    
            // Now sceneView2 starts receiving updates
            sceneView2.isPlaying = true     
        }
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            let configuration = ARWorldTrackingConfiguration()
            sceneView.session.run(configuration)
        }
        override func viewWillDisappear(_ animated: Bool) {
            super.viewWillDisappear(animated)
            sceneView.session.pause()
        }
        func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
            DispatchQueue.main.async {
                self.updateFrame()
            }
        }
        func updateFrame() {   
            // Clone pointOfView for Second View
            let pointOfView: SCNNode = (sceneView.pointOfView?.clone())!
    
            // Determine Adjusted Position for Right Eye
            let orientation: SCNQuaternion = pointOfView.orientation
            let orientationQuaternion: GLKQuaternion = GLKQuaternionMake(orientation.x, 
                                                                         orientation.y, 
                                                                         orientation.z, 
                                                                         orientation.w)
            let eyePos: GLKVector3 = GLKVector3Make(1.0, 0.0, 0.0)
            let rotatedEyePos: GLKVector3 = GLKQuaternionRotateVector3(orientationQuaternion, 
                                                                       eyePos)
            let rotatedEyePosSCNV: SCNVector3 = SCNVector3Make(rotatedEyePos.x, 
                                                               rotatedEyePos.y, 
                                                               rotatedEyePos.z)  
            let mag: Float = 0.064 // Interocular distance (in metres)
            pointOfView.position.x += rotatedEyePosSCNV.x * mag
            pointOfView.position.y += rotatedEyePosSCNV.y * mag
            pointOfView.position.z += rotatedEyePosSCNV.z * mag
    
            // Set PointOfView for SecondView
            sceneView2.pointOfView = pointOfView    
        }
    }
    

    For more details look at this project on a GitHub.

    enter image description here