Custom Metal Drawing in SceneKit

Dennis Ippel
2 min readMay 3, 2019

SceneKit is a powerful framework with many useful features. I’ve been using it on a daily basis for the past six months and I’ve grown to love it. However, one thing that Apple hasn’t done well is providing us with extensive documentation. Using SceneKit means digging through GitHub, StackOverflow and the very few meaningful results returned by Google.

One of the things that is hard to figure out is how to perform custom Metal drawing after SceneKit has rendered a scene. Apple’s documentation reveals the following:

… to perform custom Metal or OpenGL rendering before or after SceneKit renders the scene, specify your own custom object that implements the SCNSceneRendererDelegate protocol for the view’s delegate property.

Two methods in SCNSceneRendererDelegate are of interest:

func renderer(SCNSceneRenderer, willRenderScene: SCNScene, atTime: TimeInterval)
Tells the delegate that the renderer has cleared the viewport and is about to render the scene.

and

func renderer(SCNSceneRenderer, didRenderScene: SCNScene, atTime: TimeInterval)
Tells the delegate that the renderer has rendered the scene.

Apple’s documentation has one last bit of useful information:

To render using Metal, use the renderer parameter to retrieve the scene renderer’s currentRenderCommandEncoder object and encode your own drawing commands. If you need to reference other Metal state, see the properties listed in SCNSceneRenderer.

That’s where the documentation ends so it is up to us to figure out the rest.

Let’s Draw A Triangle

There are some really good SceneKit and Metal tutorials out there so for the sake of brevity I won’t go into the basics.

First you’ll need to setup a new project in Xcode using the “Game” template for iOS or macOS. This will generate a new SceneKit project with a rotating airplane.

Open the GameViewController.swift file and make sure it conforms to the SCNSceneRenderer protocol:

Next, assign the delegate to SCNView inviewDidLoad():

Now we are going to set up the resources we need for Metal. First, add two instance variables:

Time to add the function that takes care of setting up the Metal resources we’ll need:

Our new function should be called in viewDidAppear():

When creating the MTLRenderPipelineDescriptor we referenced two shader functions called passthrough_vertex and passthrough_fragment . These functions need to be defined in a Metal shader file.

Create a new file called Shaders.metal and paste the following:

Now the only thing left to do is implement SCNSceneRenderer‘s renderer(didRenderScene:) method:

Run the project and behold the colorful triangle:

This is a very basic example but hopefully it’ll allow you to create your own, more exciting, 3D content.

It took me a while to figure this out so I hope it’ll benefit anyone looking to add custom Metal drawing to SceneKit. Let me know if it did.

--

--