Errata for Metal by Tutorials 3rd Edition

Creating this topic to catch any typos and bugs in the 3rd Edition of Metal by Tutorials.

I found a typo on the PDF page 27,
Who This Book Is For?
We recommend the Swift Apprentice book, available in our catlagoue:

Should be catalogue.

Kind regards

1 Like

Thank you for the update, I was just doing some reading over the selection I’d buffer, and noticed that there is a multiple of two which is assuming the screen draw scale is 2 this does change depending on the device and screen. Pg 252 “* 2”

I would suggest you use contentScaleFactor.native or UIScreen.main.scale. It depends on how you are accessing the screen position data.

Hope that helps, as I got caught out by this when writing my idBuffer and testing on different devices.

Cheers Si

1 Like

The ToC bookmarks in both the PDF and ePub say “Chapter 21: Imaged-based lighting”. Should be “Image-based lighting”.

In the ePub the chapter header itself is spelled correctly, while in the PDF it still says “Imaged-based”.

1 Like

@rumor - Yes! That’s a lesson in not using magic numbers.

To correct this, I think an extra parameter on params would be useful.

➤ In Common.h, add this property to params:

uint scaleFactor;

➤ In Renderer.swift, add this to the end of init(metalView:options:):

#if os(macOS)
  params.scaleFactor = uint(NSScreen.main?.backingScaleFactor ?? 1)
#elseif os(iOS)
  params.scaleFactor = uint(UIScreen.main.scale)
  params.scaleFactor = 1

➤ In PBR.metal, replace:

uint2 coord = uint2(params.touchX * 2, params.touchY * 2);


uint2 coord = uint2(
  params.touchX * params.scaleFactor,
  params.touchY * params.scaleFactor); 

Thank you :slight_smile: .

Chapter 22

Final code:

I was wondering about this line:

float2 rippleY = float2(-uv.x, uv.y) + timer

Is it the intention here to add timer to both xy components? (I’m assuming that is what adding a scalar float to a vector float does.)

Or should this line be:

float2 rippleY = float2(-uv.x, uv.y + timer);

Since timer is only added to the x component for rippleX:

float2 rippleX = float2(uv.x + timer, uv.y);

I can’t say what @mhorga’s original intention was, but the nice thing about fragment shaders is that when you’re not creating a physically exact reproduction, you can create the effect you want for your render.

I tried both options, and I prefer the original code as written. When timer is applied the same to x and y, I find that the ripples are too straight. But you can go with whatever you think looks best.

I believe I’ve found an error at the beginning of chapter 4, when creating the vertices to pass along as a raw bytes buffer to the vertex shader.

See my post here: Chapter 4 (Third Edition) shader validation error :slight_smile:

1 Like

Perhaps another possible bug, but still in chapter 4, under the Adding Another Vertex Attribute section, the snippet for creating the color buffer is the following:

guard let colorBuffer = device.makeBuffer(
  bytes: &colors,
  length: MemoryLayout<simd_float3>.stride * indices.count,
  options: []) else {
    fatalError("Unable to create quad color buffer")
self.colorBuffer = colorBuffer

I believe the length is incorrect. It should be:

MemoryLayout<simd_float3>.stride * colors.count

Otherwise we’re multiplying by 6 instead of 4, which is the amount of SIMD Float3 elements in the array!


Yes, you’re absolutely right!

colors.count is correct, not indices.count :woman_facepalming: