title: Procedurally generate seamless fractal noise textures
body: <p>I have been generating noise textures to use as height maps for terrain generation. In this application, initially there is a 256x256 noise texture that is used to create a block of land that the user is free to roam around. When the user reaches a certain boundary in-game the application generates a new texture and thus another block of terrain.</p>
  
  <p>In the code, a table of 64x64 random values are generated, and the values in the texture are the result of interpolating between these points at various 'frequencies' and 'wavelengths' using a smoothstep function, and then combined to form the final noise texture; and finally the values in the texture are divided through by its largest value to effectively normalize it. When the player is at the boundary and a new texture is created, the random number table that is created re-uses the values from the appropriate edge of the previous texture (eg. if the new texture is for a block of land that is on the +X side of the previous one, the last value in every row of the previous texture is used as the first value in every row of random numbers in the next.)</p>
  
  <p>My problem is this: even though the same values are being used across the edges of adjacent textures, they are nowhere near seamless - some neighboring points on the terrain are mismatched by many many metres. My guess is that the changing frequencies that are used to sample the random number table are probably having a significant effect on all areas of the texture. So how might one generate fractal noise poceduraly, ie. as needed, AND have it look continuous with adjacent values?</p>
  
  <p>Here is a section of the code that returns a value interpolated between the points on the random number table given a point P:</p>
  
  <pre><code>float MainApp::assessVal(glm::vec2 P){
  //Integer component of P
  int xi = (int)P.x;
  int yi = (int)P.y;
  
  //Decimal component ofP
  float xr = P.x - xi;
  float yr = P.y - yi;
  
  //Find the grid square P lies inside of
  int x0 = xi % randX;
  int x1 = (xi + 1) % randX;
  int y0 = yi % randY;
  int y1 = (yi + 1) % randY;
  
  
  //Get random values for the 4 nodes
  float r00 = randNodes-&gt;randNodes[y0][x0];
  float r10 = randNodes-&gt;randNodes[y0][x1];
  float r01 = randNodes-&gt;randNodes[y1][x0];
  float r11 = randNodes-&gt;randNodes[y1][x1];
  
  //Smoother interpolation so
  //texture appears less blocky
  float sx = smoothstep(xr);
  float sy = smoothstep(yr);
  
  //Find the weighted value of the 4
  //random values. This will be the
  //final value in the noise texture
  float sx0 = mix(r00, r10, sx);
  float sx1 = mix(r01, r11, sx);
  
  return mix(sx0, sx1, sy);
  }
  </code></pre>
  
  <p>Where randNodes is a 2 dimensional array containing the random values.</p>
  
  <p>And here is the code that takes all the values returned from the above function and constructs texture data:</p>
  
  <pre><code> int layers = 5;
  float wavelength = 1, frequency = 1;
  
  for (int k = 0; k &lt; layers; k++) {
      for (int i = 0; i &lt; stepsY; i++) {
          for(int j = 0; j &lt; stepsX; j++){
              //Compute value for (stepsX * stepsY) interpolation points
              //across the grid of random numbers
              glm::vec2 P = glm::vec2((float)j/stepsX * randX, (float)i/stepsY * randY);
              buf[i * stepsY + j] += assessVal(P * wavelength) * frequency;
          }
      }
      //repeat (layers) times with different signals
      wavelength *= 0.5;
      frequency *= 2;
  }
  
  for(int i = 0; i &lt; buf.size(); i++){
      //divide all data by the largest value.
      //this normalises the data to avoid saturation
      buf[i] /= largestVal;
  }
  </code></pre>
  
  <p>Finally, here is an example of two textures generated by these functions that <em>should</em> be seamless, but aren't:</p>
  
  <p><a href="https://i.stack.imgur.com/Hb8ps.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Hb8ps.png" alt="enter image description here"></a> <a href="https://i.stack.imgur.com/FitXY.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/FitXY.png" alt="enter image description here"></a></p>
  
  <p>The 2 images placed side by side as they are now are obviously mis-matched.</p>