Errata for Metal by Tutorials 3rd Edition

Thank you @nghiaphamsg! Yes, you are correct.

In chapter 11: Maps & Materials
I think .float type roughness will be more reasonable with the code below

1 Like

Thank you. I think you are correct.

Thinking back to olden times, I believe float didnā€™t work for this, but I canā€™t remember what file format I was using. So I would advise that whatever file format youā€™re using, you check that the output matches your expectation. If this isnā€™t a recent Apple change, I obviously didnā€™t.

When using texture maps, the roughness value is ignored in the current code. Thatā€™s another point. I was looking at some code that uses the diffuse material colour as a scalar on the diffuse texture, whereas the bookā€™s code just ignores the material if there is a texture. Maybe the code should use the roughness value as a scalar. Up to you.

Chapter 23 broken link WWDC17 - Videos - Apple Developer

Hi,
Chapter 6: When building the ViewMatrix thereā€™s a typo in the code used to indicate where the insertion is to be made:

renderEncoder.setVertexBytes(
   &uniforms,
   length: MemoryLayout<Uniforms>.stride,
   index: 1)

It refers to index: 1 where it should be index: 11

Also, could I suggest that this line be removed from the Rendererā€™s init(metalView:) as it achieves nothing?

uniforms.viewMatrix = float4x4(translation: [0.8, 0, 0]).inverse

Regards

1 Like

Huh. Well spotted!

Yes, itā€™s overridden by the assignment in draw(in:).

Thank you.

Small typo in Chapter 4: Adding Another Vertex Attribute

in the following, length should be: MemoryLayout<simd_float3>.stride * colors.count
but itā€™s okay because indices.count is greater

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
1 Like

Sorry, me again. This is not actually an error but it cost me hours of time.
You do mention in chapter 5 that Metal matrices are column-major (but not that simd matrices are too!). Nevertheless in Chapter 6 when I met MathLibrary.swift, it seemed to me that all the matrices were inverted. For instance, the X-rotation was defined thus:

init(rotationX angle: Float) {
   let matrix = float4x4(
       [1,           0,           0, 0],
       [0,  cos(angle),  sin(angle), 0],
       [0, -sin(angle),  cos(angle), 0],
       [0,           0,           0, 1])
   self = matrix
}

but this looks a lot to me like the math:

       |1             0            0   0|
       |0    cos(angle)   sin(angle)   0|
       |0   -sin(angle)   cos(angle)   0|
       |0             0            0   1|

Could I respectively suggest you add a clarifying paragraph on simd or else, better still for those of us who use matrices, define your matrices using an alternative initialiser thus:

init(rotationX angle: Float) {
  let matrix = float4x4(rows: [[1,          0,           0, 0],
                               [0, cos(angle), -sin(angle), 0],
                               [0, sin(angle),  cos(angle), 0],
                               [0,          0,           0, 1]])
  self = matrix
}

Sorry to be a pest :blush:

1 Like

Thank you. That note in chapter 5 is poorly worded. There is of course no such thing as a ā€œMetal matrixā€.

float4x4 is Appleā€™s typealias of simd_float4x4, which is a simd matrix.

Iā€™d prefer to stick with columns rather than rows, because Apple says that that the simd library uses column-major (but then proceeds to use rows in its sample code :woman_facepalming:). However, I will add a note to add columns: to the initializers. Poking around the net, I find that OpenGL utility functions tend to use column-major, and DirectX tends to use row-major.

Chapter 6 - coordinate spaces - in the final version of the Spaces project the file Transform.swift has target membership for Spaces (iOS) checked, but not for Spaces (macOS).

1 Like

Chapter 8 Textures

Texture mapping in the shipped final version is working fine on the iOS simulator, but fails on macOS (12.6.6) - it gets some of the surfaces ok, but leaves some gray and some with smeared out colors.

Capter 7 The Fragment Function - I accidentally posted this in the wrong place:

In chapter 7 - The Fragment Shader, on page 167 the setFragmentBytes of params is called with a length of MemoryLayout<Uniforms>.stride rather than MemoryLayout<Params>.stride

1 Like

@oleamichael - thatā€™s weird as thatā€™s the OS we were targeting at publication time. Thanks for letting us know. I canā€™t check it out as I donā€™t have a device with macOS 12 any more.

What hardware (device / GPU) do you have?

Is that the same for all projects that use textures?

