Tilemap Wind shader

Inspired by: https://twitter.com/RustedMoss/status/1515359363103293442

A simple shader to apply a vertex distortion on a tilemap based on a noise texture.

Shader code
shader_type canvas_item;

// helpful to visually debug the noise scrolling texture.
uniform bool render_noise = false;
// Change if you want to move the bottom vertex of each tile.
uniform bool move_top = true;
// how strong is the vertex going to be pulled.
uniform vec2 distortion_force = vec2(10.0, 0.0);
// how fast is the noise texture is going to scroll.
uniform float time_scale :hint_range(0.0, 1.0, 0.01) = 0.1;
// the distortion texture, can be hand made or generated with the Godot builtin
// noise texture.
uniform sampler2D noise_texture: hint_white;
// the scale of the texture
uniform float noise_scale :hint_range(0.0, 2.0, 0.0001)= 0.002;

// you need to pass the world position from a script as seen
// https://docs.godotengine.org/en/3.5/tutorials/shaders/shader_reference/canvas_item_shader.html#vertex-built-ins
uniform mat4 global_transform;
varying vec2 world_position;

// the size of the tilemap tiles.
const float tile_size = 8.0;

vec2 get_uv(vec2 uv, float scale, float time) {
	vec2 new_uv = uv;
	new_uv *= scale;
	new_uv += time;
	return new_uv;

void vertex(){
    world_position = (global_transform * vec4(VERTEX, 0.0, 1.0)).xy;
	vec2 world_uv = get_uv(world_position, noise_scale, TIME * time_scale); 
	vec2 noise = texture(noise_texture, world_uv).rg;
	noise *= 2.0;
	noise -= 1.0;
	noise *= distortion_force;
	float a = fract(VERTEX.y / tile_size);
	if (a == 0.0 && move_top) {
		VERTEX.x += noise.x;
		VERTEX.y += noise.y;
	if (a > 0.0 && !move_top) {
		VERTEX.x += noise.x;
		VERTEX.y += noise.y;

void fragment() {
	vec4 sample = texture(TEXTURE, UV);
	COLOR = sample;
	if (render_noise) {
		vec3 color = sample.rgb;
		vec2 world_uv = get_uv(world_position, noise_scale, TIME * time_scale); 
		color = texture(noise_texture, world_uv).rgb;
		COLOR = vec4(color, 1.0);
2d, tilemap, wind
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from afk

Tilemap cell UV

Sokpop Skybox

Circle progress mirror

Related shaders

Rimworld style tilemap shader (with tutorial video)

Tilemap cell UV

Wind Waker 2d Water Shader Canvas_Item


Newest Most Voted
Inline Feedbacks
View all comments
3 months ago

it crashed my editor xdddddd

16 days ago

with godot 4.0.2:

shoud setting: render_mode skip_vertex_transform;
then in vertex() modify line: world_position = (MODEL_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy;
at last add line: VERTEX = (MODEL_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy;

after that, it worked.