dev in the making

game development, maya and code by brainzizi

Posts Tagged ‘xna

Export Maya’s custom attributes to XNA

leave a comment »

If I only knew it was this easy…

I’m doing a spaceship shooter game, and I encountered a situation where the only solution was to write a custom xml file next to every one of my models. So I started a content pipeline extension project and began twiddling. I inherited the ModelProcessor to load info from my custom xml file, and I saw a OpaqueData dictionary in the NodeContents so I decided to google it.

With some help from http://blogs.msdn.com/b/etayrien/archive/2007/03/22/opaque-data-from-max-and-maya.aspx I got exactly what I wanted without the xml info file – getting extra information from Maya to XNA.

As the link says, soo

  • 1. Add a custom attribute to a mesh in Maya
  • 2. Read it in the OpaqueData
  • 3. ???
  • 4. Profit!

Simple as that! What you actually want to do in step 3 is pass on that extra information in a Model.Tag, or Mesh.Tag from the content pipeline to your game.

Written by brainzizizi

07.16.2010 at 13:45

Spaceships and news

leave a comment »

Been doing some really simple geometry in Maya, spaceships mostly.

As you can see none of them still textured, and I probably won’t be spending much time texturing any of them as I feel so helpless doing that. I’m really not an artistic guy (I couldn’t draw a bicycle on a piece of paper), as I ventured into 3D for my own personal needs , and I feel that texturing non-organics is my limit.

So yeah, now I’m stuck with a couple of untextured spaceship models so I decided to do a little 3D top-down space arcade / roguelike kinda action RPG where the textures won’t stand out as totally bad. And I said I’d finish it by the end of summer. We’ll see…

In other news:

  • XNA 4.0 Beta – If you got the CTP version installed you have to uninstall it, but do uninstall the whole product (not piece by piece) as you’re quickly going to find a lot of problems if you try uninstalling piece by piece. I fixed my problems using the MSI Cleanup Utility.
  • Goblin Camp v001 is out. You can call it a Dwarf Fortress killer, I call it cool. Anyhow it’s anonuncing the next generation of ascii graphics city builders. If you’re so confused right now, check http://www.goblincamp.com/ and Dwarf fortress. Only for hardcore people who play hardcore games.

Written by brainzizizi

07.15.2010 at 17:48

zAnimation – exporting models from Maya

leave a comment »

This is a short tutorial which I’m also posting on the zAnimation codeplex wiki. The next one should be about building a new project with zAnimation. This was going to be a video tutorial, but my english speaking abilities sock. As well as my english writing abilities. Also I suck at modeling/animating, so this shouldn’t be taken as a modeling tutorial. It’s a tutorial on how to export stuff.  So let’s get started. Read the rest of this entry »

Written by brainzizizi

12.10.2009 at 12:57

Posted in xna

Tagged with , , ,

zAnimation – on codeplex

with one comment

zAnimation is finally on codeplex. You can find it here: http://zanimation.codeplex.com/.

It’s all very basic for now, no samples or documentation yet. The code is somewhat documented. I believe experienced people will have no problem using it. It’s just a matter of selecting the right content processor, checking out my past blog entry to write a definitions file, and writing model.Play(“Walk”); I won’t be working on the documentation or samples the next 2 weeks, my exams are still more important.

Written by brainzizizi

11.22.2009 at 12:57

zAnimation – a simple XNA animation library

with 3 comments

Before XNA 3.1, there was a bunch of animation frameworks which could to tons of stuff like interpolation between animations and stuff like that. When the 3.1 came out all of these became obsolete – except kw animation which comes with a 3ds max exporter and is great if you’re using max, but I’m using Maya and I needed to write my own animation foundation. zAnimation is a XNA library for animating skinned models exported from Maya. It supports customizable pre-clip interpolation, and per-bone animation. No interpolation between frames or animations yet.

Pre-clip interpolation:

Before a clip is played, the model interpolates over a customizable number of frames to the starting position. It delays an animation a bit but removes jerky transitions between animations.

Per-bone animation:

When defining a clip within the animation, you also define what bones does the clip affect. Based on that you can play an animation that animates all the bones in a model, and easily override the animation on one or more bones to make them move in a different way.

Below I’m listing a couple of things that I encountered while writing zAnimation:

Maya gets all your animation keyframes and exports it in a single take called “Take 001”.

To deal with this I introduced another file (the take definition file) which contains where does a certain animation start and end, and also what bones does it affect.

XNA FBX Importer removes redundant bones.

