Non-Photorealism Rendering
* Interaction (except for what have been supplied by the
skeleton code)
- 't' and 'T': Toggle texture
- '+' / '-' : Change the silhouette line width
- Mouse left key drag : Move the point light around
the object
* Silhouette
I didn't actually detect the silhouette by myself but made
OpenGL did it for me... Greg said it's hard to draw open shapes this way, but I
don't quite understand. If there are edges that shared by only one triangle,
then it's not a silhouette edge by definition. Otherwise, for every edge that
shared by 2 triangles, we can test the dot products. Simply render the scene
twice, one with front faces filled and another with front faces culled and depth
buffer on. Other people also do it by pulling the back faces a bit backward (towards the camera) for
better silhouette.
I did search a lot on how to fast detect silhouette edges.
The most common and quite efficient way is to randomly grab a bunch of edges as
seeds, and search each neighbor until a silhouette edge is found. Once an edge
is found, it's easy to trace this silhouette line. The drawback of this method
is, it cannot guarantee to find all the silhouette edges. However, it works very
well most of the time because we don't even need the whole silhouette in a
non-photorealistic image. For each following frame, we can use the silhouette of
the previous frame as the start point because of the frame coherence.
Nonetheless, I don't think this algorithm is very
effective. Given a very huge set of polygons, it would still be a lot of work to
find the silhouette edges one by one. Coherence between frames is not always so
helpful. (And I don't think the implementation is simple :p) On the other hand,
I really don't want to do brute force, check every edges in every frame. (It's
not hard but kind of silly...) Since OpenGL can do that nicely and effectively,
why not just use?
One drawback is the lines may not be connective in the
joint points, especially when the lines are thick. The pull-backward method I
mentioned above can solve this problem and yield identical line width. And of
course, I lost flexibility in controlling the silhouette by leaving it to
OpenGL.
* Cel-Shading
I referred to
Cel-Shading
(
* Texture
I was planed to use mipmap (which seems to be suggested by the skeleton code?) but not being success. Now I simply bind the proper texture for every triangle. Still, it doesn't look every pleasing, with some distortion in *thin* triangles and noticeable discrepancy between different textures. Part of the problem may be the texture itself and part of it may be the texture mapping scheme, which is EYE_PLANE in this case.