Jump to content
• Advertisement

# blocky Perlin noise (*PICS INCLUDED*)

This topic is 5089 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

Ok, they say a picture is worth a thousand words. Here is a picture of my generated perlin noise. This is just 1 octave. I would think it has something to do with my smoothing code
template <class SmoothPolicy>
struct LinearInterpolation2DPolicy : public SmoothPolicy
{
inline float Smooth (float x, float y)
{
int integer_x    = int(x);
float fractional_x = x - integer_x;

int integer_y    = int(y);
float fractional_y = y - integer_y;

float v1 = SmoothNoise(integer_x,     integer_y);
float v2 = SmoothNoise(integer_x + 1, integer_y);
float v3 = SmoothNoise(integer_x,     integer_y + 1);
float v4 = SmoothNoise(integer_x + 1, integer_y + 1);

float i1 = Interpolate(v1 , v2 , fractional_x);
float i2 = Interpolate(v3 , v4 , fractional_x);

return     Interpolate(i1 , i2 , fractional_y);

}

inline float Interpolate(float a, float b, float x)                  //fastest
{
return  a*(1-x) + b*x;
}

};

template <int seed1, int seed2, int seed3>
struct DefaultNoisePolicy2D
{
inline float Noise (float x, float y)  // [-1.0, 1.0]
{
int n = x + y * 57;
n = (n<<13) ^ n;
return ( 1.0 - ( (n * (n * n * seed1 + seed2) + seed3) & 0x7fffffff) / 1073741824.0);
}
};

template <class NoisePolicy>
struct DefaultSmoothPolicy2D : public NoisePolicy
{
inline float SmoothNoise(float x, float y)
{
float corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16.0f;
float sides   = ( Noise(x-1, y)  +Noise(x+1, y)  +Noise(x, y-1)  +Noise(x, y+1) ) /  8.0f;
float center  =   Noise(x, y) / 4.0f;

return corners + sides + center;
}
};

template <class NoisePolicy,template<class T> class SmoothPolicy, template<class T>class InterpolationPolicy, int Octaves, class FilterPolicy=NullFilterPolicy>
class Perlin : public InterpolationPolicy<SmoothPolicy<NoisePolicy> >, public SmoothPolicy<NoisePolicy>, public NoisePolicy, public FilterPolicy
{
bool TableBuilt;               //Table lookup shit
float Frequency [Octaves];
float Amplitude [Octaves];

public:
Perlin() {TableBuilt = false;}

void BuildLookupTable(float Persistence)
{

for (int i = 0; i < Octaves; i++)
{
Frequency = powf(2.0f,(int)i+1);
Amplitude = powf(Persistence,(int)i+1);
}
}

float Generate (float x, float y)
{
float total = 0;

for (int i = 0; i < Octaves; i++)
{
total = total + (Smooth(x * Frequency, y * Frequency) * Amplitude);
}

return Filter ((total+1)/2.0f);
}

};


Sorry about the policies, but this library is actually pretty big with plenty of filters and whatnot. Here is a picture of a 2-pass noise from when the library actually worked, the first with a sigmoid filter, the second with just an identity filter. I honestly have absolutely no idea what's going on. I had a working perlin noise lib, and then I did a bunch of things to optimize it (I did triple its speed) and now it produces blocky images. But the images really do resemble the noise. Here is the same seed values for the 2-pass image with the fubar'd noise routines.

#### Share this post

##### Share on other sites
Advertisement
I remember having the same problem, but it was a long while ago so i don't remember how i fixed it or if i fixed it.

I took a look at your code but i can't find the problem. Anyway, i have code that works, it's quite similar to yours so i hope it helps:

