/* renamed LG_orennayar.sl -- tal AT renderman DOT org */
/*
* orennayar.sl - rough diffuse surface
*
*
* DESCRIPTION:
* Makes a rough surface using a BRDF which is more accurate than
* Lambert. Based on Oren & Nayar's model (see Proc. SIGGRAPH 94).
*
* Lambertian (isotropic) BRDF is a simple approximation, but not
* an especially accurate one for rough surfaces. Truly rough surfacs
* tend to act more like retroreflectors than like isotropic scatterers.
*
* PARAMETERS:
* Ka, Kd - just like matte.sl
* sigma - roughness (0 is lambertian, larger values are rougher)
*
* AUTHOR: Larry Gritz
*
* REFERENCES:
* Oren, Michael and Shree K. Nayar. "Generalization of Lambert's
* Reflectance Model," Computer Graphics Annual Conference
* Series 1994 (Proceedings of SIGGRAPH '94), pp. 239-246.
*
* NOTES:
* 1. Note that this is really just an illuminance loop that gathers
* light from the sources and applies Oren & Nayar's local reflectance
* model to the result. It could easily be packaged up as a macro
* or a function and used in any other shader, in place of diffuse().
* 2. Examination of why rough surfaces are not Lambertian will lead
* you to the solution to the famous "flat full moon" problem.
*
* HISTORY:
* 14 June 1994 -- written by Larry Gritz
*
*/
surface
LG_orennayar (float Ka = 1;
float Kd = .5;
float sigma = 0.0; )
{
point Nf, IN, Eye, LN;
color lightC = 0;
color L1, L2;
float C1, C2, C3;
float theta_r, theta_i, cos_theta_i;
float alpha, beta, sigma2, cos_phi_diff;
Nf = faceforward (normalize(N),I);
IN = normalize (I);
Eye = -IN;
theta_r = acos (Eye . Nf);
sigma2 = sigma*sigma;
illuminance (P, Nf, PI/2) {
LN = normalize(L);
cos_theta_i = LN . Nf;
cos_phi_diff = normalize(Eye-Nf*(Eye.Nf)) . normalize(LN - Nf*(LN.Nf));
theta_i = acos (cos_theta_i);
alpha = max (theta_i, theta_r);
beta = min (theta_i, theta_r);
C1 = 1 - 0.5 * sigma2/(sigma2+0.33);
C2 = 0.45 * sigma2 / (sigma2 + 0.09);
if (cos_phi_diff >= 0)
C2 *= sin(alpha);
else C2 *= (sin(alpha) - pow(2*beta/PI,3));
C3 = 0.125 * sigma2 / (sigma2+0.09) * pow ((4*alpha*beta)/(PI*PI),2);
L1 = Cs * (cos_theta_i * (C1 + cos_phi_diff * C2 * tan(beta) +
(1 - abs(cos_phi_diff)) * C3 * tan((alpha+beta)/2)));
L2 = (Cs * Cs) * (0.17 * cos_theta_i * sigma2/(sigma2+0.13) *
(1 - cos_phi_diff*(4*beta*beta)/(PI*PI)));
lightC += (L1 + L2) * Cl;
}
Oi = Os;
Ci = Os * (Cs * (Ka*ambient()) + Kd*lightC);
}