A tool to generate river meshes with flow and foam maps based on bezier curves.
1,324
stars
150
commits
GDScript
primary language
Dec 17, 2025
updated
A tool to generate river meshes with flow and foam maps based on bezier curves. Try out the demo project for an example.
Copy the folder addons/waterways into your project and activate the add-on from the Project -> Project Settings... -> Plugins menu.
I've been very impressed with examples of using flowmaps to imitate water simulations in games for a while, but most of the implementations I've seen were using either manually painted flowmaps, or flowmaps generated in an external program. I wanted to see if it was possible to have good flowmap results purely generated within Godot. Both the generation of the flowmaps and the generation of the mesh for the river was of interest to me and I've learned a lot implementing my solution.
Once the addon is active, you can simply add a River node to the scene.

Shaping
You can then use the Path controls to shape the river to your liking.

The "Snap to Colliders" constraint can be used to easily place the path of the river along a terrain.

The Axis and Plane constraints can be used for better control in moving and adding points. The implementation is similar to Blender's. You can also use the shortcuts X, Y and Z to lock movement to a given axis and shortcuts Shift + X, Y and Z to lock to planes YZ, XZ and XY. The Local mode option, switches the axis to be local to the point rather than the world and can be toggled with shortcut T.

Texture Baking
Once you are happy with the shape of your river, you can use the River -> Generate Flow & Foam Map option to bake out the textures that activate flow map and foam. The settings for the baking are located in the river's inspector, see section below.

Generating a Mesh Copy
In case you want to access the river mesh directly to use it for other purposes such as generating a collision shape. You can use the River -> Generate MeshInstance Sibling option.

Using a WaterSystem Node
To generate a global height and flowmap of a river. You can add a WaterSystem node and generate a texture based on any River child nodes with the WaterSystem -> Generate System Maps option.

Using a Buoyant Node
Adding a Buoyant node as a child to a RigidBody will allow the object to float on the river if a WaterSystem with valid maps is available.

Using flow and height maps in shaders
You can automatically assign the global textures from the WaterSystem node to MeshInstances to use them in shaders. See the WaterSystem parameters for details. Once the textures and coordinates are assigned you can use them in a shader like this:
shader_type spatial;
uniform sampler2D water_systemmap;
uniform mat4 water_systemmap_coords;
varying vec3 world_vertex;
float water_altitude(vec3 pos) {
vec3 pos_in_aabb = pos - water_systemmap_coords[0].xyz;
vec2 pos_2d = vec2(pos_in_aabb.x, pos_in_aabb.z);
float longest_side = water_systemmap_coords[1].x > water_systemmap_coords[1].z ? water_systemmap_coords[1].x : water_systemmap_coords[1].z;
pos_2d = pos_2d / longest_side;
float value = texture(water_systemmap, pos_2d).b;
float height = value * water_systemmap_coords[1].y + water_systemmap_coords[0].y;
return pos.y - height;
}
void vertex() {
world_vertex = (WORLD_MATRIX * vec4(VERTEX, 1.0)).xyz;
}
void fragment() {
float altitude = clamp(water_altitude(world_vertex), 0.0, 1.0);
ALBEDO = vec3(altitude);
}
For effects such as this:

The river's parameters are split into 4 sections.
Shape
Material
The Material section has two hardcoded parameters
The remaining parameters in the Material section are parsed from the currect shader
Parameters shared by Water and Lava shader
Parameters specific to Water shader
Albedo - Subcategory for the albedo parameters.
Transparency - Subcategory for the transparency parameters.
Foam - Subcategory for the foam options.
Parameters specific to the Lava shader
Lod
Baking
When writing custom shaders for the tool there are a few things to keep in mind.
The tool uses certain uniforms that should not be customized as that will break the tool. These uniforms are prefixed with "i_" and are:
| Uniform name | Description |
|---|---|
| i_lod0_distance | used by the LOD system |
| i_texture_foam_noise | a noise texture used to display foam on steep angles |
| i_flowmap | the generated flowmap(RG) and foam map(B) |
| i_distmap | the generated distance field(R) and pressure map(B) |
| i_valid_flowmap | a bool that is set if the generated maps are valid |
| i_uv2_sides | an int value that tells the shader how to read the UV2 layout |
Uniforms that do not start with "i_" will be parsed by the river's material inspector so they can easily be used in the tool. If the uniforms start with any of the below prefixes they will automatically be sorted into subcategories in the material section.
| Prefix name | Subcatergory name |
|---|---|
| albedo_ | Albedo |
| emission_ | Emission |
| transparency_ | Transparency |
| flow_ | Flow |
| foam_ | Foam |
| custom_ | Custom |
Additionally the river inspector will handle these uniform types specially:
float uniforms containing "curve" in their name will be displayed as an easing curve in the inspector.
uniform float albedo_depth_curve = 0.25;

mat4 uniforms containing "color" in their name will be displayed as a gradient field with two colour selectors. Here is the code setting up the water shader's albedo gradient with the two colors (0.0, 0.8, 1.0) and (0.15, 0.2, 0.5).
uniform mat4 albedo_color = mat4(vec4(0.0, 0.15, 0.0, 0.0), vec4(0.8, 0.2, 0.0, 0.0), vec4(1.0, 0.5, 0.0, 0.0), vec4(0.0));

