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
Fernando
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
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”.
@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)
#else
params.scaleFactor = 1
#endif
➤ In PBR.metal, replace:
uint2 coord = uint2(params.touchX * 2, params.touchY * 2);
with:
uint2 coord = uint2(
params.touchX * params.scaleFactor,
params.touchY * params.scaleFactor);
Thank you .
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
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
In chapter 7 right before the checker board graphic please revisit step 3. I believe you misinterpreted the result of the step function.
Hi, for chapter 7, I think the MemoryLayout
should take Params
as input instead of Uniforms
renderEncoder.setFragmentBytes(
¶ms,
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.
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! - that’s made it through three editions!
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.
Thanks!!
[Chapter 10 Lighting Fundamentals]
In Ambient Reflection part, I noticed the intensity
attribute is not there as it says in the book description
Common.h:
typedef struct {
LightType type;
vector_float3 position;
vector_float3 color;
vector_float3 specularColor;
float radius;
vector_float3 attenuation;
float coneAngle;
vector_float3 coneDirection;
float coneAttenuation;
float intensity; // <-- insert here
} Light;
SceneLighting.swift:
struct Lighting {
static func buildDefaultLight() -> Light {
var light = Light()
light.position = [0, 0, 0]
light.color = [1, 1, 1]
light.specularColor = [0.6, 0.6, 0.6]
light.attenuation = [1, 0, 0]
light.type = Sun
light.intensity = 0.1 // <-- insert here
return light
}
let ambientLight: Light = {
var light = Self.buildDefaultLight()
light.color = [0.05, 0.1, 0]
light.intensity = 0.5 // <-- change property here
light.type = Ambient
return light
}()
Lighting.metal:
float3 phongLighting(...) {
// code
case Ambient: {
ambientColor += light.color * light.intensity; // <-- that right ?
break;
}
// code
}