Nov 16, 2011

Optimized Oren-Nayar Approximation Shader Code

We presented this approximation code as part of our KGC 2011 presentation. Let me just show the code for those people who don't want to read the whole presentation.  I've also mentioned this to Wolfgang Engel during KGC 2011 because our previous Oren-Nayar code was from his wiki book.

The best part of this approximation code is that we eliminated the texture look-up, which turned out to be bottleneck for us. It is not mathematically correct, but worked fine for our game, Warhammer 40,000: Space Marine.

half ComputeOrenNayarLighting_Fakey( half3 N, half3 L, half3 V, half roughness )
  // Through brute force iteration I found this approximation. Time to test it out.
  half LdotN = dot( L, N );
  half VdotN = dot( V, N );
  half result = saturate(LdotN);
  half soft_rim = saturate(1-VdotN/2); //soft view dependant rim
  half fakey = pow(1-result*soft_rim,2);//modulate lambertian by rim lighting
  half fakey_magic = 0.62;
  //(1-fakey)*fakey_magic to invert and scale down the lighting
  fakey = fakey_magic - fakey*fakey_magic;
  return lerp( result, fakey, roughness );

Related Posts:


  1. Ryg has a mathematically correct way to eliminate texture lookups. Use his way, if you want mathematical correctness.

    See middle of the post, where it shows alpha, beta, C variables

    p.s. Our approximation might be still faster since it also eliminates bunch of divisions. (well only if it turns out to be your bottleneck)

  2. Unfortunately, for me, your approximation looks too similar to straight N dot L diffuse lighting to be really useful. Rim lighting (easily seen on a sphere with the view direction matching the light direction) is quite dark with your version, like NdotL, where Oren-Nayar is bright. The highlight area is, however, flattened roughly correctly.

    I was hoping to use a straight exponent on NdotL to get the flattened effect, however that makes the transition area between light an dark too abrupt, and it doesn't really provide a rim light either... Of course it's also not energy conserving as is, which would be an issue if you wanted to drive diffuse roughness by a texture.

    Steve M

    1. Hi Steve M,

      You are right. We initially used a full oren-nayar equation for everything, but only character artists ended up using it, so by the time we came up with this approximation, it was mostly used for flattened highlight: our characters already had what we call character fill lights, which provides something similar to rim light, so rim light was not a big concern. Also each character had its own roughness map, which also served as gloss map.

      So I guess we ended up making an approximation that only works for Space Marine...........