在逐顶点shader光照模型中 要计算每个顶点的颜色,然后用这些点的颜色经过插值来产生光华的表面效果(The colors are then interpolated across the face of the polygon to produce a smooth shading effect),这个被称作Gouraund Shading。这在早期的OpenGL 版本中,经过每个顶点颜色插值来实现光照模型是其默认实现。
然而有时候 想为每个polygon 使用一个单一的颜色,这样看起来每个polygon有种平面效果(each polygon to have a flat appearance),这在表面看起来就是这个平面的效果
的模型上很有用,如鱼鳞(个人认为)。为每个polygon用单一颜色的技术通常叫做Flat shading。
如图:
在OpenGL 4.0 中 使用flat模型 ,在其out变量前面添 flat限定符即可。
vertex shader
#version 430
layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in vec3 VertexNormal;
flat out vec3 LightIntensity;
struct LightInfo {
vec4 Position; // Light position in eye coords.
vec3 La; // Ambient light intensity
vec3 Ld; // Diffuse light intensity
vec3 Ls; // Specular light intensity
};
uniform LightInfo Light;
struct MaterialInfo {
vec3 Ka; // Ambient reflectivity
vec3 Kd; // Diffuse reflectivity
vec3 Ks; // Specular reflectivity
float Shininess; // Specular shininess factor
};
uniform MaterialInfo Material;
uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 ProjectionMatrix;
uniform mat4 MVP;
void main()
{
vec3 tnorm = normalize( NormalMatrix * VertexNormal);
vec4 eyeCoords = ModelViewMatrix * vec4(VertexPosition,1.0);
vec3 s = normalize(vec3(Light.Position - eyeCoords));
vec3 v = normalize(-eyeCoords.xyz);
vec3 r = reflect( -s, tnorm );
float sDotN = max( dot(s,tnorm), 0.0 );
vec3 ambient = Light.La * Material.Ka;
vec3 diffuse = Light.Ld * Material.Kd * sDotN;
vec3 spec = vec3(0.0);
if( sDotN > 0.0 )
spec = Light.Ls * Material.Ks *
pow( max( dot(r,v), 0.0 ), Material.Shininess );
LightIntensity = ambient + diffuse + spec;
gl_Position = MVP * vec4(VertexPosition,1.0);
}
片元shader
#version 430
flat in vec3 LightIntensity;
layout( location = 0 ) out vec4 FragColor;
void main() {
FragColor = vec4(LightIntensity, 1.0);
}
前面的flat限定符 是告诉shader 在数据到达片元shader之前不要进行插值来计算。最终一个polygon的颜色有组成这个polygon的第一个顶点或最后一个顶点的颜色确定。这个顶点叫做Provoking vertex ,这个可以通过OpenGL的函数glProvokingVertex(GL_FIRST_VERTEX_CONVENTION); 配置。或者GL_LAST_VERTEX_CONVENTION