Friday, September 16, 2011

A Very Quick Blender UV Unwrapping Tutorial

I was asked for some help with UV unwapping in blender so I put together a very, very quick tutorial on it.

This tutorial was written for Blender 2.5 and will apply a simple texture to the default cube.

1. Split off a new viewport window by dragging the corner red-boxed below.

2. Change the view of the new window to UV/Image Editor

3) Select the cube and enter edit mode

4) Change to edge select mode (either press the edge select button or press ctrl-Tab and select Edge)

5) Press the red-boxed button to turn off limit selection to visible

6) Shift-right click to select the highlighted edges

7) Press ctrl-e to bring up the edge context menu and select Mark Seam

8) Press 'a' twice; once to clear selections, a second time to select everything then press 'u' to open the unwrap context menu, select Unwrap

9) At this point you should have something that looks like the following

10) Open your texture image

11) Adjust your UV mesh to cover the correct parts of the texture

12) Change the render mode of the right viewport window to textured to check the UV mapping

That's it.  Your cube is now UV mapped.  To use this in an XNA project select File -> Export and export the image as an FBX file.  After adding the FBX file to your project do not forget to copy the texture to the content directory for the project.  Do not add the texture from Visual Studio, just make sure it is in the content directory.  If you have problems loading the texture when you build your project you may have to open the FBX file and edit the texture path to be relative to your content directory.

Here is a link to the cube texture I used for this demo: cubeTexture.JPG

Saturday, August 27, 2011

How to write an input handler library for XNA 4.0

As always source code included at the end of the post

I have been gone for a while, real work had me tied up and in NYC for a while but I am home finally and I bring updates. Most of you reading my blog, like me, are interested in using the XNA framework to develop games. A big part of that is writing the graphics code and the other exciting bits. There is also all of the other code we have to write. Stuff state management, menu screens, handling input... all stuff that is very important to making a good game, but usually not as interesting as making explosions.

Fortunately XNA makes doing this a whole lot easier but it does not make the problem go away completely. This means that, for example, we find ourselves writing a whole lot of code that looks like this

KeyboardState currentState = Keyboard.GetState();
if (currentState.IsKeyDown(Keys.Space) && lastState.IsKeyUp(Keys.Space))
{
	// do something cool
}

// rinse & repeat for all of our other input keys

lastState = currentState;

This isn't too bad... BUT there are a couple of problems with this. First once you write this code it isn't really the easiest to make configurable. The best option for that would be storing the target action key, in this example Keys.Space in a variable and load that variable in some configurable way someplace else in our game. The problem with this, which is related to our other big drawback with handling input like this, is that we could potentially have these input blocks scattered across numerous different game component Update() calls. That is exactly what the other big drawback to this approach is. Changing our input handling means we potentially need to visit each of our game component classes.

What we really want to do here is be able to separate input handling from actually doing the stuff we want to do when the input happens. An excellent model for this is the event based approach for handling things like input. Well, XNA doesn't do event based input it is all polled input. Each game update loop we poll our input sources and look for specific changes. This doesn't mean we can't emulate event based input though, and when we do that we find we now have a nice separation between handling the input and detecting the input. XNA makes this even more beautiful by registering the input handler as a game component it all just starts to work.

So with all this in mind, and the strong desire to not have to write any more input handling code. I have implemented a GameComponent that can handle all of my input detection in a nice generalized way and fire off registered events when the right input actions occur. In addition the input handler provides a built in mechanism for loading input mapping from an external XML file. To make this even more useful it has been implemented as a Game Library so that I can just include it in any of my other games.

The rest of this post will cover using InputHandler in a game. In my next post I will tear apart the InputHandler for anyone that is interested in learning more about how I put it together.

To demonstrate the use of the InputHandler I will create a game that displays two spheres and lets the player move them around with various inputs.

First the input mapping I will be using for this game, this isn't strictly required but why do extra work if i don't have to. The input mapping is stored in an XML file with the following format:

