标签(空格分隔): OpenGL着色语言
1.定向光源
是一种假定离被照亮的对象有无穷远的光。从光源发出的所有光线到达场景时全是平行的。场景中每个顶点可以使用一个单独的光方向矢量。
对于phong光照模型:I = Ka * Ia + Kd * Il * cosθ + Ks * Il * Cosn∅
K的下标a,b,s分别代表物体表面反射环境光系数、漫反射系数和反射镜面光系数。
Ia为全局环境光
Il为入射光
θ为N与L的夹角; ∅为R 与V的夹角
对部分计算矢量单位化即可化为:I = Ka * Ia + Kd * Il * (N.L) + Ks * Il * (R.V)n
实际使用中,由于R计算不方便,因此常用(N.H)代替(R.V);H为沿L和V的角平分线的单位向量。
I = Ka * Ia + Kd * Il * (N.L) + Ks * Il * (N.H)n
存在漫反射部分或者镜面反射部分的唯一可能情况是光源方向与表面发现之间的角度在范围[-90°, 90°]以内(即物体正面)。这是通过nDotVP确定的。这个值会设置为0和光源方向方向与表面法线之间的角度(即θ)的余弦这两个数中较大的一个。如果这个值为0,那么决定镜面反射数量的值也会设置为0.
void DirectionalLight(in int i,
in vec3 ambient,
inout vec4 diffuse,
inout vec4 specular)
{
float nDotVP; //normal . light direction
float nDotHV; //normal . light half vector
float pf; //幂的因子
nDotVP = max(0.0, dot(normal, vec3(gl_LightSource[i].position)));
nDotHV = max(0.0, dot(normal, vec3(gl_LightSource[i].halfVector)));
if(nDotVP == 0.0)
pf = 0.0;
else
pf = pow(nDotHV, gl_FrontMaterial.shininess);
ambient += gl_LightSource[i].ambient;
diffuse += gl_LightSource[i].diffuse + nDotVP;
specular += gl_LightSource[i].specular * pf;
}
2.点光源
与定向光源区别主要有两点:
1、对于每个顶点,光源方向是不一样的,不能用事先定好的值计算
2、表面接收的光会随着光源越来越远而减弱,每个光源都有常亮、线性、二次衰减因子
void PointLight(in int i,
in vec3 eye.
in vec3 ecPosition3,
in vec3 normal,
in vec3 ambient,
inout vec4 diffuse,
inout vec4 specular)
{
float nDotVP; //normal . light direction
float nDotHV; //normal . light half vector
float pf; //幂的因子
float attenuation; //衰减因子
float d; //从表面到光源的距离
vec3 VP; //从表面到光的位置的距离
vec3 halfVector; //最亮位置的方向
//表面到光源的矢量
VP = vec3(gl_LightSource[i].position) - ecPosition3);
//表面到光源的距离
d = length(VP);
//规格化表面到光的位置的矢量
VP = normalize(VP);
//计算衰减
attenuation = 1.0 / (gl_LightSource[i].constantAttenuation +
gl_LightSource[i].linearAttenuation * d +
gl_LightSource[i].quadraticAttenuation * d * d);
halfVector = normalize(VP + eye);
nDotVP = max(0.0, dot(normal, VP));
nDotHV = max(0.0, dot(normal, halfVector));
if(nDotVP == 0.0)
pf = 0.0;
else
pf = pow(nDotHV, gl_FrontMaterial.shininess);
ambient += gl_LightSource[i].ambient;
diffuse += gl_LightSource[i].diffuse + nDotVP * attenuation;
specular += gl_LightSource[i].specular * pf * attenuation;
}
3.聚光灯
聚光灯有一个聚焦方向(gl_LightSource[i].spotDirection),这个方向会与从光源位置到表面的矢量(-VP)相乘。得到的余弦值会与事先计算的余弦截止值(gl_LightSource[i].spotCosCuttoff)做比较,以便确定表面上的这个位置是位于聚光灯的光照锥形之内还是之外。如果在外部,则将聚光灯的衰减设置为0,否则就计算这个值的gl_LightSource[i].spotExponent次幂。得到的聚光灯衰减因子会与前面计算的衰减因子相乘,得到总的衰减因子。
void SpotLight(in int i,
in vec3 eye.
in vec3 ecPosition3,
in vec3 normal,
in vec3 ambient,
inout vec4 diffuse,
inout vec4 specular)
{
float nDotVP; //normal . light direction
float nDotHV; //normal . light half vector
float pf; //幂的因子
float spotDot; //聚光灯间的角度的余弦
float spotAttenuation; //聚光灯衰减因子
float attenuation; //计算的衰减因子
float d; //从表面到光源的距离
vec3 VP; //从表面到光的位置的距离
vec3 halfVector; //最亮位置的方向
//表面到光源的矢量
VP = vec3(gl_LightSource[i].position) - ecPosition3);
//表面到光源的距离
d = length(VP);
//规格化表面到光的位置的矢量
VP = normalize(VP);
//计算衰减
attenuation = 1.0 / (gl_LightSource[i].constantAttenuation +
gl_LightSource[i].linearAttenuation * d +
gl_LightSource[i].quadraticAttenuation * d * d);
//查看表面上的点是否位于光照锥形之内
spotDot = dot(-VP, gl_LightSource[i].spotDirection);
if(spotDot < gl_LightSource[i].spotCosCutOff)
spotAttenuation = 0.0; //光照没有影响
else
spotAttenuation = pow(spotDot, gl_LightSource[i].spotExponent);
//结合聚光灯和距离衰减的效果
attenuation *= spotAttenuation;
halfVector = normalize(VP + eye);
nDotVP = max(0.0, dot(normal, VP));
nDotHV = max(0.0, dot(normal, halfVector));
if(nDotVP == 0.0)
pf = 0.0;
else
pf = pow(nDotHV, gl_FrontMaterial.shininess);
ambient += gl_LightSource[i].ambient;
diffuse += gl_LightSource[i].diffuse + nDotVP * attenuation;
specular += gl_LightSource[i].specular * pf * attenuation;
}