#### Archived

This topic is now archived and is closed to further replies.

# Perlin Noise takes too long?

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

## Recommended Posts

Right now I am using perlin noise to generate clouds but it takes forever to generate them, is this common or am I doing something wrong? Do you generate your noise everytime your app starts?

##### Share on other sites
quote:
Original post by griffenjam
Right now I am using perlin noise to generate clouds but it takes forever to generate them, is this common or am I doing something wrong?

how long?

i generate a 1024x1024 texuture with exponential clouds + alpha in aboug 1.5s with a rip of Ken Perlins original code. at the loading i generate 7 1024x1024 texutres for my clouds for different weathers and i interpolate them.

post your code here so we can see where is the bottleneck.

##### Share on other sites
This is my perlin noise code.

float CPerlin_Parent::Noise2d(int x, int y){   long int n = x + y * 57;   n = (n<<13) ^ n;   float ret = (float)( 1.0 - ( (n * (n * n * 15731 + 789221)                           + 1376312589) & 0x7fffffff ) / 1073741824.0);   return ret;}float CPerlin_Parent::SmoothNoise2d(int x, int y){   float corners = ( Noise2d(x-1, y-1) + Noise2d(x+1, y-1) + Noise2d(x-1, y+1) + Noise2d(x+1, y+1) ) / 16.0f;   float sides = ( Noise2d(x-1, y) +Noise2d(x+1, y) + Noise2d(x, y-1) + Noise2d(x, y+1) ) / 8.0f;   float center = Noise2d(x, y) / 4.0f;   return corners + sides + center;}float CPerlin_Parent::Interpolate(float x, float y, float a){   float fac1 = (float) (3*pow((1-a), (double)2) - 2*pow((1-a) ,(double)3));   float fac2 = (float) (3*pow(a,2) - 2*pow(a,3));   return x*fac1 + y*fac2; //add the weighted factors}float CPerlin_Parent::GetValue(float x, float y) {   int Xint = (int)x;   int Yint = (int)y;   float Xfrac = x - Xint;   float Yfrac = y - Yint;   float x0y0 = SmoothNoise2d(Xint, Yint);  //find the noise values of the four corners   float x1y0 = SmoothNoise2d(Xint+1, Yint);   float x0y1 = SmoothNoise2d(Xint, Yint+1);   float x1y1 = SmoothNoise2d(Xint+1, Yint+1);   //interpolate between those values according to the x and y fractions   float v1 = Interpolate(x0y0, x1y0, Xfrac); //interpolate in x direction (y)   float v2 = Interpolate(x0y1, x1y1, Xfrac); //interpolate in x direction (y+1)   float fin = Interpolate(v1, v2, Yfrac);  //interpolate in y direction   return fin;}float CPerlin_Parent::Cosine_Interpolation(float a, float b, float x){   double ft = (x+1) * 3.1415927;	double f = (1 - cos(ft)) * 0.5;	return  (float)a*(1-f) + (float)b*f;}float CPerlin_Parent::Cosine_Interpolate2D(float x, float y, int i){   int integer_X = (int)x;   float fractional_X = x - integer_X;   int integer_Y    = (int)y;   float fractional_Y = y - integer_Y;   float v1 = SmoothNoise2d(integer_X,     integer_Y);   float v2 = SmoothNoise2d(integer_X + 1, integer_Y);   float v3 = SmoothNoise2d(integer_X,     integer_Y + 1);   float v4 = SmoothNoise2d(integer_X + 1, integer_Y + 1);   float i1 = Cosine_Interpolation(v1 , v2 , fractional_X);   float i2 = Cosine_Interpolation(v3 , v4 , fractional_X);   return Cosine_Interpolation(i1 , i2 , fractional_Y);}float CPerlin_Parent:erlinNoise2D(float x, float y){   float total = 0;   fFreq = 1;   float fPersistance = 1.0f; //The "weight" each octave will have   for(int i=0; i   {      total += GetValue((x/64.0f)*fFreq, (y/64.0f)*fFreq) * fPersistance;      fFreq *= 2;      fPersistance *= fPersistanceMod;   }//   total = total*0.5 + 0.5;    if(total < 0)      total = -total;   if(total > 1.0f)      total = 1.0f;      return total;}

I would post my cloud code as well, but everything thaty uses perlin noise takes forever*, including landscape.

*forever is 5 minutes for a 512x512 texture.

##### Share on other sites
thats indeed long. try inlineing all those functions. or the inner loop ones at least.

##### Share on other sites
You need to try a different approach...

Instead of using the perlinnoise function that does all the smoothing and everything, just use your basic noise function.

That will give you a texture that looks like static on a tv screen. Then render this to a larger texture using bilinear filtering. This will smooth it out faster for you and you can still get the same effect by starting with a small noise texture(16x16 or 32x32) and rendering it to your final sized texture(1024x1024 prob.). Then move up a size and do the same. Then combine them all.

Like this:

1)
16x16    render to 1024 w/ bilinear filtering32x32    render to 1024 w/ bilinear filtering64x64    render to 1024 w/ bilinear filtering128x128  render to 1024 w/ bilinear filtering 256x256  render to 1024 w/ bilinear filtering512x512  render to 1024 w/ bilinear filtering

