简易顶点光照知识点: Vertex Lighting - MartinRGB/GLES30_ProgrammingGuide_NDK GitHub Wiki
直射光知识点
首先,根据OpenGL ES 3.0编程指南:第八章. Vertex Shaders---(二),回顾一下光照的几种类型:
漫反射光照计算
漫反射光照颜色 = 光照强度 光照颜色 cos(光照与法线夹角)
镜面反射-Phong
镜面反射特性:当R与V重合时光照最强,稍微有一点偏差就会有很大的衰减。
镜面反射光照颜色 = pow(dot(R, V), 光照颜色
参考:
镜面反射-BlinnPhong
镜面反射光照颜色 = pow(dot(H, N), 光照颜色)
参考:
简易顶点平行光-Directional Light: 参考 8.2.2
方向光,也叫平行光,是一个距离被照明物体无限远的光源,比如太阳光。由于距离物体无限远,所以方向光的光线都是平行的,照明方向向量是一个常量,不需要逐顶点计算。
注:因为本案例中,官员和观察看着在无限远的地方放所以,半平面向量 = ||Light.xyz + (0,0,1)||
vec4 compute_color(vec3 normal)
{
vec4 computed_color = vec4(c_zero, c_zero, c_zero, c_zero);
float ndotl; // 光线与法线弧度
float ndoth; // 半平面量与法线弧度
ndotl = max(c_zero, dot(normal, light_direction));
ndoth = max(c_zero, dot(normal, light_halfplane));
computed_color += (light_ambient_color * material_ambient_color);
computed_color += (ndotl * light_diffuse_color * material_diffuse_color);
if (ndoth > c_zero) {
computed_color += (pow(ndoth, material_specular_exponent) * material_specular_color * light_specular_color);
}
return computed_color;
}
最后生成的颜色,将逐个顶点漫反射和反射颜色整合为单个颜色(computed_color)给出。实际上,要为每个光源计算环境、漫反射、反射,然后乘以材料的对应项,生成每个顶点的颜色。
着色器中点积的物理意义:
点积得到数值(弧度,可以转为角度)
两个向量之间的夹角= dot(a,b)=arccos(a·b / (|a|·|b|))
通过点积得到两个向量之间的夹角,通过点积的正负值,可以判断两个向量的方向关系。如果为正,即>0,他们夹角为(0,π/2)。如果为负,夹角为(π/2,π)。
简易顶点聚光-SpotLight 参考 8.2.3
聚光灯兼具位置和方向,所以兼具光线距离衰减和光轴中心角度衰减
1.光线距离衰减: 与光锥中轴形成的 不同角度光射线 VPlight 和 spot-direction 点乘得出
聚光灯的光线距离衰减公式:
距离衰减 = 1/(k0 + k1*||VPlight|| + k2*||VPlight||
2.光轴中心角度衰减: 光线的强度根据 与光锥中心所形成的角度 得出的 点截止因子 进行衰减,点截止因子在 spot-direction 给出的方向上为1.0,根据 spot-cutoff-angle 给出的角度,按距离衰减公式,衰减为0
#version 320 es
layout (binding = 1) uniform u_light
{
vec4 light_position;
vec4 light_ambient_color;
vec4 light_diffuse_color;
vec4 light_specular_color;
vec3 light_spot_direction; //规范化点方向向量
vec3 light_attenuation_factors; //距离衰减因子 k0 k1 k2
float light_spot_exponent; //用于计算点截止因子的聚光灯指数
float light_spot_cutoff_angle; //聚光灯截止角度
};
layout (binding = 0) uniform u_material
{
vec4 material_ambient_color;
vec4 material_diffuse_color;
vec4 material_specular_color;
float material_specular_exponent;
};
uniform mat4 u_mvpMatrix;
uniform mat3 u_mvMatrix;
uniform bool light_compute_distance_attenuation;
const float c_zero = 0.0;
const float c_one = 1.0;
vec4 spot_light_color (vec3 normal, vec4 position)
{
vec4 computed_color = vec4 (c_zero, c_zero, c_zero, c_zero);
vec3 lightDir; //光轴中心
vec3 halfplane;
float NdotL, NdotH; //法线与光线方向弧度
float att_factor; //法线与光线出入射半量角弧度
att_factor = c_one;
//通过向量的相减,得到光轴中心到顶点位置的方向向量,也就是方向
lightDir = light_position.xyz - position.xyz;
//### 距离衰减,参照公式
if (light_compute_distance_attenuation) {
vec3 att_dist;
att_dist.x = 1;
att_dist.z = dot (lightDir, lightDir);
att_dist.y = sqrt(att_dist.z);
att_factor = c_one / dot(att_dist, light_attenuation_factors);
}
// 各个光线距离衰减计算完成后,归一化向量
lightDir = normalize (lightDir);
//### 光束角度衰减
if (light_spot_cutoff_angle < 180.0) {
//计算光束与光锥中轴的角度
float spot_factor = dot (-lightDir, light_spot_direction);
//如果角度大于了聚光灯截止角度,衰减
if (spot_factor >= cos(radians(light.spot_cutoff_angle)) )
spot_factor = pow (spot_factor, light_spot_exponent);
//否则不衰减
else
spot_factor = c_zero;
//综合距离衰减和光束角度衰减
att_factor *= spot_factor;
}
if (att_factor > c_zero) {
//综合光的环境色,和材质的环境色
computed_color += light_ambient_color * material_ambient_color;
//计算从光轴中心的入射方向与法线的弧度
NdotL = max(c_zero, dot(normal, lightDir));
//综合光的漫反射色,和材质的漫反射色
computed_color += NdotL * light_diffuse_color * material_diffuse_color;
halfplane = normailze (lightDir + vec3(c_zero, c_zero, c_one));
//计算从光轴中心的 入射方向与反射方向中心 与法线的弧度
NdotH = dot (normal, halfplane);
//如果 halfplane 没有与法线重合,那么发生了反射
if (NdotH > c_zero) {
//综合光的反射色,和材质的反射色
computed_color += pow (NdotH, material_specular_exponent) * material_specular_color * light_specular_color;
}
//最后,让光的颜色结合 光轴轴心角度衰减 以及 光线距离衰减
computed_color *= att_factor;
}
return computed_color;
}
void main()
{
gl_Position = u_mvpMatrix * a_position;
v_color = spot_light_color(normalize(u_mvMatrix * a_normal), u_mvpMatrix * a_position);
}