A friend just linked me to this question, and I thought I'd try and clear up a couple things that aren't addressed in the accepted answer.
Elias' interesting and helpful article uses "value noise" not "Perlin noise". Value noise involves curve-fitting of randomized points. Gradient noise (of which Perlin noise is a primary example) creates a lattice of 0-value points and gives each one a random gradient. They are frequently confused with one another!
http://en.wikipedia.org/wiki/Gradient_noise
Secondly, using a 3rd value as a seed is expensive. If you want random terrain, consider translating your origin a random amount instead. 3D calls are significantly more expensive than 2D calls (e.g., prefer getNoise2D(x + XSEED, y + YSEED)
over getNoise3D(x, y, ZSEED)
). Assuming the z value remains constant, all you are doing is using the z value to select a particular slice of 2D noise.
Thirdly, the straight function call is going to return values that are fairly smooth and rolling overall, not as craggy as real terrain, since it's randomness is limited to a single frequency. To get craggier terrain, a good technique is to sum together multiple calls that progress through the noise space at differing frequencies, usually set a "fractal" values.
Thus, for example, sum together noise(x, y) + (1/2)(noise(x*2, y*2) + (1/4)(noise(x*4, y*4)
...
The resulting sum will probably often be outside the range -1 to 1, so you will have to normalize the result before the values are useful. I'd like to suggest setting up a series that is guaranteed to remain within [-1, 1], for example, by progressive weighting depending upon how many 'octaves' you use. (But I don't know if this is truly the most efficient way to do this.)
Example with four octaves: (1/15)(noise(x, y) + (2/15)(noise(2x, 2y) + (4/15)(noise(4x, 4y) + (8/15)(noise(8x, 8y)
Fourthly, when mapping the results, which range from -1 to 1, to the normalization more often used with color values or color maps (0 to 1), Ken Perlin described two algorithms. One was given the name "smooth", where the mapped values are operated on by a simple translation algorithm:
f(x) = (x + 1) / 2
The other was given the name "turbulent", where the mapped values are computed as follows:
f(x) = | x |;
With the former, the resulting values will range over the color range, with sparser population at the extremes. With the latter, the resulting values will "fold" at one end of the color range or color map. This folding will give the terrain angular ridges at the fold point, as opposed to being smoothly rolling. (This assumes that one is keeping the sum of the octaves within the range -1 to 1, and that if a custom color mapping is being used, the color ranges progress smoothly over the course of the map. Neither of these conditions is "required" though, and can be played with for interesting effects.)
I'm working on a SimplexNoise visualizer... [Edit: now up at GitHub: SiVi: A Java-based 2D Gradient Noise Visualizer] ... as a Java project. A first draft of the visualizer can be found ... [Edit: I am deleting a dead link to the old java-gaming.org site. The site has been migrated to jvm.gaming.org. If you go to jvm-gaming, be warned that older references to SiVi tend to have dead links, as well.]
Great article on how SimplexNoise works (and Perlin vs Gradient background):
http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf
Stefan Gustavson did a really nice job of this!