If a bone has no weights defined on a skin it gets deleted. The same thing happens if the bone doesn’t move (change) in the keyframes. So I introduced 2 special parts of the animation, the “Bind” part and the “Init” part. The bind part acts like a starting transform, and the init part is just there so you don’t forget that you have to animate a bone if you want to have it.

So based on that there are a few rules and limitations to zAnimation:

– smooth binding only

– each bone in each skin has to have some weights, so no root bones with no weights (or it won’t be imported as a bone)

– each bone has to have at least 2 keyframes that are not the same (or it won’t show up in the keyframes at all)

– strictly defined animation timeline:

-at frames 0 and 1 keyframe every bone at its bind pose position. This is the position your animation starts with.

-at frame 3 you should keyframe every bone it any position other than its bind pose. I select all my bones and rotate them in the x-axis about 45 deg.

-at frame 4 you should keyframe your bind pose again.

– after frame 4 animate your model as you wish

– when importing a model create a takes.def file in the same directory as your exported fbx is in the XNA content folders, set its build action to none from Visual Studio

– takes.def file has a specific structure that is line delimited, so the first line should look like this:

Bind, 0, 2, AffectedBone0, AffectedBone1, AffectedBone2

and each line after that should look like this:

AnimationName, StartFrame, EndFrame, AffectedBone0, AffectedBone1, AffectedBone2

here’s an example of a takes file

Bind, 0, 2, root, door
Open, 4, 34, door
Opened, 34, 36, door
Close, 36, 66, door

That’s more or less it. I’ll release it on codeplex in a couple of days. Check it out if you’re a XNA developer working with Maya.


Written by brainzizizi

11.05.2009 at 08:52

Posted in xna

Tagged with , , , ,

GameOfLife – Source code

leave a comment »

O hai! Last time I’ve posted I promised you some code so here it is.

GameOfLifeGPU is a simple project to implement Conway’s Game Of Life algorithm on a GPU. I’m using a 400×300 grid with edge wrapping, loading premade patterns from 400×300 content files and a simple mechanism for switching between those premade patterns. I’m also using a QuadDrawer class which you can find somewhere on Ziggyware.

GameOfLife.cs:


using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.IO;

namespace GameOfLifeGPU
{
 /// <summary>
 /// This is the main type for your game
 /// </summary>
 public class GameOfLife : Microsoft.Xna.Framework.Game
 {
 GraphicsDeviceManager graphics;
 SpriteBatch spriteBatch;
 private QuadRenderer quadDrawer;

 private int width = 400;
 private int height = 300;
 private RenderTarget2D gridRT;
 private Texture2D texture;

 private Effect clearEffect;
 private Effect updateEffect;

 private string currentTexture = "gliders";

 private KeyboardState keyState;
 private KeyboardState oldKeyState;

 public GameOfLife()
 {
 graphics = new GraphicsDeviceManager(this);
 Content.RootDirectory = "Content";

 quadDrawer = new QuadRenderer(this);
 Components.Add(quadDrawer);
 }

 /// <summary>
 /// Allows the game to perform any initialization it needs to before starting to run.
 /// This is where it can query for any required services and load any non-graphic
 /// related content.  Calling base.Initialize will enumerate through any components
 /// and initialize them as well.
 /// </summary>
 protected override void Initialize()
 {
 graphics.PreferredBackBufferWidth = 1024;
 graphics.PreferredBackBufferHeight = 786;
 graphics.PreferMultiSampling = false;
 graphics.ApplyChanges();

 IsFixedTimeStep = true;
 IsMouseVisible = true;
 TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 10);

 base.Initialize();
 }

 /// <summary>
 /// LoadContent will be called once per game and is the place to load
 /// all of your content.
 /// </summary>
 protected override void LoadContent()
 {
 // Create a new SpriteBatch, which can be used to draw textures.
 spriteBatch = new SpriteBatch(GraphicsDevice);

 clearEffect = Content.Load<Effect>("Effects\\clear");
 updateEffect = Content.Load<Effect>("Effects\\update");
 gridRT = new RenderTarget2D(GraphicsDevice, width, height, 1, SurfaceFormat.Color);

 texture = Content.Load<Texture2D>("glider");
 }

 /// <summary>
 /// UnloadContent will be called once per game and is the place to unload
 /// all content.
 /// </summary>
 protected override void UnloadContent()
 {
 }