<?xml version="1.0"?>
<InputMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Functions>
    <Function>
      <FunctionName>Obstacle.LeftMouse</FunctionName>
      <InputActions>
        <KeyboardInput>
          <Key>L</Key>
          <Modifiers>
            <Key>RightControl</Key>
          </Modifiers>
        </KeyboardInput>
        <MouseInput>
          <Button>LeftButton</Button>
          <Modifiers>
            <Key>RightControl</Key>
          </Modifiers>
        </MouseInput>
      </InputActions>
    </Function>
  </Functions>
</InputMap>

Our XML file defines an InputMap that contains Functions collection where we define Function that define a FunctionName and a InputActions. InputActions are a list of either KeyBoardInput or MouseInput elements. KeyboardInput and MouseInput elements may optionally include Modifies. When we instantiate an InputHandler with a file name the named XML file will be loaded into an InputMap that can be referenced by game code to map game functions to input configuration.

If you haven't done so already now would be a good time to download the GameUtility.dll.

Create a new project right click References in the solution explorer select "Add Reference". Change the Add References dialog tab to Browse and find the GameUtility.dll, select it and add it to the project.

That's it for the set up, now we will make our changes to the game class.

First add a private member to the game class to hold our InputHandler and a boolean value so we can keep track of our first time we call update.

/* Define our input handler.  We will make this a global
 * member incase we ever want to refer to it again in the
 * game class.
 */
InputHandler inputHandler;

/* Keep track of the first time
 * we call our update method
 */
private bool firstUpdate = true;

Now we are going to add a bit of code to the Initialize method. This will add our InputHandler to the game components and game services element. Adding the InputHandler as a GameComponent will cause its Initialize and Update methods to be called during appropriate moments in the games life cycle. Adding the InputHandler as a game service is optional but it makes it easier to access the handler from other components.

protected override void Initialize()
{
    /* Make our mouse pointer visible
     */
    this.IsMouseVisible = true;

    /* get a new input handler
     */
    inputHandler = new InputHandler(this, "test.xml");

    /* add it as a service so we can access it from our other game
     * game components and add it as a component so that its update
     * method is called each game update cycle
     */
    Services.AddService(typeof(InputHandler), inputHandler);
    Components.Add(inputHandler);

    /* add a new player and obstacle component
     */
    Components.Add(new PlayerComponent(this));
    Components.Add(new ObstacleComponent(this));

    /* call base initialize to init our other game components
     */
    base.Initialize();
}

Here you see we are also adding a PlayerComponent and ObstacleComponent here, we will get to those implementations later.

We are almost done with the game class. First a small change to LoadContent...

/* Add the sprite batch as a service so it can be accessed from the
* other game components
*/
Services.AddService(typeof(SpriteBatch), spriteBatch);

Like the InputHandler adding the SpriteBatch as a service will make it more accessible to our other game components.

Now the final change to the game class.
if (firstUpdate)
{
    inputHandler.Started = true;
    firstUpdate = false;
}

This just tells our InputHandler that we are ready for it to start handling input as soon as the first game update cycle processes. Of course in a real game we could turn on, or off for that matter, input handling how ever we like.

That's it we now have a running game that will handle input for us, we just need to register the actions we want to take.

In order to make this more interesting add a new DrawableGameComponent to your game project.

/* Players in this game have a texture and a position
 */
private Texture2D texture;
public Vector2 position;

/* Keep a reference to our input handler
 * so that we do not have to keep looking it
 * up from the Game.Services property
 */
private InputHandler inputHandler;

/* Some other useful information about our
 * player
 */
private bool MovingLeft = false;                    // Are we moving left?
private float buttonSpeed = 100.0f;                 // How many pixels per second do we move?
private bool MouseDrag = false;                     // Are we being drug by the mouse?
private Vector2 LeftClickOffset = Vector2.Zero;     // Were did the mouse grab us in relation to our corner?

Here we are just adding a bunch of class members to store things like out texture, position, a reference to the InputHandler (which we will look up a little later) and a few other values to manage the movement of the object.

