Thursday, March 19, 2020

Loading 3D Models in SceneKit

COLLADA 3D Models


Figure 1. 3D Model of a Neuron.

The Mac has supported the visualization of COLLADA 3D models since 2009. If you created or downloaded a model this could be viewed in Finder and Preview. With the introduction of the 3D Framework, SceneKit, it is relatively simple to load and display a 3D model in iOS or OSX.

What is COLLADA?



COLLADA (COLLAborative Design Activity) is a file format for 3D applications. COLLADA documents are effectively XML files, usually identified with a .dae (digital asset exchange) filename extension. This file format has its own ISO standard (17506:2012).

So if you are choosing a 3D software application to create digital assets for your iOS app, make sure that it can export to the COLLADA (.dae) file format.

In addition to being able to use .dae files with SceneKit, many game engines also provide native support for COLLADA.

Getting a 3D Model


In order to import and display a 3D model we are going to need to have one! For this tutorial, I downloaded a model from clara.io. Clara.io has free online modelling tools plus free downloads from their library. Make sure that your model is in COLLADA format.

SceneKit


SceneKit is an iOS/OSX framework that allows you to build and manipulate 3D objects within a 3D scene. SceneKit has a high-performance rendering engine and a descriptive API for import, manipulation, and rendering of 3D assets.

SceneKit is based on the concept of nodes. Each 3D object that you want to render using SceneKit is a node. The SCNScene object is a container for the node hierarchy and global properties that together form a displayable 3D scene.

To build a 3D scene, you use nodes to create its structure, and then add lights and a camera to create the visible content. SceneKit implements content as a hierarchical tree structure of nodes, also known as scene graph. The rootNode object in a scene defines the coordinate system of the rendered 3D world.

The Code


Assuming you now have the 3D model which you want to display, drag it into the art.scnassets folder in Xcode. You can then load a 3D model in SceneKit using one line of code.

let scene = SCNScene(named: "art.scnassets/brain-simple.dae")!

If you select the iOS Game template when you create a new project in Xcode, then the remainder of the boiler plate code will do everything else. The only class you need to modify is GameViewController. I have moved things around a bit to make the functionality more obvious. The viewDidLoad function becomes:
var cameraNode: SCNNode!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // create a new scene
        let scene = SCNScene(named: "art.scnassets/brain-simple.dae")!
        
        // create and add a camera to the scene
        cameraNode = setupCamera(for: scene)
        
        // create and add a light to the scene
        setupLighting(for: scene)
     
        // Setup our scene view:
        setupSceneView(with: scene)
    }
The functions called from viewDidLoad are then:
func setupCamera(for scene: SCNScene!) -> SCNNode {
        // Create and add a camera to the scene:
        let cameraNode = SCNNode()
        
        cameraNode.camera = SCNCamera()
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
        scene.rootNode.addChildNode(cameraNode)

        return cameraNode
    }
    
    func setupLighting(for scene: SCNScene!) {
        // 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)
    }
    
    func setupSceneView(with scene: SCNScene!) {
        // retrieve the SCNView
        let sceneView = self.view as! SCNView
        
        // set the scene to the view
        sceneView.scene = scene
        
        // allows the user to manipulate the camera
        sceneView.allowsCameraControl = true
        
        // show statistics such as fps and timing information
        sceneView.showsStatistics = true
        
        // configure the view
        sceneView.backgroundColor = UIColor.black
        
        // add a tap gesture recognizer
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
        sceneView.addGestureRecognizer(tapGesture)
    }
That's it! Run the code and you can rotate, tilt and pan your 3D model.

Selecting the Material which Responds to a Tap


Figure 2. Xcode SceneKit Editor


In our setupSceneView() function we assign a tap gesture which turns the first material in our model red whenever we tap the screen. How do you know what the first material is?

Well, Xcode includes a SceneKit Editor. If you click on your 3D Model file (.dae) in the aert.scnassets folder, then it will appear in the SceneKit editor (Figure 2). Click on the image of the model and then click on the material inspector icon (top right of the editor), and you will see a list of materials available in the model. Mine includes four materials labelled default, red, green and blue. So in my case the first material is "default" which is a light grey colour in my model.

If we want one of the other materials to glow red when the screen is tapped then instead of the firstMaterial property, we can use its name. For example if I wanted the green material to glow red, then I would change this line in the handleTap() function as shown:

let material = result.node.geometry!.material(named: "green")!



No comments:

Post a Comment