The new version of the Silverlight Toolkit (December 2011) for Silverlight 5 is out and you can grab it here:
http://silverlight.codeplex.com/releases/view/78435
Update: Babylon Engine now uses Silverlight 5 Toolkit: http://code.msdn.microsoft.com/Babylon-3D-engine-f0404ace
I had the pleasure of working on this version and I’m pleased to write this article to help you discover how the Toolkit enhances Silverlight 5 with the following features:
- Seamless integration of 3D models and other assets with the Content Pipeline
- New Visual Studio templates for creating:
- Silverlight 3D Application
- Silverlight 3D Library
- Silverlight Effect
- New samples to demo these features
Seamless integration with the Content Pipeline
The toolkit comes with a new assembly : Microsoft.Xna.Framework.Content.dll. This assembly allows you to load assets from the .xnb file format (produced by the Content Pipeline).
Using the new Visual Studio templates (which I will describe later), you can now easily port existing 3D projects directly to Silverlight 5!
Microsoft.Xna.Framework.Content.dll assembly will add the following classes to Silverlight 5:
- ContentManager
- Model
- SpriteFont and SpriteBatch
The toolkit comes also with the Microsoft.Xna.Framework.Tookit.dll assembly which will add the following classes to Silverlight 5:
- SilverlightEffect
- Mouse, MouseState
- Keyboard, KeyboardState
ContentManager
The documentation for this class can be found here:
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.content.contentmanager.aspx
The ContentManager class is the representative for the Content Pipeline inside your code. It is responsible for loading objects from .xnb files.
To create a ContentManager you just have to call the following code:
- ContentManager contentManager = new ContentManager(null, "Content");
There are restrictions for this class : *The ContentManager for Silverlight can only support one Content project and the RootDirectory must be set to “Content”*
Using it is really simple because it provides a simple Load method which can be used to create your objects:
- // Load fonts
- hudFont = contentManager.Load<SpriteFont>("Fonts/Hud");
-
- // Load overlay textures
- winOverlay = contentManager.Load<Texture2D>("Overlays/you_win");
-
- // Music
- backgroundMusic = contentManager.Load<SoundEffect>("Sounds/Music");
Model
The documentation for this class can be found here:
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.model.aspx
The model class has the same API as in XNA 4 and it will allow you to load and render 3D models from XNB files:
- // Draw the model.
- Model tankModel = content.Load<Model>("tank");
- tankModel.Draw();
You can also use bones if your model supports them:
- Model tankModel = content.Load<Model>("tank");
- tankModel.Root.Transform = world;
- tankModel.CopyAbsoluteBoneTransformsTo(boneTransforms);
-
- // Draw the model.
- foreach (ModelMesh mesh in tankModel.Meshes)
- {
- foreach (BasicEffect effect in mesh.Effects)
- {
- effect.World = boneTransforms[mesh.ParentBone.Index];
- effect.View = view;
- effect.Projection = projection;
-
- effect.EnableDefaultLighting();
- }
-
- mesh.Draw();
- }
You can import models using .x or .fbx format:

And thanks to the FBX importer, you can also import .3ds, .obj, .dxf and even Collada.
SpriteFont & SpriteBatch
The documentation for these classes can be found here:
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.spritebatch.aspx
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.spritefont.aspx
The SpriteBatch class is used to display 2D textures on top of the render. You can use them for displaying a UI or sprites.
- SpriteBatch spriteBatch = new SpriteBatch(graphicsDevice);
-
- spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque);
-
- spriteBatch.Draw(texture, new Rectangle(0, 0, width, height), Color.White);
-
- spriteBatch.End();
As you can see, SpriteBatch only needs a texture to display.
SpriteFont allows you to use sprites to display text.
- SpriteFont hudFont = contentManager.Load<SpriteFont>("Fonts/Hud");
- spriteBatch.DrawString(hudFont, value, position + new Vector2(1.0f, 1.0f), Color.Black);
- spriteBatch.DrawString(hudFont, value, position, color);
SpriteFont relies on SpriteBatch to draw and needs a font definition from the ContentManager:

