Showing posts with label xcode. Show all posts
Showing posts with label xcode. Show all posts

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")!



Wednesday, December 23, 2015

Moving to embedXcode...

The Problem


We have been using the Arduino IDE to develop on. Which is fine (and free) but it does have some limitations. In particular, we ran into the problem of having too many tabs (files) in our main controller sketch. This came about as a result of another issue, which is not unrelated.

As with most people we started developing our robot code organically using mostly straight c with c++ functionality reserved for included libraries. By the time you add 13 sensors, speech synthesis, speech recognition, 2 motor controllers, serial comms for the Bluetooth remote (which will be described in a subsequent post) and an I2C bus connecting the real time clock, pressure / altitude module and 2 auxiliary Arduino's used for display and logging, the code gets messy and hard to maintain. A simplified schematic of the robot so far is shown below. The schematic was produced using Fritzing which I have mentioned previously and strongly recommend.



As an aside, we are using SPI for the logging Arduino to communicate with its OLED shield, so we have all the available communication options covered (with the possible exceptions of WiFi and RF - stay tuned)!

To fix the messy, unmaintainable code issue, we started to translate our c code into c++ classes where it made sense. This made the code much more modular but each class requires a new tab which brings us back to the first issue mentioned above. Once the number of tabs fill up the top row of the IDE, it becomes a bit of a pain to move to the tabs not displayed. There is a keyboard shortcut to go to the next and previous tab, but that is a bit clunky and was the straw that sent me on a search for a better IDE to develop Arduino code on.


The other short comings of the Arduino IDE are:
  1. No code completion; and
  2. The syntax highlighting is a bit hit and miss. You could fix a particular issue by editing the keywords.txt file in the appropriate library but that is pretty fragile.

The Solution


A quick google search will turn up LOTS of different options for programming the Arduino. Our preferred solution would incorporate the following:
  1. Minimal learning curve;
  2. Preferably free;
  3. Works on a Mac;
  4. Can upload a sketch from within the IDE;
  5. Includes a serial terminal similar to the serial monitor provided by the Arduino IDE; 
  6. Has code completion and syntax highlighting; and
  7. Handles multiple files well; and
  8. Doesn't create any new issues.
With this shopping list in mind, the field quickly narrows to a plug in for Xcode called embedXcode. This ticks all our requirements and has (almost) no learning curve since we use Xcode for our App Development work.



The other IDE we considered was Eclipse which is the basis of Android Studio that we use for Android Development. What swayed or decision was that the setup looked a lot easier for Xcode and we were more familiar with this IDE as well. Have a look at this blog by a chap in the US, he had the same issues but decided on Eclipse. Going with what you are already familiar with makes a lot of sense.

Setting up embedXcode


This is straight forward and described in detail in the (large) user manual. In summary:
  1. Install Xcode if you don't have it already.
  2. Download embedXcode. We went for the free version to evaluate how good the plug in is. Should it work out we will either upgrade to embedXcode+ or pay a donation. We want to encourage ongoing development of the plugin. We know that Xcode changes frequently and with each new release normally breaks legacy code.
  3. Install the plug in and open up Xcode. That's it! You should now have the option to open a new embedXcode AVR project (see below).

Importing Sketches


