Cycles: improve the Oren-Nayar BSDF (roughness value for Diffuse), to avoid
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 22 Feb 2012 15:04:22 +0000 (15:04 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 22 Feb 2012 15:04:22 +0000 (15:04 +0000)
undesired dark rings, and give more accurate lighting when the light is
behind the object. As a bonus, the code is simpler & faster.

Patch by Yasuhiro Fujii, detailed explanation here:
http://mimosa-pudica.net/improved-oren-nayar.html

intern/cycles/kernel/svm/bsdf_oren_nayar.h

index 0ad7cad06bbc0139d54cf22bc00977bfbb9ccc59..81884de8798b9f280856acb1adecf66205e451dd 100644 (file)
@@ -55,25 +55,11 @@ __device float3 bsdf_oren_nayar_get_intensity(const ShaderClosure *sc, float3 n,
 {
        float nl = max(dot(n, l), 0.0f);
        float nv = max(dot(n, v), 0.0f);
+       float t = dot(l, v) - nl * nv;
 
-       float3 al = normalize(l - nl * n);
-       float3 av = normalize(v - nv * n);
-       float t = max(dot(al, av), 0.0f);
-
-       float cos_a, cos_b;
-       if(nl < nv) {
-               cos_a = nl;
-               cos_b = nv;
-       }
-       else {
-               cos_a = nv;
-               cos_b = nl;
-       }
-
-       float sin_a = sqrtf(max(1.0f - cos_a * cos_a, 0.0f));
-       float tan_b = sqrtf(max(1.0f - cos_b * cos_b, 0.0f)) / max(cos_b, 1e-8f);
-
-       float is = nl * (sc->data0 + sc->data1 * t * sin_a * tan_b);
+       if (t > 0.0f)
+               t /= max(nl, nv) + FLT_MIN;
+       float is = nl * (sc->data0 + sc->data1 * t);
        return make_float3(is, is, is);
 }
 
@@ -84,9 +70,9 @@ __device void bsdf_oren_nayar_setup(ShaderData *sd, ShaderClosure *sc, float sig
 
        sigma = clamp(sigma, 0.0f, 1.0f);
 
-       float div = 1.0f / ((1.0f + 0.5f * sigma) * M_PI_F);
+       float div = 1.0f / (M_PI_F + ((3.0f * M_PI_F - 4.0f) / 6.0f) * sigma);
 
-       sc->data0 =  1.0f * div;
+       sc->data0 = 1.0f * div;
        sc->data1 = sigma * div;
 }