在上一节ADSGouraud着色模式下,我们看到当小球旋转时,亮光的部分时隐时现的,这是由于三角形之间的不连续造成的。
我们可以用ADSPhong着色模式来解决这种问题,在ADSGouraud着色模式下,顶点着色器传入片段着色器的是每个顶点的颜色值,顶点之间的颜色是通过线性插值计算出来的,这样在小球旋转的情况先就可能产生亮光的部分时隐时现的的情况 ,ADSPhong着色模式中顶点着色器传入到片段着色器的是顶点表面法线和光源向量,顶点之间的颜色值通过表面法线的插值计算出来,这样就会减弱闪烁的情况。
下面是顶点着色器ADSPhong.vp的全部代码
//需要的OpenGL的最低版本
#version 130
//需要外界传入的参数
//顶点
in vec4 vVertex;
//顶点法线
in vec3 vNormal;
//模型视图变换矩阵
uniform mat4 mvpMatrix;
//视图变换矩阵
uniform mat4 mvMatrix;
//模型视图变换矩阵法线矩阵
uniform mat3 normalMatrix;
//光源的位置
uniform vec3 vLightPosition;
// 表面法线
smooth out vec3 vVaryingNormal;
//光源向量
smooth out vec3 vVaryingLightDir;
void main(void)
{
// 获取表面法线在照相机坐标系下的值
vVaryingNormal = normalMatrix * vNormal;
//获取顶点在照相机坐标系下的值
vec4 vPosition4 = mvMatrix * vVertex;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
// 获取光源的向量
vVaryingLightDir = normalize(vLightPosition - vPosition3);
// 把顶点变换到照相机坐标系下
gl_Position = mvpMatrix * vVertex;
}
下面是片段着色器ADSPhong.fp的全部代码
//需要的OpenGL的最低版本
#version 130
//传出带光栅化阶段的颜色值
out vec4 vFragColor;
//环境光颜色值
uniform vec4 ambientColor;
//漫反射光颜色值
uniform vec4 diffuseColor;
//镜面光颜色值
uniform vec4 specularColor;
//从顶点着色器传入的值
//表面法线
smooth in vec3 vVaryingNormal;
//光源向量
smooth in vec3 vVaryingLightDir;
void main(void)
{
// 得到漫反射强度
float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir)));
// 漫反射颜色*漫反射强度
vFragColor = diff * diffuseColor;
// 加上环境光
vFragColor += ambientColor;
// 计算镜面光
vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir), normalize(vVaryingNormal)));
float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection));
if(diff != 0) {
float fSpec = pow(spec, 128.0);
vFragColor.rgb += vec3(fSpec, fSpec, fSpec);
}
}
代码实现部分只需要把初始化函数SetupRC中的
ADSLightShader = shaderManager.LoadShaderPairWithAttributes("ADSGouraud.vp", "ADSGouraud.fp", 2, GLT_ATTRIBUTE_VERTEX, "vVertex",
GLT_ATTRIBUTE_NORMAL, "vNormal");
换成
ADSLightShader = shaderManager.LoadShaderPairWithAttributes("ADSPhong.vp", "ADSPhong.fp", 2, GLT_ATTRIBUTE_VERTEX, "vVertex",
GLT_ATTRIBUTE_NORMAL, "vNormal");
即可