RayTracing / raytracing.github.io

Main Web Site (Online Books)
https://raytracing.github.io/
Creative Commons Zero v1.0 Universal
8.8k stars 866 forks source link

Use Schlick's formula for metal reflections #844

Open Naturseptime opened 3 years ago

Naturseptime commented 3 years ago

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);
}

spheres spheres_corrected

hollasch commented 3 years ago

Nice!

hollasch commented 2 months ago

More information:

It seems there are two choices:

  1. 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
  2. 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.