Everything has Fresnel

You can sorta think of this post as part 2 of my “Everything is shiny rant”. While standard specular lighting is pretty common in games, one effect that we rarely see in games is proper fresnel.

Hopefully, you know what specular is by now. The most common model for specular in video games is Blinn-Phong, which is:

H = normalize(V+L);
specVal = pow(saturate(dot(H,N)),power);

In this case, V is the view vector, L is the light vector, N is the normal vector, and power is the specular exponent. H is the derived half vector, and it is the vector half-way between the View and Light vectors.

How does it work? Here’s a diagram.

You can see the View, Light, and Normal vector. Now, with this function, where will the specular value peak? Intuitively, you would want the specular function to max out when the view vector is at a reflection vector to the light. And that is what happens. This function peaks when the half vector is aligned exactly with the normal, which happens to be when the reflection of the View vector points right at the light. And life makes sense.

Here is another case:

Once again, the View vector reflects exactly into the Light vector. In this case, would the specular highlight be the brighter, dimmer, or exactly the same as the first case? Well, it would be the same, since you are viewing the maximum value of the specular highlight in both cases. Is this how the real world works? The short answer is no.

Here is a picture of a brick, from two different camera angles. In the top image, the light and camera are both looking straight down, which resembles the first case. In the second line, the light is hitting the surface at a grazing angle, as in the second case. I’ve split the specular and diffuse components with polarization so the diffuse is on the left and the specular is on the right. Let’s check out a brick.

So, wtf? For a material as simple as a freak’n brick, the Blinn-Phong model for specular is completely wrong. And it turns out this happens because of a little thing called fresnel.

Let’s take another look at our two cases of specular. According to Blinn-Phong, they should have the same intensity, but in reality, the one at the grazing angle is much brighter.

To account for this affect, you can use Fresnel. A pretty good realtime approximation for Fresnel is the Schlick Fresnel. From the GPU Gems 3 chapter on skin:

float base = 1 – dot(V,H);
float exponential = pow( base, 5.0);
float fresnel = exponential + F0 * (1.0 – exponential);
specVal *= fresnel;

For some reason, most people tend to want fresnel only on the really shiny surfaces, like water, glass, and metals. But really, fresnel has a strong effect on almost every material. In fact, I would argue that fresnel is more important visually on the less-shiny materials. Here is a piece of PVC pipe.

Certainly, PVC has a fresnel. But in my opinion, I would say that the fresnel has a more visually important effect on the brick than the PVC. Going from almost nothing to very specular is much more important than going from high to higher specular. Isn’t that a more visually important effect? For me, it’s a mistake to think about fresnel only as an effect for water/glass/metal, because it makes a tremendous visual difference on the less shiny surfaces. Here are a few more examples.

Poor cardboard. So misunderstood. It always gets referred to as a “pure diffuse material”, even though it actually deserves to hang out with its shiny friends. The specular is important at straight angles because it adds a subtle desaturation, but cardboard has a very bright specular reflection at grazing angles.

Ever wonder why it feels bright when you drive to work in the morning? Most people think that happens because the sun is in their eyes. Actually, the major source of brightness is that road pavement has a strong fresnel as well. Next time you are driving and the sun is in your eyes, look at your side-view mirror and check out how much darker the pavement in the side-view mirror is relative to the pavement in front of you.

Here is some cloth. It’s a towel from Ikea. Rough, cotton cloth is about the least specular common material that you will see around the house. This comparison isn’t that great because the second image is brighter overall, so it’s harder to see the relative change of the specular to the diffuse. If you want a better example, I’m leaving that as an exercise for the reader.

And just for kicks, let’s check out an X-Rite color checker. When using a color checker, they always recommend that you hold it perpendicular to the camera. Hopefully you don’t need me to tell you why that is.

Viva la Fresnel!

