This article is compatible with the latest version of Silverlight.
Introduction
In this article I will try to simulate rain in Silverlight application that can be programmatically configured to meet your expectations. Although Silverlight at the time being is very CPU consuming, rain effect may be a common challenge for a developer or designer.
I believe that there are many computer graphics techniques, such as Particle system, to simulate realistically processes that involve tiny particles interacting with each other. However, in this article I will show you how to simulate rain with almost no effort with some very simple algorithm.
Here is a little demo and source code of what we will have done at the end in just a few minutes:
View live demo - with a small amount of raindrops to avoid performance issues
Download source code
Also check the second part of this series - "Simulating rain in Silverlight Part 2 - Optimization"!
The idea
Before looking at the algorithm, let me make the main flow clear. As I wrote a few lines above, the designer adjusts programmatically the rain on his own. That is – the height and width of the scene, the interval of falling drops and the amount of drops animated at a time. This all is achieved with a couple of classes that form the rain nature:
- Drop – holds the drop view
- DropSettings – describes a drop and its settings; currently only the height that the drop pours is implemented; this act as a view-model as I use it to bind in the drop view when animating the motion from top to bottom part of the scene
- Rain – this is my main object to maintain the rain process; it uses a simple algorithm, I will next describe, to simulate drops falling randomly through scene
The algorithm
Now it’s time for the algorithm. It, actually, is really very simple one. What determines the average rain? Yes, you are right and this is what I was looking for – direction and intensity.
First, to simulate the rain, we need to perform the algorithm exactly as many times, as we had previously defined to be the amount of drops to fall simultaneously. Furthermore, this should be done exactly as many times as we have specified to be the interval between the raindrops.
We start with the following:
for
(
int
i = 0; i <
this
.DropsPerInterval; ++i)
{
}
To distinguish between UI elements in the scene, when constructing the Rain object, a canvas is specified, and this panel is where the rain will be simulated in. Every drop that we create should be a child of this panel.
Drop drop =
new
Drop(
this
.DropSettings);
this
.Scene.Children.Add(drop);
Next step is to generate the depth in which the drop is shown in the scene. Depth visually controls the scale and further you go deep in the scene, drops become smaller.
double
depth = rand.NextDouble();
drop.RenderTransform =
new
ScaleTransform
{
ScaleX = depth,
ScaleY = depth,
};
The direction of the rain affects directly on the angle which drops fall the ground in. In the demo this angle is fixed to be between 0 and 10 degrees clockwise rotation.
double
angle = rand.NextDouble() * 10;
drop.LayoutRoot.RenderTransform =
new
RotateTransform
{
Angle = angle,
};
So far we had spread the drops randomly in depths and directions between 0 and 10 degrees. To put the finishing touches, we need to randomly scatter the raindrops in the two dimensional perspective of the scene.
drop.Margin =
new
Thickness(Convert.ToInt32(rand.NextDouble() *
this
.Width), 0, 0, 0);
This will set gratuitously from 0 to the right most corner the gap between the drop and most left corner.
Finally, the last thing to do is to start the animation.
That's it!
Designing the drop
To design the raindrop view I use Expression Blend. Here is the XAML for it (for clarity I have omitted the Data attribute):
<
Path
Stretch
=
"Fill"
Data="...
"
VerticalAlignment
=
"Stretch"
RenderTransformOrigin
=
"0.5,0.5"
Margin
=
"1.222,-2.518,-4.94,-7.559"
UseLayoutRounding
=
"False"
>
<
Path.Fill
>
<
LinearGradientBrush
EndPoint
=
"1.420529961586,0.976535022258759"
StartPoint
=
"0.331510990858078,0.976535022258759"
>
<
LinearGradientBrush.RelativeTransform
>
<
TransformGroup
>
<
SkewTransform
AngleY
=
"0"
AngleX
=
"17.4704"
CenterY
=
"0.976535"
CenterX
=
"0.331511"
/>
<
RotateTransform
Angle
=
"-61.3206"
CenterY
=
"0.976535"
CenterX
=
"0.331511"
/>
</
TransformGroup
>
</
LinearGradientBrush.RelativeTransform
>
<
GradientStop
Color
=
"#FE739EAD"
/>
<
GradientStop
Color
=
"#FFD3E9F9"
Offset
=
"1"
/>
</
LinearGradientBrush
>
</
Path.Fill
>
</
Path
>
It is nothing more than a path with some gradient brush on it. This results in the following, magnified about 20 times:
To simulate the drop falling I use a storyboard that:
- animates the height the drop is in each moment
- animate the visibility to collapsed when the desired height is reached, that is the drop has fallen through the whole scene
<
Storyboard
x:Name
=
"Pour"
>
<
DoubleAnimationUsingKeyFrames
BeginTime
=
"00:00:00"
Storyboard.TargetName
=
"drop"
Storyboard.TargetProperty
=
"(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"
>
<
SplineDoubleKeyFrame
KeyTime
=
"00:00:00"
Value
=
"0"
/>
<
SplineDoubleKeyFrame
KeyTime
=
"00:00:00.6"
Value
=
"{Binding FallHeight}"
/>
</
DoubleAnimationUsingKeyFrames
>
<
ObjectAnimationUsingKeyFrames
BeginTime
=
"00:00:00"
Storyboard.TargetName
=
"drop"
Storyboard.TargetProperty
=
"(UIElement.Visibility)"
>
<
DiscreteObjectKeyFrame
KeyTime
=
"00:00:00.6"
Value
=
"Collapsed"
/>
</
ObjectAnimationUsingKeyFrames
>
</
Storyboard
>
To obtain the scene height I use binding to the DropSettings object that is injected in the constructor when the raindrop is created.
Let’s start raining!
This was all you need to simulate rain. To actually start it you have to call the classes we created in a manner that satisfies our expectations.
DropSettings dropSettings =
new
DropSettings(300);
Rain rain =
new
Rain(dropSettings,
this
.Scene, 40, 3, 400);
rain.Start();
Conclusion
Although Silverlight is still very CPU consuming, in this article I’ve shown you how to use a simple algorithm to simulate rain. For all that we still should not expect miracles when it comes to real time particle simulations. But I hope soon we shall have what we wish to make our application look and behave really realistic.
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.