What is the hardest part of creating seamless textures? Yes, making sure they look natural when they repeat. The usual problem is that no matter how hard you try, the seam is usually clearly visible.
I thought that it may make it easier if you work on the edges first (in the middle of the canvas), then move them to the edges of the physical canvas.
I know this probably sounds strange, but just take a look at the instructions section below for a better explanation.
You can download the precompiled effect DLL here: SeamlessHelper.dll
Just drop this file in your \program files\Paint.NET\effects directory and you should be all set.
The best way to use this is to follow these steps:
1) Create a canvas that is an even width and even height. For example, 200 x 200. It is critical that you do not use odd dimensions.
2) Start creating your texture by focusing on the middle of the canvas. Do not place anything too close to the edges at this point.
I will be creating a repeating texture of American coins. Here you can see this step:
Notice that I am only concerned about covering the area marked in red. Do not include red lines, they are only here to illustrate the area that I'm trying to cover.
3) Flatten your image down to a single layer.
3) Run the Seamless Helper effect. Your image should now look like this:
Notice how the coins have been moved to the edges. Your texture is now seamless.
To illustrate this more simply, take a look at this image (before on left, after on right):
The effect DLL basically splits your image into 4 parts
and rearranges those parts as show above.
4) Now finish off the center of the image being careful to again stay away from the edges. I'll just add 3 quarters to the picture:
5) Save the file in your favorite format (GIF, JPG, or PNG).
That's it! You have created a seamless texture!
You can quickly test these by putting it on your desktop and chose the "tile" option.
The codelab script is fairly straight forward:
void Render(Surface dst, Surface src, Rectangle rect)
PdnRegion selectionRegion = EnvironmentParameters.GetSelection(src.Bounds);
Rectangle selection = this.EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt();
int CenterX = (int)(((selection.Right - selection.Left) / 2)+selection.Left);
int CenterY = (int)(((selection.Bottom - selection.Top) / 2)+selection.Top);
int srcX = 0, srcY = 0;
for(int y = rect.Top; y < rect.Bottom; y++)
for (int x = rect.Left; x < rect.Right; x++)
if (selectionRegion.IsVisible(x, y))
srcX = x;
srcY = y;
if (x < CenterX)
srcX += CenterX;
srcX -= CenterX;
if (y < CenterY)
srcY += CenterY;
srcY -= CenterY;
dst[x,y] = src[srcX,srcY];