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

Smoke effect

(97 votes)
Miroslav Miroslavov
>
Miroslav Miroslavov
Joined Nov 24, 2009
Articles:   8
Comments:   6
More Articles
9 comments   /   posted on May 17, 2010
Categories:   White Papers , General

This article is compatible with the latest version of Silverlight.

This is part 5 of the series “Silverlight in Action”.

Here we’re sharing our experience from the amazing CompletIT web site.

Maybe the hardest feature to implement from the entire site was the Smoking menu effect. We’ve tried out a lot of ideas and I’m going to summarize some of them:

  1. We thought to use a video as a background, but its performance was bad. Blending the video with the background was hard to do. Randomizing the smoke to make it more realistic would be almost impossible if using a video, as well.
  2. After that we tried to make a Path that looks close to one knot from the smoke. We copied that path for example 50-100 times, randomized these paths in some manner and animated them to move like smoke. This idea was partly close to the effect, but still far away from a real smoke effect. And also hard to scale.
  3. One very interesting approach that we found was to create a snapshot of real smoke. And then to use PixelShader effect to create the fluid movement of the smoke. This idea could be implemented but needs a lot of work, more than basic physics knowledge and the writing of lots of code in HLSL, which wasn’t that easy. Also it was not very clear if this was going to perform good enough (knowing that the whole site is moving and flying around).
  4. Particle system. There are already some Silverlight smoke particle system realizations out there on the web. This was maybe the most obvious way of creating a smoke effect and also somehow easy to do, but the actual result was not very satisfying and didn't look like fluid smoke.

 

Here is a snapshot of the real look of the smoke.

Smoke

Smoke effect in Action

Get Microsoft Silverlight

The Idea - Sprite Animation

We’ve decided to implement an idea that is very old and well-know in games development. A sprite animation is a predefined sequence of related images that looks like an animation/movement when changed in a fast way. In our example we change smoke frames on 20 frames per second. All image frames are around 100.

Implementation

There are a couple of different approaches to achieve sprite by using Silverlight. And one of the widespread implementations includes creating an Image control in Blend for every frame and after that creating a Key-Frame animation that hides the previous and shows the new one. Also you can create a big image that has all the frames and you can then clip this big image to show the current frame.

But we’ve implemented it in another way. We hold only one Image control and change its Source property on every frame. We’ll create a base class called ImageSequenceControl that will do most of our job. It’ll hook up the CompositionTarget.Rendering event and will change the frames accordingly.

In the constructor of this control we’ll pass a parameter - fps (frames per second). When having it we can calculate the interval between the frames.

 protected ImageSequenceControl(int frames, double fps)
     : this()
 {
    this.frames = frames;
    averageInterval = TimeSpan.TicksPerSecond / fps;
 }

And here is the CompositionTarget.Rendering handler.

 //Raised before drawing of every frame.
 private void CompositionTarget_Rendering(object sender, EventArgs e)
 {
     long now = DateTime.Now.Ticks;
 
     //Since we run on custom fps, we need to check if it's time to draw new frame.
     if (now - lastTick < averageInterval)
         return;
  
    if (AutoReverse && now < pauseStart + pauseSec)
         return;
  
     //We've finished the frames and may start again.
     if (frame == frames)
     {
         if (AutoReverse)
         {
             Randomise();
             pauseStart = now;
         }
         frame = startFrame;
     }
  
     if (AutoReverse)
     {
         //Managing the opacity to make the effect of disapearing when reaching the last frames.
         double ratio = (double)(frame - startFrame) / (frames - startFrame);
         image.Opacity = .5 - 2 * (.5 - ratio) * (.5 - ratio);
     }
  
     //Show the next frame.
     image.Source = images[frame - 1];
     frame += 1;
  
    lastTick = now;
 }

The actual Image information (url sources) is implemented in the sub-classes like SmokeControl.

 public class SmokeControl : ImageSequenceControl
 {        
    private static readonly Random random = new Random();
  
     public SmokeControl()
         : base(118, 10)
     {
         AutoReverse = true;
         RenderTransformOrigin = new Point(0, 1);
     }
  
     protected override string GetImageName(int index)
     {
         return string.Format("Smoke/Comp 1 {0:000}.png", index);
     }
  
     protected override void Randomise()
     {
         CompositeTransform transform = this.EnsureTransform();
   
         transform.Rotation = random.Next(-30, 0);
   
         startFrame = random.Next(1, frames / 2);
     }
 }

Download the code

Stay tuned for more articles from this series coming up next week.


Subscribe

Comments

  • -_-

    RE: Smoke effect


    posted by Aaron on May 19, 2010 16:26
    Brilliant!  You guys rock!
  • -_-

    RE: Smoke effect


    posted by Ian on May 26, 2010 00:29

    Yep, seriously thinking of integrating this into my curent app. 

    I'll let you know how it goes.

  • -_-

    RE: Smoke effect


    posted by me on Aug 25, 2010 17:26
    smoking hot.
  • LawBot

    RE: Smoke effect


    posted by LawBot on Jan 21, 2011 18:33

    First: The idea is brilliant.

    Regarding your coding in the CompositionTarget_Rendering handler I would like to provide an alternative approach to implement a frame changing on "frame per second" basis:

    01.Private cnt As Double = 0
    02.Private ccnt As Double = 0
    03.Private totalFrameCounter As Integer = 0
    04.Private fps As Double = 24
    05.Private Sub MakeSprite(ByVal sender As Object, ByVal e As EventArgs)
    06.  ccnt += 1 / 60
    07.  If ccnt >= (1 / 60) * 60 / fps Then
    08.    cnt += 1
    09.    imScene.Source = New BitmapImage With {.UriSource = New Uri(GetImageName(cnt), UriKind.RelativeOrAbsolute)}
    10.    If cnt = 118 Then
    11.      RemoveHandler CompositionTarget.Rendering, AddressOf MakeSprite
    12.      cnt = 0
    13.    End If
    14.    ccnt = 0
    15.  End If
    16.End Sub

    Best regards,

    Martin Krüger

  • LawBot

    RE: Smoke effect


    posted by LawBot on Jan 21, 2011 18:35

    Ah ... sorry. What I forgot to mention is:

    The alternative approach provided works because the CompositionTarget.Rendering event is called by Silverlight 60 times each second.

    Best regards,

    Martin Krüger

  • -_-

    RE: Smoke effect


    posted by John on May 31, 2011 14:02

    Really great instruction Miroslav!

    I'm waiting for more!

    Greetings

    Windows Phone 7 

  • sammys111

    Re: Smoke effect


    posted by sammys111 on Aug 08, 2011 00:48
    Very cool effect and it is great that you are willing to share it with the community like this. One questions I had was do you have any sample source code doing this in VB.NET? I'm a VB.NET user and I love to see tutorials in this language as opposed to C#. For example a tutorial like this one - that explains conditions in VB.NET is very helpful.
  • BlueBierd

    Re: Smoke effect


    posted by BlueBierd on Oct 05, 2011 04:31

    Thanks for sharing this. The smoke effect is very good, and very similar to how smoke moves in real life. Is it possible to change the way the smoke moves by increasing the number of frames per second? Or would it end up looking unnatural?

     Gordon - Green Smoke Coupon

  • miromiroslavov

    Re: Smoke effect


    posted by miromiroslavov on Oct 05, 2011 10:17

    You can increase the FPS and it should still look natural, but this will decrease the overall performance, because will have to redraw it more often. But still if it's not a problem for you, why not.

    Thanks for your comment.

Add Comment

Login to comment:
  *      *       

From this series