Jump to content

  • Log In with Google      Sign In   
  • Create Account

Like
2Likes
Dislike

The Water Effect Explained

By Roy Willemse | Published Feb 15 2000 03:58 AM in Graphics Programming and Theory

wavemap wave angle surface light value beam incoming normal
If you find this article contains errors or problems rendering it unreadable (missing images or files, mangled code, improper text formatting, etc) please contact the editor so corrections can be made. Thank you for helping us improve this resource

An Introduction

Of the many effects in computer graphics, the water effect is one that will definitely catch the viewer's attention. It simulates the behavior of water when it is disturbed.

This article consists of two parts. The first part describes how the behavior of water is simulated. The second part describes how you can calculate the refraction of light when it hits a transparent surface. Together they provide you with the knowledge to program an eye-catching simulation.

Part 1 - How Waves Are Simulated

This mechanism behind this effect is remarkably simple. It is so simple, that I believe that it was invented by accident while experimenting with area sampling. But before I dive into the calculations behind the wave simulation, I will tell you something about area sampling.

Area Sampling
Area sampling is a very common algorithm in computer graphics. Considering a two-dimensional map, the value at (x, y) is affected by values surrounding position (x, y), such as (x+1,y), (x-1,y), (x,y+1) and (x,y-1). Our wave simulation actually works in three dimensions, but I'll get to that later.

Area Sampling Example: A Simple Blur
Blurring a map is very simple. You'll need two maps: one containing the data you want to blur, and one for the resulting map. The algorithm (using five sample values) looks like this:

ResultMap[x, y] := ( SourceMap[x, y] +
				 	SourceMap[x+1, y] +
				 	SourceMap[x-1, y] +
				 	SourceMap[x, y+1] +
				 	SourceMap[x, y-1] ) DIV 5

In plain English: the value at (x, y) depends on the average value of surrounding values. Sure, things get a bit more complicated when you want to blur images, but you get the idea.

Creating a wave simulation is basically the same, but the value at (x, y) is calculated in a different manner. Earlier I mentioned that our wave simulation works in three dimensions. Well, our third dimension is time. In other words: while calculating our wave simulation, we have to know how the waves looked like one moment earlier. The resulting map becomes the source map for the next frame.

This is the actual wave simulation algorithm:

ResultMap[x, y] := (( CurrentSourceMap[x+1, y] +
					  CurrentSourceMap[x-1, y] +
					  CurrentSourceMap[x, y+1] +
					  CurrentSourceMap[x, y-1] ) DIV 2 ) -
					  PreviousResultMap[x, y]

You'll notice that the first four values obtained from the current source map are divided by two. This results in a value twice the average. Next, we subtract the value at our working location (x, y) from the previous result map. This produces a new value. Look at figure a and b to learn how this effects the wave.

Attached Image: figure_a.gif

The horizontal gray line represents the average height of the waves. If the previous value at (x, y) was lower than average, then the wave will rise towards average level, as shown in figure a.

Attached Image: figure_b.gif

If the previous value at (x, y) was higher than average, as shown in figure b, the wave will drop towards average level.

Damping
Every time a wave moves up and down, its energy is distributed over a growing area. This means that the amplitude of the wave drops until the wave levels out. Using a damping factor simulates this. The factor, a certain amount or percentage of the amplitude, is subtracted from the current amplitude to let high amplitudes die out fast, and low amplitudes die out slow. In the example below, one sixteenth of the amplitude is subtracted each time it moves.

Wave Simulation Example
The following code fragment originally included some inline assembler, but I replaced it by native Pascal code so it can be easily ported to any language and/or platform.

.
.
const
  MAXX = 320;			 	{ Width and height of WaveMap }
  MAXY = 240;
  DAMP = 16;				  { Damping factor }

{ Define WaveMap[frame, x, y] and frame-indices }
var
  WaveMap: Array[0..1, 0..(MAXX-1), 0..(MAXY-1)] of SmallInt;
  CT, NW: SmallInt;

.
.
procedure UpdateWaveMap;
var
  x,y,n: Smallint;
