LoginSignup
36
27

More than 5 years have passed since last update.

SceneKitで全天球画像ビューアを作ろう

Last updated at Posted at 2016-04-06

この記事の概要

SceneKitとCoreMotionを使ってiOSで全天球画像のビューアを作ろう

出来上がるもの

全天球カメラビューア pic.twitter.com/LBjIeMrCk5

— noppe (@noppefoxwolf) 2016年4月4日

カメラと照明と球体を用意する

Screen Shot 2016-04-05 at 13.17.25.png

新規プロジェクトからGameを選択します。

まずはカメラと全天球の珠を置いてみましょう。

Screen Shot 2016-04-05 at 13.19.38.png

イメージとしては、このようにカメラを球体の中に入れて球体の内側に画像を表示することで全天球を表示します。

まずはシーンを作成します。このシーンにカメラや球体を置くことでシーンを実装していきます。
シーンは言わばレゴの

baseplates.jpg

みたいなものです。


    let scene = SCNScene()
    guard let scnView = self.view as? SCNView else { return }
    scnView.scene = scene

下のスクリーンキャプチャから分かるように、このViewControllerのviewはSCNViewとなっています。
Screen Shot 2016-04-05 at 09.58.42.png

通常は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にすることで表裏にテクスチャを貼ることが出来ます。(内側からテクスチャを見ることが出来る)

Screen Shot 2016-04-06 at 22.36.38.png

この時点で起動するとこのように内側のテクスチャが映ります。

端末の動きに合わせてカメラを動かす


    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として補正しています。

これで端末の傾きと合わせて全天球画像を見ることが出来ました。

画像は
http://www.naoj.org/Gallery/j_360deg.html
より

36
27
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
27