3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SceneKitで座標軸をつくる

Posted at

はじめに

SceneKitで座標軸をつくる際の実装メモです。

作るもの

SceneKit上で3次元空間の基準となる座標軸を作成します。

SCNCameraで見かける下図のようなものです。
img_03.png
(SceneKitは右手系座標です。)

完成イメージです。

img_01.jpg

対象読者

  • SceneKitを利用したことがある人向けです。

Game Applicationを作成

Game Applicationを作成しておきます。
img_02.png

コード

作成した Game Application のコードを以下のように修正します。

class GameViewController: UIViewController {

    /// オブジェクト追加用のルートノード
    let rootNode = SCNNode()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // create a new scene
        let scene = SCNScene()
        
        // create and add a camera to the scene
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        scene.rootNode.addChildNode(cameraNode)
        
        // place the camera
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
        
        // 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)
        
        // シーンにルートノードを追加する
        scene.rootNode.addChildNode(rootNode)
        
        
        // retrieve the SCNView
        let scnView = self.view as! SCNView
        
        /* デバッグ用設定 */
        // 背景を灰色に設定する
        scnView.backgroundColor = UIColor.gray
        // 現在の視点をユーザーが操作できるように設定
        scnView.allowsCameraControl = true
        // レンダリングパフォーマンス統計を表示する
        scnView.showsStatistics = true
        scnView.debugOptions = [
            .showBoundingBoxes, // オブジェクトのバウンディングボックスを表示する
            .showWireframe, // ワイヤーフレームを表示する
            .showCameras, // 仮想カメラを表示する
        ]
        
        // set the scene to the view
        scnView.scene = scene
        
        // 原点を追加する
        rootNode.addChildNode(makeOriginNode())
        
        // 座標軸を追加する
        rootNode.addChildNode(makeAxisNode())
    }
    
    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
        }
    }
}

/// 追加するオブジェクト
extension GameViewController {
    
    /// 原点を作成する
    func makeOriginNode() -> SCNNode {
        let sphere = makeSphereNode(radius: 0.25)
        sphere.position = SCNVector3(0, 0, 0)
        return sphere
    }
    
    /// スフィア(球体)ノードを追加する
    func makeSphereNode(radius: CGFloat = 1.0) -> SCNNode {
        let sphere: SCNGeometry = SCNSphere(radius: radius)
        let sphereNode = SCNNode(geometry: sphere)
        return sphereNode
    }
    
    /// 座標軸ノードを作成する
    func makeAxisNode() -> SCNNode {
        let node = SCNNode()
        node.name = "asix"
        
        // x軸
        node.addChildNode(makeXAxisNode())
        // y軸
        node.addChildNode(makeYAxisNode())
        // z軸
        node.addChildNode(makeZAxisNode())
        
        return node
    }
    
    /// x軸ノードを作成する
    func makeXAxisNode(radius: CGFloat = 0.1, height: CGFloat = 5.0, color: UIColor = .red) -> SCNNode {
        let cylinderNode = makeCylinderNode(radius: radius, height: height, color: color)
        // z軸を基準に90度(0.5π)回転する
        cylinderNode.simdRotate(
            by: simd_quatf(
                angle: .pi * 0.5, // 回転角
                axis: simd_normalize(simd_float3(0, 0, 1)) // 回転軸
            ),
            aroundTarget: simd_float3(0, 0, 0)
        )
        // 原点まで移動する
        cylinderNode.position = SCNVector3(height * 0.5, 0, 0)
        return cylinderNode
    }
    
    /// y軸ノードを作成する
    func makeYAxisNode(radius: CGFloat = 0.1, height: CGFloat = 5.0, color: UIColor = .green) -> SCNNode {
        let cylinderNode = makeCylinderNode(radius: radius, height: height, color: color)
        // 原点まで移動する
        cylinderNode.position = SCNVector3(0, height * 0.5, 0)
        return cylinderNode
    }
    
    /// z軸ノードを作成する
    func makeZAxisNode(radius: CGFloat = 0.1, height: CGFloat = 5.0, color: UIColor = .blue) -> SCNNode {
        let cylinderNode = makeCylinderNode(radius: radius, height: height, color: color)
        // x軸を基準に90度(0.5π)回転する
        cylinderNode.simdRotate(
            by: simd_quatf(
                angle: .pi * 0.5, // 回転角
                axis: simd_normalize(simd_float3(1, 0, 0)) // 回転軸
            ),
            aroundTarget: simd_float3(0, 0, 0)
        )
        // 原点まで移動する
        cylinderNode.position = SCNVector3(0, 0, height * 0.5)
        return cylinderNode
    }
    
    /// シリンダー(円柱)ノードを作成する
    func makeCylinderNode(radius: CGFloat, height: CGFloat, color: UIColor = .white) -> SCNNode {
        let cylinder = SCNCylinder(radius: radius, height: height)
        let node = SCNNode(geometry: cylinder)
        let material = SCNMaterial()
        material.diffuse.contents = color
        node.geometry?.firstMaterial = material
        return node
    }
}

おわりに

SceneKitの動作を確認する為に作成しました。
行っていること自体は単純で、
オブジェクトを追加して移動、回転を行っているだけです。

参考にさせていただいたサイト

3
4
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
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?