Should be displaying a VRML world here
If instead you're seeing this text, you need a more modern web browser.
Drag your mouse left and right to rotate the view.
Drag it forward and backward to walk forward or backward
Roll the mouse wheel, or on a touch screen drag 2 fingers, to look up or down.
Press the PageUp or PageDn keys to jump between viewpoints.
Right-click, or long-tap to get the menu if you want to choose full-screen view.
The ESC key escapes from full-screen, or on a touch-screen long-tap brings up the menu again then choose to end full-screen mode.
My experiment with a single wave had worked (after a lot of trial and error). Now I wanted to extend that to cover a large area of water in my worlds with water that showed moving waves.
How might I do that? If I want to build upon my previous wave experiment then I could try tiling an area with many small wave tiles.
The first thing I noticed is that my previous single wave didn't tile properly. The beginning and end sections didn't match. I needed a 9th section so that the first and last edges were always the same height as they waved. This was easy, as I'd originally calculated the sine wave in 9 parts and left off the final one. Silly me. Now I just added it back in.
Also the waves were a bit jerky, so to move them more smoothly I doubled the number of keyframes. The original had 4 keyframes with a 5th to get back to the start position. This more smoothly moving version had 8 keyframes plus the 9th which was a duplication of the start of the cycle. The 9 keyframes have nothing to do with the 9 segments of the wave. It was just easier to re-use my height values by shifting them along one for each tick of the animation.
Tiling an area was much simpler than I expected. I surrounded the water tile with a Group node which I DEFined as "patch" like this:
DEF patch Group { children [ Shape { # beginning of the wave IndexedFaceSet
Then I made any number of instances of the wave patch translated to different positions like this:
Transform { translation -7 0 0 children [ USE patch ] } Transform { translation 7 0 0 children [ USE patch ] }
In the example at the top of this page I used 240 instances of the one patch, but I first experimented with just 3 patches, then 48.
There were a number of immediate problems.Even though the first and last parts of the waves matched in position, they still didn't match in shading. This is because I smoothed the shading to hide the creases between the flat segments, making it look like a smoothly varying curve. Unfortunately there was no way to make the end of the wave smoothly shade into the beginning of the next one. There would always be that apparent crease between the first and last edge. Reducing the creaseAngle in the IndexedFaceSet made it less obvious, but meant it showed the creases between all the other faces. At a distance it was almost okay because it made the waves shimmer a bit, but up close it was terrible. In the end I "solved" the shading mismatch by making the waves matte -- that is, not shiny -- and increasing their ambient light, so they don't show shading. Not really a good solution, but it also lessens some of the other problems.
I tried to vary the waves' uniformity by varying their height across the width of the wave, at right-angles to the motion of the waves. If I lessened or increased the waves in their direction of travel then the ends mismatched badly, which looked terrible. As it was the sides mismatched anyway, which ruined it a bit when viewed close up, but from a distance it didn't look too bad. You can see it here.
The problem of seeing under the edges of the tiles was avoided by placing a second sheet under the waves that was the same color.
I found that the waves looked less mechanical if I reduced their amplitude. That way when they lapped against the shore they looked more like gentle waves or swells, as you can see in the example at the top of this page.
I should mention how I made the terrain too. I used the wonderful, free, paint and image-processing program, Gimp to create a 256x256 pixel black, grayscale image. Then I used its spraypaint tool to draw lighter areas on it. (When used for a heightfield later the lighter parts would be higher and darker parts lower.) A nice side-effect of using the spraypaint tool is the uneven, rocky appearance of the surface.
That was saved as a png image, then converted using ImageMagick to the text-format pgm image:
convert "terrain-for-waves-256x256.png" -compress none -depth 8 "terrain-for-waves-256x256.pgm"
Having converted it to pgm text format, I could then simply copy/paste the numbers from the body of the file into the VRML in the heightfield that was the terrain. The color is set in the VRML, of course. I added a tiny amount of transparency (0.2) to the water to give just a hint of the terrain underneath.
Even though the water looks very unrealistic as a matte color without shade or reflection, I'm still very happy with the movement of it against the rocky shore. I wish I could improve the surface characteristics too, but I think that's beyond VRML's capabilities.
I should experiment with using a script node to animate the values of a heightfield. That way I wouldn't need to worry about tiles. That would eliminate a lot of the problems of using an IndexedFaceSet for the water. I could make the water shiny too.