/// 
/// Function to handle the left movement key
/// 
/// Provides a snapshot of timing values.public void moveLeft(GameTime gameTime)
{
    /* We are going to demonstrate using key down and key up
     * triggers to force one discrete action per key press
     */

    /* If we are already in our move left state do not
     * do anything else
     */
    if (!MovingLeft)
    {
	/* We started moving left so set our move left state
	 * to true
	 */
	MovingLeft = true;

	/* and move us by our time scaled offset
	 */
	position += new Vector2(
	    -buttonSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds,
	    0.0f);
    }
}

/// 
/// This method is called on our mapped left function key up event.
/// When the key is released we will leave our move left state.
/// 
/// public void stopLeft(GameTime gameTime)
{
    /* the left button was just released so leave the move
     * left state.
     */
    MovingLeft = false;
}

/// 
/// For our right movement function we will continue to move
/// as long as our mapped right function key is held down.
/// 
/// Provides a snapshot of timing values.public void moveRight(GameTime gameTime)
{
    /* move by our time scaled off est
     */
    position += new Vector2(
	buttonSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds,
	0.0f);
}

/// 
/// For our up movement function we will continue to move
/// as long as our mapped up function key is held down.
/// 
/// Provides a snapshot of timing values.public void moveUp(GameTime gameTime)
{
    /* Move up by our time scaled offset
     */
    position += new Vector2(
	0.0f,
	-buttonSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds);
}

/// 
/// For our down movement function we will continue to move
/// as long as our mapped down function key is held down.
/// 
/// Provides a snapshot of timing values.public void moveDown(GameTime gameTime)
{
    /* Move down by our time scaled offset
     */
    position += new Vector2(
	0.0f,
	buttonSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds);
}

As you can see these are all simple functions that are going to perform a single distinct action when called. You may have noticed though that the method moveLeft seems a little more complicated. This is just to demonstrate how we can leverage the fact that we actually get two events with each key press, a down event and up event.

We will also add a method to handle mouse input. This method will just make sure that the mouse pointer is in the area of the screen that sprite is currently in and then set the drag state to true. Just as with keys releasing a mouse button will fire a button up event that fire the mouseReleaseLeft method.

/// 
/// We can drag and drop our player around the screen.  If the mapped
/// button click happens over our player sprite enter our MouseDrag
/// state and remain in it until our button up event is processed.
/// 
/// Provides a snapshot of timing values.public void mouseClickLeft(GameTime gameTime)
{
    /* Get the current mouse position
     */
    Vector2 mousePos = inputHandler.MousePosition;

    /* If we are not already in drag mode
     * and our mouse click happens inside the rectangle of
     * our player sprite...
     */
    if (!MouseDrag
	&& mousePos.X >= position.X && mousePos.X <= (position.X + texture.Width)
	&& mousePos.Y >= position.Y && mousePos.Y <= (position.Y + texture.Height))
    {
	/* Enter the mouse drag state
	 */
	MouseDrag = true;

	/* And figure out the offset between the top
	 * left corner of the player sprite and the pointer
	 * at the time of the click event.
	 */
	LeftClickOffset = position - mousePos;
    }
}

/// 
/// When our mapped button is released we will leave the
/// mouse drag state.
/// 
/// Provides a snapshot of timing values.public void mouseReleaseLeft(GameTime gameTime)
{
    /* Leave the mouse drag state
     */
    MouseDrag = false;
}

Now that we have our methods that will actually handle the input we just need to tie them to our input handler. This is done in the Initialize method.