SilverlightEffect
The toolkit introduces a new class called SilverlightEffect which can be used to apply .fx files.
It also support .slfx which is the default extension. There is no difference between .slfx and .fx but as XNA Effect Processor is already associated with .fx, the Silverlight Content Pipeline had to select another one.
You can now define a complete effect inside a Content project and use it for rendering your models.
To do so:
- Create a .fx file with a least one technique
- Shader entry points must be parameterless
- Define render states
For example here is a simple .fx file:
- float4x4 WorldViewProjection;
- float4x4 World;
- float3 LightPosition;
-
- // Structs
- struct VS_INPUT
- {
- float4 position : POSITION;
- float3 normal : NORMAL;
- float4 color : COLOR0;
- };
-
- struct VS_OUTPUT
- {
- float4 position : POSITION;
- float3 normalWorld : TEXCOORD0;
- float3 positionWorld : TEXCOORD1;
- float4 color : COLOR0;
- };
-
- // Vertex Shader
- VS_OUTPUT mainVS(VS_INPUT In)
- {
- VS_OUTPUT Out = (VS_OUTPUT)0;
-
- // Compute projected position
- Out.position = mul(In.position, WorldViewProjection);
-
- // Compute world normal
- Out.normalWorld = mul(In.normal,(float3x3) WorldViewProjection);
-
- // Compute world position
- Out.positionWorld = (mul(In.position, World)).xyz;
-
- // Transmit vertex color
- Out.color = In.color;
-
- return Out;
- }
-
- // Pixel Shader
- float4 mainPS(VS_OUTPUT In) : COLOR
- {
- // Light equation
- float3 lightDirectionW = normalize(LightPosition - In.positionWorld);
- float ndl = max(0, dot(In.normalWorld, lightDirectionW));
-
- // Final color
- return float4(In.color.rgb * ndl, 1);
- }
-
- // Technique
- technique MainTechnique
- {
- pass P0
- {
- VertexShader = compile vs_2_0 mainVS(); // Must be a non-parameter entry point
- PixelShader = compile ps_2_0 mainPS(); // Must be a non-parameter entry point
- }
- }
The Toolkit will add required processors to the Content Pipeline in order to create the .xnb file for this effect:

