Help us understand the problem. What is going on with this article?

SceneKitで座標軸をつくる

はじめに

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

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

qooqle
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした