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:

In chapter 7 right before the checker board graphic please revisit step 3. I believe you misinterpreted the result of the step function.

1 Like

Hi @burkejoh26 and welcome to the forums :slight_smile: !

:woman_facepalming: - Thank you!

Step 3 should say something like:

Hi, for chapter 7, I think the MemoryLayout should take Params as input instead of Uniforms

  length: MemoryLayout<Uniforms>.stride,  // HERE, should it be <Params>?
  index: 12)

Good catch - thanks! It’s allocating too much memory using Uniforms as the stride.

1 Like

Hi, for chapter 8, for the picture that denoted as “UV coordinates”, I think the coordinates whose y value are 0.15 should swap with the ones whose y values are 0.34.


It certainly looks like it! :clap:- that’s made it through three editions!

1 Like

Chapter 6: Coordinate Spaces

The Starter Project

I think it should be MTLVertexDescriptor right ?

1 Like

Absolutely yes! Thank you very much for pointing this out.

Enjoying the book. I noticed in chapter 11 on normal maps, page 296 the first section ends: “and that’s the power of normal apps” and I think you intended that final word to be maps.


1 Like