#include "stdafx.h"#include "perlinnoise.h"#include "image.h"#include "vectors.h"CPerlinNoise::CPerlinNoise(){}float CPerlinNoise::LinearInterpolation(float t, float a, float b){	return a * (1.0f - t) + b * t;}float CPerlinNoise::SCurve(float a){	return a * a * (3.0f - 2.0f * a);}float CPerlinNoise::RandomFloat(){	return (float)( (rand() % (MASK + MASK) - MASK) ) / (float)MASK;}void  CPerlinNoise::GenerateTables(){	srand(GetTickCount());	int i;	for (i = 0; i < MASK; i++) 	{		permutationTable = i;		randomTable.x = RandomFloat();		randomTable.y = RandomFloat();		randomTable = Normalize(randomTable);	}	int k, temp; 	CVector2 t;	for (i = 0; i < MASK; i++)	{		k = rand() % MASK;		temp = permutationTable;		permutationTable = permutationTable[k];		permutationTable[k] = temp;//		t = randomTable;//		randomTable = randomTable[k];//		randomTable[k] = t;	}		for (i = MASK; i < MASK + MASK; i++)	{		permutationTable = permutationTable[i - MASK];		randomTable = randomTable[i - MASK];	}}void CPerlinNoise::Setup(float x, int &grid1, int &grid2, float &dist1, float &dist2){	float t = x + MAXIM;	int it = (int)t;	grid1 = it % MASK;	grid2 = (grid1 + 1) % MASK;	dist1 = t - it;	dist2 = dist1 - 1.0f;}float CPerlinNoise::PNoise2D(float x, float y){	int Xint0, Xint1, Yint0, Yint1;	float Xfrac0, Xfrac1, Yfrac0, Yfrac1;		Setup(x, Xint0, Xint1, Xfrac0, Xfrac1);	Setup(y, Yint0, Yint1, Yfrac0, Yfrac1);	int index1 = permutationTable[Xint0];	int index2 = permutationTable[Xint1];	int corner1 = permutationTable[index1 + Yint0];	int corner2 = permutationTable[index2 + Yint0];	int corner3 = permutationTable[index1 + Yint1];	int corner4 = permutationTable[index2 + Yint1];	CVector2 v;	float kx, ky, sx, sy;	float a, b;	sx = SCurve(Xfrac0);	sy = SCurve(Yfrac0);	v = randomTable[corner1]; 	kx = Xfrac0 * v.x + Yfrac0 * v.y;	v = randomTable[corner2]; 	ky = Xfrac1 * v.x + Yfrac0 * v.y;	a = LinearInterpolation(sx, kx, ky);	v = randomTable[corner3]; 	kx = Xfrac0 * v.x + Yfrac1 * v.y;	v = randomTable[corner4]; 	ky = Xfrac1 * v.x + Yfrac1 * v.y;	b = LinearInterpolation(sx, kx, ky);	return LinearInterpolation(sy, a, b);}float CPerlinNoise::GenData(float x, float y, float freq, int octaves, float pers){	int		i;	float	f = 0.0f;			float fr = freq;	float amp = 1.0f;	for (i = 0; i < octaves; i++)	{		f += PNoise2D(x * fr, y * fr) * amp;		fr *= 2;		amp *= pers;	}		return f;}int CPerlinNoise::Generate(unsigned char *buf, int colors, int size, float freq, int octaves, float pers){	float		*data;	float		min, max, sc, val;	int			i, j;	float		freq_fact = freq;	GenerateTables();	data = new float [size * size];	if (!data)	{		return SYS_ERR;	}	min = 1.0f; max = -1.0f;	for (i = 0; i < size; i++)	{		for (j = 0; j < size; j++)		{									val = GenData(i, j, freq, octaves, pers);						data[i * size + j] = val;			if (val < min) min = val;			if (val > max) max = val;		}	}	sc = 1.0f / (max - min);	BYTE value;	for (i = 0; i < size * size; i++)	{			               buf  = (BYTE)(((data - min) * sc) * 255.0f);	}	delete [] data;	return SYS_OK;}

EDIT: Separated source file from header, removed some bugs uninterseting stuff
#ifndef _TER_GEN_H#define _TER_GEN_H#include "vectors.h"#define MAXIM 4096#define MASK 256class CPerlinNoise{public:		CPerlinNoise();		int Generate(unsigned char *buf, int colors, int size, float freq, int octaves, float pers);private:	void  Setup(float x, int &grid1, int &grid2, float &dist1, float &dist2);	float SCurve(float a);	float LinearInterpolation(float t, float a, float b);	float PNoise2D(float, float);	float GenData(float x, float y, float freq, int octaves, float pers);	void  GenerateTables();	float RandomFloat();	int	  permutationTable[MASK + MASK];	CVector2 randomTable[MASK + MASK];};#endif

[Edited by - Ilici on January 2, 2005 4:44:07 AM]

#### Share this post

##### Share on other sites
No time to read it yet, but thank you! I'll look through your code

Rating++;

#### Share this post

##### Share on other sites
I think the interpolation and smoothing part is fine; the math checks out, anyways. Looking at the picture, it seems like the interpolated regions are fine - the real problem is that the corners of each region don't interpolate into the same values.

If I'm reading your templating right, the problem is most likely in the use of the SmoothNoise() function instead of calling Noise() directly from the interpolator, the way standard Perlin works. Classic Perlin takes a pre-generated array of random values and basically runs them through a bilinear (or trilinear) filter. I've been staring at the SmoothNoise() function for about 20 minutes now and I still can't figure out what exactly it is supposed to be doing. The effect is basically to pull random data from all around the sample point and blend it together (I think) - but with floating point error it feels to me like the net effect would be utter chaos. The patterns in your multi-octave sample image suggest this as well - that the problem isn't interpolation, the problem is interpolating between the right numbers.

