In this tutorial, we’ll explore two essential techniques for creating animated procedural materials: building stylized water in Blender and panning textures in Unreal Engine 5. By combining procedural patterns, UV manipulation, distortion, color, and animation, you’ll learn how simple shader concepts can produce dynamic, expressive visual effects suitable for games and VFX.
MATERIAL SETUP
I will be using the Node Wrangler add-on
Open the Shader Editor, create a new material, and give it a descriptive name such as Stylized Water
We’re going to construct the shader from several procedural layers, so it helps to keep the node tree organized as we go
Our first task is to create the basic wave pattern
WAVE PATTERN
Use SHIFT + A to add a Voronoi Texture node
Change its Dimensions to 4D and its Feature Output to Distance to Edge
This is important because, unlike the standard Voronoi pattern, Distance to Edge gives us lines around the cells
These lines are going to become the foundation of our stylized waves
At this point, though, the pattern looks far too perfect
The edges are straight and regular, which doesn’t look much like water
So before using the Voronoi pattern, we need to distort it
DISTORTION
Select the Voronoi Texture and use CTRL + T to add a Texture Coordinate node and Mapping node
Add a Mix Color node after the Mapping node and change the Blending Mode to Linear Light
Now add a Noise Texture
Take the Color output from the Noise Texture and connect it to the second input of the Mix Color node
The important idea here is that the Noise Texture is bending and disturbing the coordinates before they reach the Voronoi pattern
The once-perfect Voronoi cells should now appear irregular and fluid
Try reducing the Mapping Scale and keep the Linear Light factor subtle
A Value around 0.1 is a good starting point
If the water looks excessively warped, don’t worry. You can control the amount of distortion in two main ways:
- Adjust the scale of the Noise Texture
- Reduce or modify the Linear Light settings
The trick is to create enough irregularity to make the water feel organic without destroying the underlying wave structure
SHARP MASK
Now we need to turn the soft Distance to Edge information into a clean graphic pattern
Add a Math node after the Voronoi Texture and set its operation to Greater Than
Lower the threshold until you get a pattern of sharp black lines against white
This is useful because we’re no longer dealing with a gradual falloff
Instead, we have a clean mask that can be used to define exactly where our stylized waves appear
COLOR
Add a Mix Color node after the Math node and connect the Math node to the Factor of the Mix Color node
The two color inputs of the Mix Color node now become our water colors
Choose a blue or cyan for the B-input [B: #6298BDFF]
You should now have the beginnings of the water material – a colored surface broken up by a procedural wave pattern
But one layer isn’t enough
To make the water more interesting, we’re going to introduce a second wave pattern
SECOND WAVE
Select the Voronoi, Math, and Mix Color nodes that form your first wave layer and duplicate them using SHIFT + D
Make sure to connect the Linear Light to the second Voronoi texture
For this layer, change the A-input color to a darker blue [#3B5B71FF]
To combine the two layers, add a Mix Color node and connect the two Mix Color node layers
When the two layers are viewed together, you’ll notice a problem – their wave patterns tend to sit directly on top of one another
Instead of looking like two independent layers of water, they look like the same pattern being painted twice
We need to randomize the second layer
SECOND PATTERN
Add another Math node and change its operation to Multiply
Connect the Value into the W input of the second Voronoi texture and use a relatively large value, such as 200, as a starting point
If you change the Factor of the last Mix Color node you will now see two variations of the Voronoi Texture
This effectively changes the fourth-dimensional coordinate used by the Voronoi texture, causing the second pattern to be different from the first
The result is two related but independently distributed wave patterns
Now we can combine them without having every wave perfectly overlap
Use the Greater Than result from the first layer as the Factor controlling the final mix between the two wave colors
EXPORTING
Under the Output Properties tab, I change the Resolution to 2K
I set up my camera and light – scaling the light to the same size as the plane and placing it in front of the camera
Render the image
MATERIAL SETUP (UE)
First, create a new material and open it in the Material Editor
In your Project Settings you will need to turn off Substrate Materials
NOTE: I would recommend making and using a tiled texture
I used the Seamless Texture Generator – it isn’t perfect but close enough for this tutorial
Change the Blend Mode to Translucent
You can also use an appropriate shading model depending on the effect you’re creating
For this example, we’ll keep the material extremely simple
Hold down the T-key and left-click to add a Texture Sample
Choose the texture you just made
Connect the Texture Sample to the Emissive Color input
At this point, you should have a basic material
Now let’s make that texture move
TEXTURE OFFSET
Before we make anything move automatically, it’s useful to understand what makes a texture move
The secret is the texture’s UV coordinates
Normally, the Texture Sample receives UV coordinates from the mesh
Those coordinates determine which part of the image is displayed at each point on the surface
If we add a value to those coordinates, we’re effectively shifting the texture
Start by holding down the U-key and left-clicking to add a Texture Coordinate node
Add an Add node by holding down the A-key and left-clicking
Connect the Texture Coordinate node to the Add node
Then connect the output of the Add node to the UVs input of your Texture Sample
Nothing should visibly change yet because we’re effectively adding zero to the UV coordinates
Now let’s create some controls
OFFSET CONTROLS
Create two scalar parameters by holding down the S-key and left-clicking
Name the first one Offset X and the second one Offset Y
For each parameter, set the minimum and maximum values to approximately -1 and 1
This gives you a convenient range for moving the texture in either direction
Now right-click and search for an Append Vector node
Connect Offset X to the A input and Offset Y to the B input
The result is a two-dimensional vector containing our horizontal and vertical offsets
Connect this Append Vector to the second input of the Add node
Apply and Save the material
Back in the Content Browser, right-click on the Material and create a Material Instance from it
Open the instance and you’ll now have controls for Offset X and Offset Y
Increase Offset X and you’ll see the texture slide horizontally
Increase Offset Y and it will slide vertically
AUTOMATIC OFFSET
Manually changing Offset X isn’t particularly useful for an animation
We could keep increasing the value ourselves, but what we really want is a number that continuously increases as the material runs
That’s exactly what the Time node provides
Go back to your material, right-click and add a Time node
Instead of using the Offset X parameter directly, connect Time to the X input of your UV offset setup
Now the texture should begin moving automatically
The reason is simple – time continuously increases while the material is being rendered
Since that changing number is being added to the UV coordinates, the sampled position changes continuously as well
We’ve just created our first animated texture
SPEED AND DIRECTION CONTROLS
The Time node gives us movement, but we still need control over it which can be done through multiplication
Hold down the M-key and left-click to add a Multiply node
Connect the Time to the A-Input and the Offset X to the B-input
Connect the Multiply node to the A-input of the Append node
Change the Offset X Parameter Name to Speed X and change the default Value to 0.1
Add a Multiply node and connect the Y Axis Parameter to the B-input
Connect the Time node to the A-input of the second Multiply node
Connect the Multiply node to the B-input of the Append node
Change the Offset Y Parameter Name to Speed Y and change the default Value to 0.1
Now you have independent controls for both directions
You can now use the Material Instance to change the speed in real time
Using negative values makes textures travel in the opposite direction
PANNER NODE
There’s just one problem
Although this setup is useful for understanding what’s happening, it contains several nodes just to achieve a very common operation
Fortunately, Unreal Engine has already packaged this functionality into a single node
Hold down the P-key and add a Panner node
Connect the Panner node to the UVs of the Texture Sample
Use CTRL + D to duplicate the Multiply, Speed X and Speed Y nodes
Connect the Speed X to the A-input of the new Multiply node
Connect the Speed Y to the B-input of the new Multiply node
Connect the Multiply node to the Speed input of the Panner
Apply and Save the material
CONCLUSION With these techniques, you now understand how procedural textures can be shaped, layered, colored, and animated to create convincing stylized effects. Blender gives you powerful tools for generating unique water patterns, while Unreal Engine makes texture animation straightforward. Together, these workflows provide a strong foundation for creating flexible, reusable materials and VFX.