Wednesday, April 11, 2007

Precomputed Vertex Color Lighting

While setting up the nights level of soft museum, I reached the point of working indoors. 1 directional light for the sun was not going to cut it anymore. I needed lots of point lights to replicate the lighting inside of the museum. For simplicity (laziness) I descided to go with precomputed static lighting for the terrain, and each placeable mesh would be dynamic lit with 1 or more point lights assigned to it.

For the terrain lighting I set it up in 3d studio max with the color-per-vertex tool. The tool computes vertex color values based on all the lights in the scene, and even takes into account shadows and radiosity. So I exported my terrain as usual but put vertex colors instead of the normals into my file. I modified my shader to use the colors instead of normals and loaded up the game. It looked terrible! the colors were clearly sitting on the wrong verticies. I checked and rechecked and I was getting the vertex colors with the exact same indexes that I had been getting the normals with. So why were the normals correct and the vertex colors wrong?

Answer: 3d studio uses a whole different vertex channel/buffer for color verticies, just as it does for texture verticies. There is no 1-to-1 ratio of Position&Normal vertecies with color verticies. The solution was to compromise and only take the vertex colors that lie on a texture vertex (being there are more texture verticies than position verticies). So when exporting a mesh,
for each texture vertex in the mesh
{
for each polygon that referances that vertex
{

  • get the same polygon from the position buffer and the same polygon index (1,2,or 3) that referanced the texture vertex I am on, and save this position value
  • get the same polygon from the color-per-vertex buffer and the same polygon index (1,2,or 3) that referanced the texture vertex I am on, and save this color value
}
  • for however many position values were gathered, I checked to make sure they are all the same value. If not then there are problems problems and the easiest choice will be to break up the mesh polygon by polygon( the correct choice though is to explode all buffers then un-explode them while combining vertex that are the same in all 3 buffers) (so far I have never run into this, I always have more or the same texture vertex than I do position vertex)

  • for however many color-per-vertex values were gathered, average them (some values might be lost, but if anything it will look more blended. If I am sharing a texture coordinate between two polies then I might as well share the color.)

  • output the texture vertex, 1 of the position vertex (that should all be the same), and the averaged color vertex
}

then to output the index buffer I just use the texture-polygon index buffer which will now map to each of the 3 buffers.

Tuesday, March 13, 2007

dynamic blocks of unmanaged memory in XNA

In XNA, a problem ive found with using structs instead of classes is that in order to have referances you need pointers, and pointers are really annoying and impractical to use in managed code.
So how can you get unmanaged blocks of memory?

Stackalloc: this only works if you need a block on the stack, and is useless if you want to keep the memory to use throughout the life of your game.

Heapalloc: this is a good choice if you are writing a game for windows, but the .net compact framework does not offer this interop service, so it is not possible if you want your game to work on xbox 360.

the GCHandle struct: this is the only way I have found to do it. A GCHandle is a struct which holds the address,size and type of a block of Managed memory. You might be thinking, "What is the use of a handle to managed memory? I thought we want unmanaged memory so we can use pointers in it?" Technically it is managed, but in all practical sense it can be "unmanaged" by getting the handle using GCHandleType.Pinned. With an address to pinned memory, you can use pointers all you like and know that what you expect to be there will actualy be there.

here is how you would get the handle to a block of memory:
MY_STRUCT[] mybuffer;
mybuffer = new MY_STRUCT[100];
GCHandle pinbuffer = GCHandle.Alloc(mybuffer,GCHandleType.Pinned)


here is how you would get a pointer to use in your buffer:
MY_STRUCT* mypointer = (MY_STRUCT*)pinbuffer.AddrOfPinnedObject().ToInt32();
now you can use that pointer all you like,or you can cast it into different pointers, or you can do whatever, just dont overrun the buffer.

you must explicitly free your memory like this:
pinbuffer.Free();


Lastly, I am still a newbie at managed programming, so if anythign I said is incorrect I opologize. Though this method has worked very well for me, and on critical areas I get a nice performance boost by using structs and pointers instead of classes and class referances.
Not to mention it feels more like home.

Monday, March 12, 2007

Dream Build Play

I like most XNA users am aiming to enter the DBP competition. I cannot use the NiGHTS clone of course being it is a clone;P. So I descided to continue working on it to develop the engine I will use for the DBP entry. I have teamed up with my good 3d artist friend for the contest. He will be doing the artwork, I will be doing the programming, and we both will be doing the designing.

The basic plan at this stage is a track-based flying shooter. The player will be moving along a 3d track at a speed he cannot control. (very fast :)) What he can control is his offset from the track
and of course he can aim and shoot. The setting will be thick forest and ruins, most of the game will be up in the tree cannopy, but some will be down near the forest floor and some in caverns under the forest. There are many more aspects to the game but they wont be documented at this point (top secret :)) (also we havent thought of them yet).

