基本公式描述
一个由 Robert L. Cook 和 Kenneth E. Torrance开发的光照模型. CT比 Phong或Blinn-Phong模型更加接近真实的物理模拟. 它通常用来描述一个物体的高光部分.这个模型将物体描述为由无数的微面组成的整体.在粗糙的物体上,微面之间的夹角变化大,光滑的物体上则更趋近一致.
在大多数光照模型中,反射由ambient,diffuse和specular组成,lambertian(n·l)通常用来计算diffuse.CT通常用来替代specular的计算,基本公式如下:

这里的k是一个因子用来平衡diffuse和specular;rs则是高光算子,公式如下:

高光部分由三个因素组成: The fresnel (F), the roughness (= the directional distribution of the microfacets, D) and the geometric attenuation(G).
Fresnel
真实的fresnel过于复杂,基本shader都使用的Schilck近似,计算公式如下:

Fλ是反射因子,I是光源方向向量,h是半向量(光源和视角).
Roughness (microfacet distribution)
表面粗糙度,用来表现表面粗糙物体到平滑物体之间的区别.
通常使用的计算公式使用Beckmanns (1963) distribution function:

m用来控制表面粗糙程度.
Geometrical attenuation
用来描述光束在微面之间造成的影响,这个因子的质在0到1之间.
There are therefore three cases of how light reacts with the surface: (a) the light is reflected without interference, (b) some of the reflected light is blocked after reflection and (c) some of the light is blocked before reaching the next microfacet (TODO: add images).
光和表面的交互有以下结果:
a.光被完全反射
b.一些光在反射后被阻挡
c.一些光在到达其它微面前被阻挡
第一种情况,光源到达观察者数值为1.
第二种情况为:

第三种情况:

The geometrical attenuation factor is calculated as the minimum of these three values:

The geometric attenuation calculation is described in detail by Blinn (1977).
precision highp float; //set default precision in glsl es 2.0 uniform vec3 lightDirection; varying vec3 varNormal; varying vec3 varEyeDir; void main() { // set important material values float roughnessValue = 0.3; // 0 : smooth, 1: rough float F0 = 0.8; // fresnel reflectance at normal incidence float k = 0.2; // fraction of diffuse reflection (specular reflection = 1 - k) vec3 lightColor = vec3(0.9, 0.1, 0.1); // interpolating normals will change the length of the normal, so renormalize the normal. vec3 normal = normalize(varNormal); // do the lighting calculation for each fragment. float NdotL = max(dot(normal, lightDirection), 0.0); float specular = 0.0; if(NdotL > 0.0) { vec3 eyeDir = normalize(varEyeDir); // calculate intermediary values vec3 halfVector = normalize(lightDirection + eyeDir); float NdotH = max(dot(normal, halfVector), 0.0); float NdotV = max(dot(normal, eyeDir), 0.0); // note: this could also be NdotL, which is the same value float VdotH = max(dot(eyeDir, halfVector), 0.0); float mSquared = roughnessValue * roughnessValue; // geometric attenuation float NH2 = 2.0 * NdotH; float g1 = (NH2 * NdotV) / VdotH; float g2 = (NH2 * NdotL) / VdotH; float geoAtt = min(1.0, min(g1, g2)); // roughness (or: microfacet distribution function) // beckmann distribution function float r1 = 1.0 / ( 4.0 * mSquared * pow(NdotH, 4.0)); float r2 = (NdotH * NdotH - 1.0) / (mSquared * NdotH * NdotH); float roughness = r1 * exp(r2); // fresnel // Schlick approximation float fresnel = pow(1.0 - VdotH, 5.0); fresnel *= (1.0 - F0); fresnel += F0; specular = (fresnel * geoAtt * roughness) / (NdotV * NdotL * 3.14); } vec3 finalValue = lightColor * NdotL * (k + specular * (1.0 - k); gl_FragColor = vec4(finalValue, 1.0); }