public override void Initialize()
{
    // Start the player at 0,0
    position = Vector2.Zero;

    // Get our input handler from the Game.Services property
    inputHandler = Game.Services.GetService(typeof(InputHandler)) as InputHandler;

    /* Register our key press functions.  We have a key don and key
     * up functions for the left key press and key down functions for
     * right, up and down.
     * 
     * Look up the actual key from the InputMap in our input handler.  This
     * lets us externally configure our input options.
     */
    inputHandler.MapFunctionEntry(
	inputHandler.InputMap.GetFunctionEntries("Player.Left"),
	this.moveLeft, this.stopLeft);
    inputHandler.MapFunctionEntryDown(
	inputHandler.InputMap.GetFunctionEntries("Player.Right"),
	this.moveRight);
    inputHandler.MapFunctionEntryDown(
	inputHandler.InputMap.GetFunctionEntries("Player.Up"),
	this.moveUp);
    inputHandler.MapFunctionEntryDown(
	inputHandler.InputMap.GetFunctionEntries("Player.Down"),
	this.moveDown);

    /* Register our mouse click functions for drag and drop to work correctly
     * we need a button down and a button up function
     */
    inputHandler.MapFunctionEntry(
	inputHandler.InputMap.GetFunctionEntries("Player.LeftMouse"),
	this.mouseClickLeft, this.mouseReleaseLeft);

    base.Initialize();
}

In Initialize we register our input handler methods by looking up some input definitions from our input map loaded in the InputHandler. We will pass these input definitions to our InputHandler along with either one method to be called on the key or button down event or two methods one for the down action one for the up.

Finally just two small additions to the Update and Draw methods.

In update we are just going to change the player position to follow the mouse pointer if we are in the mouse drag state.

public override void Update(GameTime gameTime)
{
    /* If we have been clicked on by the mouse and not
     * yet released update our position to follow the
     * mouse pointer
     */
    if (MouseDrag)
    {
	/* Our new position will be the current mouse position
	 * offset by the distance from the player corner of the
	 * original click.
	 */
	position = LeftClickOffset + inputHandler.MousePosition;
    }

    /* Since keyboard input will be handled by the InputComponent nothing else
     * to do here
     */

    base.Update(gameTime);
}

and in draw we just need to draw our sprite out the screen.

public override void Draw(GameTime gameTime)
{
    /* Get our sprite batch from the Game.Services property
     */
    SpriteBatch spriteBatch = Game.Services.GetService(typeof(SpriteBatch)) as SpriteBatch;

    /* Draw the player sprite
     */
    spriteBatch.Begin();
    spriteBatch.Draw(texture, position, Color.White);
    spriteBatch.End();

    base.Draw(gameTime);
}

That's it. Running the game now will display our player sprite to the screen and allows it to respond to input. If we want to change our game around so that it responds to different button or key presses it's now as easy as editing the single XML file our input is mapped from.

To make this demo more interesting I have also implemented an ObstacleComponent that is pretty much identical to the PlayerComponent just to give us a wider range of input responses.

Feel free to use this InputHandler in your own projects or just use it to learn from.
Enjoy.

GameUtilities.dll
InputMappingFramework.zip

Thursday, August 11, 2011

More XNA Cel Shading - Cel Shaded Animated Models using a SkinnedModelProcessor

This short post builds upon my previous article A Cel-Shading Example in XNA 4.0, applying what we did there to a skinned model with animation.

Before you begin
First you will need to complete and understand the Skinned Model tutorial on the MSDN AppHub site http://create.msdn.com/en-US/education/catalog/sample/skinned_model. After that this example is pretty straight forward as long as you understand what digitalerr0r did in his post XNA Shader Programming Tutorial 7, Toon shading and what we in my previous post A Cel-Shading Example in XNA 4.0.

Update CelShader.fx
First we will update out CelShader.fx and call it SkinnedCelShader.fx.  Using the Microsoft stock effects as an example add the following message to get the skinning data from the model.
/* Get the skinning data from each of the bones
 */
void Skin(inout VertexShaderInput vin, uniform int boneCount)
{
    float4x3 skinning = 0;

    [unroll]
    for (int i = 0; i < boneCount; i++)
    {
        skinning += Bones[vin.Indices[i]] * vin.Weights[i];
    }

    vin.Position.xyz = mul(vin.Position, skinning);
    vin.N = mul(vin.N, (float3x3)skinning);
}
And then call Skin from your vertex shader before making any of the other position calculations
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    Skin(input, 4);

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);

    output.Tex = input.Tex;
    output.L = normalize(LightDirection);
    output.N = normalize(mul(InverseWorld, input.N));

    return output;
}
The game class
The modifications to the game class are pretty simple.  Start with the game class you implemented in the SkinnedEffect tutorial.

