Cg Programming/Unity/Smooth Specular Highlights

This tutorial covers per-pixel lighting (also known as Phong shading).

It is based on. If you haven't read that tutorial yet, you should read it first.

The main disadvantage of per-vertex lighting (i.e. of computing the surface lighting for each vertex and then interpolating the vertex colors) is the limited quality, in particular for specular highlights as demonstrated by the figure. The remedy is per-pixel lighting which computes the lighting for each fragment based on an interpolated normal vector. While the resulting image quality is considerably higher, the performance costs are also significant.

Per-Pixel Lighting (Phong Shading)
Per-pixel lighting is also known as Phong shading (in contrast to per-vertex lighting, which is also known as Gouraud shading). This should not be confused with the Phong reflection model (also called Phong lighting), which computes the surface lighting by an ambient, a diffuse, and a specular term as discussed in.

The key idea of per-pixel lighting is easy to understand: normal vectors and positions are interpolated for each fragment and the lighting is computed in the fragment shader.

Shader Code
Apart from optimizations, implementing per-pixel lighting based on shader code for per-vertex lighting is straightforward: the lighting computation is moved from the vertex shader to the fragment shader and the vertex shader has to write the vertex input parameters required for the lighting computation to the vertex output parameters. The fragment shader then uses these parameters to compute the lighting. That's about it.

In this tutorial, we adapt the shader code from to per-pixel lighting. The result looks like this: Note that the vertex shader writes a normalized vector to  in order to make sure that all directions are weighted equally in the interpolation. The fragment shader normalizes it again because the interpolated directions are no longer normalized.

Summary
Congratulations, now you know how per-pixel Phong lighting works. We have seen:
 * Why the quality provided by per-vertex lighting is sometimes insufficient (in particular because of specular highlights).
 * How per-pixel lighting works and how to implement it based on a shader for per-vertex lighting.