XNA Tutorials, Samples and Thoughts
2D
2D Pie Drawing updated to 4.0
Sep 20th
UberGeekGames just provided me with an version of the Pie Drawing sample, updated to XNA 4.0
You can find it on the sample’s page, or download it directly from here.
Enjoy!
2D Skeletal Animations
Jun 14th
What is your preferred way of doing animations in 2D?
Most of you will probably answer “spritesheets”, and you’d be right. Creating animations using spritesheets is quick, easy, there are helpful resources on the net and if you work with an external artist, he only needs to give you the individual frames of the animation (which also makes his life easy).
You would want to have a framerate of at least 12 for your animations, and you soon end up with something like this:
And with minimal effort, you can write code that loads this and displays it as an animation [SpriteSheetAnimation.zip]
All is well in the world, until you realize your game needs LOTS of animations and the memory consumption goes way up, together with the time required to load all the data. Also, to limit the size, you need to limit yourself to a low FPS for the animation (like 12), which also means the animation doesn’t look as smooth as you’d like. This is where skeletal animation comes in.
When using skeletal animation, the animation is composed of several bones which are connected to one another. Affecting a bone also affects all of its children. By composing different transformations on each bone, you obtain different poses for the skeleton.
Now, if you define keyframes with certain transformations for a point in time for each of the bones in the skeleton, you can interpolate between the keyframes to obtain a smooth transition and thus animate the skeleton.
In the attached code, I used a class named Transformation, which contains data about 2D transformations, like translation, rotation and scale. Then, a Keyframe is defined by a frame number and one such Transformation. A collection of Keyframes defines a KeyframeAnimation. Finally, a SkeletonAnimation is a collection of KeyframeAnimations, one for each bone in the skeleton.
Separately, I use a Skeleton, which keeps a list of Joints that define the hierarchy of bones in the skeleton. Each bone is then assigned a certain texture, like the ones below:
Each of the parts are individually animated relative to their parent bone, and thus the animation is obtained. In the sample, the animation is stored in two XML files that are loaded directly into a Skeleton (see machine_skeleton.xml ) and a SkeletonAnimation (see machine_animation.xml ) using the ContentPipeline at runtime. Here’s a video of the sample using skeleton animation:
As you can see, it runs much smoother than the initial frame-based animation. Also, looking at the resources used, the amount of texture data loaded into memory is significantly reduced (from 5.12 Mb to only 73Kb).
A word on how the XML file was generated. There are multiple options here.
- make a tool for editing animations, where you would set-up the positions of each frame and serialize it to disk using the IntermediateSerializer.
- let your artist create the animation in a software of is choice that can output the keyframes to XML, and then write a small program that converts that XML in the suitable format to be loaded by the Content Pipeline. For the animation above, I used a Flash animation created by a friend, exported the keyframes to ActionScript3 XML, and then converted that XML into the one you can see in the sample. (I won’t release that mini-tool however, since its code is a mess thrown together in about 1 hour).
A word of warning: while skeletal animation helps solve some problems with memory, loading times, smoothness, it is not a silver bullet. The amount of detail that can go into a normal sprite-sheet animation far surpasses what can be done with a skeletal animation. In skeletal animations you are limited to certain transformations on each ‘piece’ of the animation: translate, rotate, scale, flip. Meanwhile, frame-based animation allows the artist to add any kind of effect he likes.
I hope you enjoyed this sample. Feel free to leave any feedback and questions below.
To get the code, either download it directly (SkeletalAnimation.zip) or go to the sample’s page.
Until next time,
Happy coding!
My technique for the shader-based dynamic 2D shadows
Jul 11th
It’s been a long time coming, but finally I get the time to explain the technique I came up with for drawing shader-based dynamic 2D shadows.
If you want to dive right into the code, you can go to the sample’s page.
Still here? Ok then, let’s get started.
The core of the technique is drawing all the possible shadow casters around a light into a texture, and then using a few shaders to turn this image into one containing all shadows cast in the scene. First, for a general view, consider the following scene.
Out goal is to have all objects cast shadows, with the two orange squares being the sources of light.
The first step is to build for each light a image of all the casters around it. This basically means drawing all objects with a black color into a texture, centered around the light. The technical side of this should be pretty trivial, and can also be seen in the code.
![]()
![]()
The tricky part comes next and this is the main part of the technique. I will explain the whole process a little later, but for now just know that the technique I use takes as input these “caster maps” and produces a “shadow image”, as seen below.
Having these two shadow images, it is now easy to blend them together, using the desired light color for each, and then blending the result over the “ground”.
![]()
In the end, drawing the items in the scene leads to our desired result.
Most of these steps should be fairly easy. The problem comes in getting from the image containing all the shadow casters to the image containing the shadows themselves.
The technique is really not that complicated, so I’ll explain each step, together with shader code and images. So let’s start with the beginning, namely the shadow casters image.
![]()
1. Starting from this, for each non-transparent pixel (non-white in the illustration), I output the distance from the center of the texture to that pixel (i.e. the distance from the light source to the pixel).
float4 ComputeDistancesPS(float2 TexCoord : TEXCOORD0) : COLOR0
{
float4 color = tex2D(inputSampler, TexCoord);
//compute distance from center
float distance = color.a>0.3f?length(TexCoord - 0.5f):1.0f;
//save it to the Red channel
distance *= renderTargetSize.x;
return float4(distance,0,0,1);
}
One thing to notice is that I multiply by the size of the render target and save to a floating point format. I do this in order to preserve precision. You could store this as a value between 0 and 1, and write it into a render target with the Color surface format, but this can lead to some imprecision when using large lights.
The results looks something like below (shown in grayscale for easy visualization).
![]()
2. In the next step, I divide the image into four quadrants around the light (center of this image), and distort it in such a way that all “light rays” (which are at the moment spreading in all directions from the light) are positioned in parallel. This is much easier to understand with an image, as seen below.
![]()
![]()
In the pictures above, the quadrant to the left (and the one to the right) has been distorted so it takes up half of the image, and all pixels are placed as if the rays starting from the light are parallel. The reason I am doing this will be obvious in the next step. Since I need this data for all the quadrants, I make the same operation for the vertical direction (rotating the result so it’s also horizontal).
I know the text doesn’t make as much sense as I would like but hopefully the images illustrate what I mean. Finally, to reduce memory usage and to perform more computations in parallel, I store the result of the horizontal distortion in the red channel, and the result of the vertical distortion in the green channel.
![]()
I know it doesn’t look like much, but know that all the data we need for all directions is now stored in a single texture. The code that achieves this step is the shader function below. This code can probably be simplified (to avoid the conversions between the [0,1] and [-1,1] domains, but I find it clearer this way.
float4 DistortPS(float2 TexCoord : TEXCOORD0) : COLOR0
{
//translate u and v into [-1 , 1] domain
float u0 = TexCoord.x * 2 - 1;
float v0 = TexCoord.y * 2 - 1;
//then, as u0 approaches 0 (the center), v should also approach 0
v0 = v0 * abs(u0);
//convert back from [-1,1] domain to [0,1] domain
v0 = (v0 + 1) / 2;
//we now have the coordinates for reading from the initial image
float2 newCoords = float2(TexCoord.x, v0);
//read for both horizontal and vertical direction and store them in separate channels
float horizontal = tex2D(inputSampler, newCoords).r;
float vertical = tex2D(inputSampler, newCoords.yx).r;
return float4(horizontal,vertical ,0,1);
}
3. Now that we have the distorted images of the distances from the light along each ray going out from the light, it’s time to compute the minimum along each of these rays. I do this by successive reduction of the image along the horizontal direction, until a texture of width 2 is obtained. This texture is something very similar to a shadow map in 3D, in that it contains for each ray, the minimum distance from the light where a shadow caster is present.
This step is also currently the bottleneck of the algorithm, since reducing a texture of 512*512 to a size of 2*512 requires about 9 passes (the dimension is reduced by a factor of 2 through each pass). The reduction shader is a simple one:
float4 HorizontalReductionPS(float2 TexCoord : TEXCOORD0) : COLOR0
{
float2 color = tex2D(inputSampler, TexCoord);
float2 colorR = tex2D(inputSampler, TexCoord + float2(TextureDimensions.x,0));
float2 result = min(color,colorR);
return float4(result,0,1);
}
At this point, it should be clear why I distorted the pixels in such a way (in order to be able to apply a horizontal reduction) and why the vertical components were also rotated and stored in a separate channel. Basically, we make the reductions on all directions at the same time.
Note: because this is the bottleneck, an option is to store the caster texture and do all operation on half the size of the actual light area. Thus for a light area of 512*512 you could make the processing on textures of 256*256. This way you loose some crispiness (not always a bad thing when it comes to shadows) but you also gain some performance.
4. At this moment, we can generate the shadow image. We draw the area surrounding the light, and for each pixel, we compare the distance between this pixel and the light to the distance stored in the shadow map along the same ray. This information tells us if we are in front or behind the shadow caster.
float4 DrawShadowsPS(float2 TexCoord: TEXCOORD0) : COLOR0
{
// distance of this pixel from the center
float distance = length(TexCoord - 0.5f);
distance *= renderTargetSize.x;
//apply a 2-pixel bias
distance -=2;
//distance stored in the shadow map
float shadowMapDistance;
//coords in [-1,1]
float nY = 2.0f*( TexCoord.y - 0.5f);
float nX = 2.0f*( TexCoord.x - 0.5f);
//we use these to determine which quadrant we are in
if(abs(nY)<abs(nX))
{
shadowMapDistance = GetShadowDistanceH(TexCoor
}
else
{
shadowMapDistance = GetShadowDistanceV(TexCoord);
}
//if distance to this pixel is lower than distance from shadowMap,
//then we are not in shadow
float light = distance < shadowMapDistance ? 1:0;
float4 result = light;
result.b = length(TexCoord - 0.5f);
result.a = 1;
return result;
}
The functions that read from the shadow map make an inverse transformation of coordinates in order to read from the proper location in the shadowmap.
float GetShadowDistanceH(float2 TexCoord)
{
float u = TexCoord.x;
float v = TexCoord.y;
u = abs(u-0.5f) * 2;
v = v * 2 - 1;
float v0 = v/u;
v0 = (v0 + 1) / 2;
float2 newCoords = float2(TexCoord.x,v0);
//horizontal info was stored in the Red component
return tex2D(shadowMapSampler, newCoords).r;
}
float GetShadowDistanceV(float2 TexCoord)
{
float u = TexCoord.y;
float v = TexCoord.x;
u = abs(u-0.5f) * 2;
v = v * 2 - 1;
float v0 = v/u;
v0 = (v0 + 1) / 2;
float2 newCoords = float2(TexCoord.y,v0);
//vertical info was stored in the Green component
return tex2D(shadowMapSampler, newCoords).g;
}
(Note: in the source code, you might notice a commented out version of the DrawShadowsPS function. That one was using three taps in order to smooth out the aliasing of the shadows, quite similar to what PCF method for 3D shadow maps does. This was left out because the smoothing through blur is much better looking)
Another thing to notice is that we store the distance from the center in the Blue component of the result. This is useful when we want to smooth out the shadows by applying Gaussian blur, with radius depending on the distance from the light. Thus we obtain harder shadows closer to the light source, and softer shadows further away.
5. Next in my implementation, I apply a horizontal blur, followed by a vertical blur. The code for this is not too special, except for the fact that the blur radius depends on the distance from the light. All shader source can be seen in the attached archive, and I will not reproduce the blur shader here. When doing the final blur step, I also add some attenuation to the light, and the result is finally the one we were looking for.
And this concludes the explanations about the algorithm I used for the shader-based soft 2D shadows. I hope my explanations were clear enough ![]()
You can download the source code from the sample’s page, found here.
Until next time, have fun coding!
Adding softness to shadows
Oct 1st
In my efforts to make the shadows soft, based on the formulas for penumbras, I finally realized that my method does not support physically correct penumbra softness, but I will explain the reason for this when I do the tutorial.
Until then, here’s what I came up with, after applying some Gaussian blur to the final shadow image. (variable degree of softness)
Even if it’s not physically correct, I still think the softness looks good enough.
There’s also an interesting looking result when the radius of the Gaussian Blur depends on the distance from the light…
Working on shadows…
Sep 30th
Those that follow my twitter account have seen this already, but I wanted to let everyone know I’m working on a system for 2D dynamic shadows, again.
However, this one is very different from the last sample I made on the subject. In that one, you had to define the geometry of the shadow casters, and build the shadows based on that. This process also implied lots of computations done each frame on the CPU, which yielded in low peformance. So all in all, even though it looked great, I was never really satisfied with tat technique for shadows.
I spent a lot of time thinking of an alternative way to do dynamic 2D shadows, while not using the CPU too much, and having unlimited complexity for the shadow casters. And two weeks ago, the idea hit me. I’m not going to go into technical details just yet, since I plan to make a nice tutorial about this, but I can say that my idea was based on taking the concept of shadow maps from 3D and somehow use it in 2D.
Here’s two pictures of how it looks so far:
As you can see, the casters can have any shape and complexity, and furthermore, the complexity of the shadow casters has no effect on the framerate.
I’m still working on this, but you’ll know as soon as it’s done.
Loading ToonBoom animations in XNA
Aug 29th
Last time, I talked about my experience with drawing and animating 2D images with ToonBoom. In the end of that post, I said that one way to load ToonBoom animations in XNA was to export the animation as a sequence of images, and then load these images and animate them in XNA. So today we will look at a quick way to to just that.
The exporting part is easy enough: just user File->Export Movie in ToonBoom, and then select Image Sequence as the Export Format. The result will be a collection of images, depending on the framerate you choose. The result from my cat animation can be seen in this archive.
The next step is assembling all the images in a single image, usually called a sprite-sheet. Of course, you could also simply load all the images as they are in several Texture2D variables, but working with sprite-sheets yields better performance. For the creation of the sprite-sheet, there are several options.
The first one is to open an image processing application, load all small images, and assemble them in a single image manually. You can imagine this is time consuming, and only worthy if you plan on doing this operation for a very small number of sprites.
The second option, which I used for this sample, is to write a small program that takes the images as input, and generates the sprite-sheet as you want it. My version of this was quickly hacked in a few minutes, so you can see from the source code (get it here) that it makes several assumptions:
- all input images are the same size, and are rectangular
- the output sprite will contain all input sprites arranged on a single row
- the input files are all named similarly (cat1.png, cat2.png, …, cat14.png)
While definitely not an elegant solution, it did it’s job, and I was quickly able to obtain the following image (click for larger size):
The third option, which is the recommended one for a larger project, is to use a more complex program for creating sprite-sheets. You can either create one yourself, based on certain file formats you want to use internally, or around certain restrictions you want to impose on your engine; or you can use an existing one, such as Ziggyware’s Sprite Sheet Creator. Note that if you go for this option, you’ll have to follow certain conventions in your runtime code, imposed by your program used for creating the sprite-sheets.
That being said, we now have a sprite sheet with all the frames of the walking cat animation, and are ready to load this in XNA.
After creating a new XNA project, I read through Nick’s article about Sprite Sheet Animations, and created the following class to hold all information needed for animations. For a detailed explanation, go ahead and read Nick’s article.
1: class Animation
2: {
3: Rectangle[] frames;
4: float frameLength = 1f / 5f;
5: float timer = 0f;
6: int currentFrame = 0;
7:
8: /// <summary>
9: /// Gets of sets the FPS of the animation
10: /// </summary>
11: public int FramesPerSecond
12: {
13: get { return (int)(1f / frameLength); }
14: set { frameLength = 1f / (float)value; }
15: }
16:
17: /// <summary>
18: /// Gets the Rectangle containing the current frame of animation
19: /// </summary>
20: public Rectangle CurrentFrame
21: {
22: get { return frames[currentFrame]; }
23: }
24:
25: /// <summary>
26: /// Creates an animation object
27: /// </summary>
28: /// <param name="width"> the total width of the input image</param>
29: /// <param name="height"> the height of the input image</param>
30: /// <param name="numFrames"> the number of frames in the sprite-sheet</param>
31: /// <param name="xOffset"> the X origin of the sprite-sheet</param>
32: /// <param name="yOffset"> the Y origin of the sprite-sheet</param>
33: public Animation(int width, int height, int numFrames, int xOffset, int yOffset)
34: {
35: frames = new Rectangle[numFrames];
36: int frameWidth = width / numFrames;
37: for (int i = 0; i < numFrames; i++)
38: {
39: frames[i] = new Rectangle(xOffset + (frameWidth * i), yOffset,
40: frameWidth, height);
41: }
42: }
43:
44: /// <summary>
45: /// update the animation
46: /// </summary>
47: /// <param name="elapsed"> seconds since the last frame</param>
48: public void Update(float elapsed)
49: {
50: timer += elapsed;
51:
52: if (timer >= frameLength)
53: {
54: timer = 0f;
55: currentFrame = (currentFrame + 1) % frames.Length;
56: }
57: }
58:
59: /// <summary>
60: /// resets the animation
61: /// </summary>
62: public void Reset()
63: {
64: currentFrame = 0;
65: timer = 0f;
66: }
67:
68: }
Next, I created a class for the cat, holding a few members we need for the animation.
1: class Cat
2: {
3: Texture2D texture; //sprite-sheet containing the cat animation
4: Animation walkingAnimation; //animation object used for animating
5: Vector2 velocity; //movement direction
6: float movementSpeed; //movement speed
7: Vector2 origin; //origin of the image
8: bool isMirrored = false; //draw the image mirrored
9:
10: public Vector2 Position { get; set; } //position on the screen
Nothing really special here… Maybe except the isMirrored variable. We use this because our image for the cat shows it facing left. So when we want it to move towards the right, rather than creating a separate sprite with the cat facing right, we mirror the existing sprite. Of course, you can’t always use this trick (or a right-handed character suddenly becomes left-handed), but there are many cases when this trick is enough.
The constructor is straightforward, with some hard-coded values tweaked until I was satisfied with how things looked.
1: public Cat(Texture2D texture, int frameCount, Vector2 origin)
2: {
3: this.texture = texture;
4: //create a new animation object
5: walkingAnimation = new Animation(texture.Width, texture.Height, frameCount, 0, 0);
6:
7: //tweak the FramesPerSecond and movementSpeed values until you're satisfied with how things move
8: walkingAnimation.FramesPerSecond = 14 * 3;
9: movementSpeed = 256;
10:
11: //reset position
12: Position = Vector2.Zero;
13:
14: this.origin = origin;
15: }
For movement, input from both keyboard and gamepad is analyzed, and the velocity’s value is updated.
1: public void HandleInput()
2: {
3: KeyboardState keyState = Keyboard.GetState();
4: GamePadState gamepadState = GamePad.GetState(PlayerIndex.One);
5:
6: velocity = Vector2.Zero;
7:
8: if (gamepadState.IsConnected)
9: {
10: velocity = gamepadState.ThumbSticks.Left;
11: velocity.Y *= -1;
12: }
13:
14: if (keyState.IsKeyDown(Keys.Left))
15: velocity.X = -1.0f;
16: if (keyState.IsKeyDown(Keys.Right))
17: velocity.X = 1.0f;
18: if (keyState.IsKeyDown(Keys.Up))
19: velocity.Y = -1.0f;
20: if (keyState.IsKeyDown(Keys.Down))
21: velocity.Y = 1.0f;
22: }
In the Update function, we first look which way the cat is facing, and update the value of isMirrored. Then, if the cat is moving, we update the animation and position on the screen.
1: public void Update(GameTime gameTime)
2: {
3:
4: //mirror the cat if we are moving towards the right
5: if (velocity.X > 0.1f)
6: isMirrored = true;
7: if (velocity.X < -0.1f)
8: isMirrored = false;
9:
10: //normalize velocity vector
11: if (velocity.Length() > 1.0f)
12: velocity.Normalize();
13:
14: //get elapsed seconds
15: float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
16:
17: //only animate if we are moving
18: float speed = velocity.Length();
19: if (speed > 0.0f)
20: walkingAnimation.Update(elapsed * speed);
21:
22: //update position
23: Position += velocity * elapsed * movementSpeed;
24: }
Finally, the Draw function takes as a parameter the active spriteBatch, and draws the current animation frame using it. Here we can see how to mirror the sprite using SpriteEffects.FlipHorizontally.
1: public void Draw(SpriteBatch spriteBatch)
2: {
3: SpriteEffects spriteEffect = SpriteEffects.None;
4:
5: //mirror the image if necessary
6: if (isMirrored)
7: spriteEffect = SpriteEffects.FlipHorizontally;
8:
9: spriteBatch.Draw(texture, Position, walkingAnimation.CurrentFrame,
10: Color.White, 0.0f, origin, 1.0f, spriteEffect, 1.0f);
11: }
With this class created, using it in our Game class is trivial. Simply load the texture in LoadContent() and create a Cat object, update it’s input and internal state in Update() and draw it in Draw().
1: public class Game1 : Microsoft.Xna.Framework.Game
2: {
3: GraphicsDeviceManager graphics;
4: SpriteBatch spriteBatch;
5: Cat cat;
6:
7: public Game1()
8: {
9: graphics = new GraphicsDeviceManager(this);
10: Content.RootDirectory = "Content";
11: }
12:
13: protected override void LoadContent()
14: {
15: spriteBatch = new SpriteBatch(GraphicsDevice);
16:
17: //load cat texture
18: Texture2D catTexture = Content.Load<Texture2D>("catWalk");
19:
20: //create cat object
21: cat = new Cat(catTexture,14,new Vector2(64,128));
22:
23: //place it in the center of the screen
24: cat.Position = new Vector2(400, 300);
25: }
26:
27: protected override void Update(GameTime gameTime)
28: {
29: // Allows the game to exit
30: if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
31: this.Exit();
32:
33: //update cat's input
34: cat.HandleInput();
35: //update cat's state
36: cat.Update(gameTime);
37:
38: base.Update(gameTime);
39: }
40:
41: protected override void Draw(GameTime gameTime)
42: {
43: GraphicsDevice.Clear(Color.CornflowerBlue);
44:
45: spriteBatch.Begin();
46: //draw cat
47: cat.Draw(spriteBatch);
48: spriteBatch.End();
49:
50: base.Draw(gameTime);
51: }
52: }
If you run the game now, you’ll be able to move the cat around the screen with the keyboard or the mouse. As you can see, getting an animation from ToonBoom into an XNA game is not difficult at all.
I hope you enjoyed this short post, and if you did, you can download the source for this sample here: ToonBoomAnimationSample.zip
New Sample: XNA GS 3.1 Video Support
Jun 11th
You probably heard by now that XNA Game Studio 3.1 is out.
After a quick download, uninstalling 3.0 and installing 3.1, I quickly put together this sample that shows how to use the new support for videos.
More info on the sample’s page, here.
Or, if you’re in a hurry, here’s the direct link to the download: VideoSample.zip
World of Goo Cursor sample
Jan 26th
As an exception, I will post the sample for now, and come back with the informative and explanatory blog post in a few days, since my exams don’t allow me too much XNA work at once.
So the first sample deals with the XNA implementation of something similar to the mouse cursor encountered in World of Goo. My blog post later this week will contain more information about how I built the sample, but until then, you can try it out, and play with it.
To download it, access the sample’s page, here.
Have fun toying with the configurable parameters!
Can a 2D image intersect a 3D model?
May 19th
Yes it can
My may sample is also my first public sample written in XNA Game Studio 3.0 CTP, and it shows how to restore the depth buffer from a depth texture.
This way, models drawn to a render target, with post processing applied to them can intersect and obscure normal models, drawn after all the post processing is done.
For more details, jump to the sample’s page: Restoring the Depth Buffer, where you can find a short explanation on how the sample works.
To dive right into the code, download it here. Please note that the sample is written in XNA Game Studio 3.0 CTP, but the technique also works just fine in 2.0.
April Sample Online!
May 2nd
I finally finished the April sample. I know it’s May already but the MVP Summit and the Easter Holiday took most of this month
So for April we have Dynamic 2D Shadows. Check it out in the Samples section, and let me know what you think. Or download it directly, here.
I hope you will enjoy this sample.