 /// <summary>
 /// Allows the game to run logic such as updating the world,
 /// checking for collisions, gathering input, and playing audio.
 /// </summary>
 /// <param name="gameTime">Provides a snapshot of timing values.</param>
 protected override void Update(GameTime gameTime)
 {
 oldKeyState = keyState;
 keyState = Keyboard.GetState();
 if (keyState.IsKeyDown(Keys.Space) && !oldKeyState.IsKeyDown(Keys.Space))
 {
 string[] textures = Directory.GetFiles(Content.RootDirectory);
 for (int j = 0; j < textures.Length; j++)
 {
 textures[j] = Path.GetFileNameWithoutExtension(textures[j]);
 }

 int i = Array.IndexOf(textures, currentTexture);
 texture = Content.Load<Texture2D>(textures[(i + 1)%textures.Length]);
 currentTexture = textures[(i + 1)%textures.Length];
 Window.Title = "GameOfLife - " + currentTexture;
 }

 base.Update(gameTime);
 }

 /// <summary>
 /// This is called when the game should draw itself.
 /// </summary>
 /// <param name="gameTime">Provides a snapshot of timing values.</param>
 protected override void Draw(GameTime gameTime)
 {
 GraphicsDevice.SetRenderTarget(0, gridRT);
 updateEffect.Begin();
 updateEffect.Parameters["Texture"].SetValue(texture);
 updateEffect.Parameters["GridSize"].SetValue(new Vector2(width, height));
 updateEffect.CurrentTechnique.Passes[0].Begin();
 quadDrawer.RenderFullscreen();
 updateEffect.CurrentTechnique.Passes[0].End();
 updateEffect.End();

 GraphicsDevice.SetRenderTarget(0, null);
 texture = gridRT.GetTexture();
 GraphicsDevice.Clear(Color.Black);
 spriteBatch.Begin();
 spriteBatch.Draw(texture,
 new Rectangle(0, 0, GraphicsDevice.PresentationParameters.BackBufferWidth, GraphicsDevice.PresentationParameters.BackBufferHeight),
 Color.White);
 spriteBatch.End();

 base.Draw(gameTime);
 }

 }
}

Just simple pattern switching code in the Update region and the draw mechanism in the Draw region.

Content\Effects\clear.fx:


struct VertexShaderInput
{
 float4 Position : POSITION0;
};

struct VertexShaderOutput
{
 float4 Position : POSITION0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
 VertexShaderOutput output;
 output.Position = input.Position;

 return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
 return float4(0, 0, 0, 1);
}

technique Technique1
{
 pass Pass1
 {
 VertexShader = compile vs_1_1 VertexShaderFunction();
 PixelShader = compile ps_1_1 PixelShaderFunction();
 }
}

Content\Effects\update.fx:


texture Texture;
sampler2D TextureSampler = sampler_state
{
 Texture = <Texture>;
 ADDRESSU = WRAP;
 ADDRESSV = WRAP;
 MAGFILTER = POINT;
 MINFILTER = POINT;
 MIPFILTER = POINT;
};

float2 GridSize;

struct VertexShaderInput
{
 float4 Position : POSITION0;
 float2 Texcoord : TEXCOORD0;
};

struct VertexShaderOutput
{
 float4 Position : POSITION0;
 float2 Texcoord : TEXCOORD0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
 VertexShaderOutput output;

 output.Position = input.Position;
 output.Texcoord = input.Texcoord;

 return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
 float4 cell = float4(0, 0, 0, 1);
 float4 alive = float4(1, 1, 1, 1);
 float4 dead = float4(0, 0, 0, 1);

 float2 pixel = 1.0f / GridSize;

 float n = 0.0f;

 // count neighbours
 n += tex2D(TextureSampler, float2(input.Texcoord.x - pixel.x, input.Texcoord.y - pixel.y)).r;
 n += tex2D(TextureSampler, float2(input.Texcoord.x - pixel.x, input.Texcoord.y)).r;
 n += tex2D(TextureSampler, float2(input.Texcoord.x - pixel.x, input.Texcoord.y + pixel.y)).r;
 n += tex2D(TextureSampler, float2(input.Texcoord.x, input.Texcoord.y - pixel.y)).r;
 n += tex2D(TextureSampler, float2(input.Texcoord.x, input.Texcoord.y + pixel.y)).r;
 n += tex2D(TextureSampler, float2(input.Texcoord.x + pixel.x, input.Texcoord.y - pixel.y)).r;
 n += tex2D(TextureSampler, float2(input.Texcoord.x + pixel.x, input.Texcoord.y)).r;
 n += tex2D(TextureSampler, float2(input.Texcoord.x + pixel.x, input.Texcoord.y + pixel.y)).r;