Forest means thick, thick, view blocking, totaly immersive vegitation. This will be a challenge, but I have made the silly goal of trying to rival speedtree with my vegitation system. :) So far, all I have is some grass which I will be testing in the NiGHTS game to get it thick, detailed, and covering everything. After the grass will be leaves, mushrooms, flowers, sticks and various fungus. Then will be plants, tall weeds and vines. Then will be Trees and hanging vines all thickly covered in leaves. Then will be things blowing through the air like leaves, spores, twigs and grass if it gets disturbed enough. Basically I plan for this vegitation system to be over the top and will push the xbox gpu to the rendering limit for the 360 version, and a geforce 8800 to the rendering limit for the pc version. I do not plan to do any kind of collision or fancy render effects with the vegitation and will devote everything to pure polygon pushing. My biggest fear is that I know I will run out of video memory on the 360, so I will have to have a thread to load in new chunks. For now I will just focus on PC version so I have plenty of mem to work with. The goal for this system is to get a player to think "I cannot name a game that has this much vegitation on screen!" This of course is useless without an incredibly fun game, but a goal none the less. This pure volumn of vegitation will be achieved by relying on the fact that you are moving very fast and that you are only viewing the scene from 1 direction. That is the 1-up on FPS games which need to draw vegitation that is acurate from all angles, and that will be closely inspected by the user. Not to mention the viewable distance in this game will be very short.

Billboarded Animated Sprites

(History blog)
I had thought these would be very easy, I had a sound plan for the sprite animation which was implemented smoothly. The textures for a sprite were setup with the frames being placed side by side in the bitmap. The shader received a framenumber and the width of each frame image, then added width*framenumber to the texturecoordinate x. The billboarding and rendering though, ended up being the most terrible system of code ive ever developed.
These where some things I had to take into account when designing the system:

1. sprites must be part of the scene depth buffer (that ruled out using spritebatch)
2. point sprites are crappy (mostly because I could not get them to work ;))
3. sprites do not need to be lit by scene lights
4.sprites will need to be able to have collision tests on each one
5.there will be thousands of sprites
6.sprites are part of larger sprite objects, the sprite objects have linear animations they perform on their child sprites


The method I chose was:
1. keep a single quad for each type of sprite
2.calculate a billboard rotation matrix
3. go through each spriteobject in a active grid area and:
1.update the animated locations of the childsprites
2. maintain of worldmatrix stack that include the animation translations and rotations from the sprite object animations, set rotation to identity, add the billboard rotation, render, and pop stack back to animation object to process the next child sprite

This turned out to be the most slow, crappy, useless, just plain wrong way to handle these billboard-sprites. With any decent amount of sprites on screen my framerate would drop to 40 or lower due to the tons of small draw calls.


After much considering I conluded the only way to do this is do the billboarding and position animation in a shader. Though this way uses more graphics memory being you have a buffer of all child quads in a sprite object. In order to do the bilboarding the rotation center of each quad must be known by the shader. Being the billboards do not need to be lit by the scene, normal was used to hold the position of the rotation center.
Bascialy the same process was used but this time in the shader. so a whole sprite object could be rendered all at once, giving the shader the billboardmatrix, worldmatrix for object, and position animation data to calculate for the child quads. This improved method was many times faster and works quite well. Framerate is minimaly effected by the volumn of sprites rendered.

So, a big lesson was learned implementing this system of billboarded sprites, using many draw calls is very very slow.

Shaders

(History blog)
The first level I was doing was Soft Museum but the problem was, it was not at all soft. The ground is suppose to behave like rubber or a trampolene in that level, and I was not sure how to implement this. Changing the vertex in the buffer each frame would be much to slow, the only choice was doing something in the shader. After some research on shaders, I made a vertex shader to take a parameter which is the position of the character, and if a vertex is within a certain distance of this position, then offset it by an amount based on how close it is to the position. The closer the vertex to the character, the more the vertex is offset. For bouncing back into shape when the character leaves an area of terrain quickly (jumps or something), I added a faked-physics animation to the offset range. This method turned out to be very nice looking after some tweaking.

Next I needed the final render to be softer, I was not using any kind of texture sampling being the NiGHTS textures were not bled, so it was very pixilated and ugly the closer the camera was to a texture. I did some research on post processing shaders and render targets, and developed a glow/blurr/blend 3-pass shader. The results after some tweaking were again very nice.

During this time I also added scrolling backgrounds, which still to this day need some work being they scroll rather unnaturaly.

