在逐顶点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); }
#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