この記事の概要
SceneKitとCoreMotionを使ってiOSで全天球画像のビューアを作ろう
出来上がるもの
全天球カメラビューア pic.twitter.com/LBjIeMrCk5
— noppe (@noppefoxwolf) 2016年4月4日
カメラと照明と球体を用意する
新規プロジェクトからGameを選択します。
まずはカメラと全天球の珠を置いてみましょう。
イメージとしては、このようにカメラを球体の中に入れて球体の内側に画像を表示することで全天球を表示します。
まずはシーンを作成します。このシーンにカメラや球体を置くことでシーンを実装していきます。
シーンは言わばレゴの
みたいなものです。
let scene = SCNScene()
guard let scnView = self.view as? SCNView else { return }
scnView.scene = scene
下のスクリーンキャプチャから分かるように、このViewControllerのviewはSCNViewとなっています。
通常はUIViewControllerのviewはUIViewですから、一度as?でSCNViewか確認してSCNViewのインスタントとして扱っていきます。
SCNViewのsceneプロパティにSCNSceneを入れることで、sceneをviewに表示します。
次にカメラを用意します。
SceneKitでは全てがSCNNodeで表されるので、SCNNodeを作りそこにカメラを与えます。
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3Zero
scene.rootNode.addChildNode(cameraNode)
次に環境光を設定します。
無いと真っ暗になります。
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light?.type = SCNLightTypeAmbient
ambientLightNode.light?.color = UIColor.whiteColor()
scene.rootNode.addChildNode(ambientLightNode)
これでカメラと環境光が設置出来たので、球体を作り中にカメラを入れます。
let sphereGeometry = SCNSphere(radius: 20)
let material = SCNMaterial()
material.doubleSided = true
material.diffuse.contents = UIImage(named: "tex")
sphereGeometry.firstMaterial = material
let boxNode = SCNNode(geometry: sphereGeometry)
scene.rootNode.addChildNode(boxNode)
SCNSphareは球体のノードを生成します。
SCNMaterialでテクスチャを作ります。
doubleSidedをtrueにすることで表裏にテクスチャを貼ることが出来ます。(内側からテクスチャを見ることが出来る)
この時点で起動するとこのように内側のテクスチャが映ります。
端末の動きに合わせてカメラを動かす
guard let queue = NSOperationQueue.currentQueue() else { return }
manager.startDeviceMotionUpdatesToQueue(queue) { (motion, error) in
guard let motion = motion else { return }
cameraNode.orientation = self.orientationFromCMQuaternion(motion.attitude.quaternion)
}
private func orientationFromCMQuaternion(q: CMQuaternion) -> SCNVector4 {
let gq1 = GLKQuaternionMakeWithAngleAndAxis(GLKMathDegreesToRadians(-90), 1, 0, 0)
let gq2 = GLKQuaternionMake(Float(q.x), Float(q.y), Float(q.z), Float(q.w))
let qp = GLKQuaternionMultiply(gq1, gq2)
let rq = CMQuaternion(x: Double(qp.x), y: Double(qp.y), z: Double(qp.z), w: Double(qp.w))
return SCNVector4Make(Float(rq.x), Float(rq.y), Float(rq.z), Float(rq.w))
}
iPhoneは画面を上に置いた時の方向を0としているのでorientationFromCMQuaternion
で縦に立てた時を0として補正しています。
これで端末の傾きと合わせて全天球画像を見ることが出来ました。