Charles Petzold

Attempt at Simple WPF 3D Cell-Shading

September 5, 2007
New York, N.Y.

I received a recent query about cell-shading in WPF. Cell-shading is the technique of using just a few solid colors to imitate hand-drawn animation.

The first idea that occurred to me was fiddling around with the Normals collection of a MeshGeometry3D by restricting it to just a few values. I derived from my TeapotMesh class (described here) and reset all the items in the Normals collection to the closest vector among the group (1, 0, 0), (–1, 0, 0), (0, 0, 1), and (0, 0, –1). Then I aimed some directional light at (1, 0, –1), and I rotated the teapot a bit relative to the light, and here's what it looked like:

That result, although interesting in its own way, is only a very distant relative to this example shown in the Wikipedia article on cell shading:

The problem, of course, is that the normals are vertex normals, and the surface of each pixel in each triangle in the mesh is shaded based on the averaqe of the shading at the triangle's vertices. (See Chapter 4, "Light and Shading," of my book for details.) That's why there's a transition area between the light and dark shading. From this point, "posterizing" the image doesn't help much:

The color-change boundary needs to be independent of the boundaries of the triangles in the mesh — otherwise you get the choppy appearance in my image. You actually get a much better result if you just posterize the unadulterated teapot:

It's fairly straightforward to perform whatever fancy post-processing you want on a 3D scene by composing the scene in a Viewport3DVisual and dumping it to a RenderTargetBitmap for fiddling. That approach could be adequate if you were interested in a single scene, but becomes much clumsier if you also desire real-time animation.

I believe this job could be accomplished with a custom BitmapEffect derivative that let you restrict the color palette to only those colors in a particular BitmapPalette object, but apparently deriving from BitmapEffect is a rather messy exercise, and doesn't seem to be well documented.

Anyway, if you'd like to play around with the program that implements the restriction of normals, here's the XBAP:


And here's the source code, including the necessary source code files from the Petzold.Media3D library.

Buy my book and we'll both be happy! quantumbooks
Barnes & Noble Amazon Canada Amazon UK
Amazon Fran├žais Amazon Deutsch Amazon Japan