What's New in Silverlight 5: Graphics Changes


This content is based on the Beta release; expect many changes in the final release.

Introduction

In this article, we'll have a brief discussion of the new features in 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 using lessons learned from Windows Phone 7. More on that later in this article.
  • Hardware Acceleration: Silverlight 5 now depends more on GPU for graphics processing. This frees the CPU from much work, and as a result, improves performance.
  • New 3D API: The most exciting feature yet. Silverlight 5 now supports a native 3D API. More comes 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 detail.  

Performance Improvements

To improve rendering performance, Silverlight 5 uses the composition model available in Windows Phone 7. This model implies using 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 the 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 a native 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 go on. 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 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:

Cube-Sample.png

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

Cube-Sample-Project.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.

Solar-Wind-Sample.jpg

Babylon3D

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

Babylon3D.jpg   

Summary

Silverlight 5 has 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 the 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. The community will likely develop a wrapper to simplify it's use.
  • Vector Printing: Very useful for certain cases, not available in the Beta.
  • Print Preview: Allows for print previews. Not in Beta.
Now, check out other What's New in Silverlight 5? articles.

Next Recommended Readings