begin
  { Skip the edges to allow area sampling }
  for y := 1 to MAXY-1 do begin
	for x := 1 to MAXX-1 do begin
	  n := ( WaveMap[CT,x-1,y] +
		 	WaveMap[CT,x+1,y] +
		 	WaveMap[CT,x,y-1] +
		 	WaveMap[CT,x,y+1] ) div 2 -
		 	WaveMap[NW,x,y];

	  n := n - (n div DAMP);

	  WaveMap[NW,x,y] := n;
	end;
  end;
end;
.
.

When this code is executed, you would render the result to an image buffer. How this is done is explained in part 2. Important is that you swap the source and result map for the next iteration, after rendering the image:

Temporary_Value := CT;
CT := NW;
NW := Temporary_Value;

But what do CT and NW mean? CT and NW are variables that point to different wavemaps. CT is the current wavemap, which contains the data we need to generate the new wavemap, pointed to by NW. CT and NW can hold two values, 0 and 1, and can never be the same. Because we swap the maps after each iteration, the new wavemap contains the data of the wavemap generated before the current wavemap. I realize that this might sound complicated, but it really isn't.

Getting It To Move
The procedure above simply levels out the waves. So, how can we make the whole thing move? Exactly, by lowering values in the wavemap. An undisturbed wavemap contains only zero's. To create a wave, just pick a random location and change the value like this:

WaveMap[x, y] := -100;

The higher the value the bigger the waves.

Part 2 - Transparent Surface Ray-Tracing

Now we have our wavemap, we want to have some fun with it. We take a beam of light and let it pass through the surface vertically. Because water has a higher density than air, the beam refracts towards the surface normal, and we can calculate where the beam hits whatever is under there (an image, for example).

First we have to find out what the angle between the incoming light and the surface normal is (figure c).


Attached Image: figure_c.gif

In figure c, the red line represents the surface normal. The vertical line running through the wavemap represents the incoming light, and the arrow connected to the vertical line is the refracted beam. As you can see, the angle between the refracted beam and the surface normal is smaller than the angle between the incoming beam and the surface normal.

Determining The Angle Of The Incoming Light
This is done by measuring the difference in height between (x, y) and (x-1, y), and between (x, y) and (x, y-1). This gives us a triangle with a base of 1. The angle equals arctan( height difference / 1 ), or arctan( height difference ). Look at figure d for an explanation:

Attached Image: refract.gif

Calculating the angle between the surface normal and the incoming light is very simple in our case. If we draw an imaginary triangle as shown here in red, all we need to do is determine alpha. We get the tangent of alpha when we divide y (height difference) by x (1). In other words, the height difference is the tangent of alpha, and alpha is ArcTan( height difference ).

To convince you of the fact that this is actually the angle between the surface normal and the incoming light, I rotated the red triangle 90 degrees counter-clockwise. As you can see, the hypothenusa runs parallel to the surface normal.

Next, we calculate the refraction. If you remember your high school physics, you know that:

refraction index = sin( angle of incoming light ) / sin( angle of refracted light )

so that the angle of the refracted beam can be calculated like this:

angle of refracted light = arcsin( sin( angle of incoming light ) / refraction index )

where the refraction index is that of water: 2.0.

Third, we need to calculate where the refracted beam hits the image, or its relative position to the place where the incoming light beam originally entered:

displacement = tan( angle of refracted beam ) * height difference

Transparent Surface Ray-Tracing Example
The following code fragment is not optimized, because you would miss out on all the important details of the calculation.

for y := 1 to MAXY-1 do begin
  for x := 1 to MAXX-1 do begin
	xDiff := Trunc(WaveMap[x+1, y] - WaveMap[x, y]);
	yDiff := Trunc(WaveMap[x, y+1] - WaveMap[x, y]);

	xAngle := arctan( xDiff );
	xRefraction := arcsin( sin( xAngle ) / rIndex );
	xDisplace := Trunc( tan( xRefraction ) * xDiff );

	yAngle := arctan( yDiff );
	yRefraction := arcsin( sin( yAngle ) / rIndex );
	yDisplace := Trunc( tan( yRefraction ) * yDiff );

	if xDiff < 0 then begin
	  { Current position is higher - Clockwise rotation }
	  if yDiff < 0 then
		newcolor := BackgroundImage[x-xDisplace, y-yDisplace]
	  else
		newcolor := BackgroundImage[x-xDisplace, y+yDisplace]
	end else begin
	  { Current position is lower - Counterclockwise rotation }
	  if yDiff < 0 then
		newcolor := BackgroundImage[x+xDisplace, y-yDisplace]
	  else
		newcolor := BackgroundImage[x+xDisplace, y+yDisplace]
	end;

	TargetImage[x, y] := newcolor;
  end;