Unfortunately you can't just import sketches that you have done with the Arduino IDE. There is a process that you need to follow:
  1. Open a new project in Xcode. You can call it the same name as your sketch. Make sure you select the correct board type (e.g. Uno) in the new project options. The scope options are sketch or library and this also sets the extension of the main file (.ino for sketches and .cpp for libraries).
  2. Open your sketch in the Arduino IDE and copy the contents into the ino file in your Xcode project. There is some pre-processor definitions used for code sensing at the top of the ino template file in Xcode. Don't overwrite these unless you know what you are doing (e.g. if you are using a recent Arduino you can replace the lot with #include "Arduino.h".
  3. The next step is to find your Arduino libraries folder in Finder and drag it across to the Sketchbook group. When the choose options for adding these files dialog comes up, don't select "copy items if needed" (unless you want multiple copies of your library files), select index in "add to targets" (see below). You also need to change the type from plain text to "c++ source". This option is found in the right hand pane of Xcode after selecting the main sketch (shown in the second screenshot below).
  4. The thing I stuffed up initially was not also listing the libraries used in the makefile. If you get an error saying a library can't be found, this may be the answer To fix it, select the makefile in the left hand pane and add the names of the libraries used.  There are two types of libraries you will use most often, application libraries and user defined libraries. Generally, the application libraries are the ones defined using <> (e.g.  #define <SoftwareSerial>) and the user libraries are defined using"" (e.g. #define "blunoAccessory"). However the <TimerOne> library was an exception to this rule and needed to be defined as a user library (e.g. "APP_LIBS_LIST = SoftwareSerial" and "USER_LIBS_LIST = U8glib blunoAccessory TimerOne". Different libraries are separated by a space and don't show the file extension. Read the user manual if you are still confused, it covers this topic in some detail.



Once you have completed the four steps above, you should be able to build (compile) your project, but only if your board is connected.

New Issues?


The only issues which have arisen so far are fairly minor apart from the speed of compilation and uploading. This is significantly slower than the Arduino IDE. If you purchased  embedXcode+ then you have two options:

  1. Build -> All targets which builds and links everything, and is slow.
  2. Make -> Fast -> additional targets only, which builds the main sketch and the libraries in the local folder, so it is much faster (up to 10x according to the developer).

If you only downloaded the free version then you are stuck with option 1. Other areas to be aware of are:
  1. You can't Build (compile) a project unless you are connected to your board via USB. This is a bit of a pain as you could just compile using the Arduino IDE without being connected to the board. Solved this. From the Product menu item select Scheme -> Build.
  2. Instead of Serial Monitor in the Arduino IDE you use Terminal on the Mac. The default baud rate for terminal is 9600. Which is ok if that is the baud rate you want to use on the serial port but I have a sketch which communicates with a BlueTooth LE shield on the same comm port that needs 115200 baud. Theoretically you can change the baud rate in Terminal using stty (e.g. stty 115200), but this doesn't seem to work. I have also tried "screen /dev/tty.usbmodemfd121 115200", but no cigar. I will keep working on this but the work around for now is to use 9600 baud if you can or use the old Arduino Serial Monitor if all else fails. Other solutions are welcome, so feel free to comment below. I have found the answer to this as well. There is an option in the makefile that you can use to set the baud rate, namely:  "SERIAL_BAUDRATE = 115200".
  3. Getting code sense to work for me took a bit of tweaking. First make sure that the sketch (ino file) has index selected for Target Membership (click on this file to check). Save the file and close the project. A small update is required to the user manual instructions. In the current version of Xcode (v7.2), projects is now a separate dialogue to Organiser but it is still found under the Windows menu in Xcode. Delete your derived data for your project and then reopen your project. After indexing, code sense for the Arduino specific definitions should work. You can change the syntax colouring in preferences, fonts and color.

If anything else comes up, I will add it here. All in all I am pretty happy with this solution. We will still use the Arduino IDE for simple sketches but for something as complicated as a robot, an IDE like Xcode is essential. Well done embedXcode!

Update 27th December 2015


I was so impressed with embedXcode that I upgraded to embedXcode+. This is worth doing if you use the plugin regularly. It also encourages the developer to keep supporting the product which is important given the frequent updates to Xcode.

Error: Serial port not available (Step2.mk)




If you come across this error (I did), there is a simple fix. First open up terminal and find out the name of your serial port. Type the following command: ls /dev/tty.usb*


This will provide the name of your serial port. Copy this and then open the main Makefile in Xcode uncomment the line:

#BOARD_PORT = /dev/tty.usbmodem*

and specify either a more general name:  e.g. BOARD_PORT = /dev/tty.usbmodem*

or the specific USB port name of the board that you got from Terminal e.g. in my case:

BOARD_PORT = /dev/tty.usbmodemfd121