XNA UK User Group

A helping hand for bedroom coders throughout the land.
in

RandomChaos

April 2008 - Posts

  • Generic XNA - Water

    http://www.youtube.com/v/fy8oFZ_3O68 <p><a href="http://www.youtube.com/v/fy8oFZ_3O68">http://www.youtube.com/v/fy8oFZ_3O68</a></p>  

    Yes, I know, I have already put up the NVIDIA ocean shader, but after a member of the community had some issue with it, mostly how it played with the SkySphere sample I found that in my naive XNA days (I know, I am still learning) I made a shed load of errors in the implementation of the class. This I am going to remedy in my next post, so expect the Ocean Shader II post to be next.

    During my investigation of the issues David Reilly was having with the combination of Ocean and SkySphere I came across a water shader that I found ages ago. I cant for the life of me remember where I got it from, but I am glad I found it. It's written by Anirudh S Shastry and it does all the stuff the NVIDIA shader does but I personally think that it has better performance. I guess putting them both up here gives you the choice when it comes to water shaders. I also plan to come up with my own water shader at some point, but for now here are the third party shaders I have.

    As far as the shader goes, I have not changed much, there was a redundant routine or two, but other than that it is pretty much as I found it. As with the NVIDIA shader, all I have done is provided an XNA class that gives access to the shader and it's parameters.

     

    Hope you find it useful. Solution can be found here.

  • Generic XNA - Wiring your own Events

    GenericXNAEvents

    As I mentioned in one of the post responses on this blog here is an examples of how you can wire up events in your game object. As usual I have tried to keep this as simple as I can to try and make it clear whats going on.

    I guess the first thing to do is describe what an event is, well an event can be anything that occurs during the execution of your game, an enemy shoots, a bomb detonates, the player passes the mouse over a game object (as in this example) but rather than checking ALL your objects each loop you just want to be told when this happens so you can do what you need to do to handle the event. I guess this is a pretty basic C# skill, but if you are not a C# developer you may not know how to do this, so here is my example of Events and how I wire them up.

    So off to the code, I created a new project called GenericXNAEvents, off this project I created the object I am going to use in this example, a simple object that will display a coloured rectangle and have events attached to it that tell me when the mouse is passed over it, clicked on it and when the mouse leaves it. The first thing I do is create a delegate that defines my event, I make this public so it is accessible outside of my class as this dictates how the event handler will be written by those "subscribing" to the events. This done I then create my events, these are logical instances of the delegate that are going to be used to "Fire" my events when they occur, "Subscribers" will also be able to attach (wire) them selves to these events.

     

    // Delegate definition of an event.
    public delegate void FiredEvent(object sender);

    // Instances of delegate event.
    public FiredEvent OnMouseOver;
    public FiredEvent OnMouseOut;
    public FiredEvent OnMouseClick;

     

    As you can see I have three events, one for when the mouse is over this object, one for when it moves off this object and one for when this object is clicked.

    Now, I create the conditions that fire my events in the Update method.

    // Is the mouse over me?
    Point mouseCoord = new Point(Mouse.GetState().X,Mouse.GetState().Y);
    Rectangle mouseRec = new Rectangle(mouseCoord.X, mouseCoord.Y, 1, 1);
    
    Rectangle me = new Rectangle(left,top,width,height);
    
    // Check for mouse over and moust out.
    if (me.Intersects(mouseRec))
    {
        moueOver = true;
        
        // If someone has subscribed to this event, tell them it has fired.
        if (OnMouseOver != null)
            OnMouseOver(this);
    }
    else
    {
        if (moueOver)
        {
            moueOver = false;
            // If someone has subscribed to this event, tell them it has fired.
            if (OnMouseOut != null)
                OnMouseOut(this);
        }
    }
    
    // Check for mouse clicked.
    if (moueOver && Mouse.GetState().LeftButton == ButtonState.Pressed)
    {
        // If someone has subscribed to this event, tell them it has fired.
        if (OnMouseClick != null)
            OnMouseClick(this);
    }

    First thing I do is create the rectangles that will be used to check for intersection with the mouse, if the mouse intersects the object then I set my boolean flag marking that the mouse is over me to true, then check to see if anyone has subscribed to my OnMouseOver event, if they have I call there event handlers. If I am not intersecting the mouse and the mouse has been over me, then the mouse must have moved off of me, so I set my flag to false, check to see if anyone has subscribed to my OnMouseOut event, if they have I call there event handlers. Finally, if the mouse is over me and it has been clicked I check if anyone has subscribed to my OnMouseClick event and if they have, call there event handlers.

    So that's the mechanics of it, how do I now subscribe to these events??

    In the constructor of my Game1 Class I create three instances of my EventObjects, placed at different locations on the screen with different names and colours, I then "wire" up my event handlers.

    EventObject obj1 = new EventObject(this, "Obj1", Color.Red, 100, 150, 32, 32);
    EventObject obj2 = new EventObject(this, "Obj2", Color.Gold, 100, 500, 64, 32);
    EventObject obj3 = new EventObject(this, "Obj3", Color.Silver, 400, 200, 64, 64);
    
    // Wire up mouse over events.
    obj1.OnMouseOver += new EventObject.FiredEvent(MouseOver);
    obj2.OnMouseOver += new EventObject.FiredEvent(MouseOver);
    obj3.OnMouseOver += new EventObject.FiredEvent(MouseOver);
    
    // Wire up mouse out events.
    obj1.OnMouseOut += new EventObject.FiredEvent(MouseOut);
    obj2.OnMouseOut += new EventObject.FiredEvent(MouseOut);
    obj3.OnMouseOut += new EventObject.FiredEvent(MouseOut);
    
    // Wire up mouse click events
    obj1.OnMouseClick += new EventObject.FiredEvent(MouseClick);
    obj2.OnMouseClick += new EventObject.FiredEvent(MouseClick);
    obj3.OnMouseClick += new EventObject.FiredEvent(MouseClick);

    I now need to create my event handlers, these handlers MUST have the same pattern (return value and parameters) as the FiredEvent delegate defined earlier or you will get a compile error. Also note that I have appended (+=) the event handlers to the objects events, this means you can have a single event fire more than one event handler, you can associate a single handler if you like (=), and this will replace ALL previously set handlers to the one you specify.

    public void MouseOver(object sender)
    {
        if (sender is EventObject)
        {
            message = string.Format("Mouse is over {0}", ((EventObject)sender).Name);
        }
    }
    
    public void MouseOut(object sender)
    {
        message = "No Message.";
    }
    
    public void MouseClick(object sender)
    {
        if (sender is EventObject)
        {
            message = string.Format("Mouse clicked {0}", ((EventObject)sender).Name);
        }
    }

    As you can see I am checking to see what the sender is before I do anything with it, you could have objects with a similar event definition call this event handler also, but in this case we just have the one.

    So effectively you can have an event call multiple event handlers and have event handler called by multiple objects and object types. Pretty cool eh?! Thanks Microsoft :)

    Full solution example can be found here.

    Any questions, please post them here and I will do my best to answer them.

  • RandomChaos Game State Manager Source Release

    So, as I said in my last post, I have decided to put up the source code for the GSM. To use it in your projects, either add the project to your solution and add the reference from the project tab of the Add Reference window or, build it and brows for it when adding it as a reference. Then you need to make sure the built content folders and there contents are in the build folder of your project or you will get build errors.

    I am also including a game written using the GSM to show how you can simply inherit from it to build a quick and easy menu system for your game. In this case I chose something I knew would be quick to write as a demo, Space Invaders. All assets, both image and sound are courtesy of Classic Arcade Games.

    All in all it took me about 3 days to code the game with the GSM, so that's about a hour and a half a night,hmm, maybe 2, so say 6 hours to do this. Now the assets are pre built so did not have to do those, well broke them up a little and formatted them, but not much really. Anyway, I think it shows how fast you can create a simple demo.

      

    It's pretty simple stuff, I have not put any nice animation, the bunkers can't be damaged and the invaders are not animated.. I know, half a job... Oh well, you have the GSM source now and my half done Space Invaders....enjoy.

    If you have any queries or issues using the GSM, give me a shout, just remember, it comes warts and all...

    Download located here.

  • Space Invaders GSM

    Now, I am getting very lazy, and have decided to not do a great deal more with my GSM (currently in Beta, you can get a copy here), and may even just put my source code out there rather than trying to be all clever and just putting out a library. I was thinking, "who does that benefit?" and came to the answer of "no one"

    To show how you can quickly set up a game with the GSM I am also going to release it with a gem project, only space invaders, but what the hell, it was quick and easy and as I say I am getting more and more lazy...

    I found the resources for the game at this site for classing arcade games, dead good site. Thanks for the assets guys!

    Here is a screen shot of what I have been doing with them

    So my next post will probably be the GSM source along with this game, I am not going to go into much detail with the GSM. Not many people seem to want GSM code anyway, guess the CC sample is ample, but I'm going to put it up anyway as it now stands in Beta format, as with the RC engine with all my ugly unfinished bits in.

    Best laid plans of mice and men and all that.....

  • 3D Billboard Particles Tutorial VI

    http://www.youtube.com/v/tnsSfwGfM3U <p><a href="http://www.youtube.com/v/tnsSfwGfM3U">http://www.youtube.com/v/tnsSfwGfM3U</a></p>

    So, we have seen PointSprite particles in 3D, but what about billboarding??

    You may be asking at this point, what is billboarding and why would I want to use it when I already have a nice PoitSprite system that does the job I want...?

    A billboard object is basically a textured quad, again the question "What is a textured quad?" Well this is two triangle primitives used to draw a square and has a texture applied to it. It gets the name quad as it is four points in space rather than three.

    As to why use them, well I can only tell you my experiences of the two, first off I go for a PointSprite system pretty much every time when it comes to effects as it tends to be faster and 9 times out of 10 will do all that you need to, but in the case of the cloud system I am doing my best to write, Leaf pointed out that what is described as the "Parting of the Red Sea" effect by Ninian in here paper can be avoided by using billboarding. I assume because the position of a PointSprite is indeed that a single point in space, where as a billboard is a textured quad so has five points, I say five as you have each corner plus the centre and so when passing through the camera does not give that odd parting effect, also I think you are limited to a maximum PointSprite size, this can be altered in the RenderState using PointSizeMax but this too has an upper limit, a billboard does not. So like in the CC sample for billboarding, they can be used for grass and trees or like my cloud system.....clouds. Also, if a point sprite system does all that you need, then don't worry about billboarding.

    The main issues you have with creating billboards is keeping them facing the camera in the way you want them to, now you could do this how I used to in my old RandomChaos Engine and orientate each billboard on the CPU, this, as you can imagine is not a very good way of doing things as it just kills your FPS once you have a decent number of particles. The best way, just like in the CC billboard sample is to do it in the shader.

    Onto some code, and I will start where I did with the other tutorials with the particle definition, this is pretty much identical to the PointSprite definition, but we do need to add a TEXCOORD field to it, if we don't then we will not be able to apply textures to the billboard correctly. I guess if you really needed it you could also add Tangent data here if you wanted to bumpmap your particles, I have done this in the past, but it looked a little odd, may well have been my lighting algorithms though. Anyway, here is the data structure we are going to use for our billboard particle system

    public struct BillboardParticleElement
    {
        Vector3 position;
        Vector2 textureCoordinate;
        Color color;
        Vector4 data;
    
        public Vector3 Position
        {
            get { return position; }
            set { position = value; }
        }
        public Vector2 TextureCoordinate
        {
            get { return textureCoordinate; }
            set { textureCoordinate = value; }
        }
        public Vector4 Data
        {
            get { return extras; }
            set { data = value; }
        }
        public Color Color
        {
            get { return color; }
            set { color = value; }
        }
    
        public float SpriteSize
        {
            get { return data.X; }
            set { data.X = value; }
        }
        public float AlphaValue
        {
            get { return data.Y; }
            set { data.Y = value; }
        }
    
        public BillboardParticleElement(Vector3 Position, Vector2 TextureCoordinate, Vector2 XYScale, Color Color)
        {
            position = Position;
            textureCoordinate = TextureCoordinate;
            data = Vector4.One;
            color = Color;
        }
        static public VertexElement[] VertexElements = new VertexElement[]
            {
                new VertexElement(0,0,VertexElementFormat.Vector3,VertexElementMethod.Default,VertexElementUsage.Position,0),
                new VertexElement(0,4*3,VertexElementFormat.Vector2,VertexElementMethod.Default,VertexElementUsage.TextureCoordinate,0),                
                new VertexElement(0,4*5,VertexElementFormat.Color ,VertexElementMethod.Default,VertexElementUsage.Color,0),
                new VertexElement(0,4*6,VertexElementFormat.Vector4,VertexElementMethod.Default,VertexElementUsage.Position,1),
            };
    
        public static int SizeInBytes = (3 + 2 + 1 + 4) * 4;
    }

    As you can see there is little difference in this structure and the one used for the PointSprite system. I have added a Vector2 for the TEXCOORD field and so in the Element array I have added an extra element so it can be passed to the Vertex Shader.

    Now onto the emitter, this again is almost identical to the one in tutorial I, only this time I am going to set up up ready to be bolted into our game Agent. There area couple of new elements to go into this emitter, we need a DynamicVertexBuffer to store our particle array in, and a DynamicIndexBuffer to store the draw order of the primitives, and a VertexDeclaration, this gives the Graphics Device a definition of our particle structure. All the other fields are pretty much the same as what we have in the previous tutorials, the real difference comes when we are loading, updating and drawing the particles. The emitter  class looks like this

    public class ParticleEmitter
    {
        private DynamicVertexBuffer vb;
        private DynamicIndexBuffer ib;
        VertexDeclaration m_vDec;
    
        public BillboardParticleElement[] particleArray;
    
        public Vector3 myPosition;
        public Vector3 myScale;
        public Quaternion myRotation;
    
        public Color particleColor;
    
        public int partCount;
    
        Effect shader;
    
        Game game;
    
        int nextParticle = 0;
        BasicModel targetPos;
        Vector3 myLastpos;
    
        public ParticleEmitter(Game game, int particleCount,BasicModel model)
        {
            this.game = game;
            myPosition = Vector3.Zero;
            myScale = Vector3.One;
            myRotation = new Quaternion(0, 0, 0, 1);
    
            partCount = particleCount;
            targetPos = model;
    
            particleColor = Color.White;
        }
    
        public void LoadContent()
        {
            m_vDec = new VertexDeclaration(game.GraphicsDevice, BillboardParticleElement.VertexElements);
    
            shader = game.Content.Load<Effect>("Shaders/BillboardShader");
            shader.Parameters["particleTexture"].SetValue(game.Content.Load<Texture2D>("Textures/smoke"));
    
            
            myLastpos = targetPos.myPosition;
    
            LoadParticles();
        }
    
        private void LoadParticles()
        {
            particleArray = new BillboardParticleElement[partCount * 4];
    
            for (int p = 0; p < partCount; p+=4)
            {
                for (int thisP = 0; thisP < 4; thisP++)
                {
                    int currentParticle = p + thisP;
    
                    particleArray[currentParticle] = new BillboardParticleElement();
                    particleArray[currentParticle].Position = myPosition;
                    particleArray[currentParticle].Color = particleColor;
                    particleArray[currentParticle].Data = new Vector4(1f,1f,0,0);
                    switch (thisP)
                    {
                        case 0:
                            particleArray[currentParticle].TextureCoordinate = Vector2.Zero;
                            break;
                        case 1:
                            particleArray[currentParticle].TextureCoordinate = new Vector2(1, 0);
                            break;
                        case 2:
                            particleArray[currentParticle].TextureCoordinate = new Vector2(0, 1);
                            break;
                        case 3:
                            particleArray[currentParticle].TextureCoordinate = Vector2.One;
                            break;
                    }
                }
            }
                       
            short[] indices = new short[6 * partCount];
    
            for (int part = 0; part < partCount; part++)
            {
                int off = part * 6;
                int offVal = part * 4;
    
                indices[off + 0] = (short)(0 + offVal);
                indices[off + 1] = (short)(1 + offVal);
                indices[off + 2] = (short)(2 + offVal);
    
                indices[off + 3] = (short)(1 + offVal);
                indices[off + 4] = (short)(3 + offVal);
                indices[off + 5] = (short)(2 + offVal);
            }
    
            ib = new DynamicIndexBuffer(game.GraphicsDevice, typeof(short), 6 * partCount, BufferUsage.WriteOnly);
            ib.SetData(indices);
        }
    
        public void Update(GameTime gameTime)
        {
            for (int p = 0; p < particleArray.Length; p+= 4)
            {
                for (int thisP = 0; thisP < 4; thisP++)
                {
                    if (p == nextParticle && myLastpos != myPosition)
                    {
                        particleArray[p + thisP].Position = myLastpos;
                        particleArray[p + thisP].Color = particleColor;
                    }
    
                    particleArray[p + thisP].SpriteSize = (Vector3.Distance(particleArray[p + thisP].Position, targetPos.myPosition) / 5);
                }
            }
            nextParticle++;
    
            if (nextParticle >= particleArray.Length/4)
                nextParticle = 0;
    
            vb = new DynamicVertexBuffer(game.GraphicsDevice, typeof(BillboardParticleElement), 4 * partCount, BufferUsage.WriteOnly);
            vb.SetData(particleArray);
    
            myLastpos = targetPos.myPosition;
        }
        public void Draw(GameTime gameTime)
        {
            game.GraphicsDevice.VertexDeclaration = m_vDec;
            game.GraphicsDevice.Vertices[0].SetSource(vb, 0, BillboardParticleElement.SizeInBytes);
            game.GraphicsDevice.Indices = ib;
    
            bool AlphaBlendEnable = game.GraphicsDevice.RenderState.AlphaBlendEnable;
            Blend DestinationBlend = game.GraphicsDevice.RenderState.DestinationBlend;
            Blend SourceBlend = game.GraphicsDevice.RenderState.SourceBlend;
            bool DepthBufferWriteEnable = game.GraphicsDevice.RenderState.DepthBufferWriteEnable;
            BlendFunction BlendFunc = game.GraphicsDevice.RenderState.BlendFunction;
    
            game.GraphicsDevice.RenderState.AlphaBlendEnable = true;
            game.GraphicsDevice.RenderState.SourceBlend = Blend.One;
            game.GraphicsDevice.RenderState.DestinationBlend = Blend.One;
    
            game.GraphicsDevice.RenderState.DepthBufferWriteEnable = false;
    
            Matrix World = Matrix.CreateScale(myScale) * Matrix.CreateFromQuaternion(myRotation) * Matrix.CreateTranslation(myPosition);
            shader.Parameters["world"].SetValue(World);
            Matrix vp = Camera.myView * Camera.myProjection;
            shader.Parameters["vp"].SetValue(vp);
    
            shader.Begin();
            for (int ps = 0; ps < shader.CurrentTechnique.Passes.Count; ps++)
            {
                shader.CurrentTechnique.Passes[ps].Begin();
                game.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 4 * partCount, 0, partCount * 2);
                shader.CurrentTechnique.Passes[ps].End();
            }
            shader.End();
    
            game.GraphicsDevice.RenderState.DepthBufferWriteEnable = true;
    
            game.GraphicsDevice.RenderState.AlphaBlendEnable = AlphaBlendEnable;
    
            game.GraphicsDevice.RenderState.DestinationBlend = DestinationBlend;
            game.GraphicsDevice.RenderState.SourceBlend = SourceBlend;
    
        }
    }

    The first obvious change is in the LoadContent method, other than the assets beign from different files at the top we set up the VertexDeclarartion. LoadParticles is TOTALY different. This is because we have to set up a billboard per particle, so at the top we have to set our array to the number of particles we want * 4 as each bill board has 4 corners, then we have  the main loop that go through each particle and in that a second loop that moves us through each point of that particle.

    For the given array element we create a new particle instance, the position is set to that of the emitter for each corner, don't worry about this as the billboards size will be set in the shader. We set the color and the data of the particle setting the scale and alpha (unsing additive blending in this example so alpha wont be used).

    We then need to set the TEXCOORD of this corner, as I am sure you know TEXTCOORDS range from 0,0 which is the top left corner to 1,1 which is the bottom right corner. So if I had a texture that was 100 x 100 pixels and I wanted to get the pixel in the very centre (well just off centre) it would be located at .5,.5 this would get me pixel 50,50 off the image.

    We then set up the draw order of our billboard corners in the DynamicIndexBuffer, you will see I am using a short[] array to store this data, this is because I have a very poor Graphics Card that can't handle 32 bit index buffers, if you have a good card, swap these types for an int. You will also notice that we have 6 indices per particle, this is because the bill board is made up from 2 triangles.

    The Update method is really the same as before only we have to jump 4 elements per particle as we now have 4 elements per particle. The major change here is the addition of setting the DynamicVertexBuffer

    The Draw method again has few changes, at the top we set the VertexDeclaration, bind the vertex buffer and index buffer to the device, setup our blending method and shader, send the particles to the device and reset our RenderStates.

    So as you can see the major difference is setting up the Graphics device to use our particle array and the fact that our particles are now made from 4 corners.

    In this tutorial I have gone strait to binding the emitter to a game agent, for simplicity I have taken the BasicModel class I did for my A.I. Finite State Machine sample and removed the A.I. from it, added an instance of our emitter and that was pretty much it. The BasicModel class now looks like this

    public class BasicModel : DrawableGameComponent
    {
        private Model Mesh;
        public Vector3 myPosition;
        public Quaternion myRotation;
        public Vector3 myScale;
    
        ParticleEmitter emitter;
    
        Effect shader;
    
        string modelAsset;
        string shaderAsset;
    
        Vector4 AmbientColor = Color.Brown.ToVector4();
    
        public Vector3 velocity = Vector3.Zero;
        public float speed = .01f;
    
        public BasicModel(Game game, string modelAsset, string shaderAsset) :base(game) 
        {
            this.modelAsset = modelAsset;
            this.shaderAsset = shaderAsset;
    
            myPosition = new Vector3(0, 0, -1);
            myRotation = new Quaternion(0, 0, 0, 1);
            float scale = .5f;
            myScale = new Vector3(scale, scale, scale);
    
            emitter = new ParticleEmitter(game, 200, this);
    
        }
        public override void Update(GameTime gameTime)
        {
            velocity = new Vector3((float)Math.Cos(gameTime.TotalGameTime.TotalSeconds) * 20, (float)Math.Sin(gameTime.TotalGameTime.TotalSeconds) * 20, (float)Math.Sin(gameTime.TotalGameTime.TotalSeconds) * 30);
            Move();
            emitter.Update(gameTime);
    
            base.Update(gameTime);
        }
        protected override void LoadContent()
        {
            emitter.LoadContent();
            Mesh = Game.Content.Load<Model>(modelAsset);
            shader = Game.Content.Load<Effect>(shaderAsset);
    
            base.LoadContent();
        }
        public override void Draw(GameTime gameTime)
        {
            Matrix World = Matrix.CreateScale(myScale) *
                            Matrix.CreateFromQuaternion(myRotation) *
                            Matrix.CreateTranslation(myPosition);
    
            shader.Parameters["World"].SetValue(World);
            shader.Parameters["View"].SetValue(Camera.myView);
            shader.Parameters["Projection"].SetValue(Camera.myProjection);
    
            shader.Parameters["EyePosition"].SetValue(Camera.myPosition);
    
            shader.Parameters["AmbientLightColor"].SetValue(AmbientColor);
            shader.Parameters["DiffuseColor"].SetValue(Color.Aquamarine.ToVector4());
            shader.Parameters["LightDiffuseColor"].SetValue(Color.SteelBlue.ToVector4());
            shader.Parameters["SpecularPower"].SetValue(16);
            shader.Parameters["LightSpecularColor"].SetValue(Color.Silver.ToVector4());
    
            shader.Parameters["LightPosition"].SetValue(new Vector3(-10, 10, 0));
    
            for (int pass = 0; pass < shader.CurrentTechnique.Passes.Count; pass++)
            {
                for (int msh = 0; msh < Mesh.Meshes.Count; msh++)
                {
                    ModelMesh mesh = Mesh.Meshes[msh];
                    for (int prt = 0; prt < mesh.MeshParts.Count; prt++)
                        mesh.MeshParts[prt].Effect = shader;
                    mesh.Draw();
                }
            }
    
            emitter.Draw(gameTime);
            base.Draw(gameTime);
        }
    
        public virtual void Translate(Vector3 distance)
        {
            myPosition += Vector3.Transform(distance, Matrix.CreateFromQuaternion(new Quaternion(0, 0, 0, 1)));
        }
        public virtual void Rotate(Vector3 axis, float angle)
        {
            axis = Vector3.Transform(axis, Matrix.CreateFromQuaternion(myRotation));
            myRotation = Quaternion.Normalize(Quaternion.CreateFromAxisAngle(axis, angle) * myRotation);
        }
        public void LookAt(Vector3 target, float speed)
        {
            Vector3 tminusp = target - myPosition;
            Vector3 ominusp = Vector3.Backward;
    
            tminusp.Normalize();
    
            float theta = (float)System.Math.Acos(Vector3.Dot(tminusp, ominusp));
            Vector3 cross = Vector3.Cross(ominusp, tminusp);
    
            cross.Normalize();
    
            Quaternion targetQ = Quaternion.CreateFromAxisAngle(cross, theta);
            myRotation = Quaternion.Slerp(myRotation, targetQ, speed);
        }
    
        private void Move()
        {
            // Calulate the distance I need to travel.
            Vector3 distance = velocity * speed;
    
            // Find out my direction of facing as I move.
            Vector3 target = Vector3.Transform(distance, Matrix.CreateFromQuaternion(new Quaternion(0, 0, 0, 1)));
            target += myPosition;
            LookAt(target, .1f);
    
            // Move.
            Translate(distance);
    
        }
    }

    All we need to do now is add our agent to the Game.Components collection and away we go.

    HLSL

    OK now as you can see in all that code, not once do we try and make the billboard face the camera, this is all done in the shader. This is how I do it.

    First of all I get me world UP vector, this tells me what orientation is the UP vector, I do this by getting the cross product of -1,0,0 and 0,0,-1, I then need the eye vector of the viewer and I can get this from the View elements of the ViewProjection Matrix like this vp._m02_m12_m22, I can then get the side and up vector of the billboard orientation by getting the normalized cross produce of the eyeVector and the world up vector. I can then apply this to the final position of my Vertex. This is done in two steps, the first manages the sideVector orientation, I subtract .5 from the current TEXCOORD.x multiply that by the sideVector and the scale I want the particle to be, the second step I subtract the current  TEXCCORD.y from .5 and multiply that by the upVector and the scale I want the particle to be. As you can see with that methods you can scale both the X and Y dimensions of your billboard differently.

    Why am I subtracting .5 from the TEXCOORD in the first stage and the TEXCOORD from .5 in the second stage. Well, as I said before .5 puts us in the centre of our billboard so for the side orientation the left most point with be at x:0 so giving us -.5 to add to our particle position, this will give us a point in space .5 to the left of the particle, the right most will be x:1 so this will give us the right most point from the centre in space. In the case of the second stage, subtracting .5 from the TEXCOORD puts us at -.5  above the centre, and from the other extream it puts us .5 bellow that centre.

    The rest of the shader is pretty much as before, other than the extra handling TEXCOORDS

    half4x4 world : World;
    half4x4 vp : ViewProjection;
    
    #define worldUp cross(half3(-1,0,0),half3(0,0,-1))
    
    texture particleTexture;
    sampler partTextureSampler = sampler_state 
    { 
        Texture = <particleTexture>; 
        MinFilter = Linear;
        MagFilter = Linear;
        MipFilter = Linear;
    };
    
    struct VertexIn
    {
        half4 Position       : POSITION0;             
        half2 TextureCoords: TEXCOORD0;    
        half4 Color        : COLOR0;
        half4 Data : POSITION1;
    };
    struct VertexOut
    {
        half4 Position       : POSITION0;      
        half2 TextureCoords: TEXCOORD0;
        half4  Color        : COLOR0;    
    };
    
    struct PixelToFrame
    {
        half4 Color : COLOR0;
    };
    VertexOut VS(VertexIn input)
    {
        VertexOut Out = (VertexOut)0;
        
        half3 center = mul(input.Position,world);    
        half3 eyeVector = vp._m02_m12_m22;
        
        half3 finalPos = center;
        half3 side;
        half3 up;
        
        side = normalize(cross(eyeVector,worldUp));    
        up = normalize(cross(side,eyeVector));        
        
        finalPos += (input.TextureCoords.x - 0.5) * side * input.Data.x;
        finalPos += (0.5 - input.TextureCoords.y) * up * input.Data.x;
        
        half4 finalPos4 = half4(finalPos,1);    
        
        Out.Position = mul(finalPos4,vp);
        Out.TextureCoords = input.TextureCoords;
        
        Out.Color = input.Color;    
        
        // Alpha
        Out.Color.a = input.Data.y;
        
        return Out;
    }
    
    PixelToFrame PS(VertexOut input)
    {
        PixelToFrame Out = (PixelToFrame)0;
        
        half2 texCoord;
        
        texCoord = input.TextureCoords.xy;    
        
        half4 color = tex2D(partTextureSampler,texCoord);
        
        Out.Color = color * input.Color;    
        
        return Out;
    }
    
    technique Go
    {
        pass P0 
        {
            VertexShader = compile vs_2_0 VS();
            PixelShader  = compile ps_2_0 PS();
        }
    }

    Here is another example of billboards being used, the code and sahders are a little more work than shown here but it is pretty much the same technique.

    http://www.youtube.com/v/uMvjai9ggzI <p><a href="http://www.youtube.com/v/uMvjai9ggzI">http://www.youtube.com/v/uMvjai9ggzI</a></p>

    In the sample source I'm using the smoke texture provided by MS, and the biplane model that comes with the DirectX SDK. You can download the solution project here.