# Relationship between Phong and Blinn lighting model

March 29, 2012 8 Comments

version : 1.1 – Living blog – First version was 29 March 2012

Phong and Blinn are the two most used lighting models in game development. The properties of the two have been debate a lot of time and I won’t discuss this here. See [1] to know why you should use Blinn rather than Phong when you do physically based rendering. The point of interest I would discuss is the relationship between Phong lobe shape and Blinn lobe shape. This relationship matter when you use image based lighting (IBL). In this case you generally have only one cubemap sample and can only emulate Phong shape highlight (see AMD Cubemapgen for physically based rendering). The problem come when you want to use IBL and try to match it with analytic Blinn lighting model use for direct lighting. The highlight shape don’t match. Here is a comparison between an analytic Phong (Left) and Blinn (Right) highlight with the same specular power (Click for high rez).

This post will study what we can do to better match Blinn and Phong highligh. There is really few paper about this subject [2] [3]. About Phong and Blinn relationship, it can be show that the Phong angle is twice the Blinn angle [3]:

This relation allows to write

Where is the specular power, is the Phong angle ( ) and is our unknown parameter. Finding the value of which best fit this equation will provide our relationship between Phong and Blinn.

Yoshiharu Gotanda give 4.2 for the value of in [2]. Frederick Fisher and Andrew Woo give 4 in [3]. Following sections will discuss these results.

## Solving the equation

To solve the equation I used Mathematica [4]. Mathematica is one of those tools which became important to learn for modern graphic programmers. I provide all the Mathematica code I use in this post, so you can play with it.

Mathematica has a powerful language which allow to do a lot of thing. Solving our unknown parameter can be done in a single line:

F[SpecPower_]:=x /. FindFit[Table[{a,Cos[a]^SpecPower},{a,0,\[Pi]/2,0.01}],Cos[b/2]^(SpecPower*x),{x},b];

Step by step, we create a table of data with equation for x varying from to (as advice in [3], no need to go further than 90°). Then we use the FindFit method with our Phong/Blinn equation to try to find the value which best match our data.

Then we can create a graph which will display best fit value for SpecularPower from 1 to 500.

DiscretePlot[F[SpecPower], {SpecPower, 1, 500}, PlotRange -> {0, 6}, Filling -> None, Joined -> True]

As we can see, there is a slope near SpecularPower 1 then the solution rapidly converge to 4. The SpecularPower of 0 is a degenerate case and is not handled here.

DiscretePlot[{F[SpecPower], 4}, {SpecPower, 1, 20}, PlotRange -> {0, 6}, Filling -> None, Joined -> True]

We see on these graphs than we don’t have a unique value for . But 4 is a very good candidate when SpecularPower is high. Let’s try to find a simple function which approximate this solution curve.

For this we will apply FindFit again. The solution curve looks like a hyperbolic function of the form . This is a good candidate to give to FindFit. After some trial, I find the following hyperbolic function.

data = Table[{SpecularPower, F[SpecularPower]}, {SpecularPower, 1, 500, 1}]; G[X_] = a/X^3 + b/X^2 + c/X + d /. FindFit[data, a/x^3 + b/x^2 + c/x + d, {a, b, c,d}, x];

The result is

Following graph show the comparison between the solution curve and this approximate solution curve

DiscretePlot[{F[SpecularPower], G[SpecularPower]}, {SpecularPower, 1,500}, PlotRange -> {0, 6}, Filling -> None, Joined -> True] DiscretePlot[{F[SpecularPower], G[SpecularPower]}, {SpecularPower, 1, 10}, PlotRange -> {0, 6}, Filling -> None, Joined -> True]

Rather good approximation (Curves match, so you see only one on the graphs).

## Result comparison

In the previous section we have found an approximate curve for the Phong and Blinn relationship.

Here is a comparison between the reference, [2], [3] and this curve.

First some numerical value from the approximate curve for the first 20 SpecularPower, to compare with the 4 and 4.2 value of [2] and [3].

Then the graph for few SpecularPower (Red: Reference, green : x set with approximate solution curve, blue : x set to 4.2 like in [2], Purple : x set to 4.0 like in [3], click for high rez):

DrawComparison[N_] := Plot[{Cos[x]^N, Cos[x/2]^(N*G[N]), Cos[x/2]^(4.2*N), Cos[x/2]^(4*N)}, {x, 0, \[Pi]/2}, PlotStyle -> {Red, Green, Blue, Purple}];

