Specular Lighting and Fog

Diffuse light makes a surface look matte. Glossy materials, such as varnished wood, a foil-stamped title or a globe, also show specular highlights, the reflected image of the light; and in a large room, distant objects fade into fog. Both are a few lines of fragment shader. The fourteenth part of webgl-helper.js collects the section's techniques into one shader for BookNest's shelf, which the subsections take apart:

webgl-helper.js, fourteenth part: the shelf's lighting and fog fragment shaderJavaScript
// Section 3.10: BookNest's shelf shader for GLH.lit(): two point lights with Blinn-Phong
// highlights, a glossy foil title band on each face (uFoil), and exponential-squared fog
GLH.shelfFS = `#version 300 es
  precision highp float;
  struct Light { vec3 position, color; };
  in vec3 vPosition, vNormal; in vec2 vUV; out vec4 outColor;
  uniform Light uLights[2];
  uniform vec3 uColor, uAmbient, uEye, uFogColor;
  uniform float uShininess, uGloss, uFoil, uFogDensity, uAlpha;
  void main() {
    vec3 n = normalize(vNormal), v = normalize(uEye - vPosition);
    float band = step(abs(vUV.y - 0.78), 0.05);              // a title band near the top
    vec3 diffuse = uAmbient, specular = vec3(0.0);
    for (int i = 0; i < 2; i++) {
      vec3 toLight = uLights[i].position - vPosition;
      float d = length(toLight), fade = clamp(1.0 - pow(d / 4.0, 4.0), 0.0, 1.0) / (d * d);
      vec3 l = toLight / d, h = normalize(l + v);             // Blinn's half vector
      float lambert = max(dot(n, l), 0.0);
      float shine = lambert > 0.0 ? pow(max(dot(n, h), 0.0), uShininess) : 0.0;   // lit side
      diffuse += uLights[i].color * lambert * fade;
      specular += uLights[i].color * shine * fade;
    }
    vec3 color = uColor * diffuse + specular * (uGloss + uFoil * band);
    float fog = exp(-pow(uFogDensity * distance(uEye, vPosition), 2.0));   // 1 = clear
    outColor = vec4(mix(uFogColor, color, fog), uAlpha);
  }`;

Subsections