nuclear@0: #version 110 nuclear@0: nuclear@0: #define SQ(x) ((x) * (x)) nuclear@0: #define PI 3.141592653 nuclear@0: nuclear@0: /* -- Lambert's cosine law nuclear@0: * J. H. Lambert, Photometria sive de mensura de gratibus luminis, colorum et umbrae. nuclear@0: * Eberhard Klett, 1760. nuclear@0: */ nuclear@0: float lambert(vec3 norm, vec3 ldir) nuclear@0: { nuclear@0: return max(dot(norm, ldir), 0.0); nuclear@0: } nuclear@0: nuclear@0: /* -- Phong specular model nuclear@0: * B. T. Phong, "Illumination for Computer Generated Pictures" nuclear@0: * Communications of the ACM, 1975. nuclear@0: */ nuclear@0: float phong(vec3 view, vec3 norm, vec3 ldir, float spow) nuclear@0: { nuclear@0: vec3 lref = reflect(-ldir, norm); nuclear@0: return pow(max(dot(lref, view), 0.0), spow); nuclear@0: } nuclear@0: nuclear@0: /* -- Blinn-Phong specular model nuclear@0: * J. F. Blinn, "Models of Light Reflection for Computer Synthesized Pictures" nuclear@0: * in Proceedings of SIGGRAPH 1977 nuclear@0: */ nuclear@0: float blinn(vec3 norm, vec3 hvec, float spow) nuclear@0: { nuclear@0: return pow(max(dot(norm, hvec), 0.0), spow); nuclear@0: } nuclear@0: nuclear@0: /* -- Cook & Torrance model. nuclear@0: * R. L. Cook and K. E. Torrance, "A Reflectance Model for Computer Graphics" nuclear@0: * in Proceedings of SIGGRAPH 1981. nuclear@0: */ nuclear@0: float cook_torrance(vec3 view, vec3 norm, vec3 ldir, vec3 hvec, float rough, float ior) nuclear@0: { nuclear@0: float m = max(rough, 0.0001); nuclear@0: nuclear@0: // various useful dot products nuclear@0: float ndoth = max(dot(norm, hvec), 0.0); nuclear@0: float ndotv = max(dot(norm, view), 0.0); nuclear@0: float ndotl = dot(norm, ldir); nuclear@0: float vdoth = max(dot(view, hvec), 0.0); nuclear@0: float ndoth_sq = SQ(ndoth); nuclear@0: nuclear@0: // geometric term (shadowing/masking) nuclear@0: float geom_a = (2.0 * ndoth * ndotv) / vdoth; nuclear@0: float geom_b = (2.0 * ndoth * ndotl) / vdoth; nuclear@0: float geom = min(1.0, min(geom_a, geom_b)); nuclear@0: nuclear@0: // beckmann microfacet distribution term nuclear@0: float sin2_ang = 1.0 - ndoth_sq; // sin^2(a) = 1 - cos^2(a) nuclear@0: float tan2_ang = sin2_ang / ndoth_sq; // tan^2(a) = sin^2(a) / cos^2(a) nuclear@0: float d_mf = exp(-tan2_ang / SQ(m)) / (SQ(m) * SQ(ndoth_sq)); nuclear@0: nuclear@0: // fresnel term nuclear@0: float c = vdoth; nuclear@0: float g = sqrt(SQ(ior) + SQ(c) - 1.0); nuclear@0: float ftmp = (c * (g + c) - 1.0) / (c * (g - c) + 1.0); nuclear@0: float fres = 0.5 * (SQ(g - c) / SQ(g + c)) * (1.0 + SQ(ftmp)); nuclear@0: nuclear@0: return (fres / PI) * (d_mf / ndotl) * (geom / ndotv); nuclear@0: } nuclear@0: nuclear@0: /* -- Oren & Nayar model nuclear@0: * M. Oren and S. K. Nayar, "Generalization of Lambert's Reflectance Model" nuclear@0: * in Proceedings of SIGGRAPH 1994. nuclear@0: */ nuclear@0: float oren_nayar(vec3 view, vec3 norm, vec3 ldir, float rough) nuclear@0: { nuclear@0: float vdotn = max(dot(view, norm), 0.0); nuclear@0: float ldotn = max(dot(ldir, norm), 0.0); nuclear@0: nuclear@0: float theta_r = acos(vdotn); nuclear@0: float theta_i = acos(ldotn); nuclear@0: float cos_pr_minus_pi = dot(normalize(view - norm * vdotn), normalize(ldir - norm * ldotn)); nuclear@0: float alpha = max(theta_r, theta_i); nuclear@0: float beta = min(theta_r, theta_i); nuclear@0: nuclear@0: float sigma_sq = SQ(rough); nuclear@0: float a = 1.0 - 0.5 * sigma_sq / (sigma_sq + 0.33); nuclear@0: float b = 0.45 * sigma_sq / (sigma_sq + 0.09); nuclear@0: nuclear@0: if(cos_pr_minus_pi >= 0.0) { nuclear@0: b *= cos_pr_minus_pi * sin(alpha) * tan(beta); nuclear@0: } else { nuclear@0: b = 0.0; nuclear@0: } nuclear@0: nuclear@0: return ldotn * (a + b); nuclear@0: } nuclear@0: nuclear@0: /* TODO: need tangent/bitangent nuclear@0: float ward(vec3 view, vec3 norm, vec3 ldir, vec3 hvec, vec3 tang, vec3 bitan, float ax, float ay) nuclear@0: { nuclear@0: float vdotn = dot(view, norm); nuclear@0: float ldotn = dot(light, norm); nuclear@0: } nuclear@0: */