iOS で SceneKit を試す(Swift 3) その53 - SceneKit の Point Of View
これまで紹介した SceneKit のカメラは、コードで設定するか、scn ファイル内のカメラで設定していた。
SceneKit の SCNView(SCNSceneRenderer)には pointOfView というプロパティがあり、 これに SCNCamera を設定しているノードを設定するとカメラに設定することができる。
わかりやすい例だと、SCNView で allowsCameraControl を true に設定した時。
画面の操作が行われると pointOfView がコントロール可能なカメラに変更される。
ちなみに iOS 11 では SCNCameraController で allowsCameraControl の振る舞いを変更できる。
利用用途
allowsCameraControl = true の際、ダブルタップで初期位置へスムースにアニメーションが行われる。
これと同様に複数のカメラ間での移動や回転のアニメーションを pointOfView を使用して行うことができる。
動作例
コードを書いてみる
方法としては、異なる SCNCamera のノードを2つ作成し、pointOfView に設定したものをアニメーションさせる。
いつも通り iOS の Game テンプレートでプロジェクトを作成し、 GameViewController.swift のカメラの記述を削除。
シーン上にカメラを配置し、タッチイベントで pointOfView をアニメーションしている。
GameViewController.swift
import UIKit import QuartzCore import SceneKit class GameViewController: UIViewController { let cameraNode1: SCNNode = SCNNode() let cameraNode2: SCNNode = SCNNode() override func viewDidLoad() { super.viewDidLoad() // create a new scene let scene = SCNScene(named: "art.scnassets/ship.scn")! // create and add a light to the scene let lightNode = SCNNode() lightNode.light = SCNLight() lightNode.light!.type = .omni lightNode.position = SCNVector3(x: 0, y: 10, z: 10) scene.rootNode.addChildNode(lightNode) // create and add an ambient light to the scene let ambientLightNode = SCNNode() ambientLightNode.light = SCNLight() ambientLightNode.light!.type = .ambient ambientLightNode.light!.color = UIColor.darkGray scene.rootNode.addChildNode(ambientLightNode) // retrieve the ship node let ship = scene.rootNode.childNode(withName: "ship", recursively: true)! // animate the 3d object ship.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1))) let scnView = self.view as! SCNView // set the scene to the view scnView.scene = scene // allows the user to manipulate the camera scnView.allowsCameraControl = true // show statistics such as fps and timing information scnView.showsStatistics = true // configure the view scnView.backgroundColor = UIColor.black // --- 追加分 --- cameraNode1.name = "camera1" cameraNode1.camera = SCNCamera() cameraNode1.position = SCNVector3(x: 0, y: 0, z: 15) scene.rootNode.addChildNode(cameraNode1) cameraNode2.name = "camera2" cameraNode2.camera = SCNCamera() cameraNode2.position = SCNVector3(x: 0, y: 20, z: 0) cameraNode2.eulerAngles = SCNVector3(x: Float.pi * -0.5, y: 0, z: 0) scene.rootNode.addChildNode(cameraNode2) scnView.pointOfView = cameraNode1 // add a tap gesture recognizer let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:))) scnView.addGestureRecognizer(tapGesture) } func handleTap(_ gestureRecognize: UIGestureRecognizer) { // retrieve the SCNView let scnView = self.view as! SCNView let cameraNode:SCNNode! if scnView.pointOfView?.name == "camera1" { cameraNode = scnView.scene?.rootNode.childNode(withName: "camera2", recursively: true) } else { cameraNode = scnView.scene?.rootNode.childNode(withName: "camera1", recursively: true) } SCNTransaction.begin() SCNTransaction.animationDuration = 4.0 scnView.pointOfView = cameraNode SCNTransaction.commit() } override var shouldAutorotate: Bool { return true } override var prefersStatusBarHidden: Bool { return true } override var supportedInterfaceOrientations: UIInterfaceOrientationMask { if UIDevice.current.userInterfaceIdiom == .phone { return .allButUpsideDown } else { return .all } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Release any cached data, images, etc that aren't in use. } }
注意点
シーン上にカメラを配置していないとアニメーションは行われず、瞬時にカメラが変わる。
また、iOS シミュレーターではアニメーションが微妙な動きをする場合があるので注意。
今回はここまで