Home       About Me       Contact       Downloads       Part 83    Part 85   

Part 84: Seamless Textures

June 28, 2013

I continue to mess around with GUI and platform stuff, but very slowly. Since there's nothing there I want to show you, here's a quick note on seamless textures.

I had looked this up a long time ago and found the usual tricks for mirroring and editing the edges of textures. This wasn't what I wanted. I had also realized on my own that if I cut a shape out of a 3D block of noise, it would naturally be seamless, since the source noise is continuous.

So I knew you could easily get a seamless texture in one dimension by cutting out a cylinder. I did this with the DontHitMe track, which is a long cylinder and is seamless around the circumference. To be seamless in both directions, I figured you could use a torus, but that shape doesn't work. The inner and outer radius of the torus are very different and that gives you a lot of distortion in the texture.

I ran into something on the net which said "just do it in four dimensions." You can get a seamless texture in x by sampling a circle in two dimensions, and do the same for y using the other two dimensions. So the noise is sampled with a code like

for (i = 0; i < height; i++)
{
  y = 2*PI*i/height;
  for (j = 0; j < width; j++)
  {
    x = 2*PI*j/width;
    texture[i*width+j] = simplexNoise(sin(x), cos(x), sin(y), cos(y));
  }
}

In my code, I'm summing several octaves of noise to get the result, so there's an inner loop:

for (i = 0; i < height; i++)
{
  y = 2*PI*i/height;
  for (j = 0; j < width; j++)
  {
    x = 2*PI*j/width;

    octaves = 8;
    scale = 1.0;
    amplitude = 1.0;

    v = 0.0;
    for (oct = 0; oct < octaves; oct++)
    {
      noise = simplexNoise(sin(x)*scale, cos(x)*scale, sin(y)*scale, cos(y)*scale);
      v += noise * amplitude;
      scale *= 2.0;
      amplitude *= 0.5;       
    }
    texture[i*width+j] = v;
  }
}
For each octave, I'm doubling the frequency (scale) and halving the amplitude. The final value is the sum of all eight octaves.

This works just fine. Below you can see the generated tile and a 3 by 3 grid of them. No seams!




Animation

Using four dimensions to build the texture does create a new problem -- animation. I was using the extra dimensions to move the texture through a circle to create a loop of animations. I did this in Part 48 when I created the lightning texture for the flying saucer.

I only have Simplex Noise code for 4 dimensions. I looked for higher dimension versions but couldn't find any. To build an animation with seamless textures, I tried just moving the 4D cylinder around in a circle. That works, but has an odd sort of look to it:





It is seamless in x, y and time. But if you compare that to the saucer animation, which was independent in one animation dimension, I think there's a difference. The new animation sort of looks like it's shifting around, not evolving into a new pattern.

This would make sense, since it's just moving a cylinder center around in a circle, and some of the new location will intersect the old location, just as two slightly-offset circles would intersect.

I played with some variations on this, but couldn't come up with anything better. No matter what you do to the shape, if you just move it around in the same space, frames are going to intersect. Moving a larger distance isn't a solution. Then the shape changes too much between frames to produce a smooth animation.

I generated a "lava" texture for use with DontHitMe and it's OK. I would use a larger patch than this (and slower animation), but you get the idea:




So this technique works well enough. The only disadvantage is you have to generate the texture procedurally, which I'm not very good at. I spend hours tweaking the noise function and colors and I'm still not satisfied. Oh well.

Home       About Me       Contact       Downloads       Part 83    Part 85   

blog comments powered by Disqus