Several people in the Godot community have helped me out with this.
Beyond the Godot community, I should also mention these resources.
If you want to contribute to the project or just work on your own version, clone the repository and add Zylann's terrain addon into the project as I don't include it in this repository, but use it in the test scene.
GDScript
79.0%
GLSL
21.0%
A tool to generate river meshes with flow and foam maps based on bezier curves.
1,324
stars
150
commits
GDScript
primary language
Dec 17, 2025
updated
A tool to generate river meshes with flow and foam maps based on bezier curves. Try out the demo project for an example.
Copy the folder addons/waterways into your project and activate the add-on from the Project -> Project Settings... -> Plugins menu.
I've been very impressed with examples of using flowmaps to imitate water simulations in games for a while, but most of the implementations I've seen were using either manually painted flowmaps, or flowmaps generated in an external program. I wanted to see if it was possible to have good flowmap results purely generated within Godot. Both the generation of the flowmaps and the generation of the mesh for the river was of interest to me and I've learned a lot implementing my solution.
Once the addon is active, you can simply add a River node to the scene.

Shaping
You can then use the Path controls to shape the river to your liking.

The "Snap to Colliders" constraint can be used to easily place the path of the river along a terrain.

The Axis and Plane constraints can be used for better control in moving and adding points. The implementation is similar to Blender's. You can also use the shortcuts X, Y and Z to lock movement to a given axis and shortcuts Shift + X, Y and Z to lock to planes YZ, XZ and XY. The Local mode option, switches the axis to be local to the point rather than the world and can be toggled with shortcut T.

Texture Baking
Once you are happy with the shape of your river, you can use the River -> Generate Flow & Foam Map option to bake out the textures that activate flow map and foam. The settings for the baking are located in the river's inspector, see section below.

Generating a Mesh Copy
In case you want to access the river mesh directly to use it for other purposes such as generating a collision shape. You can use the River -> Generate MeshInstance Sibling option.

Using a WaterSystem Node
To generate a global height and flowmap of a river. You can add a WaterSystem node and generate a texture based on any River child nodes with the WaterSystem -> Generate System Maps option.

Using a Buoyant Node
Adding a Buoyant node as a child to a RigidBody will allow the object to float on the river if a WaterSystem with valid maps is available.

Using flow and height maps in shaders
You can automatically assign the global textures from the WaterSystem node to MeshInstances to use them in shaders. See the WaterSystem parameters for details. Once the textures and coordinates are assigned you can use them in a shader like this:
shader_type spatial;
uniform sampler2D water_systemmap;
uniform mat4 water_systemmap_coords;
varying vec3 world_vertex;
float water_altitude(vec3 pos) {
vec3 pos_in_aabb = pos - water_systemmap_coords[0].xyz;
vec2 pos_2d = vec2(pos_in_aabb.x, pos_in_aabb.z);
float longest_side = water_systemmap_coords[1].x > water_systemmap_coords[1].z ? water_systemmap_coords[1].x : water_systemmap_coords[1].z;
pos_2d = pos_2d / longest_side;
float value = texture(water_systemmap, pos_2d).b;
float height = value * water_systemmap_coords[1].y + water_systemmap_coords[0].y;
return pos.y - height;
}
void vertex() {
world_vertex = (WORLD_MATRIX * vec4(VERTEX, 1.0)).xyz;
}
void fragment() {
float altitude = clamp(water_altitude(world_vertex), 0.0, 1.0);
ALBEDO = vec3(altitude);
}
For effects such as this:

The river's parameters are split into 4 sections.
Shape
Material
The Material section has two hardcoded parameters
The remaining parameters in the Material section are parsed from the currect shader
Parameters shared by Water and Lava shader
Parameters specific to Water shader
Albedo - Subcategory for the albedo parameters.
Transparency - Subcategory for the transparency parameters.
Foam - Subcategory for the foam options.
Parameters specific to the Lava shader
Lod
Baking
When writing custom shaders for the tool there are a few things to keep in mind.
The tool uses certain uniforms that should not be customized as that will break the tool. These uniforms are prefixed with "i_" and are:
| Uniform name | Description |
|---|---|
| i_lod0_distance | used by the LOD system |
| i_texture_foam_noise | a noise texture used to display foam on steep angles |
| i_flowmap | the generated flowmap(RG) and foam map(B) |
| i_distmap | the generated distance field(R) and pressure map(B) |
| i_valid_flowmap | a bool that is set if the generated maps are valid |
| i_uv2_sides | an int value that tells the shader how to read the UV2 layout |
Uniforms that do not start with "i_" will be parsed by the river's material inspector so they can easily be used in the tool. If the uniforms start with any of the below prefixes they will automatically be sorted into subcategories in the material section.
| Prefix name | Subcatergory name |
|---|---|
| albedo_ | Albedo |
| emission_ | Emission |
| transparency_ | Transparency |
| flow_ | Flow |
| foam_ | Foam |
| custom_ | Custom |
Additionally the river inspector will handle these uniform types specially:
float uniforms containing "curve" in their name will be displayed as an easing curve in the inspector.
uniform float albedo_depth_curve = 0.25;

mat4 uniforms containing "color" in their name will be displayed as a gradient field with two colour selectors. Here is the code setting up the water shader's albedo gradient with the two colors (0.0, 0.8, 1.0) and (0.15, 0.2, 0.5).
uniform mat4 albedo_color = mat4(vec4(0.0, 0.15, 0.0, 0.0), vec4(0.8, 0.2, 0.0, 0.0), vec4(1.0, 0.5, 0.0, 0.0), vec4(0.0));

Several people in the Godot community have helped me out with this.
Beyond the Godot community, I should also mention these resources.
If you want to contribute to the project or just work on your own version, clone the repository and add Zylann's terrain addon into the project as I don't include it in this repository, but use it in the test scene.
GDScript
79.0%
GLSL
21.0%