DrawComparison[1]

DrawComparison[3]

DrawComparison[10]

DrawComparison[500]

The only noticeable difference appear when SpecularPower < 5. But should we care about this in practice ?

Following are teapot rendered with Phong, Blinn, Blinn with approximate solution curve, Blinn with 4.0, Blinn with 4.2 (Click for high rez).

Specular power 1

Specular Power 5

Specular Power 100

Specular Power 1000

For details, I use the following code (Note that I boost specular to get visible highligh and I don’t use energy conserving factor):

#define METHOD 0 float p_value = 10.0; float multiplier_spec = 3.0; (...) #if METHOD == 0 // Phong vec3 r = reflect(-light, n); float rdotv = saturate(dot(r, view)); float spec = multiplier_spec * pow(rdotv, p_value); #elif METHOD == 1 // Blinn-Phong float ndoth = saturate(dot(n, h)); float spec = multiplier_spec * pow(ndoth, p_value); #elif METHOD == 2 // approximate curve float p_value_2 = p_value * p_value; float p_value_3 = p_value_2 * p_value; float factor = 4.00012 - (0.624042 / p_value_3) + (0.728329 / p_value_2) + (1.22792 / p_value); float ndoth = saturate(dot(n, h)); float spec = multiplier_spec * pow(ndoth, factor * p_value); #elif METHOD == 3 // Fisher and Woo float ndoth = saturate(dot(n, h)); float spec = multiplier_spec * pow(ndoth, 4.0 * p_value); #elif METHOD == 4 // Gotanda float ndoth = saturate(dot(n, h)); float spec = multiplier_spec * pow(ndoth, 4.2 * p_value); #endif (...)

Final result:

– For Specular power > 10 there is almost no difference between candidates (with bright highligh as the teapot sample you can see small variation). And all candidates are good approximation.

– For very low specular < 5, the result is bad anyway, whatever the candidate. This is due to the size of the highligh. Still the result usable as an approximation.

– Compare theorical result is good but compare visual result is better

The takeaway :

– Just use the simplest factor

– Mathematica skill achievement (PDF link of Mathematica code from this post)

## Reference

[1] Hoffman, “Crafting Physically Motivated Shading Models for Game Development” and “Background: Physically-Based Shading” http://renderwonk.com/publications/s2010-shading-course/

[2] Gotanda, “Real-time Physically Based Rendering – Implementation”, http://research.tri-ace.com/Data/cedec2011_RealtimePBR_Implementation.pptx

[3] Fisher, Woo, “R.E Versus N.H Specular Highlights” in. Graphics Gems IV

[4] Mathematica, http://www.wolfram.com/mathematica/

Next try a Minimax Polynomial fit (or even a Rational Minimax). You’ve got a bounded range, it should work fine.

Hey,

can you provide some hint on this ? I think I miss something🙂

I try to play with RationalInterpolation/MiniMaxApproximation in mathematica, but didn’t get it to work with my function (at least, I don’t understand how to make them work)…

Thank you

Small update: Add screenshot for specular power 5, 10, 1000, provide code and affine final result.

If I may, those two models are strongly different from a conceptual point of view: one models the BRDF shape, the other one models the NDF. At grazing angle, a “Phong” lobe is completely istropic and a “Blinn-Phong lobe” is highly anisotropic. This should give you major visual differences even for medium specular power >5.

You can easily see that on Wang’s paper (http://research.microsoft.com/en-us/um/people/jpwang/paper_stuffs/ppsg.pdf), especially on the supplement material (http://research.microsoft.com/en-us/um/people/jpwang/paper_stuffs/sg_supp.pdf), figure 9, where they try to approximate a “Blinn-Phong lobe” with an isotropic lobe (spherical gaussian lobe). The differences are obvious for grazing angles.

As you said, it’s not only a power issue, it’s mainly a visual difference issue!🙂

Totally agree, people should use Blinn anyway. I use this trick only to try to match preconvolved cubemap (with isotropic lobe) with analytic Blinn like Tri-Ace (http://research.tri-ace.com/Data/cedec2011_RealtimePBR_Implementation_e.pptx). Fail at grazing angle of course, but better than nothing🙂

Pingback: Confluence: Art

Pingback: Real-Time Rendering · Seven Things for June 22nd

Pingback: Real-Time Rendering · New CRC Books