效果图:左起分别为 平行光光源,点光源,聚光灯光源
片元shader
uniform vec4 U_LightPos;//光源位置
uniform vec3 U_EyePos;//眼睛位置
uniform vec4 U_LightDirection;//聚光灯中心线向量
uniform float U_Cutoff;//聚光灯中心线向量和入射光线最大夹角
uniform float U_DiffuseIntensity; //漫反射光强度
uniform vec4 U_AmbientLightColor;//环境光颜色
uniform vec4 U_AmbientMaterial;//环境光材质
uniform vec4 U_DiffuseLightColor;//漫反射光颜色
uniform vec4 U_DiffuseMaterial;//漫反射光材质
uniform vec4 U_SpecularLightColor;//镜面光颜色
uniform vec4 U_SpecularMaterial;//镜面光材质
varying vec3 V_Normal; //转换到世界空间的法向量
varying vec3 V_WorldPos;
void main()
{
//角度转弧度
float radianCutoff=U_Cutoff*3.14/180.0;
float cosThta=cos(radianCutoff);
//聚光灯中心线向量归一化
vec3 spotLightDirection=normalize(U_LightDirection.xyz);
//--计算环境光
vec4 ambientColor=U_AmbientLightColor*U_AmbientMaterial;
//--计算漫反射光
//入射光向量
vec3 L=vec3(0.0);
float distance=0.0;
float attenuation=1.0;
float constantFactor=0.5;
float linearFactor=0.3;
float expFactor=0.1;
if(U_LightPos.w==0.0)//如果是方向光光源
{
//方向光光源 入射光线是平行的
L=U_LightPos.xyz;
}
else //如果是点光源
{
//入射光线的方向是从被照射点指向光源的位置
L=U_LightPos.xyz-V_WorldPos;
//计算入射光线的长度
distance=length(L);
//计算光线的衰减因子
attenuation=1.0/(constantFactor+linearFactor*distance+expFactor*distance*distance);
}
//入射光线归一化
L=normalize(L);
//法向量归一化
vec3 n=normalize(V_Normal);
float diffuseIntensity=0.0;
if(U_LightPos.w!=0.0f&&U_Cutoff>0.0)//如果是聚光灯
{
//计算聚光灯中心线和入射光线的夹角
float currentCosThta=max(0.0,dot(-L,spotLightDirection));
if(currentCosThta>cosThta)
{
if(dot(L,n)>0.0)//为了减少计算量,过滤掉照射到背面的光
{
//为了让聚光灯边缘变的光滑
diffuseIntensity=pow(currentCosThta,U_LightDirection.w);
}
}
}
else
{
//点光源或者方向光
diffuseIntensity=max(0.0,dot(L,n));
}
vec4 diffuseColor=U_DiffuseLightColor*U_DiffuseMaterial*diffuseIntensity*attenuation*U_DiffuseIntensity;
//--镜面光的计算
//计算眼睛到被观察点的向量
vec3 viewDir=U_EyePos-V_WorldPos;
viewDir=normalize(viewDir);
//根据Blin-phone计算反射光
vec3 halfVector=L+viewD