Phong and Blinn-Phong

Lighting models are not a new aspect of computer graphics and research has been on-going for several decades. The model proposed by Phong Bui-Tuong is possibly one of the oldest and arguably the most classic model still in use today. Whilst not as sophisticated as the models described in the following chapters it is very simple to implement, has good performance characteristics and generates acceptable results.

This chapter covers a modification to the original model – that proposed by James Blinn. He put forward a simplified version of Phong’s original equation that has even better performance yet minimal effect on the final result. Several sources will claim James Blinn’s modifications as an approximation to Phong Bui-Tuong’s but a recently published paper ([Ngan et al. 04]) claims otherwise: James Blinn’s modifications match measured data more accurately than Phong Bui-Tuong’s model.

These simplifications along with equivalent or better quality have effectively made the Blinn-Phong form the baseline lighting model for three decades.

Developers familiar with the fixed-function lighting pipeline from previous versions of Direct3D will be familiar with the results as the Blinn-Phong model is. Obviously the fixed-function pipeline has now been removed, but the SDK ships with the “FixedFuncEmu” sample that implements the entire functionality of this legacy pipeline in terms of the Direct3D 10’s shader model 4. Looking through this SDK sample it is possible to find an implementation of the Blinn-Phong lighting model in the CalcLighting() function inside FixedFuncEMU.fx.

The Phong Equation

In the “Foundation and Theory” chapter the Lambertian N•L factor was introduced – this works fine for simple diffuse lighting terms where light energy is distributed evenly across the hemisphere defined by the surface and its normal vector. Diffuse lighting is independent of the observer’s position relative to the surface. However this does not work for another class of light reflectance – specular. Phong Bui Tuong’s 1973 model ([Phong73]) introduces this term for improved realism. Specular lighting is effectively the opposite of diffuse lighting as it only reflects light energy in the mirror direction.

The Phong equation computes the reflection of the incoming light energy about the surface normal, therefore modelling the fact that specular light has a particular distribution function. This reflected light energy will only be picked up by the observer if the view direction corresponds to the region defined by this distribution function and therefore makes it a view-dependent result. Ultimately this leads to brighter highlights on the final image – perfect for representing shiny materials.

Diagram 4.1

The trusty dot-product operation can be used to determine the relationship between the observer and the reflected light energy but it is not quite enough for the desired results. Diagram 4.1 shows three different shapes for the reflected light – the specular highlight will only appear in the final image if the view direction intersects with the volume shown. Normally the dot-product will work for the full hemisphere defined by the vector (assuming we clamp it to 0.0-1.0 in the same way as the Lambertian term does) but we need to raise the dot product to a power in order to change the effective ‘range’ of the dot-product.

What diagram 4.1 is really showing is three different exponents – the variable employed by Phong’s equation to allow for a much wider range of materials to be represented. A high exponent (e.g. 50) will result in very sharp, small highlights whereas a low value (e.g. 5) will give much softer and larger highlights. There are no fixed rules for the value to be used – rather it is down to artistic license and choosing a value that looks appropriate.

Mathematically the Phong equation looks like this:

$I = Diffuse \times (Normal \bullet Light) + Specular \times (R \bullet View)^n \times Light$
$R = 2 \times Normal \times (Normal \bullet Light) - Light$

When implemented in HLSL it looks like this:

float4 phong( in float3 normal, in float3 viewer, in float3 light )
{
// Compute the reflection vector
float3 reflection   = normalize( 2.0f * normal * dot( normal, light ) - light );

// Compute the angle between the reflection and the viewer
float  RdotV        = max( dot( reflection, viewer ), 0.0f );

// Compute the specular colour
float3 specular     = cSpecular * pow( RdotV, fSpecularExponent );

// Compute the diffuse term for the Phong equation
float3 diffuse      = cDiffuse * max( 0.0f, dot( normal, light ) );

// Determine the final colour
return float4( diffuse + specular, 1.0f );
}

The Blinn-Phong Equation

