# Building the Reallistic Water Ripples Sample in Silverlight

In this tutorial:

- creating and rendering water ripples

- optimized image generation

- JPEG decoding component for Silverlight

## Algorithm

The algorithm is based on Hugo Elias’ 2D water tutorial.

On each render step we have the state of the water for the current frame and the previous frame.

The state is stored in two 2-dimensional arrays of integers that are as big as the image.

For each pixel position of the image we store the height of the water (or wave) in that position. 0 means “sea level”. Larger than 0 means that we have a raised wave, less than zero means that we have wave below “sea level”. We need information for both raised and low waves in order to be able to combine them.

On each render step we use data from the current frame (Buffer2) and the previous frame (Buffer1) and   write the results into Buffer1.

damping = some non-integer between 0 and 1 (I use 0.94)

for every non-edge element:

loop

Buffer2[x, y] = (Buffer1[x-1,y]

Buffer1[x+1,y]

Buffer1[x,y+1]

Buffer1[x,y-1]) / 2 - Buffer2[x,y]

Buffer2[x,y] = Buffer2[x,y] * damping

end loop

Swap the buffers

Display Buffer1

end loop

You can go ahead and look at Hugo’s explanation about why does this work, or continue reading here.

Because the 2 buffers contain consecutive steps for the water, we can get the water velocity at a given location [x, y] by subtracting: Buffer2[x, y] – Buffer1[x, y]

Also we want the waves to spread out, so we smooth the buffers on every frame:

Smoothed[x,y] = (Buffer1[x-1, y] +

Buffer1[x+1, y] +

Buffer1[x, y-1] +

Buffer1[x, y+1]) / 4

In the actual algorithm we multiply the smoothed value by 2 in order to decrease the effect of velocity.

And last, the waves lose energy as they travel:

Buffer2[x,y] = Buffer2[x,y] * damping

## Rendering the Water

The render buffer contains heights of the water in each pixel. We’ll render it using shading and refraction.

The shading variable below determines the direction and intensity of the light. For example, if you set shading = xoffset, you’ll get light straight from the left. I decided to set the light at the bottom-right part of the screen.

For every non-edge pixel in the buffer

Xoffset = buffer[x-1, y] – buffer[x+1, y]

Yoffset = buffer[x, y-1] – buffer[x, y+1]

shading = (xoffset - yoffset) / 2

// note: x+xoffset and y+yoffset do not wrap around the texture

t = texture[x+Xoffset, y+Yoffset]

// make sure the color is within limits

resultColor = SaturateTo255Max(resultColor)

plot pixel at (x,y) with color resultColor

End loop

## Creating Drops/Splashes

I made a simple function to create a circular splash, although you can create different splashes to simulate dropping irregular shapes into the water or other motion effects (e.g. star, line or use the letters of your name).

The function creates a splash given its radius at location (cx, cy). The splash begins below water level and rises above at the end.

dist = distance from point (x,y) to (cx, cy)

if (dist < radius) // if within splash circle

buffer1[x, y] = 255 - (512 * 1 - dist / radius)

end if

end loop

end loop

## The Silverlight Side

The rendering loop is called every 60ms and does this:

1. Add a random splash (rain drop) on the image

2. Calculate the next frame to render

3. Display the next frame

There are 3 components used to render each frame:

Renderer has the “raw” buffers of integers containing wave height for each pixel in the frame. On each frame the renderer mixes its raw buffer with the background image (decoded using FluxJpeg.Core.Image component) and outputs each it to a dynamic image generation surface (EditableImage).

Original 2D water algorithm (Hugo Elias)

This is the algorithm used as a base for the sample.

Dynamic image generation (Joe Stegman)

I’m using optimized version of Joe’s algorithm to render the effect on screen.

The binary is used to decode the JPEG image in Silverlight.

1. Nick says:

First of all thanx for the implementation in silverlight – i was looking for this for quite a while. Since i am not a developer i couldnt figure out how to translate the original example. But you agree with me that this old classic flash implementation of the same example is a lot- smoother. 🙂

By the way. Can this effect be achieved with shaders in WPF? If so – would you give it a try?

regards

n

2. nikola says:

Thank you for your comment. It’s a nice sample. It was very easy to do the Silverlight Beta2 translation in C# (1-2 hours including fit and finish). I never used Flash so far and I’m not sure how long it would take me to do equivalent of my sample in Flash. The two samples look similar. Mine has slow-spreading water drops which appear to drop on a thin layer of water, while the other one looks like deep water. I think there’s a difference in the final rendering phase…

I am planning a WPF shader water effect for the last couple of months now (haven’t started on it yet) 🙂 will post it here and on http://www.nokola.com

I want to do frosted glass effect using shaders first 🙂

3. slyi says:

The ripple effect is really sweet. I could see this being used for onclick event for headers naviagations giving a effect like your mouse click has touched the water surface.