end;

The attached files demonstrate these effects.









Comments

2016-3-22 leilei

gucci borse stephen curry shoes ralph lauren cartier glasses christian louboutin shoes canada goose uk converse sale coach outlet online coach factory outlet coach factory outlet coach factory outlet online ed hardy uk true religion jeans michael kors bags coach outlet ray ban sunglasses skechers outlet louis vuitton borse lacoste shoes ralph lauren outlet ray ban sunglasses jimmy choo outlet store christian louboutin uk polo ralph lauren outlet ugg outlet online instyler max timberland boots michael kors handbags polo ralph lauren polo ralph lauren outlet toms outlet louis vuitton pas cher ray ban sunglasses mont blanc pens prada uk longchamp levis 511 toms shoes ugg sale ray ban sunglasses nike blazer louis vuitton handbags rolex watches nike store uk toms shoes fitflops clearance nike air max 95 ray ban outlet cheap basketball shoes fitflop uk christian louboutin outlet converse uk louis vuitton handbags michael kors outlet ray bans under armour outlet michael kors handbags michael kors supra for sale true religion jeans michael kors handbags true religion michael kors outlet reebok classic michael kors outlet micahel kors adidas gazelle pandora jewelry adidas trainers omega speedmaster supra shoes kate spade outlet ralph lauren pas cher oakley outlet ray bans louis vuitton handbags michael kors watches discount oakley sunglasses coach purses on sale nike huarache ray ban outlet ghd hair straighteners oakley sunglasses nike roshe run michael kors bags coach outlet online cheap jordan shoes michael kors bags toms outlet air max 90 michael kors handbags reebok shoes michael kors louboutin calvin klein dresses coach outlet hollister uk prada handbags michael kors outlet online ghd flat iron omega watches white converse lacoste polo shirts lululemon sale coach outlet online lululemon outlet babyliss pro canada goose sale coach outlet online adidas superstars nike cortez shoes canada goose jackets canada goose sale hermes outlet burberry outlet coach factory outlet rolex daytona salvatore ferragamo sac longchamp michael kors outlet babyliss flat iron louboutin pas cher prada handbags mcm handbags fitflops outlet ray ban sunglasses asics gel kayano cheap oakley sunglasses prada outlet louboutin outlet adidas shoes mizuno running shoes converse shoes michael kors outlet coach outlet michael kors outlet coach outlet store online toms outlet store nike running shoes ralph lauren outlet longchamp outlet oakley store kate spade outlet burberry uk polo outlet kate spade outlet online michael kors outlet online ralph lauren uk fitflop shoes fitflops shoes true religion jeans ralph lauren hermes belt valentino store christian louboutin uk michael kors watches armani jeans louis vuitton bags michael kors handbags versace jimmy choo shoes asics shoes converse shoes nike free runs kate spade outlet michael kors outlet burberry outlet online burberry outlet cheap ray bans michael kors bags levis jeans gucci outlet online ray ban sunglasses outlet michael kors outlet clearance calvin klein outlet michael kors handbags sac longchamp pliage christian louboutin polo ralph lauren outlet ferragamo shoes longchamp bag nike air max 90 nike tn pas cher air max 90 michael kors outlet hollister clothing coach factory outlet air jordan shoes oakley sunglasses wholesale reebok outlet cheap oakley sunglasses cheap jordans timberland uk coach outlet online toms outlet pandora charms michael kors handbags ecco shoes coach outlet online ray ban outlet michael kors outlet online puma shoes louis vuitton kate spade handbags burberry outlet handbags coach factory outlet online coach outlet online ed hardy jordan pas cher armani exchange nike trainers reebok shoes designer handbags outlet coach outlet store online burberry michael kors coach outlet ugg outlet michael kors handbags oakley sunglasses sale coach outlet store online michael kors outlet michael kors outlet under armour shoes bottega veneta fitflops outlet burberry outlet valentino shoes coach factory outlet online new balance shoes kate spade outlet vans outlet rolex replica watches abercrombie & fitch coach outlet store canada goose uk converse sale vans shoes ralph lauren outlet coach factory online prada handbags on sale polo ralph lauren marc jacobs handbags jordan shoes coach outlet fitflops sale air max chaussure louboutin coach factory outlet ture religion outlet michael kors outlet hollister clothing store cartier watches chi flat iron nike force 1 true religion outlet

