Shader Programming, Volume 7

Specular Lighting Models

Sebastian Monroy
4 min readJun 30, 2016

Now that we’ve experimented a bit with non-photorealistic shading, let’s check out how we might simulate something a little more realistic.

Chapter 3.3

Understanding Lighting Models, Creating a Phong Specular type

The specularity of an object describes how shiny it is. It is what one would call a view-dependent effect, because in order to achieve a realistic Specular effect in your shaders, you have to take into account the direction in which the camera is facing the object’s surface.

A very basic and inexpensive Specular type is the Phong Specular effect. It is a very common Specular model, not because it is the most realistic, but because it gives a great approximation that performs well in most situations. Let’s see what the code for one looks like and step our way through it.

This shader, when attached to a material attached to a sphere object, should look like this:

For comparison, the left sphere uses Lambertian Diffuse Lighting. The right sphere uses Phong Specular Lighting.

The first thing that might be unfamiliar to you about this shader is that it uses a view-dependent lighting function. Unity comes with a set of lighting functions, including the view-dependent lighting function declared in the above code. Using this particular declaration affords us the use of the view direction vector, viewDir.

To better understand how Phong Specular lighting is calculated, let’s take a look at this diagram.

  • L = light direction
  • R = light perfect reflection direction
  • N = surface normal direction
  • V = view direction

The Phong model calculates the final light intensity of a reflective surface with the sum of two components: diffuse color and Specular value.

I = D + S

The first component, D, is the diffuse color and is the same as it was in the Lambertian model:

D = N ∙ L

The second component, S, is defined by the function

S = (R ∙ V)^p

where p is the Specular power defined as _SpecPower in the shader. The R variable is the reflection direction of the light direction, L, according to the surface normal direction, N. R can be calculated as follows:

R = 2N * (N ∙ L) - L

This is the calculation done in line 43 of the shader’s code.

Visualized by this script, these reflections look like this:

The reflection directions make sense, given that they are approximating the direction that the directional light should bounce off of the sphere’s surface.

Like shooting ping phong balls at a globe. Or something.

Let’s try an even more efficient Specular lighting model, BlinnPhong.

Chapter 3.4

Understanding Lighting Models, Creating a BlinnPhong Specular type

The BlinnPhong Specular lighting model isn’t much different from the Phong Specular model, the main difference being that instead of calculating our own reflection vectors it uses the half vector from the view direction and light direction. It really is just a simpler version of the full Phong calculation.

The half vector is calculated like this:

H = (V + L) / |V + L|

from which we can calculate the Specular value:

S = (N ∙ H)^p

Check out the comments in the BlinnPhong shader’s code below for a bit more information.

Here’s what it looks like beside our old Lambertian Diffuse shader:

It’s not much to look at, but it has been found that the BlinnPhong approach is actually more accurate than Phong’s.

Here’s how this new half vector, H, looks on the diagram we used previously to demonstrate how Phong’s reflection vector was calculated.

If you’d like to read about other interesting reflectance models, check out the Oren-Nayar reflectance model for rough surfaces. In the next post I’m going to explore the Anisotropic Specular type, which is useful for simulating brushed surfaces. And then we’ll be done with Chapter 3!

--

--