3D Billboards On Windows Phone 7


Billboards are one of the most used “primitives” in rendering, principally in mobile environments where whe dont have GPU power avaliable to render millions of real triangles.

In this post i will show how to implement Cylindric and Spherical billboards using the simple XNA SpriteBatch.

The result is not cool/fast as using shaders, but is more than enough.

To begin, we show our simple class that represents any type of billboard.

public class Billboard3D
{
        public Billboard3D(Texture2D tex, Vector3 pos, Vector2 scale)
        {
            this.Texture = tex;
            this.Position = pos;
            this.Scale = scale;
        }

        public Vector2 Scale;
        public Texture2D Texture;
        public Vector3 position;
}

Here we show the code to render the Axial Billboard (Cylindric).
For the example, we constrained it to the Y axis (most common – Vector3.Up), you can change it the way you want. (you can put this as a parameter in Billboard3D class)

            Vector3 position = CAMERA_POSITION;

            foreach (var item in Billboards)
            {
                basicEffect.World = Matrix.CreateConstrainedBillboard(item.Position, position, Vector3.Up, null, null);

                basicEffect.View = activeView;
                basicEffect.Projection = activeProjection;

                spriteBatch.Begin(0, null, null, DepthStencilState.DepthRead, RasterizerState.CullNone, basicEffect);
                spriteBatch.Draw(item.Texture, Vector2.Zero, item.Texture.Bounds, Color.White, 0, new Vector2(item.Texture.Bounds.Center.X, item.Texture.Bounds.Center.Y), item.Scale, SpriteEffects.None, 1);
                spriteBatch.End();
            }

The basicEffect variable is an instance of the classic XNA Basic Effect class.
The next code shows how to render a Spherical Billboards (will always look to the camera).
There are some magic convertions cause the coordinate space of the basic effect and the SpriteBatch are different.

Matrix invertY = Matrix.CreateScale(1, -1, 1);

            basicEffect.World = invertY;
            basicEffect.View = Matrix.Identity;
            basicEffect.Projection = activeProjection;

            spriteBatch.Begin(0, null, null, DepthStencilState.DepthRead, RasterizerState.CullNone, basicEffect);

            foreach (var item in Billboards)
            {
                Vector3 viewSpaceTextPosition = Vector3.Transform(item.Position, activeView * invertY);
                spriteBatch.Draw(item.Texture, new Vector2(viewSpaceTextPosition.X, viewSpaceTextPosition.Y), item.Texture.Bounds, Color.White, 0, new Vector2(item.Texture.Bounds.Center.X,item.Texture.Bounds.Center.Y), item.Scale, SpriteEffects.None, viewSpaceTextPosition.Z);
            }               

            spriteBatch.End();

There are others ways of drawing billboards on wp7 like creating teh vertices by hand every frame and render using RenderUserPrimitive function.

We always have pros and cons in all approaches, i prefer this =P

This technic can also be used to render Text in 3D, just change the spritebatch draw function to the equivalent draw text function.

, ,