光照是OpenGL ES里很重要的一部分,下面我们来学习总结一下如何计算不同的光照效果。
光照基础
1、环境光照
2、漫反射光照
3、镜面光照光照特性
1、发射光:由物体自身发光
2、环境光:就是在环境中充分散射的光,而且无法分辨它的方向
3、漫反射光:光线来自某个方向,但在物体上各个方向反射
4、镜面高光:光线来自一个特定的方向,然后在物体表面上以一个特定的方向反射出去材质属性
1、泛射材质
2、漫反射材质
3、镜面反射材质
4、发射材质
-
单一光照计算
1、环境光的计算环境光 = 光源的环境光颜色*物体的材质颜色
GLSL实现:
varying vec3 objectColor; void main() { //⾄至少有%10的光找到物体所有⾯面 float ambientStrength = 0.1; //环境光颜⾊色 vec3 ambient = ambientStrength * lightColor; //最终颜⾊色 = 环境光颜⾊色 * 物体颜⾊色 vec3 result = ambient * objectColor; gl_FragColor = vec4(result, 1.0); }
2、发射光的计算
发射光 = 物体的反射材质颜色
3、漫反射光的计算
漫反射颜⾊ = 光源的漫反射颜色 * 物体的漫发射材质颜色 * DiffuseFactor DiffuseFactor = max(0,dot(N,L)) 漫反射因⼦DiffuseFactor 是光线与顶点法线向量的点积
GLSL实现:
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);
4、镜面光的计算
镜面反射颜色 = 光源的镜面光的颜色 * 物体的镜面材质颜色 * SpecularFactor SpecularFactor = power(max(0,dot(N,H)),shininess) H :视线向量E与光线向量L的半向量 dot(N,H):H,N的点积几何意义,反射光线与法线夹角的cos值 shiniess : 高光的反光度
GLSL实现
//镜面强度 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/(距离衰减常量 + 线性衰减常量 * 距离 + 二次衰减常量 * 距离的平方) 距离衰减常量、线性衰减常量和二次衰减常量均为常量值
环境光、漫反射光和镜面光的强度都会受距离的增大而衰减,只有发射光和全局环境光的强度不会受影响
1)衰减因子计算
//距离衰减常量 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));
2)聚光灯因子计算
聚光灯夹角cos值 = power(max(0,dot(单位光源位置,单位光线向量)),聚光灯指数); 单位光线向量是从光源指向顶点的单位向量 聚光灯指数,表示聚光灯的亮度程度 公式解读:单位光源位置 * 单位光线向量点积的聚光灯指数次方 聚光灯因子 = clamp((外环的聚光灯角度cos值 - 当前顶点的聚光灯角度cos值)/ (外环的聚光灯⻆度cos值- 内环聚光灯的⻆度的cos值),0,1)
计算代码
//内锥角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);
-
综合光照计算终极公式
光照颜色 = 发射颜色 + 全局环境颜色 + (环境颜色 + 漫反射颜色 + 镜面反射颜色) * 聚光灯效果 * 衰减因⼦
-
平面光计算GLSL实现
//环境因子 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);
-
点光源计算GLSL实现
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);