当计算光照模型(如ADS模型)的时候,通常是在vertex shader中计算每个顶点的颜色值,然后通过这些顶点插值 传入fragment shader中,这些被称为Gouraud shading.
Gouraud shading.模型有一些不尽人意的地方,例如,高光(bright specular highlight)可能在一个polygon的中间,这样通过这种模型计算就会影响高光显示效果。
为了提高渲染结果的准确性,我们可以把计算光照模型的计算 放到fragment shader 中进行,我们通过插值物体表面的顶点和发向 而不是每个顶点的颜色,传递到fragment shader 中进行光照模型计算,这项技术程为:Phong shader 或者是 Phong interpolation 。这样通过phong shader 光照模型可以大大提高场景的真实性,但也会有一些小的瑕疵。
如图:Gouraud and Phong shading 对比
左边是Gouraud (per-vertex) shading,右边是Phong(per-fragment)shading。 在途中可以看出 右边的效果要比左边的效果更真实些。
顶点shader
#version 430 layout (location = 0) in vec3 VertexPosition; layout (location = 1) in vec3 VertexNormal; out vec3 Position; out vec3 Normal; uniform mat4 ModelViewMatrix; uniform mat3 NormalMatrix; uniform mat4 ProjectionMatrix; uniform mat4 MVP; void main() { Normal = normalize( NormalMatrix * VertexNormal); Position = vec3( ModelViewMatrix * vec4(VertexPosition,1.0) ); gl_Position = MVP * vec4(VertexPosition,1.0); }
#version 430 in vec3 Position; in vec3 Normal; uniform vec4 LightPosition; uniform vec3 LightIntensity; uniform vec3 Kd; // Diffuse reflectivity uniform vec3 Ka; // Ambient reflectivity uniform vec3 Ks; // Specular reflectivity uniform float Shininess; // Specular shininess factor layout( location = 0 ) out vec4 FragColor; vec3 ads( ) { vec3 s = normalize( vec3(LightPosition) - Position ); vec3 v = normalize(vec3(-Position)); vec3 r = reflect( -s, Normal ); return LightIntensity * ( Ka + Kd * max( dot(s, Normal), 0.0 ) + Ks * pow( max( dot(r,v), 0.0 ), Shininess ) ); } void main() { FragColor = vec4(ads(), 1.0); }