iOS Metal Tutorial with Swift Part 5: Switching to MetalKit
Learn how to use MetalKit in this 5th part of our Metal tutorial series. By Andrew Kharchyshyn.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
iOS Metal Tutorial with Swift Part 5: Switching to MetalKit
20 mins
- Getting Started
- Getting Started with MetalKit
- Switching to SIMD
- Deleting the Objective-C Wrapper
- Replacing Matrix4 With a SIMD Data Type
- Fixing the Remaining Errors
- Fixing Issues in BufferProvider.swift
- Fixing Issues in Node.swift
- Exploring float4x4+Extensions.swift
- MetalKit Texture Loading
- Fixing Issues in Cube.swift
- Fixing Issues in MetalViewController.swift
- Fixing Issues in MySceneViewController.swift
- Switching to MTKView
- Removing Redundant Code From MetalViewController.swift
- Adding the MTKViewDelegate Protocol
- Where to Go From Here?
Adding the MTKViewDelegate Protocol
To make your MetalViewController
responsible for the draw updates, it must conform to MTKViewDelegate
.
Add this extension to the end of the file to implement the protocol methods:
// MARK: - MTKViewDelegate
extension MetalViewController: MTKViewDelegate {
// 1
func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
projectionMatrix = float4x4.makePerspectiveViewAngle(float4x4.degrees(toRad: 85.0),
aspectRatio: Float(self.view.bounds.size.width / self.view.bounds.size.height),
nearZ: 0.01, farZ: 100.0)
}
// 2
func draw(in view: MTKView) {
render(view.currentDrawable)
}
}
Taking a look at the two protocol methods:
-
mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize)
runs whenever theMTKView
resizes. Here, you reset theprojectionMatrix
based on the new size. -
draw(in view: MTKView)
is called when you need to draw a new frame to the view.
Since you’ve changed the way you call render()
, you need to update the method. Find the following code:
func render() {
if let drawable = metalLayer.nextDrawable() {
self.metalViewControllerDelegate?.renderObjects(drawable)
}
}
Then, replace it with this:
func render(_ drawable: CAMetalDrawable?) {
guard let drawable = drawable else { return }
self.metalViewControllerDelegate?.renderObjects(drawable)
}
Now that you’re responding to size changes using the delegate, you can remove the viewDidLayoutSubviews()
function too.
To connect the view delegate to the view controller, add the following code to the MetalViewController
class after the list of properties:
@IBOutlet weak var mtkView: MTKView! {
didSet {
mtkView.delegate = self
mtkView.preferredFramesPerSecond = 60
mtkView.clearColor = MTLClearColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0)
}
}
This is a property observer and will connect the view’s delegate to the view controller whenever the outlet is set.
To make the actual connection from the storyboard to the outlet, you need to open up Main.storyboard and have MetalViewController.swift open in the assistant editor. Drag from the unconnected outlet (denoted by the empty circle in the gutter) to the view in the storyboard. When you release, they should be connected:
All that’s left to do is set the device
property of the MTKView
. To do that, first find these two lines in viewDidLoad()
:
device = MTLCreateSystemDefaultDevice()
textureLoader = MTKTextureLoader(device: device)
Below those two lines, add the following line:
mtkView.device = device
Finally, remove the following properties from the top of the class:
var metalLayer: CAMetalLayer! = nil
var timer: CADisplayLink! = nil
var lastFrameTimestamp: CFTimeInterval = 0.0
You’re all done, build and run your app!
The cube still looks exactly like before, but now it’s running on MetalKit! Huzzah!
OK, you might feel a little disappointed because it looks like you ended up right where you started, and that nothing’s changed, right? But don’t fret. Just remember this ancient Chinese proverb: “The journey to Model I/O starts with the single step of porting to MetalKit.” Er, or something like that! :]
Where to Go From Here?
Here is the final example project from this iOS Metal tutorial.
Take a moment to review what you’ve done:
- You switched to using SIMD’s
float4x4
. - You removed all Objective-C code from the project.
- You loaded a texture using
MTKTextureLoader
. - You integrated
MTKView
into the project, removing lots of boilerplate code. - And best of all, you didn’t break anything!
You made it! You totally deserve some rest. :]
Feel like you’re up for more Metal? We’re looking to create more Metal tutorials in the future, but in the meantime, be sure to check out some of the great resources below:
- Apple’s Metal for Developers page, which has tons of links to documentation, videos and sample code
- Apple’s Metal Programming Guide
- Apple’s Metal Shading Language Guide
- The Metal videos from WWDC 2014
- The Metal videos from WWDC 2015
- The Metal videos from WWDC 2016
- MetalByExample.com
Also, tune into the OpenGL ES video tutorials on this site and learn as Ray explains — in depth — how many of these similar concepts work in OpenGL ES.
Thank you for joining me on this tour through Metal. As you can see, it’s a powerful technology that’s relatively easy to implement once you understand how it works.
If you have any questions, comments or Metal discoveries to share, please leave them in the comments below!