Water ripples revisited (AS3-only version)

I’ve been thinking of changing my previous Pixel Bender water filter to an AS3-only version for some time (since FP10 is still in beta), but never got around to it. Until trusty old Nascom told me we might perhaps use it in a project. So here it is, added to the NascomASLib and ready for you to use :) I added some functionality so the appearance of the ripples can be altered. Overall, I’m quite happy with the performance, especially since it runs smoother with bigger ripples (and usually looks better too ;) ).

So enjoy the demo, and check the source here.

226 thoughts on “Water ripples revisited (AS3-only version)

  1. Pingback: Bomomo lite - Leaflet of Musings

  2. Hi Sam,

    Thanks for noticing! The latest updated should fix that issue. Also, don’t create a new Rippler instance every time. Just do it once at the top, otherwise it’ll slow down progressively because of the other instances still doing their calculations.

    To those who requested a performance update (checking when the ripples are visible), don’t worry, I haven’t forgotten about you. Haven’t gotten around to it yet – shifted priorities a bit, I guess :)

    Cheers,
    David

  3. Thanks a lot! I did another round of testings. Unfortunately, the problem is not gone. It was almost invisible when the strength is 300 and below. However, as strength increases, it becomes more and more obvious. (For extreme example of the problem, change strength to 1000000.)

    Sam

  4. I noticed that error as well in the old version. The new version however should fix that (tested it with your example). Are you sure you’re using the correct one? The colourTransform initialization should use 128 of 127 for it’s offset values.

  5. I copied and pasted rippler.as from “https://www.derschmale.com/demo/rippler/srcview/”. The problem is still there.
    However, I discovered that if I change “_colourTransform = new ColorTransform(1, 1, 1, 1, 127, 127, 127);” to ” _colourTransform = new ColorTransform(1, 1, 1, 1, 128, 128, 128);”, the problem is gone. Can it be because of the version of Flash I am using (CS4)? Or may be the version of player that I am using?

    Sam

  6. Sorry, it was actually my fault… I realised that I didn’t refresh “https://www.derschmale.com/demo/rippler/srcview/” after u made the change… Thanks a lot!

    Sam

  7. how can I use ripple effect in an image transition… making the ripple as transition for the images but without clicking anything, just like a slideshow (flash banner of images), but no buttons to activate it? i just need every image to stay for 1 or 2 seconds then ripple transition to the next image… and so on. hope you could help me on this.

  8. Hi Leslie,
    Off the top of my head: you could create two Rippler instance with each image as a target (one image on top of the other), and call drawRipple a couple of times with a short time interval (with x, y in the middle of the image). Then you should just fade the top image.

  9. Pingback: 波紋効果 « trico interactive

  10. Hey David, you made an awesome effect.

    I came across this page a while back when I did not even know what a document class was.

    I have recently been in an advanced flash class and finally have come back to this. I am hopping to get it to work and have some fun with it.

    Just wanted to thank you for your hard work. This effect is really sweet.

  11. Hi David,

    Great code! I have been trying to do something similar to live on top of a flex app I am making that will be on a touch screen. I want it so that when people touch anywhere on the screen it creates a ripple effect. I am pretty close to giving up so I was looking to see if something was out there and found yours.

    I think this issue might be that your version will only work on an image, is it possible that this could be imported to a swf and have be able to ripple over the whole swf?

  12. Jesse: You’re welcome, glad you like it :)

    Matthew: It should work with just any DisplayObject, so if you have a Loader class to import a swf, you could assign that as the source (I should rename it to “target” actually :D). If you run into any bugs, do let me know!

  13. holy cow -the colorTransform 127 thing was driving me nuts – was causing just the most subtle blur. 128 works oh so much better. THANK YOU

  14. Pingback: Think Again » Blog Archive » Ripple class.

  15. This is fantastic! I really appreciate it when skilled devs share classes like this.

    Is there any way to slow the ripples down as they expand? I’m playing around with simulating water rings that appear as though you’re looking down from a great height. By adjusting the values I see, I’ve been able to adjust the size and strength, but I don’t see anywhere to slow the “tweening” outward.

  16. James: With this model, there’s no way to influence the speed of the ripples while they’re diminishing, since it’s only using a density field which expands 1 pixel at a time (no velocity field). More complex fluid sims like (f.e. using shallow water equations, which I’ll hopefully get around to one day) give you control over viscosity, but even in that case it’s pretty hard to get a nice “ease out” tween, I think :)

  17. I’ve figured a way to decrease the enormous cpu usage of this effect. Just like James Friedman’s idea, I created a timer which removes the ENTER_FRAME event-listener at a specific time. But instead of handling the timer on the MouseClick-Event, I embedded it into the Rippler:

    First, create a private var:

    private var _timer : Timer;

    Then initialize it in the constructor (i set it to 2 seconds, may be customized):

    _timer = new Timer(2000, 1);
    _timer.addEventListener(TimerEvent.TIMER_COMPLETE, destroyInstance);

    Remove these lines from the constructor:

    // Create a frame-based loop to update the ripples
    _source.addEventListener(Event.ENTER_FRAME, handleEnterFrame);

    And add them to the drawRipple-method (before all the other code in there).
    Add these both lines directly underneath:

    _timer.stop();
    _timer.start();

    Finally, put this method somewhere into the class:

    private function destroyInstance(event : TimerEvent) : void
    {
    _source.removeEventListener(Event.ENTER_FRAME, handleEnterFrame);
    }

    So the CPU is stressed only when the effect really plays, not the whole time ;)

  18. Hey Sheik, nothing wrong with your English :D
    Thanks for the contribution. I had a different approach in mind, which doesn’t need a timer (and as such readjustment if you use different settings) by finding out when the ripple is faded out. Should make some time to implement it ;)

  19. hey David! Thanks for making this open source! I was wondering how do you make the ripple source follow the mouse? I looked at the code but I can’t seem to find the code to edit. Thanks (:

  20. Hi nehemiah, if you look at the source code of the example you’ll see _rippler.drawRipple(_target.mouseX, _target.mouseY, 20, 1); in the mouse move event listener, that does the trick :)

  21. ohh ya! I found it! But if I’m going to use Andrew’s edited code from above. I get this:

    import be.nascom.flash.graphics.Rippler;

    var myRippler = new Rippler(pic, 60, 6);

    myRippler.drawRipple(0, 0, 20, 1);

    function rippleFun(event:MouseEvent):void {
    myRippler.drawRipple(0, 0, 20, 1);
    }

    These are the codes for the Actionscript for my fla.file. How do I put the “_rippler.drawRipple(_target.mouseX, _target.mouseY, 20,1);” code in? Cause I try to modify my own codes and there is some error. Do I need to call added functions or? Sorry for asking so many questions.. I’m a noob at flash stuff now. Thanks in advance again! (:

  22. What you need to do is add an event listener to listen to mouse movements, for example, as such:
    stage.addEventListener(MouseEvent.MOUSE_MOVE, rippleFun);

  23. Hey David,
    I am kind of a noob to this.
    I am trying to figure out what exactly I need to do in Flex to make this work just like the Demo I tried the .fla but cant seem to get it to run a smoothly as the example you are showing.

    Thanks in advance

    JD

  24. JD: When using the Rippler on a DisplayObjectContainer containing several/nested components, things can slow down because of the DisplacementMapFilter. Other aspects that can influence the speed of the Rippler class is the source DisplayObject or image and the scale passed to the parameter (higher scale = faster). Hope that helps!

  25. that does help thank you!!

    I am now having the problem of the ripple effect following the mouse I am using the downloaded fla and I was just wondering how to make the effect follow instead of just come in from the upper right.

    I have made it more fluid “hehee” but I am ultimately trying to get it to follow the mouse thank you again for your help in advance.

  26. Can you tell me why the effect won’t work anymore when I try to change the framerate of the application? And is there a way to avoid this behavoir?

  27. JD: Just call the drawRipple method in an enterFrame or mouseMove listener, passing the mouseX and mouseY coordinates.

    Sheik: Odd, I checked it and have it working with framerate 1 up to 120. Are you using Flex (it’s discouraged to change a Flex application’s framerate).

  28. yes, flex 3.3 and flashplayer 10.. I have no problems with changing the framerate, done it in several other flex projects, just to get smoother tweenings..
    it’s not a big deal that I can’t change the framerate while using your effect (which is still awesome, btw!), I was just wondering why.. and now that you say thats it worked fine for you, I’m wondering even more xD

  29. I get an error with this code:
    Trying to get the mouse follow to occur…

    import be.nascom.flash.graphics.Rippler;

    var myRippler = new Rippler(pic, 50, 2);

    //myRippler.drawRipple(150, 50, 20, 1);

    addEventListener(MouseEvent.MOUSE_MOVE, rippleFun);

    function rippleFun(e:Event):void {
    myRippler.drawRipple(Mouse.x, Mouse.y, 20, 1);
    }

    Thanks, and very cool class…

  30. Is pic a Class containing an embedded image? If so, try:

    var bmp : Bitmap = new pic();
    addChild(bmp);
    var myRippler : Rippler = new Rippler(bmp, 50, 2);

    If it’s a BitmapData object:

    var bmp : Bitmap = new Bitmap(pic);
    addChild(bmp);
    var myRippler : Rippler = new Rippler(bmp, 50, 2);

  31. hmm all of my post didnt send… pic is the background mc already on the stage. I am just trying to get the rippler to follow the mouse. The below code from your sample fla only causes the ripple in one area: myRippler.drawRipple(150, 50, 20, 1);

    import be.nascom.flash.graphics.Rippler;
    var myRippler = new Rippler(pic, 50, 2);
    myRippler.drawRipple(150, 50, 20, 1);
    addEventListener(MouseEvent.MOUSE_MOVE, rippleFun);
    function rippleFun(e:Event):void {
    myRippler.drawRipple(150, 50, 20, 1);
    }

  32. As in the source of the post itself (not the .fla posted by Andrew), myRippler.drawRipple(pic.mouseX, pic.mouseY, 20, 1);

  33. hello david. I tried to add in that piece of code. But the ripple source still doesn’t orginate from the mouse pointer itself even though it can move along with the mouse. Do you know what’s wrong with my code?

    import be.nascom.flash.graphics.Rippler;
    var myRippler = new Rippler(pic, 100, 5);
    addEventListener(MouseEvent.MOUSE_MOVE, rippleFun);

    function rippleFun(e:MouseEvent):void {
    myRippler.drawRipple(pic.mouseX, pic.mouseY, 20, 1);
    }

  34. Is the pic’s registration point in the upper left corner? I think there’s still a bug in it, never got around to fixing it, if the top left of your target is not aligned to (0,0) :)

  35. Hello David. First of all heartiest congratulations on such a wonderful piece of work.

    Dear, I am unable to make your Rippler.as work with my application. Though I need to make it work on clicking a main container, I first tried on a sample application in which I just had one image and one canvas, I tried using the following code :-(pic is the instance name of my Image)

    import be.nascom.flash.graphics.Rippler;
    var myRippler = new Rippler(pic, 100, 5);
    addEventListener(MouseEvent.MOUSE_MOVE, rippleFun);

    function rippleFun(e:MouseEvent):void {
    myRippler.drawRipple(pic.mouseX, pic.mouseY, 20, 1);
    }

    It still does not work at all. I am working in Flex builder.

    Thanks in advance for your.
    Vicky

  36. Hi David,

    Thank you for your help in getting this running. I have it working on my swf now, but my CPU usage went up from 20% – 30% to 60% – 70% when it is not activated.

    Is there some kind of optimazation I can do? Maybe not have it run unlit called or something?

    Thanks again for helping me out on this,
    -Matthew

  37. Vicky: Thx! Glad to hear it’s working :)
    Matthew: Yeah, that’s still an open issue. I -still- haven’t gotten around to implementing the inactive optimization. A temporary solution would be to follow Sheik’s method (scroll up to his comment ;) ). You can also fiddle around with the scale parameter to get cpu usage down in general.

  38. Hi David,

    Is there any way to make this code a continuous wave? like without the mouseover? If not, do you know any code that is out there is AS3 that will accomplish this? Great wave effect by the way!

  39. Adam: I’m not sure what you’re looking for, but you can replace the mouseX and mouseY with any coordinate you want and run it in an enterFrame loop. It should also be pretty straightforward to extend the class and add some other wave sources than what happens in the drawRipple method. Hope that helps!

  40. Can I use this ripple effect code within my project? I will give credit for you, and it will add great beauty on my project.

Leave a Reply

Your email address will not be published. Required fields are marked *