Add some class members to hold our new effect data and some parameters we will need to set their properties:
/* CelShader effects and data
 */
Effect celShader; // Toon shader effect
Texture2D celMap; // Texture map for cell shading
Vector4 lightDirection; // Light source for toon shader

Effect outlineShader; // Outline shader effect
float defaultThickness = 1.0f; // default outline thickness
float defaultThreshold = 0.9f; // default edge detection threshold
float outlineThickness = 1.0f; // current outline thickness
float outlineThreshold = 0.9f; // current edge detection threshold
float tStep = 0.01f; // Ammount to step the line thickness by
float hStep = 0.001f; // Ammount to step the threshold by

// Render target for post render outlining
RenderTarget2D celTarget;

Set our light direction in the initialize method:
/* Set our light direction for the cel-shader
 */
lightDirection = new Vector4(2f, 45f, -110f, 1.0f);
And in LoadContent load our custom effects:
// load and initialize our cel shader effect
celShader = Content.Load<Effect>("SkinnedCelShader");
celMap = Content.Load<Texture2D>("celMap");

celShader.Parameters["Projection"].SetValue(proj);
celShader.Parameters["View"].SetValue(view);
celShader.Parameters["LightDirection"].SetValue(lightDirection);
celShader.Parameters["CelMap"].SetValue(celMap);

/* Load and initialize the outline shader effect
 */
outlineShader = Content.Load<Effect>("OutlineShader");
outlineShader.Parameters["Thickness"].SetValue(outlineThickness);
outlineShader.Parameters["Threshold"].SetValue(outlineThreshold);
outlineShader.Parameters["ScreenSize"].SetValue(
new Vector2(GraphicsDevice.Viewport.Bounds.Width, GraphicsDevice.Viewport.Bounds.Height));

/* Set up a render target to draw our cel shaded model to
 * for post render outlining
 */
celTarget = new RenderTarget2D(GraphicsDevice, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height,
    false, SurfaceFormat.Color, DepthFormat.Depth24);

