/************************************************************************ * locillum.h - Functions that compute the light response of locillums. * * Author: Larry Gritz (lg AT larrygritz DOT com) * * Reference: * _Advanced RenderMan: Creating CGI for Motion Picture_, * by Anthony A. Apodaca and Larry Gritz, Morgan Kaufmann, 1999. * * $Revision: 1.2 $ $Date: 2003/12/24 06:18:06 $ * ************************************************************************/ #ifndef LOCILLUM_H #define LOCILLUM_H /* * Oren and Nayar's generalization of Lambert's reflection model. * The roughness parameter gives the standard deviation of angle * orientations of the presumed surface grooves. When roughness=0, * the model is identical to Lambertian reflection. */ color LocIllumOrenNayar (normal N; vector V; float roughness;) { /* Surface roughness coefficients for Oren/Nayar's formula */ float sigma2 = roughness * roughness; float A = 1 - 0.5 * sigma2 / (sigma2 + 0.33); float B = 0.45 * sigma2 / (sigma2 + 0.09); /* Useful precomputed quantities */ float theta_r = acos (V . N); /* Angle between V and N */ vector V_perp_N = normalize(V-N*(V.N)); /* Part of V perpendicular to N */ /* Accumulate incoming radiance from lights in C */ color C = 0; extern point P; illuminance (P, N, PI/2) { /* Must declare extern L & Cl because we're in a function */ extern vector L; extern color Cl; float nondiff = 0; lightsource ("__nondiffuse", nondiff); if (nondiff < 1) { vector LN = normalize(L); float cos_theta_i = LN . N; float cos_phi_diff = V_perp_N . normalize(LN - N*cos_theta_i); float theta_i = acos (cos_theta_i); float alpha = max (theta_i, theta_r); float beta = min (theta_i, theta_r); C += (1-nondiff) * Cl * cos_theta_i * (A + B * max(0,cos_phi_diff) * sin(alpha) * tan(beta)); } } return C; } /* * Greg Ward Larson's anisotropic specular local illumination model. * The derivation and formulae can be found in: Ward, Gregory J. * "Measuring and Modeling Anisotropic Reflection," ACM Computer * Graphics 26(2) (Proceedings of Siggraph '92), pp. 265-272, July, 1992. * Notice that compared to the paper, the implementation below appears * to be missing a factor of 1/pi, and to have an extra L.N term. * This is not an error! It is because the paper's formula is for the * BRDF, which is only part of the kernel of the light integral, whereas * shaders must compute the result of the integral. * * Inputs: * N - unit surface normal * V - unit viewing direction (from P toward the camera) * xdir - a unit tangent of the surface defining the reference * direction for the anisotropy. * xroughness - the apparent roughness of the surface in xdir. * yroughness - the roughness for the direction of the surface * tangent perpendicular to xdir. */ color LocIllumWardAnisotropic (normal N; vector V; vector xdir; float xroughness, yroughness;) { float sqr (float x) { return x*x; } float cos_theta_r = clamp (N.V, 0.0001, 1); vector X = xdir / xroughness; vector Y = (N ^ xdir) / yroughness; color C = 0; extern point P; illuminance (P, N, PI/2) { /* Must declare extern L & Cl because we're in a function */ extern vector L; extern color Cl; float nonspec = 0; lightsource ("__nonspecular", nonspec); if (nonspec < 1) { vector LN = normalize (L); float cos_theta_i = LN . N; if (cos_theta_i > 0.0) { vector H = normalize (V + LN); float rho = exp (-2 * (sqr(X.H) + sqr(Y.H)) / (1 + H.N)) / sqrt (cos_theta_i * cos_theta_r); C += Cl * ((1-nonspec) * cos_theta_i * rho); } } } return C / (4 * xroughness * yroughness); } /* * LocIllumGlossy - a possible replacement for specular(), with a * more uniformly bright core and a sharper falloff. It's a nice * specular function to use for something made of glass or liquid. * Inputs: * roughness - related to the size of the highlight, larger is bigger * sharpness - 1 is infinitely sharp, 0 is very dull */ color LocIllumGlossy ( normal N; vector V; float roughness, sharpness; ) { color C = 0; float w = .18 * (1-sharpness); extern point P; illuminance (P, N, PI/2) { /* Must declare extern L & Cl because we're in a function */ extern vector L; extern color Cl; float nonspec = 0; lightsource ("__nonspecular", nonspec); if (nonspec < 1) { vector H = normalize(normalize(L)+V); C += Cl * ((1-nonspec) * smoothstep (.72-w, .72+w, pow(max(0,N.H), 1/roughness))); } } return C; } #endif /* defined(LOCILLUM_H) */