Most textures in games are “static”, in the sense that they aren’t animated. But some textures need to be animated to look good. A common example is water.
My game (Patch Quest) has tile-based terrain. Each tile has its own separate mesh with an individually applied texture. The “Patch” pictured below is made up of a 3×3 grid of these tiles, plus a border mesh that surrounds all of them.
The water texture used here has been animated such that the waves slowly drift to the right. The texture also tessellates so that you can’t see the “seams” between the tiles. In this article I’ll be explaining how I made this effect, and how you can make other kinds of animated textures in Unity.
Each of my animated textures has the same basic setup. You need a Camera, a Canvas, and some graphics to be rendered. As an example, let’s look at the setup for my Water texture.
This texture only has one graphic, an image of a wave. This image is white so that I can tint it at runtime to whatever color I may need.
An observant reader will notice that the left and right halves of this image are identical. I made this by first drawing a square, tessellating wave texture. I then copied that square texture and stuck them together – making a rectangular, tessellating wave texture.
By setting the texture up this way, I can slide it from side to side and it will always tessellate. The code I use to slide it around is very simple (the numbers come from the fact that this texture is 512 pixels wide, and therefore can slide by a maximum of 256 pixels before it needs to be repositioned).
I put all these objects on a separate Unity layer (which I’ve called “Thumbnails” because it’s also the layer I use when generating thumbnail images of my assets). Here you can see all 3 gameobjects – the Camera, Canvas and waves Image.
The camera has been set up in a particular way. First, the camera’s Culling Mask has been set to the Thumbnails layer, meaning it will only render objects on that layer. This stops the camera from accidentally picking up other things in your game scene and rendering them onto the texture. It also saves processing power, since these unwanted objects will be excluded from the camera’s rendering pipeline.
The camera’s projection mode has been set to Orthographic. This will give us a flat and uniform final texture. If the camera was set to Perspective it would distort the final output and probably ruin the tessellation.
Finally, I’ve set the Target Texture to a RenderTexture asset. Rather than rendering to the screen, this camera will now render to a texture that we can place on the terrain tiles. Below, you can see these settings in the Unity inspector.
Some things need to be seen in motion to be fully appreciated. So here’s a short clip of this animated texture in action.
Let’s See Some More Examples
You can use this technique to create all sorts of different animated textures. As a slightly more complex example, let’s look at my animated Rapids texture.
This texture tessellates in both the X and Y dimensions. If you look closely, you’ll see it’s actually made up of 4 copies of a smaller texture that have been joined together. This means I can slide it in any direction and it will still tessellate.
This texture is used at the edges of the world map, to indicate the player has reached the ocean and cannot progress further. I used a slightly more complex motion pattern with several overlapping Sine waves to create the impression of beach waves. Here’s this texture in action.
Of course, this technique isn’t limited to just water! I’ve also used it to create mudslides and quicksand. Here you can see all of my animated textures in one place.
There are many other kinds of textures you could create with this method. It doesn’t even have to be terrain (or have to tessellate) depending on your particular case. For example, you could use it to make animated signposts or faces. The biggest limitation is your imagination! The second biggest limitation is processing power.
Unity has to recalculate parts of your scene for each camera. This only creates a small processing overhead, but if you make enough cameras it will certainly add up.
To get around this I keep a tally of how many times each texture is being used. Here’s the code for my Tally class. It’s basically just a Wrapper for a Dictionary, with Increment, Decrement and Get functions exposed to the user (the Get function overloads the array accessor on this class). The class is Generic, meaning you can choose what kind of thing you want to tally. In this case, we want a Tally<Texture>.
Every time a tile view is created I increment the tally for that texture. When that view is deleted I decrement the tally. I can now check once per frame to see if each texture has at least one active usage. If it does, I enable the camera’s GameObject. Otherwise, I disable the camera’s GameObject. This ensures that only the textures that are currently being used will be rendered.
With only 5 textures, the performance benefits are pretty negligible. But if I someday have dozens of these textures the performance boost will be very important!
This technique is pretty simple to put together, but also very versatile. You can put pretty much any 2D graphics into a Canvas, and then use a Camera to render those graphics onto a RenderTexture. If you make lots of these, you can also keep a tally of which textures are in use so you can disable unnecessary cameras.
I hope this article has inspired you to put some animated textures into your game. They can provide an extra layer of polish that really pulls your game’s graphics together.
If you liked this article, why not check out some of my other ones? (like this one on 2D shader effects in Unity).
A major update for Patch Quest released the other week. Patch Quest is a tactical rogue-inspired exploration game, available for free on PC. This video will run you through the basics. If you like the look of it, why not give it a try? Your support helps me find the time to write these articles.