Xref: utzoo comp.sys.amiga:40100 comp.graphics:7484 Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!mailrus!iuvax!rutgers!netnews.upenn.edu!grad1.cis.upenn.edu!ranjit From: ranjit@grad1.cis.upenn.edu (Ranjit Bhatnagar) Newsgroups: comp.sys.amiga,comp.graphics Subject: Re: Computer Dreams and water Summary: How to Compute and Ray-trace your own WAVES for fun and profit Message-ID: <14417@netnews.upenn.edu> Date: 14 Sep 89 18:40:09 GMT References: <23951@louie.udel.EDU> Reply-To: ranjit@grad1.cis.upenn.edu.UUCP (Ranjit Bhatnagar) Organization: University of Pennsylvania Lines: 177 In article <23951@louie.udel.EDU> MFM1%LEHIGH.BITNET@ibm1.cc.lehigh.edu (mark masters) writes: >Well the local PBS finally had Computer dreams, and I must say that I >was very very impressed. Now the question which I had after watching >the show was HOW DO THEY SIMULATE THE WATER SURFACE???! Take a look at the SIGGRAPH '87 proceedings. If my memory serves me, there's at least one article in there from Pixar on some very complex, great looking wave simulations. If you want a simpler technique (the tricks in the above article took tens of megabytes of storage!), try superimposing damped sine or nearly-sine waves. The results will look like ripples in a calm pool. I did this and got an art exhibit out of it! Try this, for instance: Warning to experts: this will be old hat. /* three wave sources: ripples radiate out from (x, y) with amplitude a, damping factor d, period (wavelength) p, and speed s. */ x1 = 20; y1 = 400; a1 = 10; d1 = .9; p1 = 20; x2 = -79; y2 = 220; a2 = 7; d2 = 0; p2 = 5; x3 = -200; y3 = -60; a3 = 12; d2 = 1.7; p3 = 16; for each point x, y on the water's surface whose height you want to know: r1 = distance(x,y, x1, y1) - t * s1; r2 = distance(x,y, x2, y2) - t * s2; r3 = distance(x,y, x3, y3) - t * s3; height = damp(d1, r1) * wave(r1/p1) + damp(d2, r2) * wave(r2/p2) + damp(d3, r3) * wave(r3/p3); The wave() function gives you the shape of the cross section of a single wave. A nice simple wave function is double wave(r1) { double r1; return(sin(r1)) } However, real ocean waves aren't pure smooth sines. You could try sin squared to make waves with pointy troughs, or use table lookups and draw your own wave shapes. Try superimposing a big fat wave (large a and p) with a little tiny wave (small a and p) with the same center (x, y) to get big round but wrinkly waves. The wave function you choose should REPEAT; you may have to use a modulo function or something to get that effect, so that no matter how large r1 is, it gives a valid result. The damp() function specifies how the waves die out as they get farther from the center. You could try double damp(d, r) { double d, r; return( exp(-r*d) ) } for instance... or, as with the wave function, you can use a table lookup and draw your own damping function into the table. Like the wave function, whatever you use must be able to accept arbitrary large r's, though in this case you DON'T want the function to repeat; it should just die out. The time parameter t can be used to animate the waves. If you specify the speed for each wave source, then you can increase t as you generate successive frames of the animation, and the waves will ripple out from their centers. Or decrease t, and the waves will move backwards. You may want to add phase offsets to the distance calculations for each wave so that all the sources don't hit 0 at the same time. Want big, nearly straight waves instead of circles? Put your wave source really really far away, with no damping. (If you use the exponential damping function above, then d=0 means no damping.) But, you ask, how do I make a picture out of this? Funny you should ask. One: make a color-graph out of it: for i = 1 to 640 for j = 1 to 400 set pen color to height(i, j) mod 16 plot pixel(i, j) If you choose a nice set of waves and a good color map, you can get very nice pictures out of it. (That's where my art exhibit came from.) I posted a program called, naturally, WAVES to this newsgroup a year or two ago which did generated random color-graphs of exactly this type. Two: draw a 3-d graph in projection. There are many possibilities. If you know how, you can use hidden-line removal, z-buffering, shadows, even write a ray tracer around the waves program. Three: send the output to a commercial or PD ray tracer. Easy enough! For instance, here's approximately how to do it for QRT and for Sculpt-3D: (I don't have the documents for either, so I'm faking it.) double grid[20][20] /* define a 20x20 grid to wavify */ for i = 1 to 20 for j = 1 to 20 x = i * iscale + ioffset; /* scale coordinates */ y = j * jscale + joffset; grid[i][j] = height(x, y); /* filling in the grid array is optional, but it saves calling the height function twice on the same point */ for i = 2 to 20 for j = 2 to 20 /* find the four corners of the current grid square */ x1 = (i-1) * iscale + ioffset; /* scale coordinates */ y1 = (j-1) * jscale + joffset; x2 = i * iscale + ioffset; /* scale coordinates */ y2 = (j-1) * jscale + joffset; x3 = i * iscale + ioffset; /* scale coordinates */ y3 = j * jscale + joffset; x4 = (i-1) * iscale + ioffset; /* scale coordinates */ y4 = j * jscale + joffset; printf(FormatString, x1, y1, grid[i-1][j-1], x2, y2, grid[i][j-1], x3, y3, grid[i],[j]); printf(FormatString, x1, y1, grid[i-1][j-1], x4, y4, grid[i-1][j], x3, y3, grid[i],[j]); That's all there is to it. I had to split each grid square up into two triangles, because few ray tracers can handle a square whose corners aren't coplanar. For QRT, the format string looks something like this: FormatString = "Triangle ( x1 = %f, y1 = %f, z1 = %f, x2 = %f, y2 = %f, z2 = %f, x3 = %f, y2 = %f, z2 = %f, ambient = whatever you want, reflect = whatever you want, texture = whatever you want, etc. )"; For Sculpt 3D it looks about like this: FormatString = "set color whatever you want set texture whatever you want (%f,%f,%f) - (%f,%f,%f) - (%f,%f,%f)"; For DBW it's more like this: FormatString = "t %f %f %f %f %f %f %f %f %f" Caution! It's possible that DBW uses relative coordinates on its triangles, rather than absolute, so that to use DBW you'll have to subtract x1, y1, and grid[i][j] from all the other x, y, and grid's before printing them. Also, unlike the others, DBW does back-facing polygon removal, so that if the corners of the triangle aren't specified in the right order, it'll be invisible. You can either make sure they ARE in the right order, or just create two triangles at a time,one facing each direction, in order to guarantee that one will be visible from either side. If you don't know what I'm talking about, you probably shouldn't try to operate DBW, which is worse than WordStar on acid. Have fun! - ranjit * Ranjit Bhatnagar * 4211 Pine St * Philadelphia, PA 19104 * (215) 222-5767 * "Trespassers w" ranjit@eniac.seas.upenn.edu mailrus!eecae!netnews!eniac!... "Such a brute that even his shadow breaks things." (Lorca)