 if (tex2D(TextureSampler, input.Texcoord).r == 1.0f)
 {
 if (n == 2.0f || n == 3.0f)
 cell = alive;
 else
 cell = dead;
 }
 else
 {
 if (n == 3.0f)
 cell = alive;
 else
 cell = dead;
 }

 return cell;
}

technique Technique1
{
 pass Pass1
 {
 // TODO: set renderstates here.

 VertexShader = compile vs_2_0 VertexShaderFunction();
 PixelShader = compile ps_2_0 PixelShaderFunction();
 }
}

The algorithm kicks in the update.fx. Space cycles the premade patterns and you can make your own patterns by inserting your own 400×300 images. Check out the premade patterns. Wrapping edges were so easy to do. Easy like writing ADDRESSU = WRAP;  ADDRESSV = WRAP;. In the CPU version they are a bit more complicated. So here you go. Simple and easy. Here’s the complete project in a zip file (73kb), which you can download from MU or RS:

http://www.megaupload.com/?d=PMV3OPJF

http://rapidshare.com/files/290162624/GameOfLifeGPU.zip

EDIT: I’ve corrected a typo in the LoadContent method. The starting texture name shouldn’t be “gliders”, but “glider”. Please correct this in your downloaded project file also.

Written by brainzizizi

10.08.2009 at 07:14

Posted in xna

Tagged with , ,

Abandoned – Shadow mapping

with 2 comments

I always wanted to implement a shadow mapping technique, ever since my first big game project called Black Sun. Black Sun was going to be a space-simulation (similar to the X series or more like Freelancer), so a lot of open spaces were involved. The most logical shadowing technique to implement in that sort of game was stencil shadows (to me than). Turns out that was a bit too complicated for my skills then (and now). I kept reading about shadow mapping and how easy was to implement it, but I just ignored that then.

Now I managed to implement my first shadow mapping technique. The official name of the procedure I implemented would be Perspective Shadow Mapping (PSM) with Percentage Closer Filter (PCF) and a screen image Gaussian Blur. The scene setup is rather simple. One directional light and the only one that casts shadows. Large ground terrain (Scale about 200 x 200 x 40) with a few models on top (Scale about 1 x 2 x 1 or smaller). The procedure goes a bit like this:

1) Render a depth map of the scene from the lights position.

This sounds very simple but is a key difference in most shadow mapping techniques. The shadow map largely depends on the type of camera you’re using to render the depth map from the light’s view. Depending on the type of projection the camera can be orthographic or perspective. Based on the amount of area it captures it can be trapezoidal, or just plain “capture all”. A lot of optimizing can be done here with the projection settings, field of view settings and the distance from the camera to your focus point. The key thing you’re looking for is depth map precision. If the focus point is too far from your camera’s position, you’ll use only a small part of the limited 32bit precision (or 64bit if your GPU supports 64bit render targets).

2) Render the depth map from your normal camera.

Not a lot you can do for optimization here.

3) Check if the distance to the light is smaller than the depth value for that pixel in the first step. If it is than light that pixel.

Here is where the PCF filter is implemented. PCF means that you take multiple depth samples from the light’s depth map, and average them out. Based on the number of samples the PCF filter can be 3×3, 5×5, 7×7, and based on the sample offsets it can be a grid PCF, rotated PCF or an irregular PCF. I used an irregular 3×3 PCF, which gave me the best results. Do be careful when comparing the depth values that they’re in the same range. Always scale down the distance with your FarClip (or FarClip – NearClip if your near clip is big enough). The reason why I used PCF 3×3 is because you can use Pixel Shader version 2.0 to implement it, while 5×5 or even 4×4 doesn’t fit in a PS2.0 ( hate the 64 instruction limit ). Or at least I didn’t manage to put them in 64 instructions.

4) Take only the lighting texture and blur it by some factor.

And you’re done with the light!

5) Render the normal scene from your normal camera and apply the blurred lighting texture on top of that.

You can optimize the algorithm in many ways. I found out that increasing the shadow depth resolution is costly, and so is blurring a 1024 x 768 texture using Gaussian blur. So I render the lighting map at half size, blur that and resize is back to 1024 x 768 giving it more blur. Also I tried to avoid complicated frustum math, so I just used a PSM with 90 FOV. More on the details and the specific shaders in the next post. Also I’m not at home now, so screen shots a bit later.

Written by brainzizizi

09.07.2009 at 15:42

Posted in xna

Tagged with , , ,