Incidentally, Ilici's code differs from yours (functionally) in only one major way that I can tell after a quick skim - it doesn't include the insanity in SmoothNoise() in any form. For what it's worth I've never seen that sort of math going on (in that part of the noise pipeline, to be precise) in any working Perlin-style noise implementation, either.

Instead of calling SmoothNoise() from the Smooth() function (eurgh - sorry but your naming setup is extremely confusing [wink]) try just making a straight call to Noise().

#### Share this post

##### Share on other sites
Well, the smoothnoise function just takes a weighted average so the noise isn't so sharp. And that is why I use that instead of the noise function in my interpolater methods.

Its the same exact setup I had when i generated that one pic that looks fine. I just happened to mess something up and I can't figure it out!

Thanks though!

#### Share this post

##### Share on other sites
I spotted only one potential bug... all your problems might go away if you'll write
inline float Noise (int x, int y)  // [-1.0, 1.0]	{		 int n = x + y * 57;		 n = (n<<13) ^ n;		 return ( 1.0 - ( (n * (n * n * seed1 + seed2) + seed3) & 0x7fffffff) / 1073741824.0);	}

(fonts: bold red is where to change, bold is where change matters)

Another thing, make sure your x and y is positive. Make sure rounding mode is correct.
Tnird things about code, a: one seed is enough, b:i don't think it's really good idea to pass seeds as templated parameters, and c: if you really want some flexibility, pass noise basis function (e.g. perlin, linearly interpolated perlin,etc.) by reference to make it be runtime-changeable.

#### Share this post

##### Share on other sites
Quote:
 Original post by Grizwald-code-

[wrong stuff]
EDIT: i was wrong, your code looks like Ken Perlin's one from http://freespace.virgin.net/hugo.elias/models/m_perlin.htm

I'll compare yours to his.

1. Try using my random function instead of the one Perlin uses

#### Share this post

##### Share on other sites
Interestly enough Dmytry, my lib has runtime-changeable noise too, but its not as fast. I have three seed values to achieve the most patterns. About using integers for my method parameters though: I need to use floats. Floats allow me to 'zoom' in on the noise. I'm still not sure how I could achieve the same effects with integers. I also have a policy that fits the outputs to a certain range, as well as the inputs. This allows me to zoom in and out of the noise, translate and rotate it.

#### Share this post

##### Share on other sites
Quote:
 Original post by GrizwaldInterestly enough Dmytry, my lib has runtime-changeable noise too, but its not as fast. I have three seed values to achieve the most patterns. About using integers for my method parameters though: I need to use floats. Floats allow me to 'zoom' in on the noise. I'm still not sure how I could achieve the same effects with integers. I also have a policy that fits the outputs to a certain range, as well as the inputs. This allows me to zoom in and out of the noise, translate and rotate it.

You don't understand how
inline float Noise ( x, y) // [-1.0, 1.0]
{
int n = x + y * 57;
n = (n<<13) ^ n;
return ( 1.0 - ( (n * (n * n * seed1 + seed2) + seed3) & 0x7fffffff) / 1073741824.0);
}
works.
x is converted to integer anyway. y is multiplied by 57 and then converted to integer. I have seen this code somewhere already, really many times. Also, AFAIK seeds have to be prime.

#### Share this post

##### Share on other sites
Quote:
Original post by Dmytry
Quote:
 Original post by GrizwaldInterestly enough Dmytry, my lib has runtime-changeable noise too, but its not as fast. I have three seed values to achieve the most patterns. About using integers for my method parameters though: I need to use floats. Floats allow me to 'zoom' in on the noise. I'm still not sure how I could achieve the same effects with integers. I also have a policy that fits the outputs to a certain range, as well as the inputs. This allows me to zoom in and out of the noise, translate and rotate it.

You don't understand how
inline float Noise ( x, y) // [-1.0, 1.0]
{
int n = x + y * 57;
n = (n<<13) ^ n;
return ( 1.0 - ( (n * (n * n * seed1 + seed2) + seed3) & 0x7fffffff) / 1073741824.0);
}
works.
x is converted to integer anyway. y is multiplied by 57 and then converted to integer. I have seen this code somewhere already, really many times. Also, AFAIK seeds have to be prime.

Seeds don't HAVE to be prime, you just get better noise if you do.

#### Share this post

##### Share on other sites

• Advertisement

### Announcements

• Advertisement

• ### Popular Contributors

1. 1
2. 2
3. 3
Rutin
15
4. 4
khawk
13
5. 5
frob
12
• Advertisement

• 9
• 9
• 11
• 11
• 23
• ### Forum Statistics

• Total Topics
633669
• Total Posts
3013259
×

## Important Information

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

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!