/* 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); }