What's New in Silverlight 5? -Graphics Changes



Introduction

In this article, we'll have a brief discussion of the new features of the graphics stack in Silverlight 5.

Overview

Silverlight 5 has undergone a few changes in the XAML stack:

  • Improved Performance and Rendering:

    Performance has been improved dramatically by using lessons learned from Windows Phone 7. More comes later in this article.
     
  • Hardware Acceleration:

    Silverlight 5 now depends more on the GPU for graphics processing. This frees the CPU from much of the work, and as a result, improves performance.
     
  • New 3D API:

    The most exciting feature yet. Silverlight 5 now has a native 3D API. More later.
     
  • Vector Printing:

    Very useful for certain cases, not available in the Beta.
     
  • Print Preview:

The long-waited printing feature. Silverlight 5 now allows you to show the user a preview of what he is going to print. Yet not available in the Beta.

Now let's look at the currently available features in details.

Performance Improvements

To improve rendering performance, Silverlight 5 uses the composition model available in Windows Phone 7. This model implies use of a separate, dedicated thread for graphics rendering instead of using the UI thread. This helps freeing the UI thread from graphics work, and thus improves the performance of rendering UI elements and reduces flickers and glitchy animations that happen when a UI thread is interrupted.

In addition, moving the graphics rendering to another thread adds support for independent animations and helps with immediate-mode rendering on the GPU (in which graphics are sent directly and being rendered on the display.)

3D API

Silverlight 5 now supports natively a 3D API. This API is based on the XNA API; you have the same classes and the same code, however, the 3D API in Silverlight is not game-loop based.

While it's so amazing to have a 3D API natively supported in Silverlight, things are not as good as they seem. The 3D API of Silverlight 5 is very low-level, which means that you have access to the GPU, vertex shaders, and other 3D primitives. It's not as easy as it should be; it requires that you have a solid understanding of low-level graphics and game development to be able to interact with this API. However, the good news is that the community will likely wrap this low-level API into simpler components.

Technically, to draw graphics on the screen you need to use the new control DrawingSurface where all the rendering and graphics is done. This control offers a Draw event that you can use to supply your drawing calls. The calls are carried to a GraphicsDevice object and then would be processed and carried to the display.

Because of the complexities in this low-level API, and because we assume that you are a business developer, we won't discuss the 3D API. Instead, we'll have a brief look at two of the great samples of this API.

Cube Sample

The cube sample (download from http://bit.ly/sl5-cubesample , colored, non-textured) demonstrates how to create and rotate a 3D cube in Silverlight 5. Here's a screenshot of this sample:

Looking at the Solution Explorer at project files, we can see that the project contains some pixel shader (PS) and vertex shader (VS) files. Those files besides the HLSL files contain the code (in the HLSL language) for the effects required to render the cube.

SilGraphics1.png

Moving to MainPage.xaml you can see the DrawingSurface object used to display the graphics and drawings.

<DrawingSurface Draw="OnDraw" SizeChanged="OnSizeChanged" />

Looking at the code behind at the Draw event handler, we can see that the sample has encapsulated all the code required for drawing the cube and rotating it into a new class called Scene. The Draw event passes the GraphicsDevice object to the Scene to have it draw the cube and other graphics into the device:

// init the 3D scene
Scene scene = new Scene();

public MainPage()
{
InitializeComponent();
}

void OnDraw(object sender, DrawEventArgs args)
{
// draw 3D scene
scene.Draw(args.GraphicsDevice, args.TotalTime);

// invalidate to get a callback next frame
args.InvalidateSurface();
}


Moving to the Scene class, we can see that it creates another class that handles drawing the Cube, and has configured the view and camera position and completes the drawing in the Draw() function by clearing the screen and calling the Draw() function of the cube.

    public class Scene
    {
        Matrix view; // The view or camera transform
        Matrix projection;

        // The single Cube at the root of the scene
        Cube Cube = new Cube();

        public Scene()
        {
            // the camera's position
            Vector3 cameraPosition = new Vector3(0, 0, 5.0f);
            // the place the camera is looking (towards world origin)
            Vector3 cameraTarget = Vector3.Zero;

            // the transform representing a camera at a position looking at a target
            view = Matrix.CreateLookAt(cameraPosition, cameraTarget, Vector3.Up);
        }

        public void Draw(GraphicsDevice graphicsDevice, TimeSpan totalTime)
        {
            // clear the existing render target
            graphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer,
            Color.Transparent, 1.0f, 0);

            // draw the Cube
            Cube.Draw(graphicsDevice, totalTime, view * projection);
        }
    }



Finally, the Cube class completes all the drawing by loading the vertex and pixel shaders in its constructor, configuring cube surfaces and surface colors in the CreateCube() function, and then performs the drawing and handling the animation in the Draw() function.

public class Cube
{
// the device to use when creating resources
static readonly GraphicsDevice resourceDevice
= GraphicsDeviceManager.Current.GraphicsDevice;

// resources
VertexShader vertexShader;
PixelShader pixelShader;

public Cube()
{
// Initialize resources required to draw the Cube
vertexBuffer = CreateCube();

Stream shaderStream = Application.GetResourceStream(
new Uri(@"CubeSample;component/Cube.vs", UriKind.Relative)).Stream;
vertexShader = VertexShader.FromStream(resourceDevice, shaderStream);

shaderStream = Application.GetResourceStream(...);

}

VertexBuffer CreateCube()
{
// cube vertices
var cube = new VertexPositionColor[36];
 
// face coordinates
Vector3 topLeftFront = new Vector3(-1.0f, 1.0f, 1.0f);
Vector3 bottomLeftFront = new Vector3(-1.0f, -1.0f, 1.0f);

return vb;
}

public void Draw(GraphicsDevice graphicsDevice, ...)
{
// update cube transform
Matrix position = Matrix.Identity; // origin
Matrix scale = Matrix.CreateScale(1.0f);
// no scale modifier

// setup pixel pipeline
graphicsDevice.SetPixelShader(pixelShader);

// draw using the configured pipeline
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 12);
}
}


Lengthy, isn't it? Now, let's have a look at another example.

Solar Wind

The Solar Wind 3D sample (download from http://bit.ly/sl5-solarwind) uses the new 3D features of Silverlight 5 to draw the Earth with day and night transitions, atmosphere layers, and population density overlays. It demonstrates advanced concepts and it's very cool that you'll like to run and play with it.

Babylon3D

The most amazing sample yet (download from http://bit.ly/sl5-babylon3d), it shows a full 3D realtime engine with some advanced features and an integrated collisions system.

Summary

Silverlight 5 provides a few improvements in the graphics stack:

  • Improved performance:

    Uses the composition model of Windows Phone 7; a separate, dedicated thread for graphics and drawing.
     
  • Hardware Acceleration:

    Depending more on GPU for graphics processing. Frees CPU from much work, and as a result, improves performance.
     
  • New 3D API:

    A low-level 3D API based on XNA Framework. Difficult to work with. Community will likely wrap to simplify use.
     
  • Vector Printing:

    Very useful for certain cases, not available in the Beta.
     
  • Print Preview:

    Allows for print previews. Not in Beta.

Up Next
    Ebook Download
    View all
    Learn
    View all