光照基础
- 环境光
- 漫反射光
- 镜面光
光照特性
材质属性
- 泛射材质
- 漫反射材质
- 镜面反射材质
- 发射材质
光照计算
环境光的计算
1. 环境光的计算
环境光 = 光源的环境光颜色 * 物体的材质颜色
2. 环境光GLSL实现
varying vec3 objectColor;
void main()
{
//⾄至少有%10的光找到物体所有⾯面
float ambientStrength = 0.1;
//环境光颜⾊色
vec3 ambient = ambientStrength * lightColor;
//最终颜⾊色 = 环境光颜⾊色 * 物体颜⾊色
vec3 result = ambient * objectColor;
l_FragColor = vec4(result, 1.0);
}
发射光的计算
发射颜色 = 物体反射材质的颜色
漫反射光的计算
漫反射颜⾊色 = 光源的漫反射颜⾊色 * 物体的漫发射材质颜⾊色 * DiffuseFactor
DiffuseFactor = max(0,dot(N,L))
漫反射因子DiffuseFactor 是光线与顶点法线向量的点积
漫反射光计算代码实现
uniform vec3 lightColor;
uniform vec3 lightPo;
uniform vec3 objectColor;
uniform vec3 viewPo;
varying vec3 outNormal;
//确保法线为单位向量
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 * ojbectColor;
gl_FragColor = vec4(result,1.0);
镜面光计算
N : 平⾯面法线
I : 入射光线
H : 反射光线
E : 视线
å : 视点与反射光的夹角
镜面反射颜色 = 光源的镜面光的颜色 * 物体的镜面材质颜色 * SpecularFactor
SpecularFactor = power(max(0,dot(N,H)),shininess)
H :视线向量E 与 光线向量L 的半向量
dot(N,H):H,N的点积几何意义,平方线与法线夹角的cos值
shiniess : ⾼高光的反光度;
镜面光计算代码实现
//镜面强度
float specularStrength = 0.5;
//顶点指向观察点的单位向量
vec3 viewDir = normalize(viewPo - FragPo);
//求得光线在顶点的反射线(传入光源指向顶点的向量)
vec3 reflectDir = reflect(-lightDir ,outNormal);
// 求得夹角cos值取256次幂 注意 pow(float,float)函数参数类型
float spec = pow(max(dot(viewDir, reflectDir),0.0),256.0);
vec3 specular = specularStrength * spec * lightColor;
光照计算
光照颜色 =(环境颜色 + 漫反射颜色 + 镜面反射颜色)* 衰减因⼦
衰减因子
衰减因⼦ = 1.0/(距离衰减常量 + 线性衰减常量 * 距离 + 二次衰减常量 * 距离的平⽅)
注意:环境光,漫反射光和镜面光的强度都会受距离的增大而衰减,只有发射光和全局环境光的强度不会受影响
衰减因子代码
//距离衰减常量
float constantPara = 1.0f;
//线性衰减常量
float linearPara = 0.09f;
//二次衰减因⼦
float quadraticPara = 0.032f;
//距离
float LFDistance = length(lightPo - FragPo);
//衰减因⼦
float lightWeakPara = 1.0/(constantPara + linearPara* LFDistance + quadraticPara (LFDistance*LFDistance));
聚光因子
聚光灯夹角cos值 = power(max(0,dot(单位光源位置,单位光线向量)),聚光灯指数);
- 单位光线向量:从光源指向顶点的单位向量
- 聚光灯指数:表示聚光灯的亮度程度
- 公式解读:单位光源位置 * 单位光线向量点积的聚光灯指数次⽅。
聚光灯过度计算代码实现
//(⼀一些复杂的计算操作 应该让CPU做,提⾼高效率,不不变的量量也建议外部传输,避免 重复计算)
//内锥⻆角cos值
float inCutOff = cos(radians(10.0f));
//外锥⻆角cos值
float outCutOff = cos(radians(15.0f));
//聚光朝向
vec3 spotDir = vec3(-1.2f,-1.0f,-2.0f);
//光源指向物体的向量和聚光朝向的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);
光照计算终极公式
光照颜色 = 发射颜色 + 全局环境颜色 + (环境颜色 + 漫反射颜色 + 镜⾯反射颜色) * 聚光灯效果 * 衰减因⼦
平面光计算代码实现
//环境因⼦
float ambientStrength = 0.3;
//镜面强度
float specularStrength = 2.0;
//反射强度
float reflectance = 256.0;
//平行光方向
vec3 paraLightDir = normalize(vec3(-0.2,-1.0,-0.3));
//环境光
vec3 ambient = ambientStrength * texture(Texture ,outTexCoord).rgb;
//漫反射
vec3 norm = normalize(outNormal);
vec3 lightDir = normalize(lightPo - FragPo);
//当前顶点至光源的的单位向量
float diff = max(dot(norm ,paraLightDir),0.0);
vec3 diffuse = diff * lightColor*texture(Texture ,outTexCoord).rgb;
//镜面反射
vec3 viewDir = normalize(viewPo - FragPo);
vec3 reflectDir = reflect(-paraLightDir ,outNormal);
float spec = pow(max(dot(viewDir, reflectDir),0.0),reflectance);
vec3 specular = specularStrength * spec * texture(specularTexture ,outTexCoord).rgb;
//最终光照颜色
vec3 res = ambient + diffuse + specular;
FragColor = vec4(res,1.0);
点光源计算代码实现
float ambientStrength = 0.3;//环境因子
float specularStrength = 2.0;//镜面强度
float reflectance = 256.0;//反射强度
float constantPara = 1.0f;//常量
float linearPara = 0.09f;//线性部分因子
float quadraticPara = 0.032f; //二次项部分因数
//环境光
vec3 ambient = ambientStrength * texture(Texture ,outTexCoord).rgb;
//漫反射
vec3 norm = normalize(outNormal);
vec3 lightDir = normalize(lightPo - FragPo); //当前顶点至光源的的单位向量
//点光源
float diff = max(dot(norm ,lightDir),0.0); //光源与法线夹⻆角
vec3 diffuse = diff * lightColor*texture(Texture ,outTexCoord).rgb;
//镜面反射
vec3 viewDir = normalize(viewPo - FragPo);
vec3 reflectDir = reflect(-lightDir ,outNormal);
float spec = pow(max(dot(viewDir, reflectDir),0.0),reflectance);
vec3 specular = specularStrength * spec * texture(specularTexture ,outTexCoord).rgb;
//光线衰弱
float LFDistance = length(lightPo - FragPo);
float lightWeakPara = 1.0/(constantPara + linearPara * LFDistance + quadraticPara * (LFDistance*LFDistance));
vec3 res = (ambient + diffuse + specular)*lightWeakPara;
FragColor = vec4(res,1.0);