Search code examples
iosswiftquaternionspanoramas

Panoramic View iOS


So I have generated an nice panoramic viewer but the camera is pointing downward. Meaning if I hold my phone flat like it was on a table, it rotates and looks around the sphere nicely. I want to be able to hold it normal (up) and look around. Here is my code.

I have an extension I am using here:

import UIKit
import SceneKit
import CoreMotion

extension CMDeviceMotion {

func gaze(atOrientation orientation: UIInterfaceOrientation) -> SCNVector4 {

    let attitude = self.attitude.quaternion
    let aq = GLKQuaternionMake(Float(attitude.x), Float(attitude.y), Float(attitude.z), Float(attitude.w))

    let final: SCNVector4

    switch UIApplication.shared.statusBarOrientation {

    case .landscapeRight:

        let cq = GLKQuaternionMakeWithAngleAndAxis(Float(Double.pi), 0, 1, 0)
        let q = GLKQuaternionMultiply(cq, aq)

        final = SCNVector4(x: -q.y, y: q.x, z: q.z, w: q.w)

    case .landscapeLeft:

        let cq = GLKQuaternionMakeWithAngleAndAxis(Float(-Double.pi), 0, 1, 0)
        let q = GLKQuaternionMultiply(cq, aq)

        final = SCNVector4(x: q.y, y: -q.x, z: q.z, w: q.w)

    case .portraitUpsideDown:

        let cq = GLKQuaternionMakeWithAngleAndAxis(Float(Double.pi), 1, 0, 0)
        let q = GLKQuaternionMultiply(cq, aq)

        final = SCNVector4(x: -q.x, y: -q.y, z: q.z, w: q.w)

    case .unknown:

        fallthrough

    case .portrait:

        let cq = GLKQuaternionMakeWithAngleAndAxis(Float(-Double.pi), 1, 0, 0)
        let q = GLKQuaternionMultiply(cq, aq)

        final = SCNVector4(x: q.x, y: q.y, z: q.z, w: q.w)
    }

    return final
}
}

Then the viewcontroller looks like this:

import UIKit
import SceneKit
import CoreMotion

class ViewController: UIViewController {

let motionManager = CMMotionManager()
let cameraNode = SCNNode()


@IBOutlet weak var sceneView: SCNView!

override func viewDidLoad() {
    super.viewDidLoad()

    guard let imagePath = Bundle.main.path(forResource: "Hellbrunn25", ofType: "jpg") else {
        fatalError("Failed to find path for panaromic file.")
    }
    guard let image = UIImage(contentsOfFile:imagePath) else {
        fatalError("Failed to load panoramic image")
    }

    let scene = SCNScene()
    sceneView.scene = scene
    sceneView.allowsCameraControl = true

    //Create node, containing a sphere, using the panoramic image as a texture
    let sphere = SCNSphere(radius: 20.0)
    sphere.firstMaterial!.isDoubleSided = true
    sphere.firstMaterial!.diffuse.contents = image
    let sphereNode = SCNNode(geometry: sphere)
    sphereNode.position = SCNVector3Make(0,0,0)
    scene.rootNode.addChildNode(sphereNode)

    // Camera, ...
    cameraNode.camera = SCNCamera()
    cameraNode.position = SCNVector3Make(0, 0, 0)
    scene.rootNode.addChildNode(cameraNode)

    guard motionManager.isDeviceMotionAvailable else {
        fatalError("Device motion is not available")
    }

    // Action
    motionManager.deviceMotionUpdateInterval = 1.0 / 60.0
    motionManager.startDeviceMotionUpdates(to: OperationQueue.main, withHandler: {
       (deviceDidMove, Error)-> Void in

        let attitude: CMAttitude = deviceDidMove!.attitude

        self.cameraNode.orientation = SCNVector4Make(Float(attitude.quaternion.x), Float(attitude.quaternion.y), Float(attitude.quaternion.z), Float(attitude.quaternion.w))


    })

}
   override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func deviceDidMove(motion: CMDeviceMotion?, error: NSError?) {

    if let motion = motion {
        let orientation = motion.gaze(atOrientation: UIApplication.shared.statusBarOrientation)
        cameraNode.orientation = orientation
    }
}


}

How do I get the camera to face forward on the image. Thanks


Solution

  • I figured this out if any one else is looking for an answer. I changed the portrait mode case to the following:

    let cq = GLKQuaternionMakeWithAngleAndAxis(Float(-Double.pi*0.5), 1, 0, 0)
    let q = GLKQuaternionMultiply(cq, aq)
    
    final = SCNVector4(x: q.x, y: q.y, z: q.z, w: q.w)