3D Animation

(History blog)
This was a daunting task for a 3d newbie. Needing some animations to work with, I went back to hacking to extract some animations for the character Claris. After some tedious days, I had most of claris' animations at my disposal. I created an export script in 3d studio to get them into a basic file format of keyframed euler rotations. Now what? I was asking myself that often over the next few days;P
I better explain how the models and animations where stored in NiGHTS. A 3d model is an array of meshes, one for each bodypart. An animation key-frame is an array of XYZ-local-euler rotations for each mesh. An animation is an array of key-frame arrays and a speed to interpolate them. It was a fairly basic setup compared to the complex bone/IK/morph target deforming a skinned mesh system that games use today.
After alot of trial and error, I had the body parts finaly being rendered on screen based on the keyframes which looked like Claris was having a seizure, flailing her limbs all over the place. After alot more trial and error, I had the animation working correctly (I learned the important lesson that you cannot multiply matricies in any order you feel like).
Getting the animation working and testing the efficiency by rendering several hundred animated Claris' all running around on screen made me feel pretty hot, as if I was a pro at efficient use of XNA all ready. But when I latter tackled billboarded sprites, which turned out to be the most unefficient, slow, and downright crappy system I have ever written, I learned my lesson;P

Basic Animation Structure:
enum enumBodyPart//array indexes for each body part
{
PELVIS, CHEST, HEAD, R_SHOLDER, R_ARM, R_HAND, L_SHOLDER, L_ARM, L_HAND, R_LEG, R_CALVE, R_FOOT, L_LEG, L_CALVE, L_FOOT
}

struct BODY_PART
{
public VertexBuffer vb;//vertex (position,texture,normal)
public IndexBuffer ib;//index
public int NumPrimatives;//number of triangles in mesh
public Vector3 RootPos;//root position of bodypart (static position, standing up with arms out)
}

struct ANIMATION_FRAME
{
public Vector3[] Rotations;//array of each bodyparts euler rotation for the frame
}
struct ANIMATION
{
public int NumFrames;
public float Speed;
public ANIMATION_FRAME[] Frames;//each frame
}

struct FRAME_INFO
{
public int AnimID;//animation index
public int FrameID;//frame index
}

struct ANIM_OBJ
{
public Vector3 Pos;//position vector
public Vector3 Dir;//direction vector
public Vector3 Rot;//rotation eulers
public BODY_PART[] body;//each body part
public Texture2D tex;
public ANIMATION[] Animations;//animations
public FRAME_INFO CurFrame;//active animation
public FRAME_INFO NextFrame;//animation to interpolate to
public float LastFrameTime;//gametime of last frame interpolation
}

Animation Video: Claris Exploring Soft Museum

Terrain

(History blog)
My first step was to create a terrain engine. I needed a method that would work well with the NiGHTS terrain I had, a method that would be fast to render, a method that would work as a general level partitioning system, and a method that would be easy for a beginner to implement (most important ;)). I chose to use a method simular to that which the sonic team used, which I discovered while hacking NiGHTS. A grid of grids (I will call the smaller grids nodes).

Clarity note:Sega saturn uses a quad rendering system, and each quad(2 polygons) has a texture that covers the entire quad. It is basicaly a 3d tile system(as you can see from the texturemaps in my last blog).

Each terrain node consists of 8 by 8 tiles. A terrain grid consists of x by y nodes. My rendering system uses this grid as the level partitioning grid, so not only does each grid hold a node, but it also holds a list of placeable objects within that node, event objects, and anything else that has a position. The culling system culls these 8x8 nodes, and the hittesting tests only within an active node. So, using this method I had culling, collision, object rendering, and position-based event triggering all ready to be implemented with minimal complexity.

Basic Structure of Terrain:

struct TERRAIN_NODE
{
public VertexBuffer vb;//vertex holds position texture and normal
public float[] Heights;//8x8 heights used for terrain collision testing
public float BSphere;//bounding sphere radius, used for culling
public vector3[] BBox;//bounding box,used for more accurate culling
//after this comes any other systems that are stored per node
//example
public PLACEABLES Placeables;
public VEGITATION Vegitation;
}
struct TERRAIN_GRID
{
public int Width;//map withd
public int Height;
public int ActiveNode;//index of node used for collisions
public TERRAIN_NODE[] Grid;
public IndexBuffer ib;//index buffer used to render a node
public Texture2D texture;//terrain texture (this would be the tiled texture from my first blog)
}

During the process of developing the terrain engine, I learned alot about XNA, C#, and .NET in general. Though I took a very C approach and kept to structs, linked lists via preallocated arrays of a fixed size, and files full of simular public functions. (not much oop to be found)