Finally update Draw to draw our shaded model (you will notice this is pretty much identical to the way we drew the cel shaded model in my previous post).  The only trick here is that we need to get the model's texture.  We do not have that directly because its reference is baked into the fbx.  Because our model is loaded with its default effect as SkinnedEffect though we can get it from there with the following line of code:
Texture2D texture = ((SkinnedEffect)meshPart.Effect).Texture;
The full draw method:
protected override void Draw(GameTime gameTime)
{
    /* Set our render target
     */
    GraphicsDevice.SetRenderTarget(celTarget);

    /* Make sure we have a depth stencil for proper
     * depth culling
     */
    GraphicsDevice.DepthStencilState = DepthStencilState.Default;

    /* clear the graphics device with a color with a clear
     * alpha channel.
     */
    Color alpha = Color.White;
    alpha.A = 0;
    GraphicsDevice.Clear(alpha);

    /* Get our model bones from the animation player
     * so that we can pass this to the cel shader effect
     */
    Matrix[] bones = animationPlayer.GetSkinTransforms();

    // for each model in the mesh
    foreach (ModelMesh mesh in model.Meshes)
    {
        // for each mesh part
        foreach (ModelMeshPart meshPart in mesh.MeshParts)
        {
            // Set the vertex buffer and indices in the graphics device
            GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer,
            meshPart.VertexOffset);
            GraphicsDevice.Indices = meshPart.IndexBuffer;

            /* The texture of a skinned model is available in SkinnedEffect.Texture.
             * We are loading our model with the SkinnedModelProcessor and using
             * SkinnedEffect as the model's default effect. Use that to get the
             * texture of the current mesh part.
             */
            Texture2D texture = ((SkinnedEffect)meshPart.Effect).Texture;

            /* Set up a simple world, no translation, scaling or rotation
             * for this example
             */
            Matrix world = Matrix.Identity;

            /* Set the color map, world, inverse world and bones
             * properties of the cel shader effect
             */
            celShader.Parameters["ColorMap"].SetValue(texture);
            celShader.Parameters["World"].SetValue(world);
            celShader.Parameters["InverseWorld"].SetValue(Matrix.Invert(world));
            celShader.Parameters["Bones"].SetValue(bones);

            // for each effect pass in the cell shader
            foreach (EffectPass pass in celShader.CurrentTechnique.Passes)
            {
                // apply the effect
                pass.Apply();

                // and draw the current mesh part
                GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0,
                    meshPart.NumVertices, meshPart.StartIndex, meshPart.PrimitiveCount);
            }
        }
    }

    /* We are done with the render target so set it back to null.
     * This will get us back to rendering to the default render target
     */
    GraphicsDevice.SetRenderTarget(null);

    /* Clear the device to get ready for more drawing
     */
    GraphicsDevice.Clear(Color.Wheat);

    /* Draw the game model again without cell shading so we can do a side
     * by side comparison
     */
    foreach (ModelMesh mesh in model.Meshes)
    {
        foreach (ModelMeshPart meshPart in mesh.MeshParts)
        {
            foreach (SkinnedEffect effect in mesh.Effects)
            {
                effect.SetBoneTransforms(bones);
                effect.View = view;
                effect.Projection = proj;
                effect.EnableDefaultLighting();
                effect.SpecularColor = Vector3.Zero;
            }
            mesh.Draw();
        }
    }

    /* Draw the cel shaded model with outlining
     */
    spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied,
        null, null, null, outlineShader);
    spriteBatch.Draw(celTarget, new Vector2(-175, 0), Color.White);
    spriteBatch.End();

    /* Draw our debug message
     */
    spriteBatch.Begin();
    spriteBatch.DrawString(debugFont, debugMsg, debugLoc, consoleFgColor);
    spriteBatch.End();

    base.Draw(gameTime);
}

Things to watch out for:
After adding your animated model to the content project make sure you change its content processor property to SkinnedModelProcessor and then under set the default effect to SkinnedEffect.  If you miss either of these steps you will get errors.

Here is what the result will look like (cel shaded model on the left compared to a naturally lit model on the right).

You do not have the latest version of Flash installed. Please visit this link to download it: http://www.adobe.com/products/flashplayer/




The full code for this project can be downloaded here.

Good luck!

Tuesday, August 9, 2011

A Cel-Shading Example in XNA 4.0

Recently I came across an excellent cel-shading tutorial written by digitalerr0r titled XNA Shader Programming – Tutorial 7, Toon shading for the XNA 3.0 framework.  With a few minor updates we can get this working in XNA 4.0 as well.

This post will cover the changes necessary to apply the toon and edge detection shaders presented by digitalerr0r in XNA 4.0.  For a more in depth explanation of the cel-shading techniques used here please see digitalerr0r's original article.

Complete source code can be found at the end of this post.

HLSL Shaders
While it wasn't strictly necessary to update the shaders presented by digitalerr0r I chose to modify them to follow the HLSL code style preferred (inferred) by the Visual Studio effects templates.

The Toon Shader
Most of these updates are trivial variable name changes and the use of a struct for the input to the vertex shader function.  The most significant change here was splitting the composite word, view, projection matrix into three separate components.  While this might have a small performance hit (the matrix multiplication happens for each vertex) the style and use of the effect is more consistent with default effects provided by the XNA framework.  This should make the effect more recognizable to those of you that are just starting out with XNA and you more experienced programmers out there will know how to switch it back.

The Edge Shader
Again just a few minor changes here (and a  few small tweaks for correct alpha blending and more generalized scene handling).  First even though we do not have a vertex shader I am preserving the inferred effect style of the XNA templates.  Namely the input to the pixel shader is the output of the vertex shader.  Thus we still have our VertexShaderOutput struct that is the input for the pixel shader function.

Next I have replaced the float2 QuadScreenSize in the pixel shader function with an effect parameter float2 ScreenSize.  This variable is the same thing but it is set as a parameter letting the game code scale the effect to the texture that is being processed.

