
A renderer for producing pictures that look like sketches was the project that was implemented this quarter. It is based on the work of Markosian, et. al [1]. The main goal of the renderer's design was that it should render multiple brush styles in a relatively fast manner. The different brush styles that were to be implemented were:
There are several steps involved in creating a rendering:
To find these, first we jump-start our Z-buffer. To do this, we first render (in white) the entire mesh with all polygons shaded in. Jump-starting the Z-buffer will allow us to later get rid of non-visible silhouette edges (because they shouldn't come up in the drawing.) Once the Z-buffer is jump-started, we can then proeceed to actually finding the silhouette edges in the mesh. A silhouette edge is defined in[1] as:
A polygon is front-facing if the dot product of its outward normal and a vector from a point on the polygon to the camera position is positive. Otherwise the polygon is back-facing. A silhouette edge is an edge adjacent to one front-facing and one back-facing polygon.
Our data structure has the nice property that it is very easy to figure out the normals of the two polygons (triangles for all of our models) that share an edge. Because of this property, the modified version of Appel's algorithm that is described in the paper was not implemented.
All silhouette edges that are found in the previous step are then individually processed. Each silhouette edge is parameterized as a line so that we can offset all of the different points on the silhouette edge. We want to be able to do this to provide a random/human sketched look to the silhouette edge.
With parameterized silhouette edges, we can then parameterize the tangent of the edge as well as the normal of the edge. The tangent and normal are used in conjunction with the brush function as vector offsets for the point. The equation for this is:
q(t) = p(t) + vx(t)p'(t) + vy(t)n(t)
where:
So what exactly is a 'brush function' then? A brush function is just a function that will describe what is going on in a particular brush in a very low level. For example, the charcoal stroke's brush function is just a high frequency sawtooth curve. The justification for this can be seen if one tries to draw a charcoal-like scene on paper with a pen; one ends up shaking the pen up and down on the paper in order to achieve similar effects. The same applies here.
Table of brush functions:
| Brush | Brush function |
| Charcoal | High frequency sawtooth curves |
| Lazy | Low frequency parabolic curves |
| Hand | Low magnitude noise applied along normal and tangent |
| Rough | High magnitude noise applied along tangent |
The major problems that arose during this project were:
(It also didn't help that the silhouette edges were being computed incorrectly due to a bug. Once the bug was fixed, however, everything seemed to fall into place perfectly.)
While not a bug, one annoying thing about the system is that depending on the model, some brushes might appear highly similar. A method of solving this problem while still rendering correct pictures for the rest of the test cases was not devised.
Nonphotorealistic rendering also allows some of us with little or no artistic talent to create masterpieces (or, at least nicer drawings than we would be able to draw ourselves!)
[1] Lee Markosian, Kowalski Michael A., Trychin Samuel J., et. al, Real-Time Nonphotorealistic Rendering, Brown Univeristy, SIGGRAPH 1997