The GPU I have is AMD Radeon R9 M395. This is a late 2015 iMac so unfortunately
I canā€™t upgrade to the latest OS. I donā€™t know yet about other projects that use textures, but I will find out soon.

1 Like

There are differences with older Macs. Some features are not available. I hope youā€™re able to keep going with the simulator and iOS devices.

1 Like

I have a 2017 MacBook Pro running Ventura 13.5 with an Intel HD Graphics 630 GPU - both the iOS simulator and macOS versions work properly in this environment.

On the older iMac all the projects that use textures that I have tested so far have one problem or another. Iā€™ll see if I can write some minimalist texture apps to isolate exactly what the issue is. Iā€™m pretty sure I used multiple textures successfully using OpenGL on this machine in the past.

1 Like

I found the issue, but I donā€™t know yet why there is an issue - the problem is not with the gpu or the metal pipeline at all. Itā€™s Model I/O:
let asset = MDLAsset(
url: assetURL,
vertexDescriptor: .defaultLayout,
bufferAllocator: allocator)
On the iOS simulator this works fine, but on macOS it fails to fully populate the texture coordinate buffer - it correctly writes the first few coordinates but leaves most of them at (0, 0). I checked first using Capture GPU Workload, then added added a print loop right after the MDLAsset constructor to make sure they were not getting lost downstream (they arenā€™t):

// iOS Simulator texture coordinates

loaded texture: lowpoly-house-color.png

SIMD2(0.219114, 0.652658)

SIMD2(0.023366, 0.652658)

SIMD2(0.023366, 0.347341)

SIMD2(0.219114, 0.347341)

SIMD2(0.334651, 0.347341)

SIMD2(0.334651, 0.000113)

SIMD2(0.450188, 0.151593)

SIMD2(0.450188, 0.347341)

SIMD2(0.450188, 0.347341)

SIMD2(0.645937, 0.347341)

SIMD2(0.645937, 0.652658)

SIMD2(0.450188, 0.652658)

SIMD2(0.334651, 0.652658)

SIMD2(0.334651, 0.999887)

SIMD2(0.219114, 0.848407)

SIMD2(0.219114, 0.652658)

SIMD2(0.334651, 0.347341)

SIMD2(0.450188, 0.347341)

SIMD2(0.450188, 0.652658)

SIMD2(0.334651, 0.652658)

SIMD2(0.984034, 0.792101)

SIMD2(0.984034, 0.982614)

SIMD2(0.678717, 0.982614)

SIMD2(0.678717, 0.792102)

SIMD2(0.984034, 0.601589)

SIMD2(0.984034, 0.792101)

SIMD2(0.678717, 0.792102)

SIMD2(0.678717, 0.601589)

SIMD2(0.219114, 0.347341)

SIMD2(0.219114, 0.652658)

SIMD2(0.450188, 0.652658)

SIMD2(0.450188, 0.848407)

SIMD2(0.219114, 0.347341)

SIMD2(0.219115, 0.151593)

// macOS Simulator texture coordinates

loaded texture: lowpoly-house-color.png

SIMD2(0.219114, 0.652658)

SIMD2(0.023366, 0.652658)

SIMD2(0.023366, 0.347341)

SIMD2(0.219114, 0.347341)

SIMD2(0.334651, 0.347341)

SIMD2(0.334651, 0.000113)

SIMD2(0.450188, 0.151593)

SIMD2(0.450188, 0.347341)

SIMD2(0.450188, 0.347341)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

SIMD2(0.0, 0.0)

Strange! Other complex texture mapping apps - like the ModernRenderingWithMetal example from apple - work fine on this machine, but they are not using Model I/O.

I wonder if itā€™s the obj format. Attached is the final project from chapter 8, but using a usdz format for the house.

Thereā€™s extra code in TextureController.swift, Submesh.swift, Model.swift to cope with loading the usdz format. I took that code from the chapter 11 sample.

I created the usdz format by using Xcodeā€™s export to USD and Reality Converter to add the texture and export to usdz.

Textures.zip (2.7 MB)

1 Like

Interesting. That gets the house properly textured, but not the grass - the first texture coordinate gets loaded, but not the remaining 3. Ah, but the ground model is still .obj. Iā€™m guessing that if I convert that to usdz it too will work. Thanks!

1 Like

Thatā€™s good to hear! I hope you understood the changes to the code.

Itā€™s probably not worth putting in feedback to Apple, as it does work on newer devices. At least thereā€™s a workaround for now.

1 Like