To use this effect, you just have to instantiate a new SilverlightEffect inside your code:
- mySilverlightEffect = scene.ContentManager.Load<SilverlightEffect>("CustomEffect");
Then, you can retrieve effect’s parameters:
- worldViewProjectionParameter = mySilverlightEffect.Parameters["WorldViewProjection"];
- worldParameter = mySilverlightEffect.Parameters["World"];
- lightPositionParameter = mySilverlightEffect.Parameters["LightPosition"];
To render an object with your effect, it is the same code as in XNA 4:
- worldParameter.SetValue(Matrix.CreateTranslation(1, 1, 1));
- worldViewProjectionParameter.SetValue(WorldViewProjection);
- lightPositionParameter.SetValue(LightPosition);
- foreach (var pass in mySilverlightEffect.CurrentTechnique.Passes)
- {
- // Apply pass
- pass.Apply();
-
- // Set vertex buffer and index buffer
- graphicsDevice.SetVertexBuffer(vertexBuffer);
- graphicsDevice.Indices = indexBuffer;
-
- // The shaders are already set so we can draw primitives
- graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, VerticesCount, 0, FaceCount);
- }
Texture2D, TextureCube & SoundEffect
Silverlight 5 provides Texture2D, TextureCube and SoundEffect classes. With the Toolkit, you will be able to load them from the ContentManager:
- // Load overlay textures
- winOverlay = contentManager.Load<Texture2D>("Overlays/you_win");
-
- // Music
- backgroundMusic = contentManager.Load<SoundEffect>("Sounds/Music");
Mouse and Keyboard
In order to facilitate porting existing 3D applications and to accommodate polling input application models, we also added partial support for Microsoft.Xna.Framework.Input namespace.
So you will be able to request MouseState and KeyboardState everywhere you want:
- public MainPage()
- {
- InitializeComponent();
-
- Mouse.RootControl = this;
- Keyboard.RootControl = this;
- }
However, there is a slight difference from original XNA on other endpoints: you have to register the root control which will provide the events for Mouse and Keyboard. The MouseState positions will be relative to the upper left corner of this control:
- private void myDrawingSurface_Draw(object sender, DrawEventArgs e)
- {
- // Render scene
- scene.Draw();
-
- // Let's go for another turn!
- e.InvalidateSurface();
-
- // Get mouse and keyboard state
- MouseState mouseState = Mouse.GetState();
- KeyboardState keyboardState = Keyboard.GetState();
-
- ...
- }
The MouseState and KeyboardState are similar to XNA versions:
Extensibility
Silverlight Content Pipeline can be extended the same way as the XNA Content Pipeline on other endpoints. You can provide your own implementation for loading assets from elsewhere than the embedded .xnb files.
For example you can write a class that will stream .xnb from the network. To do so, you have to inherit from ContentManager and provide your own implementation for OpenStream:
- public class MyContentManager : ContentManager
- {
- public MyContentManager() : base(null)
- {
-
- }
-
- protected override System.IO.Stream OpenStream(string assetName)
- {
- return base.OpenStream(assetName);
- }
- }
You can also provide our own type reader. Here is for example the custom type reader for SilverlightEffect:
- /// <summary>
- /// Read SilverlightEffect.
- /// </summary>
- public class SilverlightEffectReader : ContentTypeReader<SilverlightEffect>
- {
- /// <summary>
- /// Read and create a SilverlightEffect
- /// </summary>
- protected override SilverlightEffect Read(ContentReader input, SilverlightEffect existingInstance)
- {
- int techniquesCount = input.ReadInt32();
- EffectTechnique[] techniques = new EffectTechnique[techniquesCount];
-
- for (int techniqueIndex = 0; techniqueIndex < techniquesCount; techniqueIndex++)
- {
- int passesCount = input.ReadInt32();
- EffectPass[] passes = new EffectPass[passesCount];
-
- for (int passIndex = 0; passIndex < passesCount; passIndex++)
- {
- string passName = input.ReadString();
-
- // Vertex shader
- int vertexShaderByteCodeLength = input.ReadInt32();
- byte[] vertexShaderByteCode = input.ReadBytes(vertexShaderByteCodeLength);
- int vertexShaderParametersLength = input.ReadInt32();
- byte[] vertexShaderParameters = input.ReadBytes(vertexShaderParametersLength);
-
- // Pixel shader
- int pixelShaderByteCodeLength = input.ReadInt32();
- byte[] pixelShaderByteCode = input.ReadBytes(pixelShaderByteCodeLength);
- int pixelShaderParametersLength = input.ReadInt32();
- byte[] pixelShaderParameters = input.ReadBytes(pixelShaderParametersLength);
-
- MemoryStream vertexShaderCodeStream = new MemoryStream(vertexShaderByteCode);
- MemoryStream pixelShaderCodeStream = new MemoryStream(pixelShaderByteCode);
- MemoryStream vertexShaderParametersStream = new MemoryStream(vertexShaderParameters);
- MemoryStream pixelShaderParametersStream = new MemoryStream(pixelShaderParameters);
-
- // Instanciate pass
- SilverlightEffectPass currentPass = new SilverlightEffectPass(passName, GraphicsDeviceManager.Current.GraphicsDevice, vertexShaderCodeStream, pixelShaderCodeStream, vertexShaderParametersStream, pixelShaderParametersStream);
- passes[passIndex] = currentPass;
-
- vertexShaderCodeStream.Dispose();
- pixelShaderCodeStream.Dispose();
- vertexShaderParametersStream.Dispose();
- pixelShaderParametersStream.Dispose();
-
- // Render states
- int renderStatesCount = input.ReadInt32();
-
- for (int renderStateIndex = 0; renderStateIndex < renderStatesCount; renderStateIndex++)
- {
- currentPass.AppendState(input.ReadString(), input.ReadString());
- }
- }
-
- // Instanciate technique
- techniques[techniqueIndex] = new EffectTechnique(passes);
- }
-
- return new SilverlightEffect(techniques);
- }
- }
New Visual Studio templates
The toolkit will install two new project templates and a new item template:
Silverlight3DApp
This template will produce a full working Silverlight 3D application.

