Inside the metal class, the color of the reflected ray is attenuated by the constant albedo attribute.
attenuation = albedo;
This is an rather inprecise approximation for metal reflections at grazing angles and gives unnatural dark edges around the spheres (compare the original and corrected image). This issue can be easily fixed by replacing the constant albedo with Schlick's approximation
attenuation = metal_reflectance(cos_theta, albedo);
static color metal_reflectance(double cosine, const color& albedo) {
const color white = color(1, 1, 1);
// Schlick's approximation for metals
return albedo + (white - albedo) * pow(1 - cosine, 5);
}
The metal scatter function (using attenuation=albedo) is introduced in listing 1.65, section 1.10.4.
The Schlick approximation is introduced in 1.11.4 (Schlick Approximation), for glass materials.
The Fresnel effect is not mentioned in the book.
It seems there are two choices:
Address the Fresnel effect and the Schlick approximation earlier, as a refinement to the metal scatter function, and then later apply it also to dielectric material reflectance, or
Leave the attenuation=albedo approximation in the metal scatter function, and then after addressing it for dielectric reflectance, apply it as an improvement to the metal scatter function.
I'm leaning toward option 1. Note that in both cases, we should directly name and explain the Fresnel effect, likely with at least one example image.
Inside the metal class, the color of the reflected ray is attenuated by the constant albedo attribute.
attenuation = albedo;
This is an rather inprecise approximation for metal reflections at grazing angles and gives unnatural dark edges around the spheres (compare the original and corrected image). This issue can be easily fixed by replacing the constant albedo with Schlick's approximation