XNA Tutorial: HLSL and SpriteBatch for 2D effects.

After writing most of my first XNA game using the built in sorting capability of SpriteBatch, I ran into a pretty big problem. I wanted to add a HLSL effect to certain sprites. I followed the instructions I found, setting the SpriteSortMode to Immediate. What I did not realize at the time is Immediate means IMMEDIATE.

spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);

This means that you cannot rely on the spriteBatch.Draw method to sort for you, and must sort yourself.

I posted in the XNA forums, and learned that it is actually better to sort yourself. This way you know exactly how everything is working behind the scenes, and you can really improve upon the look by implementing same neat HLSL effects. Rewriting my draw functionality was not a huge undertaking but it did take some time.

For my purposes, I decided to create an object for handling everything needed to draw later on.

 class DrawableObject
    {
 
        public Texture2D Texture;
        public Vector2 Position;
        public Vector2 Origin;
        public Color Color;
        public float Rotation;
        public float Scale;
        public float Z_Index;
        public Rectangle DisplayRect;
        public DrawType DrawType;
        public Effect Effect;
        public Object ObjectRef;
 
        public DrawableObject(Texture2D texture, Vector2 position,Rectangle displayRect, Color color, float rotation, Vector2 origin, float scale, float z_Index, DrawType drawType, Effect effect, Object objectRef)
        {
            this.Texture = texture;
            this.Position = position;
            this.Origin = origin;
            this.Color = color;
            this.Rotation = rotation;
            this.Z_Index = z_Index;
            this.Scale = scale;
            this.DisplayRect = displayRect;
            this.DrawType = drawType;
            this.Effect = effect;
            this.ObjectRef = objectRef;
 
        }
    }

In this Object, DrawType is an enumeration used to mark each object so drawing can be handled differently depending on its type. For my purposes I had Player, Projectile, Shadow, etc
I then create a list of DrawableObjects to sort based on the z index.

List listToDraw = new List();
 
            for (int x = 0; x < playerManager.Players.Count; x++)
            {
                    //Add all my players as drawable objects
                    listToDraw.Add(new DrawableObject(playerManager.Players[x].PlayerAnimation.CurrentTexture, playerManager.Players[x].PlayerAnimation.ScreenPosition ,                   playerManager.Players[x].PlayerAnimation.DisplayRect, Color.White, 0f, Vector2.Zero, 1f, playerManager.Players[x].PlayerAnimation.ScreenPosition.Y) / Map.Height, DrawType.Player, playerManager.Players[x].PlayerAnimation.PlayerEffect,  playerManager.Players[x]));
              }

I then sort ….

           //Sort for the right order
            listToDraw.Sort(delegate (DrawableObject d1, DrawableObject d2) {return d2.Z_Index.CompareTo(d1.Z_Index);});

and then draw the list

 for (int x = 0; x < DrawObjectList.Count; x++)
                {
                    if (DrawObjectList[x].DrawType == DrawType.Player)
                    {
                        Player pn = (Player)DrawObjectList[x].ObjectRef;
 
                        spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);
                        if (DrawObjectList[x].Effect != null )
                        {
                            DrawObjectList[x].Effect.Begin();
                            DrawObjectList[x].Effect.CurrentTechnique.Passes[0].Begin();
                        }
                        spriteBatch.Draw(DrawObjectList[x].Texture, DrawObjectList[x].Position, DrawObjectList[x].DisplayRect, DrawObjectList[x].Color,
                                         DrawObjectList[x].Rotation, DrawObjectList[x].Origin, DrawObjectList[x].Scale, SpriteEffects.None, DrawObjectList[x].Z_Index);
 
                        if (DrawObjectList[x].Effect != null)
                        {
                            DrawObjectList[x].Effect.CurrentTechnique.Passes[0].End();
                            DrawObjectList[x].Effect.End();
                        }
 
                        //etc etc.
                 }

Well I hope this helps someone looking for the same thing.

~J

Leave a Reply

Your email address will not be published. Required fields are marked *


− three = 5

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>