Finally the last change to this shader is a very small, rather subtle update to fix a problem with alpha blending in the original shader.  The return value has been changed to
Color*float4(result.xxx,1);
instead of 
Color*result.xxxx;
When we have an edge pixel result is 0 multiplying Color by result.xxxx causes the alpha channel of the color to also be multiplied by zero.  Remember that a value of 0 is a completely transparent pixel when alpha blending is on.  If we don't do this our nice black outlines could disappear on us!

Game Code
Finally ;) This is where the bulk of the changes are to use digitalerr0r's excellent shaders in XNA 4.0.  The main differences are in the way XNA 4 implements RenderTargets and applies effects.

XNA 4.0 completely reworked render targets, they are still there but the way they are set on a GraphicsDevice is different, supposedly easier and more efficient.  The new RenderTarget2D constructor that I will use takes 5 parameters, the GraphicsDevice, a width, height, color format and depth format.
celTarget = new RenderTarget2D(GraphicsDevice,
    GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height,
    false, SurfaceFormat.Color, DepthFormat.Depth24);
The important part here is that we set the depth format to Depth24.  This gives us a 24 bit depth buffer, without it we will not get proper (or any for that matter) depth culling.  Because our model for this example is rather simple we could get away with Depth16 for a 16 bit depth buffer but I went ahead and used 24.  The other options Depth24Stencil8 gives us a 24 bit depth buffer and an 8 bit stencil buffer (this is what you get when rendering to the default screen render target) and None which is no depth buffer and the default for new render targets.

The next XNA 4.0 change is setting the render targets.  We do not need to worry about render target indexes any more, just set it.
GraphicsDevice.SetRenderTarget(celTarget);
With the rework of the render targets Microsoft also changed up the device render states to make them easier to use.  Creating device states is still expensive so you will want to do that in code that is not time critical or use some form of state cache.  Setting states on a device is extremely inexpensive though and can be done as often as needed.  The important thing for us to know here is that when we set the graphics device to our render target our DepthStencilState will be None and we will not get depth culling.  Fix this by adding
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
after setting the render target.

The next change is with the effect.  In XNA 4.0 it is no longer necessary to begin and end an effect, just apply it.  Otherwise our drawing code is still the same:
foreach (ModelMesh mesh in model.Meshes)
{
    Matrix world = bones[mesh.ParentBone.Index];
    celShader.Parameters["World"].SetValue(world * rotation);
    celShader.Parameters["InverseWorld"].SetValue(Matrix.Invert(world * rotation));

    foreach (ModelMeshPart meshPart in mesh.MeshParts)
    {
        GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer, meshPart.VertexOffset);

        GraphicsDevice.Indices = meshPart.IndexBuffer;
        celShader.CurrentTechnique = celShader.Techniques["ToonShader"];

        foreach (EffectPass effectPass in celShader.CurrentTechnique.Passes)
        {
            effectPass.Apply();

            GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0,
                meshPart.NumVertices, meshPart.StartIndex, meshPart.PrimitiveCount);
        }
    }
}
Our cel shaded model is now drawn into our render target and ready for post processing edge detection.  Again the begin and end for the effect are gone, now we just pass the effect into the sprite batch when we call its begin.  (In this example the parameters for the edge effect are set in the content loading and update methods.)
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied,
    null, null, null, outlineShader);
spriteBatch.Draw(celTarget, Vector2.Zero, Color.White);
spriteBatch.End();
Here we are using an overload of SpriteBatch.Begin that takes a sort mode, blend state, sampler state, depth stencil state, rasterizer state and effect.  Because we do not need special sampling, depth treatment or rasterizing here those are all null.  We do use BlendState.NonPremultiplied to enable non-premultiplied alpha blending though and of course our edge outlining effect is passed in for the effect parameter.

That's it... with those changes digitalerr0r's great cel-shader code will be running in XNA 4.0.

Full source code for my example can be downloaded here XNA 4.0 Cel-Shader