   Experiences with perlin noise
  I''m about to start work on a system that will use perlin noise to generate a heightmap. I''m ok with the basic premise of adding up several noise values. What I''m wondering about is how you choose how to map the input range of your noise function to the range of values your 2D map will use.In particular; using a 1D map for simplicity, if I have 200 points I wish to generate a height value for, merely passing the position (between 0 and 199) to a noise generator that expects an integer will be no good, as each value will be totally independent of the next and the interpolation that people talk about using with Perlin noise becomes irrelevant. If you add higher-frequency noise on top where the frequency is a power of 2, this continues to be the case. So you''re not going to have anything remotely smooth because the lowest frequency you use already looks pretty high-frequency in terms of change of values.So what do you do? Normalise your range of input values from 0.0 to 1.0 for the lowest frequency noise layer, and work up from there, for example with the 2nd (lower amplitude) layer going from 0-2, the 3rd from 0-4, etc? Are there any well-tested or accepted values for this, or do people just play with the values until they get what they want? I''d also be interested to see what parameters people are passing to their noise function.   [ MSVC Fixes | STL Docs | SDL | Game AI | Sockets | C++ Faq Lite | Boost  Asking Questions | Organising code files | My stuff | Tiny XML | STLPort] 
  For my perlin noise system(s) I do the following (simplified to 1D):I generate a number of octaves of noise.  Each octave stores the amplitude and wavelength of the noise.  Amplitude is floating-point, wavelength is integer.For each point I call noise(x):noise(x){float result = 0;foreach(noiseOctave){result += noise(x, noiseOctave);}}noise(x, noiseOctave){int minimum = x / noiseOctave.wavelength;int maximum = minimum + 1;float interpolant = (x - minimum) / noiseOctave.wavelength;float result = interpolate(random(minimum), random(maximum), interpolant) * noiseOctave.amplitude;return result;}Where random(int) is your prefered random number system.So you only sample at 'wavelength' intervals, and interpolate between these, i.e. for  one octave of amplitude = 1 and wavelength = 4:x = 0: result = random(0);x = 1: result = (random(0) * 0.75) + (random(1) * 0.25);x = 2: result = (random(0) * 0.5) + (random(1) * 0.5);x = 3: result = (random(0) * 0.25) + (random(1) * 0.75);x = 4: result = random(1);Although I use cubic rather than linear interpolation.Also it's better to modify the second noise function so that instead of returning a value in the range [0..amplitude] it returns a value in the range [-amplitude/2..amplitude/2].Just realised I hadn't answered your last question.  Regarding well-tested/accepted values, I haven't found any.  I just play with the number of octaves and the amplitude and wavelength of each octave.  My last project I used octaves: (16, 12.0f), (4, 2.0f), (2, 0.5f) and (1, 0.2f) which was a bit regular on the small scale but worked well enough for what I wanted it for.EnigmaEDIT: my pseudocode was inconsistent plus added penultimate paragraph.EDIT2: and a bug!EDIT3: added last paragraph   [edited by - Enigma on February 4, 2004 7:20:51 PM];  Kylotan, I don't fully understand. Do you mean your perlin noise does not look smooth? That would bes trange because it should so because of the interpolation used for non integer input values. How do you scale your input values?Have a look at the perlin-noise-math-faq.    [edited by - VolkerG on February 4, 2004 7:23:01 PM];  Ok, so basically your wavelength of 4 means that you have a discrete random value for every 4 discrete points, with the rest interpolated. Whereas my original example implied a wavelength of 1, leading to no interpolation.Do you find 4 to be a good value here?   [ MSVC Fixes | STL Docs | SDL | Game AI | Sockets | C++ Faq Lite | Boost  Asking Questions | Organising code files | My stuff | Tiny XML | STLPort] ;quote:Original post by VolkerG  Kylotan, I don''t fully understand. Do you mean your perlin noise does not look smooth? That would bes trange because it should so because of the interpolation used for non integer input values. How do you scale your input values?   That is exactly the point I was making; if you use a frequency of 1 (as implied by some online articles about perlin noise) then there is a 1:1 scaling, and therefore no interpolation takes place. To use Enigma''s example:x = 0: result = (random(0) * 1.0) + (random(1) * 0.0);x = 1: result = (random(1) * 1.0) + (random(2) * 0.0);x = 2: result = (random(2) * 1.0) + (random(3) * 0.0);x = 3: result = (random(3) * 1.0) + (random(4) * 0.0);x = 4: result = (random(4) * 1.0) + (random(5) * 0.0);...etc...Therefore I was interested in seeing how people choose the parameter to the random function based on x, as starting with 1 is obviously flawed.   [ MSVC Fixes | STL Docs | SDL | Game AI | Sockets | C++ Faq Lite | Boost  Asking Questions | Organising code files | My stuff | Tiny XML | STLPort] ;  I just edited my post above on that point.  4 was just an example.  It really depends on what level of detail you''re looking at.  For terrain, if your points are equivalent to 1cm apart then your largest wavelength probably ought to be at least 256 for rocky terrain, if your points are equivalent to 1m apart then your largest wavelength would probably be no more thant 16.  My advice is to try a few, layer a few octaves up and see what it looks like, though one piece of advice I would give is that generally the amplitude of each wavelength should decrease exponentially with the wavelength.Enigma ;  this is code directly out of my PerlinNoise Class that I am using for my RTS.  I copied the 1D functions.  If you would like the 2D functions, I can copy them also.  Or if you want me to send you the entire class to work with and look through, I can do that too.  my email is dwiel at insightbb dot com if you want me to send you a copy.One thing is that I have a smooth function which takes an average of all of the values near it to get the one it will use, this is because I didnt want so ''bumpy'' terrain... You can completely remove this step if you want.Also, both cubic and cosine interpolation can be intermixed.  I just liked the results of the cosine one, and it wasnt much slower so I went with it.One thing I am working with is passing the result through some function at the end.  Say running the result through a/(x + b), where a nd b are constants that you can alter to fit your needs, fairly arbitralily I might add. annother one I messed with was (sin(a * x) + b) * c.  Just try different functions around.  If you happen to have a handy graphing utility such as a graphing clac of some kind of software, it makes it easier to come up with equations that fit your needs.  so if say you want the slope of points that are low to be gradual and the slope of points that are high to be steap, try to find a function that changes gradually when low and faster when high.  It is also sometimes easier to work with a dirivate function or even a second dirivative and go from there.  It all depends on what kind of output you are after.Also, hopefully this isn''t too long...   I am working on implementing code where I have 4 perlin noise functions.  3 for different terrain types, a flatland perlin, a hilly perlin and a mountainous perlin.  I interpolate the results based on the position of the 4th perlin.  I can expand on this if you want. MYINLINE float PerlinNoise::Perlin1D(float x){float frequency;float amplitude;int i = 0;float total;total = 0;for(i = 0; i < octaves; ++i){frequency = pow(2.0f, i) * divisor;amplitude = pow(persistence, i);total += InterpolatedNoiseCosine(x * frequency) * amplitude;}return total * height + offset;}MYINLINE float PerlinNoise::InterpolatedNoiseCosine(float x){return CosineInterpolation(SmoothNoise(int(x)), SmoothNoise(int(x) + 1), x - int(x));}MYINLINE float PerlinNoise::InterpolatedNoiseCubic(float x){static int intx = x;static float v0 = SmoothNoise(intx - 1);static float v1 = SmoothNoise(intx);static float v2 = SmoothNoise(intx + 1);static float v3 = SmoothNoise(intx + 2);return CubicInterpolate(v0, v1, v2, v3, x - intx);}MYINLINE float PerlinNoise::SmoothNoise(int x){return Noise(x) / 2.0f + (Noise(x - 1) + Noise(x + 1)) / 4.0f;}MYINLINE float PerlinNoise::Noise(int x){x = (x<<13) ^ x * Seed;return ( 1.0 - ( (x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff) * 0.00000000093132257461548);}Hopefully I''ve been of some assistance!Dwiel ;  Ah, now I understand. I use ridged multifractals with starting frequency one, but scale the input vector before calling the function. That's why I was confused.here's my code (sorry, only 3D) const int CNoise::m_bPerm[CNoise::TABSIZE] ={225,155,210,108,175,199,221,144,203,116, 70,213, 69,158, 33,252,  5, 82,173,133,222,139,174, 27,  9, 71, 90,246, 75,130, 91,191,169,138,  2,151,194,235, 81,  7, 25,113,228,159,205,253,134,142,248, 65,224,217, 22,121,229, 63, 89,103, 96,104,156, 17,201,129, 36,  8,165,110,237,117,231, 56,132,211,152, 20,181,111,239,218,170,163, 51,172,157, 47, 80,212,176,250, 87, 49, 99,242,136,189,162,115, 44, 43,124, 94,150, 16,141,247, 32, 10,198,223,255, 72, 53,131, 84, 57,220,197, 58, 50,208, 11,241, 28,  3,192, 62,202, 18,215,153, 24, 76, 41, 15,179, 39, 46, 55,  6,128,167, 23,188,106, 34,187,140,164, 73,112,182,244,195,227, 13, 35, 77,196,185, 26,200,226,119, 31,123,168,125,249, 68,183,230,177,135,160,180, 12,  1,243,148,102,166, 38,238,251, 37,240,126, 64, 74,161, 40,184,149,171,178,101, 66, 29, 59,146, 61,254,107, 42, 86,154,  4,236,232,120, 21,233,209, 45, 98,193,114, 78, 19,206, 14,118,127, 48, 79,147, 85, 30,207,219, 54, 88,234,190,122, 95, 67,143,109,137,214,145, 93, 92,100,245,  0,216,186, 60, 83,105, 97,204, 52};CRandom CNoise::m_random;void CGNoise::InitGradientTab (int nSeed){float *table = m_fGradientTab;float z, r, theta;int i;m_random.SetSeed (nSeed);for (i = 0; i < TABSIZE; i++){z = m_random.RandPM1 ();r = sqrt (1 - z * z);theta = f_2_PI * m_random.Rand1 ();*table++ = r * cos (theta);*table++ = r * sin (theta);*table++ = z;}}float CGNoise::Get (VECTOR3 &vec){int ix, iy, iz;float fx0, fx1, fy0, fy1, fz0, fz1;float wx, wy, wz;float vx0, vx1, vy0, vy1, vz0, vz1;ix = (int)floor (vec.x);iy = (int)floor (vec.y);iz = (int)floor (vec.z);fx0 = vec.x - ix;fy0 = vec.y - iy;fz0 = vec.z - iz;fx1 = fx0 - 1;fy1 = fy0 - 1;fz1 = fz0 - 1;wx = SmoothStep (fx0);wy = SmoothStep (fy0);wz = SmoothStep (fz0);vx0 = GLattice (ix, iy, iz, fx0, fy0, fz0);vx1 = GLattice (ix + 1, iy, iz, fx1, fy0, fz0);vy0 = lerp (wx, vx0, vx1);vx0 = GLattice (ix, iy + 1, iz, fx0, fy1, fz0);vx1 = GLattice (ix + 1, iy + 1, iz, fx1, fy1, fz0);vy1 = lerp (wx, vx0, vx1);vz0 = lerp (wy, vy0, vy1);vx0 = GLattice (ix, iy, iz + 1, fx0, fy0, fz1);vx1 = GLattice (ix + 1, iy, iz + 1, fx1, fy0, fz1);vy0 = lerp (wx, vx0, vx1);vx0 = GLattice (ix, iy + 1, iz + 1, fx0, fy1, fz1);vx1 = GLattice (ix + 1, iy + 1, iz + 1, fx1, fy1, fz1);vy1 = lerp (wx, vx0, vx1);vz1 = lerp (wy, vy0, vy1);return lerp (wz, vz0, vz1);}and for the fratal:    virtual void Get (const MAPPROC::CParam &in, MAPPROC::CParam &out){const MAPPROC::FLOATPARAM &fin = *((const MAPPROC::FLOATPARAM *)&in);MAPPROC::FLOATPARAM &fout = *((MAPPROC::FLOATPARAM *)&out);float result, frequ, signal, weight;int i;VECTOR4 vPos = fin;// get 1st octaveMAPPROC::FLOATPARAM sigParam;GetSlotValue (0, MAPPROC::FLOATPARAM(vPos), sigParam);signal = VECTOR4(sigParam).w;if (signal < 0.0f)signal = -signal;signal = m_propOffset - signal;signal *= signal;result = signal;weight = 1.0f;frequ = 1.0f * m_propLacunarity;for (i = 1; i < m_propOctaves; i++, frequ *= m_propLacunarity){vPos *= m_propLacunarity;weight = signal * m_propGain;if (weight > 1.0f)weight = 1.0f;if (weight < 0.0)weight = 0.0;sigParam = GetNoise(vPos);signal = VECTOR4(sigParam).w;if (signal < 0.0f)signal = -signal;signal = m_propOffset - signal;signal *= signal;signal *= weight;result += signal * float (pow (frequ, -m_propH));}fout = result / m_propOctaves;} It's inspired the book Texturing & Modeling, Academic Press.    [edited by - VolkerG on February 4, 2004 7:51:25 PM];quote:Original post by Kylotan  That is exactly the point I was making; if you use a frequency of 1 (as implied by some online articles about perlin noise) then there is a 1:1 scaling, and therefore no interpolation takes place.I had wondered the same thing for a bit, then inferred that they meant to use this in situations where the f(x) would actually be rendered   for non-integer x.Failing that, you could go the other way and let period = 1 be your *highest* frequency noise; to get 1/f noise, you want to attenuate by 1/2 each time, which is stunningly easy to do - just iteratively generate the next-lowest frequency noise sample, and average it 1:1 into the current results.BTW, from what I''ve read it seems that what is normally called 1-dimensional "Perlin noise" isn''t really the same thing as his 2d and 3d stuff at all - it''s just a fast approximation to 1/f^x noise. (If you want true 1/f^x noise, you can generate the Fourier transform of such noise first - I *think* it should be something like (random Gaussian distributed variable)/f^x - and take its IFFT; but that''s O(n lg n) and serious overkill for most tasks.) It would be weird applying the usual algorithm in one dimension, since the only "gradients" possible there are +/- 1 - for each frequency you''d end up with a random combination of four "codes".(Disclaimer: I only even read about this stuff a couple weeks ago because everyone was talking about it around here and I got curious  );  Ok, I have it working nicely in 1 dimension (ie. to produce a list of values that could be plotted as a smooth yet irregular 2D curve).Now how do I generalise this to 2D? I have 2 main questions on this:1) interpolation; obviously I could just interpolate the values along the 2 axes independently and take the average, and while I expect that would look ok, it wouldn''t be perfect. Any more accurate methods?2) generation of the seed value; or ''x'' as generally used in the examples. In one dimension you can just use it directly, but in 2 dimensions you have x and y to accommodate... is it best just to find a nice way of hashing them together?   [ MSVC Fixes | STL Docs | SDL | Game AI | Sockets | C++ Faq Lite | Boost  Asking Questions | Organising code files | My stuff | Tiny XML | STLPort] 