这种光照模型是由罗伯特·L·库克和Kenneth E.托兰斯的发展。库克-托兰斯模型更接近比的Phong或的Blinn-的Phong模型的物理现实。它是用来模拟不同材料的镜面反射。该模型将每个表面由许多微小面:非常小的方面,反映了入射光。在粗糙表面上,这些微小面的斜坡变化很大,并且在光滑表面的微小面以类似的方向上取向(如在1967年由托兰斯-麻雀描述)。
因为在大多数的光照模型,反射由环境,漫反射和镜面反射和朗伯(的ñ · 升用于漫反射)。该模型,而不是集中在镜面反射。下面的公式示出了基本的反射模型(以简化的形式库克&托兰斯(1982)的原配方见。):
其中,ķ ]是漫反射的光的分数(0之间的值和1)和- [R 小号是镜面反射分量,这样计算:
这种镜面反射取决于三个因素:该菲涅耳(˚F),所述粗糙度(=微小面的方向分布,ð)和几何衰减(ģ)。
菲涅尔
菲涅尔因子定义了入射光的分数被反射,哪一部分被发送。在我所见过的石里克近似的例子着色器代替原有的配方,因为原来的菲涅耳公式太耗费计算。见库克 - 托兰斯(1982年)为全面菲涅耳公式。
石里克(1994)做了菲涅耳公式的近似值来获得类似的结果具有更快的计算。他的公式是这样的:
˚F λ是在法向入射的反射率,升是光矢量和ħ是光矢量和朝向观看者指向的向量之间的半向量。
粗糙度(微面分布)
这个因素定义了以相同的方式(=作为法线矢量指向相同的方向),为的中途矢量定向微小面的分数v。上光滑的表面,所有微小面具有相似的方向,因此,所有的反射光接近反射载体。在粗糙的表面,光线分布更加广泛。
计算所述分布的一个方法是使用Beckmanns(1963)分布函数:
其中米是控制表面的粗糙度的变量。
几何衰减
在到达表面之前或反射后一些微小面遮挡入射光。的几何衰减因子是从0到1的值,表示保持此遮蔽或掩蔽已经发生后的光的比例量。该计算假定所有微小面具有V形槽的形式。
因此有三种情况的光与表面的反应:(a)该光被反射而不干扰,(二)部分的反射光被反射和(c)一些光到达下一个微面之前被阻塞后阻止(TODO:添加图片)。
在第一种情况下,到达观看者的光1.第二种情况的公式为:
对于第三种情况的公式是一样的第二种情况,但与v和升交换:
的几何衰减因子计算为最小下列三个值:
几何衰减计算在详细的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);
}