http://bit.ly/1W9i4Xx
http://bit.ly/1WIiSlZ
http://bit.ly/1TOtSbq
http://bit.ly/258USdF
http://bit.ly/1s1RJ0U
http://bit.ly/1qBWahB
http://bit.ly/1VeFRUB
http://bit.ly/22jSQFF
http://bit.ly/1YNc3h2
http://bit.ly/1ORt8pN
http://bit.ly/1NEqV0y
http://bit.ly/1OGrW37
http://bit.ly/242rjIa
http://bit.ly/1XIPXxM
http://bit.ly/258V6kZ
http://bit.ly/1TrA9Ky
http://bit.ly/1U6wC3J
http://bit.ly/1WJDvPh
http://bit.ly/1TOu1eN
http://bit.ly/1XpgmAb
http://bit.ly/1WIiYtP
http://bit.ly/1Tv9r5W
http://bit.ly/27Mmfwk
http://bit.ly/25fAR8E
http://bit.ly/1XIQ9gz
http://bit.ly/1U6wktv
http://bit.ly/258VnEt
http://bit.ly/1XpgAqU
http://bit.ly/1TmTXnI
http://bit.ly/1ORt0Xi
http://bit.ly/1TmUA0q
http://bit.ly/1U6wykp
http://bit.ly/1OGs6HL
http://bit.ly/1TrAtJb
http://bit.ly/1U6zv7m
http://bit.ly/1s1S1ow
http://bit.ly/242s83y
http://bit.ly/242rzqC
http://bit.ly/25fANFT
http://bit.ly/1ORtkoN
http://bit.ly/258Vpfw
http://bit.ly/1qBWg8R
http://bit.ly/1OGrVfC
http://bit.ly/1TmUiXy
http://bit.ly/27MmszA
http://bit.ly/1ORtEUN
http://bit.ly/258Vr78
http://bit.ly/1XIQArg
http://bit.ly/1TrAEUY
http://bit.ly/1s1RJxT
http://bit.ly/1ORtlcs
http://bit.ly/1WIj4BM
http://bit.ly/1YNcR5s
http://bit.ly/1RgEHRu
http://bit.ly/1TA56zG
http://bit.ly/1Tv9y1u
http://bit.ly/1TOuk9E
http://bit.ly/20laBTo
http://bit.ly/20lbbkb
http://bit.ly/1OGrTV4
http://bit.ly/1TrAL2T
http://bit.ly/22jTe7b
http://bit.ly/25fB2kh
http://bit.ly/25fBbEo
http://bit.ly/1RgEhur
http://bit.ly/1U6zVdW
http://bit.ly/1XpgmQJ
http://bit.ly/1ORtqgm
http://bit.ly/242rUcU
http://bit.ly/1XpgZcX
http://bit.ly/27MnHPc
http://bit.ly/1WJDX00
http://bit.ly/1s1SqY3
http://bit.ly/1U6zCA0
http://bit.ly/1TOuM7O
http://bit.ly/1TA4Qkk
http://bit.ly/1OGshmg
http://bit.ly/1NEryqY
http://bit.ly/1U6wvoO
http://bit.ly/1XIR806
http://bit.ly/1OGsnKI
http://bit.ly/20laPdf
http://bit.ly/1NErzv7
http://bit.ly/1RgF4LU
http://bit.ly/1NErh7l
http://bit.ly/25fBFu5
http://bit.ly/1WIjHew
http://bit.ly/1ORtywm
http://bit.ly/1ORtFIc
http://bit.ly/1WIjp7y
http://bit.ly/1W9j79O
http://bit.ly/20lb7Rj
http://bit.ly/1NErGqv
http://bit.ly/1U6wHV5
http://bit.ly/1TA5Ch5
http://bit.ly/1sMlyTW
http://bit.ly/1Tvapz6
 


Note: Please offer only positive, constructive comments - we are looking to promote a positive atmosphere where collaboration is valued above all else.




PARTNERS