CSE 168 (Rendering Algorithms)
Let's start out with the final product, right here, just because it looks neat:
So what the heck is this? And what was I doing? Well, first, a little background. I decided that I originally wanted to do an image in a non-photorealistic style, because Prof. Jensen showed us some slides on that topic. In particular, he showed us a boat with hatched shading, like someone had sketched it in pencil. It looked cool and I wanted to do something like it, so I decided I'd try to do one better: try to make an image that looks like it was drawn in colored pencils. This sort of evolved into wanting to do a chalk-style image by accident, when the colors I assigned to an image ended up having black as the "negative image space" instead of white. I still contend it looks pretty neat.
So, the first thing I did was implement a cel-shading-like algorithm, where instead of having a one-dimensional color texture lookup, I used a two-dimensional texture. In order to determine which texture to look up, I simply summed the red, green, and blue components of an image and then determined if it was above or below certain thresholds to set which texture to look up. To maybe explain this a little better, here are (smaller versions of) the textures I used:
You may be wondering where I got "pencil scribble" textures. I actually made them myself by buying a set of colored pencils, scribbling on a piece of paper with the black one a lot to make squares with different densities of scribble, and then scanning the paper. They turned out remarkably well.
To create the shading effect, I looked at the intensity of each pixel, and chose its color as the pixel from one of the four textures above; light areas would be looked up in the lightest texture, darker areas in the darker textures, and so on and so forth. This resulted in an image that looked like this:
This is neat, but it's kind of hard to tell what's going on in the image. It needs color.
This is about the point that I decided I wanted to make an image that looked like I did it in chalk, so I decided to basically flip the colors and the textures used from the previous image. The idea is that chalk is white on a black background, so low-density chalk would result in darker areas, and high-density chalk would result in lighter areas. Anyway, here's the result:
Already it's easier to see what everything is; I like the fact that you can now see the skull's eye socket much more clearly and you can actually tell (sort of) what the Buddha is. It still needs color, though...
Here's what the image looked like in its original color scheme, before I changed it. Note that I'm not doing any anti-aliasing here and I'm doing a rather low number of path traces per pixel; I did that in the final product only because it improved the lighting characteristics a little and for everything else, I didn't want it to take half an hour to render. You'll notice I have done path tracing and soft shadows, so you can see some light being reflected on the Buddha from the red teapot and the ground.
Not very interesting by itself. However, we know that chalk only comes in a few colors. Certainly not 2^32. So, what I did after this was compare the red to green, red to blue, and green to blue ratios on each pixel, and map large ranges of these ratios to primary colors like bright red (1, 0, 0) and bright green (0, 1, 0) and the like. Here's what I'm talking about:
Multiply that with the chalk image from before and you get this:
You'll notice that the shadows are still pretty grainy. I solved this by adding in 4x4 jittered multisampling on each pixel and averaging the results on the colors. This led to better shadows (and a much longer rendering time), resulting in this image:
Now we're getting somewhere. The contributed light in each shadow is much stronger, making the image look better, and the shadows are a little less grainy than in the previous picture. At this point I thought I was finished, but a friend pointed out that it was awfully weird that the chalk could just magically change colors at the boundary of an object. I decided that adding in some outlines would fix this problem.
In order to do that, first, I needed a depth map of the image (basically, distance away from the camera from each pixel). Luckily, that's kind of the ray tracer's job already, so I just stored the t values at each pixel and then normalized them between 0 and 1. If you show that as an image, you get this:
From this, we can use the Saito-Takahashi C0 continuity technique on the depth map above to get outlines for all of the objects in the image. That looks like this:
Add that to the chalk image, and you get my final product, which I'll show again:
At this point you may be wondering why I chose these objects. Well, I can't model and didn't feel like learning over the course of a single weekend. I started off with a sphere, and one of my friends said, "Why don't you make it like, a magic scene, where you have the sphere as a crystal ball, and you can have a skull and a candle and all of that?" That explains the skull, which I found on the Internet. However, all of the candle models I could find on the Internet were in a special .obj format that allowed quads to be defined, which our .obj loader code doesn't support. So, instead of wasting time trying to fix that, I just got the good old Buddha from Stanford and the teapot from our previous assignments, and made them all primary colors to better illustrate my rendering technique.
Anyway, that's about it. Hope you enjoyed looking at my pretty images.