Tiling (real) Perlin Noise

Started by
6 comments, last by okonomiyaki 20 years, 8 months ago
Yes, this is real Perlin Noise and not plain fBm As far as I know.. Anyway, I was using the usual fBm before but recently changed to Perlin Noise to generate my textures. For these textures to be of any use they need to be tilable. I know all about the Perlin Noise Math FAQ where it describes seamless noise, and it''s that algorithm I use to tile my noise. It worked great when I used fBm, but now when I switched to Perlin Noise, it stopped working for some reason. I have a screenshot. This is one octave, dimensions of 1024x1024, and with a frequency of 1/64. I set the tilable width and height to 16, as 1024/64 is 16, and that''s the "noise" width and height. Image has been scaled down for viewing. This is my Noise loop:

float noise::FineTunedTile(float x, float y) {

	float total = 0;
	int tempw = w, temph = h; //only for tiling

	int frequency = 1;
	float pers = persistance;

	for(short i=0; i<octaves; i++) {

		total += Noise_Tiled(x*frequency, y*frequency)*pers;

		w *= 2;  //only for tiling

		h *= 2;  //only for tiling

		frequency *= 2;
		pers *= persistance;
	}

	w = tempw;  //only for tiling

	h = temph;  //only for tiling


	return total;

}
Noise_Tile:

float noise::Noise_Tiled(float x, float y) {

	return ((  GetHeight(x,y) *(w-x) * (h-y)  +  GetHeight((x-w),y) * x * (h-y)  +  GetHeight((x-w),(y-h)) * x * y  +  GetHeight(x, (y-h)) * (w-x) * y   ) / float(w*h));

}
And finally, my GetHeight function:

float noise::GetHeight(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 s = D3DXVec2Dot(&Noise_Table(integer_X, integer_Y) , &D3DXVECTOR2(integer_X - x , integer_Y - y));
	  float t = D3DXVec2Dot(&Noise_Table(integer_X+1, integer_Y), &D3DXVECTOR2(integer_X+1 - x, integer_Y - y));
	  float u = D3DXVec2Dot(&Noise_Table(integer_X, integer_Y+1), &D3DXVECTOR2(integer_X - x, integer_Y+1 - y));
	  float v = D3DXVec2Dot(&Noise_Table(integer_X+1, integer_Y+1), &D3DXVECTOR2(integer_X+1 - x, integer_Y+1 - y));

      float i1 = Interpolate(s, t, fractional_X);
      float i2 = Interpolate(u, v, fractional_X);

      return Interpolate(i1, i2, fractional_Y);

}
I don''t expect you to go through my code, but it''s there for reference. I don''t understand why it would be different with Perlin Noise. The gist is the same: It takes x,y and get a value back. Tiling just manipulates the value in different ways. Does anyone see the problem? Thanks a lot!
Advertisement
Real Perlin noise is not continuous across borders.
That's because the octave multipliers can be entirely something else than powers of two.
You could blend more noise layers together to achieve smooth edges, using linear interpolation towards the edges.

EDIT:
By the way, are you handling the fractional interpolation correctly (sampling from correct side of pixel)?
Your image looks weird...
Sorry, didn't have time to read your code completely...

[edited by - Nik02 on August 17, 2003 7:52:20 AM]

Niko Suni

Of course it''s not naturally tilable. I''m wondering how people make it tilable, or what''s wrong with the way I''m manipulating it.
That image is what is produced with my tiling method. If I turn off tiling, the noise looks great! But of course it''s not tilable. So I know the interpolation is working right.
Yeah, I could use some kind of linear interpolation at the edges, but that seems like such a hack. There''s got to be a better way!
Thanks!
the way to make it tilable is giving all four corners of the tile the same gradient and value. you can do this by making your getheight function wrap.

earx
This might help you:

http://www.robo-murito.net/code/perlin-noise-math-faq.html

At the end of article : Seamlessly tiling noise
I''ve implemented this in my engine and it works OK. The down side is that its 4 times slower to generate.

You should never let your fears become the boundaries of your dreams.
You should never let your fears become the boundaries of your dreams.
Perhaps instead of...
int integer_Y = (int)y;
...you can have something like...
int integer_Y = (int)y & (yTile - 1);
...assuming power-of-two tiling. For fBm you'd need to adjust the tile factor for each octave (assuming frequency changes by 2 between octaves).
I did something like this for my perlin noise for clouds and it looked better (and was faster) than doing the lerp ( as in noise::Noise_Tiled() ).

Actually I just realised this is probably what Anonymous Poster was describing.

[edited by - Soiled on August 18, 2003 10:39:01 AM]
I also use the tiling from the very bottom of the perlin noise math faq in conjunction with the 2002 version of perlin noise and it works fine here.

eisscholle.de
As to stepanh and darkwing,
"I know all about the Perlin Noise Math FAQ where it describes seamless noise, and it''s that algorithm I use to tile my noise. It worked great when I used fBm, but now when I switched to Perlin Noise, it stopped working for some reason."
That''s ok, you must have replied without reading my whole post. That''s understandable though, at least you replied.

Thanks for the other suggestion though soiled and AP.. I thought doing something like that was an option, but as I said it kind of feels like a hack. I guess it works though. I''ll try it though, maybe it''ll work and look good. Thanks !

This topic is closed to new replies.

Advertisement