13 Responses to “Everything has Fresnel”

  1. Fresnel is awesome. I got quite carried away with it once and bothered to re-arrange the formulae so I could build in properly in the shading network of one of the 3D apps I use. Requires gamma correcting, but awesome. Also totally redundant as I had a fresnel shaded already done by someone else. Hmm. Does the real time one require shifting into gamma 2.2 (or whichever gamma curve you’re in)?

  2. Yep, fresnel is cool. For the gamma correction, you should be converting into linear space when you read your textures and convert from linear to gamma at the very end. But inside the shader, while doing the fresnel calculation, you shouldn’t have to do any gamma conversions.

  3. Yes indeed. A lot of people would plug in the fresnel shader and proclaim the results rubbish, but it’s only as they didn’t realize a linear (…naturally…) calculation. Only wondered about the CPU gems shader and linear as I’ve got no idea how many game pipelines use a gamma corrected workflow. I know of examples that do (well, one) but only as they’ve mentioned it, so it’s hard to tell how widespread it is. On with the awesome blog.

  4. Really good blog! Usefull to show real world sample of how light work. Can you share your opinion about Fresnel not applied on highligh but applied to Environment mapping.
    I read that an approximation of ambient specular lighting (so lighting without the light source used for the highlight) is : Fresnel with specular color and dot(N,V) * prefilteredenvmap based on roughness. And this should be done for all objects even matte. But on matte/concrete object with low roughness and low specular color, the fresnel effect seems to produce unrealistic rim lighting.

  5. Hi,

    Great post ! Using V dot H instead of N dot V is indeed the way to go. I have a small question though: Why are you multiplying (ie darkening specular) instead of performing addition to make the specular lighting go to white ?

  6. Multiplying is fine as you tend to define your overall spec/reflectivity to mean the “highest value it will reach”. The fresnel calc goes to 1 at 90 degrees (to the eye), so multiplying always gives your specified/desired value there on the rim. The rest of the equation gives you the diminishing value as it faces towards you, so multiplying reduces it accordingly.

    I’m now going to post this, after proof reading it, and find more errors in it.

  7. Mr.p: You’d be shocked at how many games do their lighting in gamma space. If you see a game, and it has that weird “for some reason this looks like a high-res PS2 game” look, it’s usually because their lighting is in gamma-space, and not linear. The best way to tell is to look at their diffuse falloff, and if it looks way too soft, it’s probably in gamma-space. Also, if you see the hue shifting as light falls off, it’s probably in gamma-space as well. You can see that a lot in characters.

    Sebastien: I’m very opposed to the dot(N,V) thing. It’s ok to add a little in a few cases if you can’t afford anything better. But as a replacement, I think it’s terrible. If I’m driving and I’m looking at the road, by that model, I would get the same fresnel brightness at high noon as well as when the light is almost even with the pavement, which is very wrong. When the dot(N,V) thing is over-used, it always looks like that cheap plastic-ish look.

  8. “This comparison isn’t that great because the second image is brighter overall”
    just because the carpet under the towel has Fresnel too! =)

  9. Hi Roman. Yeah, with all the crazy things our visual systems do, I sometimes feel like I spend more time explaining disclaimers than writing the actual post!


  11. In the land of realtime rendering would you bother to do some basic energy conservation in your shaders?

    For example, if you’re using this fresnel approximation for refl/spec, would you then invert it and multiply the diffuse/ambient shader values by it? That way you don’t get the shader returning more light than its receiving once where got reflection contributing to it. That’s a basic example, but I do it all the time in offline rendering (and infact nowadays numerous shaders do it for you), but I just wondered how much it happens in games…

  12. Energy conservation is something we probably should do more in games. But in reality, shaders in games are so duct-taped together that we have to do hacks to compensate for other hacks. So in U2 we didn’t do much with energy conservation, but I think a few other games do for their specular highlights.

  13. Regarding your fresnel function “base = 1 – dot(V,H)” — is that a typo, shouldn’t it be dot(N,L)?