Whilst the reflection vector used to compute the specular term in Phong’s original equation has mathematical correctness it is possible to simplify it (and, as previously discussed, more accurately match real-world data). James Blinn’s paper ([Blinn77]) shows that by replacing the reflection vector with a ‘half’ vector it is possible to generate results close to the original model but with a more favourable performance profile. Keep in mind that the HLSL code shown previously will be executed for every single pixel rasterized with this pipeline configuration – shaving even a few instructions can result in millions less executed when scaled up by the number of times the pixel shader is invoked.

Diagram 4.2

Using simple vector mathematics it is possible to compute the “half vector” between the light and view direction. Diagram 4.2 shows how this compares with the other vectors – in the incident plane the angles marked (θ) are related, but in the more general case (over the hemisphere in 3D) the relationship is much more complicated which gives rise to the more accurate match against real-world data.

The modified equation is therefore:

$I = Diffuse \times (Normal \bullet Light) + Specular \times (Half \bullet Normal)^n$
$Half = \frac{Light + View}{\left \Vert Light + View \right \|}$

When implemented in HLSL appears as:

float4 blinn_phong( in float3 normal, in float3 viewer, in float3 light )
{
// Compute the half vector
float3 half_vector = normalize(light + viewer);

// Compute the angle between the half vector and normal
float  HdotN = max( 0.0f, dot( half_vector, normal ) );

// Compute the specular colour
float3 specular = cSpecular * pow( HdotN, fSpecularExponent );

// Compute the diffuse term
float3 diffuse = cDiffuse * max( 0.0f, dot( normal, light ) );

// Determine the final colour
return float4( diffuse + specular, 1.0f );
}

Results

Image 4.3

The main input into both forms of this lighting model is the specular exponent which, when used well, can provide a substantial degree of flexibility. The above image shows the same sphere lit with the Phong model (top) and Blinn-Phong (bottom) with exponents of 1 (left), 15, 30 and 100 (right).

It is immediately obvious that the two models are quite different given the same inputs – there is no hard rule, but generally speaking the Blinn-Phong model requires an exponent around four times higher than Phong’s original equation to generate similar results.

As shown in both equations the diffuse and specular terms are scaled by constant colour values. Typically these constants would be fetched from textures bound to the pipeline and thus vary on a per-pixel basis. This puts a degree of responsibility on the artist to select appropriate values as unrealistic results might be generated if the incoming constants are too high. By allowing full control over the terms it is possible to represent both homogenous and non-homogenous materials (as explained in the first chapter of this section) with no changes to the code.

Whilst it might be more appropriate to measure frame-times and perform more standard benchmarks the results of these are highly specific to the underlying hardware and software such that it becomes very difficult to draw meaningful conclusions. Instead, a useful measure of the performance improvement is to look at the assembly complexity of the two techniques. By using the command-line HLSL compiler it is possible to generate a colour-coded HTML assembly listing.

The original Phong equation gets compiled to 26 instructions whereas the Blinn-Phong equation gets compiled to 23 instructions – a saving of 3. This may not sound like much but, referring back to the previous point about the number of pixel shader invocations consider the following image:

Image 4.4

The preceding image was rendered at 640x480 and thus has 307,200 pixels in total. A crude estimate using histograms shows that the model being rendered occupies 100,000 of those pixels. A saving of 3 instructions yields around 300,000 fewer instructions being executed per frame, which at the captured frame rate is 97.5 million fewer per second.

The Phong and Blinn-Phong models are good general-purpose lighting models as demonstrated by their adoption as standard in the ‘fixed function’ Direct3D pipeline. However their simplicity can reduce their applicability when representing some materials – more complex effects like the Fresnel term can make a substantial impact. A common observation is that these models give models a plastic-like appearance.

References

[Ngan et al. 04] “Experimental Validation of Analytical BRDF Models.” Addy Ngan, Fredo Durand & Wojciech Matusik. Technical Sketch, Siggraph 2004

[Phong73] “Illumination for Computer Generated Images” 1973, or “Illumination for computer generated pictures” ACM June 1975

[Blinn77] “Models of Light Reflection for Computer Synthesized Pictures”, James F. Blinn, ACM Siggraph ’77 Conference Proceedings

Navigate to other chapters in this section:

 Foundation & Theory Direct Light Sources Techniques For Dynamic Per-Pixel Lighting Phong and Blinn-Phong Cook-Torrance Oren-Nayar Strauss Ward Ashikhmin-Shirley Comparison and Summary