Skip to main content
GameDev.net gamedev.net
🔒 Locked

Cartoon Rendering

Started by Sante05 Apr 2, 2005 at 4:39 PM 5 replies 1.2k views
Original Post
Sante05
Sante05
Hi, I'm trying to implement the cartoon rendering technique into my next game. I already shade the objetcs by using a lookup texture and can draw a silhouette around them using the Stencil buffer. What I want to do now, is to mark with black lines the most prominent edges of the object. I've read some tutorials, but couldn't find a good way to do it, can someone give me a hint? FYI, I'm using DirectX 8.1 Thanks.
-----DevZing Blog (in Spanish)
tolaris
tolaris
Quote:
Original post by Sante05
What I want to do now, is to mark with black lines the most prominent edges of the object. I've read some tutorials, but couldn't find a good way to do it, can someone give me a hint?

http://www.booyah.com/article05-dx9.html <-- might help you. (no idea if you can use it straight in dx.8 ... though msdn says it's possible with fxc.exe and D3DXAssembleShader() )

"The calculation finds an edge vertex by computing N * E (vertex normal dot vertex-to-eye vector). If N * E is close to 0.0, that means the two vectors are near perpendicular, which implies that we're gazing at an edge (given our current eye position); thus, the vertex is darkened. The result of N * E once again is clamped to [0.0 to 1.0] and looked up into the edge texture, which contains dark "inked" values at 0.0 and light values at 1.0."

a cheap way to simulate fresnel effect, by the sound of it.
hplus0603
hplus0603
You really want to do something in screen space, typically using render targets.

If you're on a platform where you can read depth data, such as DX9 with a render target with depth, or OpenGL with depth textures, then you can decide to put a black pixel in any spot that has at least one neighboring pixel that's significantly less deep into the screen. This does edges, but not creases.

If you're on DX8, then you can fake it, by calculating the range between the nearest and the furthest part of the object (or the object's bounding volume), and mapping that range to alpha between 0 and 255. Then, copy the data to a render target, and use a pixel shader that outputs black if the render target alpha has a high transient, and transparent otherwise.

To do creases well, you have to calculate local curvature along edges, and then draw the creased edges manually. I haven't seen a really convincing screen-space crease detection solution yet, so that's probably your best bet. For each edge, look at the triangles connecting at that edge; if their face normals (normalized) dotted is smaller than some tolerance, turn the edge into a crease. You can sort-of do this by drawing normals to a render target, and then post-filtering, but then you typically get a two pixel wide line at each crease, which is too thick, so lines work better.
enum Bool { True, False, FileNotFound };
Sante05
Sante05
Quote:
The result of N * E once again is clamped to [0.0 to 1.0] and looked up into the edge texture, which contains dark "inked" values at 0.0 and light values at 1.0."


Yes, I already knew of this technique (similar to the one used for shading, just calculating N * E instead of N * L). However, the results aren't so good, and the outline's width isn't regular, changing depending on the object's shape.

Quote:
If you're on DX8, then you can fake it, by calculating the range between the nearest and the furthest part of the object (or the object's bounding volume), and mapping that range to alpha between 0 and 255. Then, copy the data to a render target, and use a pixel shader that outputs black if the render target alpha has a high transient, and transparent otherwise.

To do creases well, you have to calculate local curvature along edges, and then draw the creased edges manually. I haven't seen a really convincing screen-space crease detection solution yet, so that's probably your best bet. For each edge, look at the triangles connecting at that edge; if their face normals (normalized) dotted is smaller than some tolerance, turn the edge into a crease. You can sort-of do this by drawing normals to a render target, and then post-filtering, but then you typically get a two pixel wide line at each crease, which is too thick, so lines work better.


Didn't want to use pixel shaders, as the game is targetted towards lower-end computers that might not have that kind of hardware available. However, calculating the creases and drawing them as lines sounds good, and I bet it wouldn't have a deep impact in performance, as most of the work can be preprocessed.

I'll play with that idea and experiment to see what I can get, thank you.
-----DevZing Blog (in Spanish)
izzo
izzo
If you calculate the creases and then draw them as lines, you can also do funky stuff like in the animated tv show Dr Katz (they call it Squigglevision). You can subdivide the lines a couple of times (in a pre-process step) and then shift the end points by small random amounts at runtime so it looks like they've been hand-drawn and the animator hasn't drawn them exactly the same each time. Also you could draw the lines a couple of times to give it a sort of overdrawn look, as though they've drawn the line a couple of times. Maybe use a texture for the lines too if you can.

cheers
sam.
superpig
superpig
Quote:
Original post by hplus0603
If you're on a platform where you can read depth data, such as DX9 with a render target with depth, or OpenGL with depth textures, then you can decide to put a black pixel in any spot that has at least one neighboring pixel that's significantly less deep into the screen. This does edges, but not creases.
Hmm. What if you extended that to a full-blown edge detection filter, using the depth buffer as the source data?
Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.