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);
	}
}
Tags
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

Circle progress mirror

Tilemap cell UV

Joepli wobble

Related shaders

Rimworld style tilemap shader (with tutorial video)

Foliage Wind Shader

Wind Waker 2d Water Shader Canvas_Item

Subscribe
Notify of
guest

4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
maxlaughter
maxlaughter
2 years ago

it crashed my editor xdddddd

niwho
1 year 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.

Mazed
1 year ago
Reply to  niwho

Under version 4.1.1. I can not get it to run with these modifications. It seems that the noise texture is not read correctly. Maybe some tips?

randomspeech
randomspeech
1 year ago
Reply to  Mazed

Additionally to the changes mentioned above try out

uniform sampler2D noise_texture : repeat_enable;

this seemed to do the trick for me on Godot stable 4.1.1