Errata for Metal by Tutorials 4th Edition

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

1 Like

Hello!

Is there a changelog to know what changed between v3 and v4 of the book?

1 Like

There arenā€™t a lot of significant changes. The main changes are:

  • Update the code from Xcode 13 and iOS 15 to Xcode 15 and iOS 17. Apple changed a couple of small things which resulted in half the book code not working, so we took the opportunity to go through the book and update errors and the old raywenderlich links.

  • Change from OBJ file format to USD throughout the book. USD is a more modern format, and the USDZ format is the official AR format.

  • The character animation chapter code now works a lot better on more complicated models.

  • The code was temperamental when running in playgrounds, so most of the playgrounds are now removed, except where it made sense to keep them.

And @coffea - Welcome to the forums :smile: !

2 Likes

Hello! Iā€™ve decided to give the book another read now that the fourth edition is out, and in Chapter 4 weā€™re told to add the shader code:

vertex float4 vertex_main(
constant float3 *vertices [[buffer(0)]],
uint vertexID [[vertex_id]])
ā€¦

Then just afterwards the book says

When you pass a pointer into the vertex function, you must specify an address space, either constant or device . constant is optimized for accessing the same variable over several vertex functions in parallel. device is best for accessing different parts of a buffer over the parallel functions ā€” such as when using a buffer with points and color data interleaved.

Doesnā€™t this mean that in the shader code the vertices buffer should be const device instead of constant, as the 6 invocations of the vertex shader will be accessing different parts of the buffer using the vertexID as an offset?

In Chapter 9, references to a method ā€˜keysPressedā€™ should be keyPressed

Pages 222, 223, 226, 228, 229

I think thatā€™s all of themā€¦

Hi @dtdanyluk and welcome to the forums :blush: !

Iā€™m not quite sure what youā€™re referring to? You create the property (not a method) keysPressed on page 222. I named it keysPressed rather than keyPressed because itā€™s a set that can contain a number of keys currently held down.

@jonmhob - yes according to the Metal Shading Language document that is a mistake. It should be const device. Thank you for reporting it. When you come to Uniforms later, that will be a constant, because the same structure is used across multiple vertices.

Iā€™ll have to get round to testing how using the wrong address space qualifier affects larger buffers. The comment here: ios - Metal address space specifier 'device' - Stack Overflow suggests that there are different alignment requirements, but I havenā€™t researched it.

Yes, I believe that in this particular case there is functionally no difference, but I mentioned it because it contradicts the text. I agree that it would be really interesting to test the actual effects of different address spaces on performance though!

There is a talk from WWDC20 called Optimizing Metal Performance for Apple Silicon Macs and at about 34 minutes in the presenter talks about address spaces and says essentially that the rule of thumb is:

Device: For variable size buffers, or fixed size buffers that will only be read a few times.
Constant: For fixed size buffers that will be read often.

He mentions that there are special ā€œuniformā€ registers that can be preloaded when loading the shader if the compiler knows the memory layout of the constant data at compile time (i.e. not using pointers, but using references to structs). So that makes perfect sense that in the later samples when we use constant Uniforms later as you say, that that data is preloaded into constant registers and ready to use for every shader instance - while data in device memory would have to be read at run-time by the shader.

I believe the alignment requirement is only for if youā€™re making use of the offset parameter of set(Vertex)Buffer, as this has to be be a multiple of 16 on Apple Silicon and 256 on Intel Macs (as noted in the feature set pdf as ā€œMinimum constant buffer offset alignmentā€) or you get a validation error. For example Appleā€™s hybrid rendering sample has a transform matrix per mesh which they pad out from 64 bytes up to 256 bytes per item so they can access it using setVertexBuffer(ā€¦, offset: meshIndex, ā€¦). Meanwhile in the same sample they have their camera data in a similar uniform buffer, but they donā€™t pad / align this because theyā€™re always using offset: 0.

1 Like

I thought you might like to know about this misbehaviour I found:

In chapter 10, the one about Lighting Fundamentals, there is an OpenGL formula for light attenuation, towards the beginning of the section about Point Lights.

This becomes invisible when viewing in dark mode but appears fine in light mode.

I am using Safari on a Mac, but this behaviour can still be observed when looking at the electronic edition using the Books App. I see exactly the same on iOS, both in the browser and Books app.

It can easily be observed when switching between the modes through the Appearance section in the Settings App.

1 Like

Oops ā€¦ my bad ā€¦ sorry :grimacing:

1 Like

I hope this is the appropriate thread for these comments.

In chapter 4, in the starter code of Renderer.swift, several ā€œselfā€ objects were capitalized, which agonized my Xcode 15. I replaced the upper case S with a lower case s and the errors disappeared and the code built normally.

@jonmhob my Xcode version is 15.4. In file Renderer.swift of the chapter 04 starter project, where ā€œdeviceā€ (and several other vars) is defined Xcode errored out using ā€œstatic varā€.

For example, line 38

static var device: MTLDevice!

I replaced static var with ā€œletā€ thus:

let device: MTLDevice!

The error cleared and the project built normally.

Iā€™m a Swift/Metal newbie so it took me a couple of days to figure this out. But damn gratifying when the code ran as intended.

The sample code for Chapter 24-character-animation have a bug when reading the roughness and metallic values. It tries to cast them to float3, but it should be float. I realised this when loading in another usdz model into this sample code and it didnā€™t show the light secular. So this in the file Submesh.swift line 116 and line 121.

Should be and then it worksā€¦

    if let roughness = material?.property(with: .roughness),
      roughness.type == .float {
      self.roughness = roughness.floatValue
    }
    metallic = 0
    if let metallic = material?.property(with: .metallic),
      metallic.type == .float {
      self.metallic = metallic.floatValue
    }
1 Like

Thank you for your feedback, @niklasniklas and welcome to the forum :smiling_face:

This should be fixed in the fourth edition, released Dec 2023. It also depends on which version of Xcode you are using, as prior to the third edition of Metal by Tutorials, this code didnā€™t work.