Anti-tiling techniques

In UnrealEngine 3


Introduction

Tiling has always been a problem in computer graphics, especially in games. Limited human and technical resources allow for only so big textures, so they have to repeat to maintain the target texture density on a surface.
Fortunately nowadays we can use shaders to work around these problems. Instead of having many high resolution textures eating HW resources, or level designers spending time hiding the tiling, we can make a few shaders so the GPU does the tedious work.

The following examples show typical cases where tiling is an issue. The first screenshot shows the absolute worst case scenario, a big, flat, empty plane viewed from above, while the second image shows a more common point of view. On the pictures you can see the tiling version of the textures on the left for comparison.

Regular floor tiles

This texture is especially sensitive to tiling because it has areas with very different brightness. Also the broken pieces should be random, and any regularity in their pattern feels wrong. We will try to change that using a noise texture.

 

 

The idea is having a 90 degrees rotated version of the texture showing up over the original one, at random places. To achieve that first we need a proper noise texture, similar to the one on the left. It has only full white and full black pixels, and their number is equal. Also make sure that after import the filter method for this texture is set to "nearest", so pixels will not get bi-linear filtered. This way when we scale up the texture, each pixel will maintain its square shape, and not get smudged.

Now let's see the shader tree. The rotation group rotates the second diffuse texture instance. It costs 6 instructions, so if you have a tight budget you might replace this section with a panner.
The mask group generates the "random" mask for blending the original and rotated diffuse textures. Here we exploit the fact that the floor tiles are arranged in a grid. By scaling up the noise properly we can make the mask fit to that grid, so the shader switches between the original and rotated textures on a tile-by-tile basis.
Some regularity is still visible, so you can add another mask and another rotated/shifted texture layer to the mix if necessary.

Finally I added some dirt to the surface using another noise texture. This has a full range of gray values. It also has "nearest" filtering method, for similar reasons as above. I also unticked the sRGB option, so the texture will not have a gamma adjustment. It is recommended for all textures where pixel values are used for technical stuff.
Anyway, by adding 0.5 to the texture, the values are shifted to the range of 0.5 .. 1.5. This way in the next multiply node the noise will make tiles either darker or brighter. Again, the tiling of the noise is set so one of its pixels covers one floortile.

 

Irregular floor tiles

The previous technique might be hard to use with brick walls or surfaces like the one on the left. The lack of straight colums and/or not equal row/column numbers need a different approach: By shifting the rows randomly we can avoid tiling, at least in one direction.

 

 

To achieve this we need another noise texture: a series of horizontal lines. It's the same deal as earlier: "Nearest" filtering mode, sRGB off, scaled up so one line covers 1, 2, 4 or 8 rows. The more the better since this method produces some aliasing between shifted rows. Not that bad and FSAA should take care of it, just keep it in mind.

 

In the row shift group the noise is turned red so only the U (Red) component will be affected when the Add node adds it to the default UV space. We link this adjusted UV coordinates to the basic textures. The rest is pretty straightforward.

 

This time I picked a different noise texture for dirt. It has a few straight lines and 90 degree corners, which might fit beter to an artificial surface. I recommend to try different noise textures and see which one feels best. FilterForge and MapZone can generate some very interesting stuff.

 

 

Grass

The texture has no distinct features nor high contrast areas. We don't have to be so rigorous about scaling and positioning stuff, a more organic approach is better.

 

 

 

We will need a fluffy noise.

 

 

 

 

The diffuse group is pretty simple: we blend between two grass textures, one is rotated and slightly colorized. The mask is the noise texture scaled up. By scaling the values, adjusting the contrast and then clamping the whole thing to the 0..1 range we create contigous, flat areas of full white and full black. Instead having both texture layers visible more or less (which would happen using the original grayish noise), we have patches with only one texture.

At the end of the group we apply the macro texture. It is indeed similar to the dirt stuff in the previous shaders, but it's more complex, hence the fancier name. :) We use the quite distorted and slightly adjusted diffuse texture to add variation to the surface. The distorted UVs turn the texture into something psychedelic:

The great thing about this is that it has both low and high frequency detail, and only repeats after a few hundred thousand units. Of course it is quite useless in itself, but makes a nice addition to our grass, or other organic materials. (To save a few instructions, this part can be replaced by a basic, scaled up noise texture.)

Now let's see how it works: There are two noise textures with different scaling. They will provide the U and V coordinates. Their scaling has direct effect on the size of the result. The Power nodes adjust the contrasts. Changing the exponent value the pattern can be changed. Experiment with it until the result looks cool.
The adjustments in the macro group make sure that the texture will not affect too much the overall brightness of the diffuse texture at the end.

 

Rock

Here we take this texture <--, scale it, shift it and apply three times at the top of each other, using a color noise texture.

 

 

 

Using the RGB components of the image we have 3 grayscale masks. The first two is used to blend between the 3 rock textures and the third one is for the usual dirt pass.

 

 

 

The structure of the shader probably looks familiar at this point.