(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .
        Login with Facebook

Simulating rain in Silverlight Part 2 - Optimization

(8 votes)
Lazar Nikolov
Lazar Nikolov
Joined Dec 15, 2010
Articles:   6
Comments:   59
More Articles
0 comments   /   posted on May 05, 2011
Tags:   lazar-nikolov
Categories:   Gaming , General
This article is compatible with the latest version of Silverlight.


Following my first article in this series, Simulating rain in Silverlight, I tried to optimize the algorithm that generates the rain. After the big interest several weeks ago, in this article this time I made some major changes in the code that eventually result in smoother, faster and non-memory consuming technique to simulate rain effect in Silverlight application.

This new solution of the problem is based on the first one that you may get acquainted with in the first part of this series - Simulating rain in Silverlight.

Before I begin with the new approach, here is a demo of the same rain, but much more intense, a flood rain...

View live demo - 1000 drops per second

Download source code

Changes in a brief

The solution that I present you now will dramatically affect the memory that the rain simulation consumes. One of the major drawbacks in the first attempt was that it eventually turned out that in some moment the Silverlight application tries to use your entire RAM. It may happen after hours pouring, or days, but it will. This increasing usage of memory affected the smoothness and CPU consumption as well. However, the algorithm for generating the drops is pretty well designed and working, but it definitely needs some optimization when it comes to memory usage.

The secret key - reusing the drops!

From this perspective, I directed my efforts to exactly this issue. The main difference in this new idea is that I could reuse the drops that have already finished their storyboard. Imagine the following – you have a storyboard that lasts, for example, M milliseconds, C – drops that must be animated per a single interval and N – the interval duration in milliseconds. Then after M milliseconds you can reuse all drops that have finished their pouring. But how many are these drops? Having N milliseconds for an interval and C drops per interval, you have 1000 / N intervals per second and thus (1000 / N) * C drops in a second in total. Multiplying this by M / 1000, you result in the number of drops that will be poured by the end of the first storyboard. This is exactly the number of drops that you need to infinitely simulate the rain. You just need to track the current drop to reuse in a global collection.

private List<Drop> sceneDrops;
private int intervalStartIndex;

In the constructor, I initialize the collection and fill it with drops (with no rain effects on them applied – these are added in the algorithm):

int dropsCount = Convert.ToInt32(Constants.ANIMATION_DURATION * Math.Ceiling((double)1000 * (double)this.DropsPerInterval / (double)this.DropsInterval));
this.sceneDrops = new List<Drop>(dropsCount);
this.intervalStartIndex = 0;
for (int i = 0; i < this.sceneDrops.Capacity; ++i)
    Drop drop = new Drop(this.DropSettings);

The new algorithm looks like this:

if (this.intervalStartIndex >= this.sceneDrops.Count)
    this.intervalStartIndex = 0;
Random rand = new Random();
for (int currentDrop = this.intervalStartIndex; currentDrop < this.intervalStartIndex + this.DropsPerInterval; ++currentDrop)
    // Add the drop to the scene
    if (!this.Scene.Children.Contains(this.sceneDrops[currentDrop]))
    // Generate the drop depth and scale it appropriately
    double depth = rand.NextDouble();
    this.sceneDrops[currentDrop].RenderTransform = new ScaleTransform
        ScaleX = depth,
        ScaleY = depth,
    // Generate angle for the falling drop
    double angle = rand.NextDouble() * 10;
    this.sceneDrops[currentDrop].RenderTransform = new RotateTransform
        Angle = angle,
    // Generate the drop distance from most left border
    this.sceneDrops[currentDrop].Margin = new Thickness(Convert.ToInt32(rand.NextDouble() * this.Width), 0, 0, 0);
    // Animate the drop falling
this.intervalStartIndex += this.DropsPerInterval;

Using GPU Acceleration

So, that was for the memory optimization. There is one more thing that can be done to improve the smoothness. Caching. To enable composition caching at the plug-in level you must set the value of an EnableGPUAcceleration param element to true as part of the object tag that declares the Silverlight plug-in.

<param name="enableGPUAcceleration" value="true"/>

This allows you to take advantage of the hardware acceleration in the GPU. All this can yield in significant performance improvements in some specific scenarios. To specify that the drop should be cached and benefit from GPU acceleration, I use a BitmapCache object.

    <BitmapCache RenderAtScale="4"/>

You can read more about CacheMode in MSDN.


After all above, the first rain simulation I made several weeks ago now looks like a polished one. Thanks to your feedback I was encouraged to spend some time searching for a better approach. As a conclusion, it, again, as it always happens, is obvious and straightforward to realize, just waiting for you to discover it, escaping from the boundaries that you build in front of you...

About the author

Lazar Nikolov is a software developer at CompletIT - the company behind SilverlightShow.net and leader in Silverlight related technologies in Bulgaria. His main interests are focused on Silverlight rich applications and Windows Phone 7 development.

In addition to authoring Silverlight articles (his series on ‘Simulating rain in Silverlight’ became one of the most popular articles on SilverlightShow!), Lazar is involved in the verification of all SilverlightShow articles, making sure that all content is consistent and in-line with the latest Silverlight/WP7 release updates.



No comments

Add Comment

Login to comment:
  *      *       
Login with Facebook

From this series