Graphics Reference
In-Depth Information
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/
*
Non-unit surface normal in world space
*
/
varying vec3
wsInterpolatedNormal;
/
*
Unit world space dir'n to directional light source
*
/
uniform vec3
wsLight;
/
*
the "intensity" that we'll threshold
*
/
varying float
intensity;
void
main(
void
){
wsInterpolatedNormal =
normalize(g3d_ObjectToWorldNormalMatrix
*
gl_Normal);
wsInterpolatedEye =
wsEyePosition - (g3d_ObjectToWorldMatrix
*
gl_Vertex).xyz;
gl_Position = gl_ModelViewProjectionMatrix
*
gl_Vertex;
intensity = dot(wsInterpolatedNormal, wsLight);
}
Listing 33.9: The pixel shader for the first toon-shading program.
1
2
3
4
5
6
7
8
9
10
11
... same declarations ...
void
main() {
if
(intensity > 0.95)
gl_FragColor.rgb = diffuseColor;
else if
(intensity > 0.5)
gl_FragColor.rgb = diffuseColor
*
0.6;
else if
(intensity > 0.25)
gl_FragColor.rgb = diffuseColor
*
0.4;
else
gl_FragColor.rgb = diffuseColor
*
0.2;
}
The results, shown in Figure 33.6, are unsatisfactory: When the intensity is
linearly interpolated across a triangle and then thresholded, the result is a straight-
line boundary between the two color regions. When this is done for every polygon,
the result is that each color region has a visibly polygonal boundary.
Figure 33.6: Toon shading using
a vertex shader; notice the sharp
corners of the highlight area.
We can improve this substantially by using the
interpolated
surface normal
and
interpolated
light vector in the fragment shader to compute an intensity value
that varies smoothly across the polygon, and which, when thresholded, produces a
smooth boundary between color regions. In our case, with a directional light, only
the interpolation of the surface normal has an effect, but the program would also
work for more general lights.
Inline Exercise 33.1:
This program gives yet another instance of the principle
that not every pair of operations commutes, and swapping the order for sim-
plicity or efficiency only works acceptably in some cases. Explain which two
operations are not commuting in this example.
Figure 33.7: Toon shading using
a
The revised program can use exactly the same vertex shader, except that we
no longer need to declare or compute
intensity
. The revised fragment shader is
shown in Listing 33.10, and the results are shown in Figure 33.7.
Notice that in the fragment shader, we took the normal vector that was
computed at each vertex, and then interpolated to the current fragment, and
normalized
it.
fragment
shader.
Notice
the
smooth
boundary
between
the
shades of red.