Sitemap

How to Make Water Ripples Shader in UE4

3 min readAug 23, 2022

--

Press enter or click to view image in full size

Many people have tried to achieve the shader effect of ripples, and there are various ways to do it. Here, the way I implemented it is to use the Custom node to generate the normals algorithmically. In this article, I will share the ideas with you, and here is the final rendering effect.

The Final Effect

Get UWA’s stories in your inbox

Join Medium for free to get updates from this writer.

Here is the basic principle: first use UV to make a pseudo-random grid; each grid is a separate UV but with different grayscale values, and then generate multiple concentric circles of different sizes in the center of the grid, and then do scaling and edge blending.

Random Noise Generation

First of all, we define a three-dimensional vector for the calculation of three layers of ripples in different sizes. Because the value range of UV is 0–1, the value of float3 we define must be between 0–1. This value is a coefficient, not the actual size:

float3 ripple_scale3=float3(0.1,0.2,0.3)

Then, we need to generate UV grids with different shades of gray:

float3 p3 = frac(float3(p.xyx) * ripple_scale3);
p3 += dot(p3, p3.yzx +20);
return frac((p3.xy + p3.yz) * p3.zy);

p is a two-dimensional vector, in order to multiply it with ripple_scale, we can take its .XYX or .XYY arbitrarily. p3 is an accumulated value, and the final returned value is a float2. Because UV is float2, so we can just take two axes and perform the above operation. Then we define a one-dimensional vector and perform the following operations again:

float ripple_scale1 = 0.1;
float3 p3 = frac(float3(p.xyx) * ripple_scale1);
p3 += dot(p3, p3.yzx + 10);
return frac((p3.x + p3.y) * p3.z);

The above two operations are mainly to obtain a sufficiently random value, and other algorithms can also be used instead. If we tile the UV 10 times, and then use the floor as the value of p in the above code, first perform a three-dimensional operation and then multiply it with the following one-dimensional to obtain the following results (as long as an algorithm similar to the following results is obtained):

We need to use this algorithm as a function because it needs to be calculated in a loop, so it has to be declared and called with a Struct.

float ripple_scale1 = 0.1; 1D random number seed
float3 ripple_scale3 = float3(0.1, 0.11, 0.09);// 3D random number seed
float max_radius = 1;
struct rain
{
float ripple1(float2 p)
{
float3 p3 = frac(float3(p.xyx) * ripple_scale1);
p3 += dot(p3, p3.yzx + 10);
return frac((p3.x + p3.y) * p3.z);
}
float2 ripple2(float2 p)
{
float3 p3 = frac(float3(p.xyx) * ripple_scale3);
p3 += dot(p3, p3.yzx +20);
return frac((p3.xy + p3.yz) * p3.zy);
}
};
rain ra;

Read more: https://blog.en.uwa4d.com/2022/08/23/how-to-make-water-ripples-in-ue4/

--

--

UWA
UWA

Written by UWA

Read the latest news from #UWA; Learn how to analyze and solve potential performance issues during #Game, #VR and #AR project development.