Search code examples
iosswiftscenekitprogrammatically-createdscncamera

SCNCamera made programmatically not in the correct position


I am trying to programmatically create a camera for my MainScene.scn file.

I need to create the camera in code, as I am wanting to make a camera orbit node, and this is the only way I can think of. I also would like to keep using my scene file.

This is my code (simplified) from my view controller:

import UIKit
import SceneKit

class GameViewController: UIViewController {

    // MARK: Scene objects
    private var gameView: SCNView!
    private var gameScene: SCNScene!
    private var gameCameraNode: SCNNode!

    // MARK: View controller overrides
    override func viewDidLoad() {
        super.viewDidLoad()

        // Setup game
        initView()
        initScene()
        initCamera()
    }
}

private extension GameViewController {

    // Initialise the view and scene
    private func initView() {
        self.view = SCNView(frame: view.bounds) // Create an SCNView to play the game within
        gameView = self.view as? SCNView // Assign the view
        gameView.showsStatistics = true // Show game statistics
        gameView.autoenablesDefaultLighting = true // Allow default lighting
        gameView.antialiasingMode = .multisampling2X // Use anti-aliasing for a smoother look
    }
    private func initScene() {
        gameScene = SCNScene(named: "art.scnassets/MainScene.scn")! // Assign the scene
        gameView.scene = gameScene // Set the game view's scene
        gameView.isPlaying = true // The scene is playing (not paused)
    }
    private func initCamera() {
        gameCameraNode = SCNNode()
        gameCameraNode.camera = SCNCamera()
        gameCameraNode.position = SCNVector3(0, 3.5, 27)
        gameCameraNode.eulerAngles = SCNVector3(-2, 0, 0)
        gameScene.rootNode.addChildNode(gameCameraNode)
        gameView.pointOfView = gameCameraNode
    }
}

This code can easily be pasted to replace the default view controller code. All you need to do is add the MainScene.scn and drag in something like a box.

If you try the code, the camera is in the wrong position. If I use the same properties for the camera in the scene, it works, but that is not what I am looking for.

From what I have read, SceneKit may be creating a default camera as said here and here. However, I am setting the pointOfView property just as they said in those answers, but it still does not work.

How can I place my camera in the correct position in the scene programmatically?


Solution

  • After a while, I discovered that you can actually add empty nodes directly within the Scene Builder. I originally only wanted a programmatic answer, as I wanted to make a camera orbit node like the questions I linked to. Now I can add an empty node, I can make the child of the orbit the camera.

    This requires no code, unless you want to access the nodes (e.g. changing position or rotation):

    gameCameraNode = gameView.pointOfView // Use camera object from scene
    gameCameraOrbitNode = gameCameraNode.parent // Use camera orbit object from scene
    

    Here are the steps to create an orbit node:

    1) Drag it in from the Objects Library: enter image description here

    2) Setup up your Scene Graph like so:

    enter image description here