2)
combine all textures

3)
subtract a value using the texturestagestate d3dtop_subtract (ibelieve) and subtract a gray texture from it in order to get more clear areas.

##### Share on other sites
Perlin Noise can get a little expensive, especially since you're doing lots of dividing, float-int conversion, and sampling. The usual optimizations are to use fixed point and use the old scaling-the-number-range tricks to get rid of the divides in the inner loops, that way you're working strictly with integers and without dividing a whole lot.

Or do it using the method above with hardware. There was a thread about this a while back that I posted in (did you start it?) about HW PN.

------------
- outRider -

[edited by - outRider on November 17, 2003 12:22:31 AM]

##### Share on other sites
Some improvement techniques :

1/ as Eelco said, inline some functions : Noise2d() and Interpolate() are good candidates.

2/ do not use "double". When you write "1.0" or "1073741824.0" your *are* using double. The compiler will not optimize this. Instead of this you can use "1.0f" and "1073741824.0f" - these are floats (32 bits). They are *a lot* faster.

3/ starting with VC.NET a lot of floating point functions are SSE-enabled (I d not have the list here ; at least I''m sure it''s in the last MSDN library chm files). Instead of using "pow()" or "cos()" you''ll have to use "powf()" and "cosf()".

4/ use your own "ftol()" function : when you transform an float value to an integer value, the compiler implicitely calls "ftol()". This function is precise but slow. You can get nearly the same results by using a small inlined function (don''t have it here : I''m at home )

5/ the pow() function is a no-no. Use a look up table.

6/ you can do the same for the cos() function if you want.

This should speed up your implementation.

Another solution is to take the basic Ken Perlin code and to tweak it until you get decent results. You should be able to do a 512x512 texture in less than 500 ms without any kind of super-genious_optimization.

A third solution, as Chaucer proposed, is to use multiple simple noise layers (this is what you do with your loop). I believe that clanlib as a noise function which work like that (very fast).

Hope it helps,

--
Emmanuel Deloget

##### Share on other sites
You don''t need a look-up table or pow() when you''re doing x^2 or x^3. Just use (x*x) or (x*x*x), it''s probably faster than a table look-up. I''d also try using a non-smoothed noise function and linear interpolation and see if the quality is good enough for your application.

1. 1
Rutin
22
2. 2
3. 3
4. 4
5. 5

• 9
• 9
• 9
• 14
• 12
• ### Forum Statistics

• Total Topics
633308
• Total Posts
3011294
• ### Who's Online (See full list)

There are no registered users currently online

×