Jump to content
  • Advertisement
Sign in to follow this  
MrSplosion

Creating Perlin Noise

This topic is 2497 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

So I've been experimenting with perlin noise but I'm having trouble adding multiple octaves together. There aren't that many sources out there and articles such as this and this don't quite go into enough detail. The first article I linked really doesn't talk about it at all and the other says I should make a array of both an x and y number then multiply it by 2 squared by the current octave. I've tried this method but haven't had any success.

I'm confused could someone please help me or go into more detail about adding multiple octaves together?

Script:
function PerlinNoise(){
var texture = new Texture2D(width, height, TextureFormat.ARGB32, false);
for(q=0; q<=width; q++){
for(w=0; w<=height; w++){
var a = Noise2d(q, w);
var b = new Color(a, a, a, 0);
texture.SetPixel(q, w, b);
}
}
texture.Apply();
renderer.material.mainTexture = texture;
}



function Noise2d(x : int, y : int){
var n;
n = x + y * 57;
n = (n<<13) ^ n;
var res = (1.0 - ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
return res;
}

Pics
Thanks!

Share this post


Link to post
Share on other sites
Advertisement
The first article covers multiple octaves (towards the end). It describes it by this pseudo code:

[source]

function PerlinNoise_2D(float x, float y)

total = 0
p = persistence
n = Number_Of_Octaves - 1

loop i from 0 to n

frequency = pow(2, i)
amplitude = pow(p, i)

total = total + InterpolatedNoisei(x * frequency, y * frequency) * amplitude

end of i loop

return total

end function
[/source]

Share this post


Link to post
Share on other sites
You don't seem to be interpolating your noise; you're almost producing static. The idea is to smooth values using their neighbors. I made the same mistake, the actual generation is quite a bit more complicated than what you're doing. It involves adding values of decreasing weight (persistence) at an increasing frequency of random number sampling (frequency multipler)

As for octaves: Given X octaves you have a third inner loop which runs X times. Each time, it multiples the frequency and amplitude by some frequency multiplier and the persistence. For the nth iteration of the octave loop, the amplitude is persistence^(n-1) and the frequency is frequencyMultiplier^(n-1).

Here is the c# code I wrote for 2D perlin noise (well, I wrote all of it except the GenDoubleNoise algorithm), hopeful it will help you out. To see an example of what it can do, look at the terrain near the bottom of this blog post.

[source lang=csharp]
/// <param name="toFill" >The array to be filled with perlin noise.</param>
/// <param name="sqrtNumFeatures">The square root of the number of static random point in the noise.</param>
/// <param name="frequencyMulti" >The base of the exponential factor that causes variety by increasing sample distance</param>
/// <param name="persistence" >The smaller this is, the less each iteration after the first is weighted. Persistence is typically less than 1.0</param>
/// <param name="octaves" >The number of iterations to combine with the original.</param>
/// <param name="startingX" >The x-offset into the random number space.</param>
/// <param name="startingY" >The y-offset into the random number space.</param>
/// <param name="seed" >The seed to the random number generator used by this method.</param>
static public void GenPerlinNoise( double[,] toFill,
int sqrtNumFeatures,
double frequencyMulti,
double persistence,
int octaves,
int startingX,
int startingY,
int seed )
{
int width;
int height;

int effectiveX;
int effectiveY;

double regionSize;

double frequency;
double amplitude;

width = toFill.GetLength(1);
height = toFill.GetLength(0);

regionSize = width / sqrtNumFeatures; // Every time x or y passes a multiple of regionSize
// a new random point becomes dominate, because its integer
// portion grows. Then will be SqrtNumFeatures squared points like that.
for( int x = 0; x < width; x++ )
{
for( int y = 0; y < height; y++ )
{
effectiveX = x + startingX;
effectiveY = y + startingY;

frequency = 1;
amplitude = 1;
for( int oct = 0; oct < octaves; oct++ )
{
toFill[x,y] += SimpleNoise2D.GenInterpolatedNoise(effectiveX/(float)width * regionSize * frequency,
effectiveY/(float)width * regionSize * frequency, seed) * amplitude;

frequency *= frequencyMulti;
amplitude *= persistence ;
}
}
}
}

/// <summary>
/// Generate
/// </summary>
/// <param name="x">The first value</param>
/// <param name="y">The second value</param>
/// <param name="seed">A seed for the generator</param>
/// <returns>A random number between -1.0 and 1.0 that is very close to adjacent numbers in the random number space</returns>
static public double GenInterpolatedNoise( double x, double y, int seed )
{
int floorX = (int)x;
int floorY = (int)y;

double center, centerRight, bottom, bottomRight;
double centerInter, bottomInter;

center = GenSmoothNoise( floorX , floorY, seed );
centerRight = GenSmoothNoise( floorX+1, floorY, seed );
bottom = GenSmoothNoise( floorX , floorY+1, seed );
bottomRight = GenSmoothNoise( floorX+1, floorY+1, seed );

centerInter = GraphMath.CosineInterpolate( center, centerRight, floorX - x ); //Interpolates the two
bottomInter = GraphMath.CosineInterpolate( bottom, bottomRight, floorX - x ); // Horizontal parts.

return GraphMath.CosineInterpolate( centerInter, bottomInter, y - floorY ); //Interpolatse the interpolated
//Horizontal parts vertically
}

/// <summary>
/// Generates a random number that is smoothed by adjacent values in the number space using two values and a seed
/// </summary>
/// <param name="x">The first value</param>
/// <param name="y">The second value</param>
/// <param name="seed">A seed for the generator</param>
/// <returns>A random number between -1.0 and 1.0</returns>
static public double GenSmoothNoise( int x, int y, int seed )
{
double corners, sides, center;

// This influences the number by doing a weighted adverage with it
// and its eight neighbhors
center = GenDoubleNoise( x, y, seed )/4.0;

sides = (GenDoubleNoise( x+1, y, seed ) +
GenDoubleNoise( x-1, y, seed ) +
GenDoubleNoise( x, y+1, seed ) +
GenDoubleNoise( x, y-1, seed ))/8.0;

corners = (GenDoubleNoise( x+1, y+1, seed ) +
GenDoubleNoise( x+1, y-1, seed ) +
GenDoubleNoise( x-1, y+1, seed ) +
GenDoubleNoise( x-1, y-1, seed ))/16.0;

return corners + sides + center;
}

/// <summary>
/// Generates a random double between -1.0 and 1.0 using two values and a seed
/// </summary>
/// <param name="x">The first value</param>
/// <param name="y">The second value</param>
/// <param name="seed">A seed for the generator</param>
/// <returns>A random values between -1.0 and 1.0</returns>
static public double GenDoubleNoise( int x, int y, int seed )
{
int n;
n = x + y * 57;
n = (n<<13 * seed<<11) ^ n;

return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
}
[/source]

Good luck.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!