Hi, and welcome to tutorial 7 of my XNA Shader Tutorial series. Today I will cover a simple algorithm for rendering a non-photorealistic scene using Cel shading/Toon shading, using HLSL and XNA 3.0.
Executable and source-code can be found at the end of this article.
To implement this effect, we need two shaders:
(a) The toon shader will add lighting based on a look-up texture, by using the diffuse algorithm covered in XNA Shader Tutorial 2( see gamecamp.no or come to my presentations at NITH, Oslo ).
(b) A post process edge detection algorithm.
First of all, we render the scene with the first shader(a) to a render target, and then we use this texture in shader (b) to find the edges and finally combining the edges with the scene:
Shader (a) + (b) results in the final output color.
Cel/Toon shader
To create the cel/toon shading shader we compute the diffuse light ( N dot L ) and use this as a texture x-coordinate:
Tex.y = 0.0f;
Tex.x = saturate(dot(L, N));
float4 CelColor = tex2D(CelMapSampler, Tex);
where CelMapSampler sampler for a 2D lookup texture(resolution 32×1) looking like this:
if the angle between L and N is large( dot product = 0 ) the texture at coordinate 0.0,0.0 will be used. If the angle between N and L is 0( dot product = 1 ) the pixels at coordinate 1.0,0.0 will be used, and anything inbetween will range from 0.0->1.0. As you can see on the texture, only 3 different colors is used.
By returning the CelColor from the pixel shader, the output will be the diffuse shading using the colors in the lookup texture:
But we want textures as well. This can simply be done in the same way as in Shader Tutorial 2, but instead of using the diffuse color multiplied with the texture color, we can multiply the texture color with the toon-shaded diffuse map CelColor:
return (Ai*Ac*Color)+(Color*Di*CelColor);
The result of this shader will look like this:
Not very hard eh? 🙂
Ok. This looks pretty good and can be used. But in some cases, one might want to have outlines like many drawings have.
– One approach to this is by first rendering the culled version of the object totally black, and then rendering the cel-shaded version of the object, but a tiny bit smaller,
– Another approach is to render the scene to a texture, and applying post process edge detection shader to the scene. This is how we are going to do it in this tutorial.
Post process Edge Detection
The edge detection shader in this shader is a kernel filter with the following matrix:
A kernel filter works by applying a kernel matrix to every pixel in the image. The kernel contains multiplication factors to be applied to the pixel and its neighbors. Once all the values have been multiplied, the pixel is replaced with the sum of the products. By choosing different kernels, different types of filtering can be applied.
Applying this shader to a texture will create a black and white texture, where the edges are black and the rest is white.
This makes it very easy to create combine the normal scene with the edges:
Color*result.xxxx;
Where Color is the scenetexture, and result.xxxx is the edge detection texture.
When multiplying Color with result, all pixels that is not a part of an edge is white(in result ) and is the same as 1.0, and edges is 0.0( black ). Multiplying Color with 1.0 equals color, and multiplying color with the black edges( 0.0 ) will result in a 0.0( black color ).
As you can see, toon-shaders is not very hard and can easily be implemented in any scenes with a few lines of code. If you haven’t yet done so, download the executable files and the source, and start experimenting!
NOTE:
You might have noticed that I have not used effect.commitChanges(); in this code. If you are rendering many objects using this shader, you should add this code in the pass.Begin() part so the changed will get affected in the current pass, and not in the next pass. This should be done if you set any shader paramteres inside the pass.
Thanks for the great tutorial! Would you mind explaining how you could limit the line detection to a single model? The current tutorial overwrites the entire scene with the buffer.
Hi, great tutorial. I only have a problem with it. It only renders one object and leaves out all the other things i want to render aswell, like my terrain. I tried adding effect.CommitChanges() before AND after effect.Begin(). Wasn\’t sure where to put it exactly. But it seemed to have no affect…I also tried setting RenderTargetUsage.PreserveContents, but still no luck. I just see that one object on which i applied the shader. Is it possible at all to use this shader with more objects..??Do you have any idea what the problem could be?
thanks for uploading these i’m really fascinated by shader programming. i want to learn it in school but mine doesn’t teach it. if i taught myself, what math do you recommend i really know to design my own toon shadersg? I mean what subjects in trig, or algebra besides the dot product?
now with khan academy its so easy to learn math.. i have to try.
Thank you for considering giving a small donation! Any donations is really apprechiated, and will go to creating more content and tutorials on this blog.
Kule tutorials, har du en samleside for alle disse? 😀
Yeah, i got a collection of all the other tutorials at gamecamp.no, but I will convert them all to XNA 3.0 and post them here on this blog 🙂
Very nice and easy-to-follow tutorial! Great work!
Thanks for the great tutorial! Would you mind explaining how you could limit the line detection to a single model? The current tutorial overwrites the entire scene with the buffer.
Hi, great tutorial. I only have a problem with it. It only renders one object and leaves out all the other things i want to render aswell, like my terrain. I tried adding effect.CommitChanges() before AND after effect.Begin(). Wasn\’t sure where to put it exactly. But it seemed to have no affect…I also tried setting RenderTargetUsage.PreserveContents, but still no luck. I just see that one object on which i applied the shader. Is it possible at all to use this shader with more objects..??Do you have any idea what the problem could be?
http://www.wholesaleedhardyca.comhttp://www.vibramfivesfingers.comhttp://www.cd-encyclopedia.com
http://www.mtboutlets.com/http://www.us-dioroutlet.com/http://www.newbalanceshoes-outlet.com/http://www.us-pumaoutlet.com/
http://www.mtboutlets.com/ MBT Shoes in fashionhttp://www.us-dioroutlet.com/ Cheap Dior shoeshttp://www.newbalanceshoes-outlet.com/ Discount New Balance shoeshttp://www.us-pumaoutlet.com/ Discount PUMA Outlet
http://www.nike-airjordan-shoes.comhttp://www.handbagshunting.comhttp://www.airmax-stores.comhttp://www.sunglass-mall.comhttp://www.timberland-outlets.com
“When they commit a http://www.nikeshoes-outlet.com violation, it’s like a waiting game,” he said of the parolees he often faces. “When they walk in, they don’t http://www.nikeshoes-outlet.com know when they’ll be leaving, so they’re often on edge. We don’t know what’s in their minds. A lot of http://www.nikeshoes-outlet.com these guys take it very personal.”
Thanks for the great tutorial! I have updated the example to XNA 4.0 and would be happy to send it to you if you like.
Thanks, can you post the link and I’ll add it to the tutorial 🙂
Cheers!
Of course… http://adventureincode.blogspot.com/2011/08/cel-shading-example-in-xna-40.html
I figured I might as well start blogging what I am learning.
Thanks again for the great tutorial.
thanks for uploading these i’m really fascinated by shader programming. i want to learn it in school but mine doesn’t teach it. if i taught myself, what math do you recommend i really know to design my own toon shadersg? I mean what subjects in trig, or algebra besides the dot product?
now with khan academy its so easy to learn math.. i have to try.
Hurrah! Finally I got a webpage from where I be capable of actually obtain valuable data concerning my study
and knowledge.