In Review

In this tutorial, you have learned the following:

Further Study

Try doing these things with the given programs.

  • Change the shaders to use the diffuse color as the specular color. You may need to drop the specular color somewhat to keep from over-brightening the scene. How this all looks will be particularly evident with the colored cylinder.

Further Research

As you might guess, this is far from the end on specular reflections and specular highlights. Accurately modelling specular reflection is very difficult; doing so while maintaining high performance is even moreso.

If you are interested in more accurate models of specular highlights, there is the Beckmann distribution. This is a particular statistical distribution of microfacets that is more physically based than a Gaussian distribution. It may or may not be a bit more computationally expensive than Gaussian; Beckmann lacks the inverse cosine, but has more other math to it. The two do have a roughness factor that has the same range, (0, 1], and the roughness has the same general meaning in both distributions.

If you want to go even farther, investigate the Cook-Torrance model of specular reflection. It incorporates several terms. It uses a statistical distribution to determine the number of microfacets oriented in a direction. This distribution can be Gaussian, Beckmann, or some other distribution. It modifies this result based on a geometric component that models microfacet self-shadowing and the possibility for multiple interreflections among a microfaceted surface. And it adds a term to compensate for the Fresnel effect: an effect where specular reflection from a surface is more intense when viewed edge-on than directly top-down.

GLSL Functions of Note

vec reflect(vec I,
 vec N);

Computes the vector that would be reflected across the normal N from an incident vector I. The vector result will be normalized if the input vectors are normalized. Note that I vector is the vector towards the surface.

vec pow(vec X,
 vec Y);

Raises X to the power of Y, component-wise. If a component of X is less than 0, then the resulting value is undefined. If X is exactly zero, and Y is less than or equal to 0, then the resulting value is undefined.

vec acos(vec X);

Returns the inverse cosine of X, component-wise. This returns the angle in radians, which is on the range [0, π]. If any component of X is outside of the [-1, 1] range, then that component of the result will be undefined. This is because the cosine of a value is always on [-1, 1], so the inverse-cosine function cannot take values outside of this range.

vec exp(vec exponent);

Returns the value of eexponent, component-wise.