- 光照计算在片元着色器执行,计算每一个像素点的颜色
一、光照计算
1、环境光计算
环境光 = 光源的环境光颜色 * 物体的材质颜色
- 环境光 = 光的颜色 * 材质颜色;
光是有颜色的,比如红光、绿光等;
材质颜色也就是纹理颜色。
2、发射光的计算
发射颜色 = 物体的反射材质颜色
- 物体本身是有颜色的,比如手电筒,其本身能发光,发出的光的颜色就是发射颜色。
3、漫反射光照计算
- 光照有阴面和阳面,由法线计算光与物体之间的夹角,这个夹角分为入射角和反射角
漫反射颜色 = 光源的漫反射颜色 * 物体的漫反射材质颜色 * DiffuseFactor
DiffuseFactor = max(0, dot(N, L));
- 漫反射因子DiffuseFactor 是光线与顶点法线向量的点积,是光线与法线之间的夹角,其值不能小于0
4、镜面光计算
镜面反射颜色 = 光源的镜面光颜色 * 物体的镜面材质颜色 * SpecularFactor
SpecularFactor = power(max(0, dot(N, H)), shininess);
H:视线向量E 与光线向量L 的半向量
dot(N, H):H,N的点积几何意义,平方线与法线夹角的cos值
shininess:高光的反光度
- 镜面因子SpecularFactor,shininess反光度越小光照越集中
5、普通光照计算
光照颜色 = (环境颜色 + 漫反射颜色 + 镜面反射颜色) * 衰减因子

衰减因子 = 1.0 / (距离衰减常量 + 线性衰减常量 * 距离 + 二次衰减常量 * 距离的平方)
距离衰减常量、线性衰减常量和二次衰减常量均为常量值
tips:环境光、漫反射光和镜面光的强度都会受距离的增大而衰减,只有发射光和全局环境光的强度不会受影响
6、聚光灯因子
聚光灯夹角cos值 = power(max(0, dot(单位光源位置, 单位光线向量)), 聚光灯指数);
单位光线向量:是从光源指向顶点的单位向量
聚光灯指数:表示聚光灯的亮度程度
公式解读:单位光源位置 * 单位光线向量 点积 的 聚光灯指数次方
- 增加过渡计算
聚光灯因子 = clamp((外环的聚光灯角度cos值 - 当前顶点的聚光灯角度cos值) / (外环的聚光灯角度cos值 - 内环聚光灯的角度cos值), 0.1);
7、光照计算终极公式
光照颜色 = 发射颜色 + 全局环境颜色 + (环境颜色 + 漫反射颜色 + 镜面颜色) * 聚光灯效果 * 衰减因子
平面光终极公式
- 平面光也就是平行光,没有具体的方向
点光源终极公式
- 比如灯泡光源,点光源是有方向的
二、光照的GLSL实现
1、环境光的GLSL实现
varying vec3 objectColor;
void main() {
//至少有10%的光照到物体所有面
float ambientStrength = 0.1;
//环境光颜色 = 环境光比率 * 环境光颜色
vec3 ambient = ambientStrength * lightColor;
//最终颜色 = 环境光颜色 * 物体颜色
vec3 result = ambient * objectColor;
//vec3转化成vec4
gl_FragColor = vec4(result, 1.0);
}
2、漫反射光的GLSL实现
uniform vec3 lightColor; //光源颜色
uniform vec3 lightPo; //光源位置
uniform vec3 objectColor; //物体颜色
uniform vec3 viewPo; //物体位置
varying vec3 outNormal; //传入当前顶点平面的法向量
//确保法线为单位向量,normalize为内建函数,把法向量转换成单位向量
vec3 norm = normalize(outNormal);
//顶点指向光源的单位向量
vec3 lightDir = normalize(lightPo - FragPo);
//得到两向量的cos值,小于0则为0
float diff = max(dot(norm, lightDir), 0.0);
//夹角乘以光照颜色得到漫反射的光源向量
vec3 diffuse = diff * lightColor;
vec3 result = diffuse * objectColor;
gl_FragColor = vec4(result, 1.0);
3、镜面光的GLSL实现
//镜面强度
float specularStrength = 0.5;
//顶点指向观察点的单位向量
vec3 viewDir = normalize(viewPo - FragPo);
//光线在顶点的反射线(传入光源指向顶点的向量),镜面光是反方向的光线
vec3 reflectDir = reflect(-lightDir, outNormal);
//夹角cos值,取256次幂,镜面因子
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 256.0);
vec3 specular = specularStrength * spec * lightColor;
4、衰减因子计算
//距离衰减常量
float constantPara = 1.0;
//线性衰减常量
float linearPara = 0.09;
//二次衰减因子
float quadraticPara = 0.032;
//距离
float lightWeakPara = 1.0/(constantPara + linearPara * LFDistance + quadraticPara * (LFDistance * LFDistance));
5、聚光灯过渡计算
//一些复杂的计算操作应该让CPU做以提高效率,不变的量也建议外部传输,避免重复计算
//内锥角cos值
float inCutoff = cos(radians(10.0));
//外锥角cos值
float outCutoff = cos(radians(15.0));
//聚光朝向
vec3 spotDir = vec3(-1.2, -1.0, -2.0);
//光源指向物体的向量和聚光朝向的cos值
float theta = dot(lightDir, normalize(-spotDir));
//内外锥角cos差值
float epsilon = inCutoff - outCutoff;
//clamp(a, b, c);若b<a<c则函数返回a,若不是则返回最小b,最大c
/*(theta - outCutoff)/epsilon 若theta的角度小于内锥角则其值>=1,
若theta的角度大于外锥角则其值<=0,这样光线就在内外锥角之间平滑变化*/
float intensity = clamp((theta - outCutoff) / epsilon, 0.0, 1.0);
网友评论