一、光照三组成元素
(一)、环境光
定义:环境光是指从四面八方照射到物体上,全方位360°都均匀的光;特点:不依赖于光源位置,而且没有方向性;计算公式:环境光照射结果 = 材质的反射系数 X 环境光强度。直接在着色器中给定值,不需要计算vertex.sh → vAmbient = vec4(0.15,0.15,0.15,1.0);
frag.sh → gl_FragColor=finalColor*vAmbient;
(二)、散射光
定义:散射光是指从物体表面向全方位360°均匀反射的光;
特点:与光源位置相关,散射光反射的强度与入射的强度以及入射的角度密切相关;
计算公式:散射光照射结果 = 材质的反射系数 X 散射光强度 X max(cos(入射角), 0);
求入射角过程:顶点法向量和顶点到光源的向量规格化后的点积即为入射角的余弦值。
uniform mat4 uMVPMatrix; //总变换矩阵 uniform mat4 uMMatrix; //变换矩阵(包括平移、旋转、缩放) uniform vec3 uLightLocation; //光源位置 attribute vec3 aPosition; //顶点位置 attribute vec3 aNormal; //顶点法向量 varying vec3 vPosition; //用于传递给片元着色器的顶点位置 varying vec4 vDiffuse; //用于传递给片元着色器的散射光分量 void pointLight ( //散射光光照计算的方法 in vec3 normal, //法向量 inout vec4 diffuse, //散射光计算结果 in vec3 lightLocation, //光源位置 in vec4 lightDiffuse //散射光强度 ){ vec3 normalTarget=aPosition+normal; //计算变换后的法向量 vec3 newNormal=(uMMatrix*vec4(normalTarget,1)).xyz-(uMMatrix*vec4(aPosition,1)).xyz; newNormal=normalize(newNormal); //对法向量规格化 //计算从表面点到光源位置的向量vp vec3 vp= normalize(lightLocation-(uMMatrix*vec4(aPosition,1)).xyz); vp=normalize(vp); //规格化vp float nDotViewPosition=max(0.0,dot(newNormal,vp)); //求法向量与vp向量的点积与0的最大值 diffuse=lightDiffuse*nDotViewPosition; //计算散射光的最终强度 } void main(){ gl_Position = uMVPMatrix * vec4(aPosition,1); //根据总变换矩阵计算此次绘制此顶点的位置 vec4 diffuseTemp=vec4(0.0,0.0,0.0,0.0); pointLight(normalize(aNormal), diffuseTemp, uLightLocation, vec4(0.8,0.8,0.8,1.0)); vDiffuse=diffuseTemp; //将散射光最终强度传给片元着色器 vPosition = aPosition; //将顶点的位置传给片元着色器 }
(三)、镜面光
定义:现实世界中当光滑表面被照射时会有方向很集中的反射光,这就是镜面光;
特点:依赖于入射光与被照射点法向量的夹角和观察者位置;
计算公式:镜面光照射结果 = 材质的反射系数 X 镜面光强度 X max(0, cos((半向量与法向量的夹角))^粗糙度;
半向量:顶点到观察者的向量和顶点到光源的向量平均向量,即两向量求和
求入射角过程:顶点法向量和半向量规格化后的点积即为入射角的余弦值。
uniform mat4 uMVPMatrix; //总变换矩阵 uniform mat4 uMMatrix; //变换矩阵 uniform vec3 uLightLocation; //光源位置 uniform vec3 uCamera; //摄像机位置 attribute vec3 aPosition; //顶点位置 attribute vec3 aNormal; //法向量 varying vec3 vPosition; //用于传递给片元着色器的顶点位置 varying vec4 vSpecular; //用于传递给片元着色器的镜面光最终强度 void pointLight( //定位光光照计算的方法 in vec3 normal, //法向量 inout vec4 specular, //镜面反射光分量 in vec3 lightLocation, //光源位置 in vec4 lightSpecular //镜面光强度 ){ vec3 normalTarget=aPosition+normal; //计算变换后的法向量 vec3 newNormal=(uMMatrix*vec4(normalTarget,1)).xyz-(uMMatrix*vec4(aPosition,1)).xyz; newNormal=normalize(newNormal); //对法向量规格化 //计算从表面点到摄像机的向量 vec3 eye= normalize(uCamera-(uMMatrix*vec4(aPosition,1)).xyz); //计算从表面点到光源位置的向量vp vec3 vp= normalize(lightLocation-(uMMatrix*vec4(aPosition,1)).xyz); vp=normalize(vp);//格式化vp vec3 halfVector=normalize(vp+eye); //求视线与光线的半向量 float shininess=50.0; //粗糙度,越小越光滑 float nDotViewHalfVector=dot(newNormal,halfVector); //法线与半向量的点积 float powerFactor=max(0.0,pow(nDotViewHalfVector,shininess)); //镜面反射光强度因子 specular=lightSpecular*powerFactor; //最终的镜面光强度 } void main() { gl_Position = uMVPMatrix * vec4(aPosition,1); //根据总变换矩阵计算此次绘制此顶点的位置 vec4 specularTemp=vec4(0.0,0.0,0.0,0.0); pointLight(normalize(aNormal), specularTemp, uLightLocation, vec4(0.7,0.7,0.7,1.0));//计算镜面光 vSpecular=specularTemp; //将最终镜面光强度传给片元着色器 vPosition = aPosition; //将顶点的位置传给片元着色器 }
二、定位光与定向光
定向光不需要计算光的方向
三、点法向量与面法向量
面法向量
点法向量在顶点A的位置放置3个不同的顶点,每个顶点看作是公属于一个面。各个顶点的法向量即为其属于的面的法微量,这种策略就是面法微量的策略,比较适合棱角分明的物体。
顶点A的位置公认为存在一个顶点,其法向量取其所属的所有面法向量的平均值。这种策略就是点法向量策略,比较适合用于多个平面搭建平滑曲面的情况。