The new solution will be composed of 4 projects:
- Silverlight3DApp : The main project
- Silverlight3DAppContent : The content project attached with the main project
- Silverlight3DWeb : The web site that will display the main project
- Silverlight3DWebContent : A content project attached to the website if you want to stream your .xnb from the website instead of using embedded ones. This will allow you distribute a smaller .xap.

The main project (Silverlight3DApp) is built around two objects:
- A sceneobject which
- Create the ContentManager
- Handle the DrawingSurface Draw event
- A cubeobject
- Create a vertex buffer and index buffer
- Use the ContentManager to retrieve a SilverlightEffect (Customeffect.slfx) from the content project
- Configure and use the SilverlightEffect to render

Silverlight3DLib
This template will produce a Silverlight Library without any content but with all Microsoft.Xna.Framework references set:

And the resulting project will look like:

SilverlightEffect
This item template can be used inside a Content project to add a custom .slfx file that will work with SilverlightEffect class:

The file content will be the following:
- float4x4 World;
- float4x4 View;
- float4x4 Projection;
-
- // TODO: add effect parameters here.
-
- struct VertexShaderInput
- {
- float4 Position : POSITION0;
-
- // TODO: add input channels such as texture
- // coordinates and vertex colors here.
- };
-
- struct VertexShaderOutput
- {
- float4 Position : POSITION0;
-
- // TODO: add vertex shader outputs such as colors and texture
- // coordinates here. These values will automatically be interpolated
- // over the triangle, and provided as input to your pixel shader.
- };
-
- VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
- {
- VertexShaderOutput output;
-
- float4 worldPosition = mul(input.Position, World);
- float4 viewPosition = mul(worldPosition, View);
- output.Position = mul(viewPosition, Projection);
-
- // TODO: add your vertex shader code here.
-
- return output;
- }
-
- float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
- {
- // TODO: add your pixel shader code here.
-
- return float4(1, 0, 0, 1);
- }
-
- technique Technique1
- {
- pass Pass1
- {
- // TODO: set renderstates here.
-
- VertexShader = compile vs_2_0 VertexShaderFunction();
- PixelShader = compile ps_2_0 PixelShaderFunction();
- }
- }
New samples to demo these features
Finally, to help you discover and learn all these features, we added some cools samples:
Bloom
This sample shows you how to use sprites to accomplish post-processing effects such as “bloom”. It also uses the Content Pipeline to import a tank model from a .fbx file.

CustomModelEffect
This sample shows you how custom effects can be applied to a model using the Content Pipeline.

Generated geometry
This sample shows how 3D models can be generated by code during the Content Pipeline build process.

Particles
This sample introduces the concept of a particle system, and shows how to draw particle effects using SpriteBatch. Two particle effects are demonstrated: an explosion and a rising plume of smoke:

Primitives3D
This sample provides easily reusable code for drawing basic geometric primitives:

Platformer
This sample is a complete game with 3 levels provided (you can easily add yours). It shows the usage of SpriteBatch, SpriteFont and SoundEffect inside a platform game. It also uses Keyboard class to control the player.

SimpleAnimation
This sample shows how to apply program controlled rigid body animation to a 3D model loaded with the ContentManager:

Skinning
This sample shows how to process and render a skinned character model using the Content Pipeline.

Conclusion
As you noticed, all these new additions to the Silverlight Toolkit are made to make it easy to get started with new Silverlight 3D features by providing developer tools to improve usability and productivity.
You can now easily start a new project that leverages both concepts of XNA and Silverlight. It becomes easy to work with 3D concepts and resources like shaders, model, sprites, effects, etc...
We also try to reduce the effort to port existing 3D applications to Silverlight.
So now it’s up to you to discover the wonderful world of 3D using Silverlight 5!