Positioned Shockwave

Based on the shockwave shader tutorial by Nolkaloid: https://www.youtube.com/watch?v=SCHdglr35pk

The shader itself is the same, but now you can pass the [global position of the object – global position of the camera] to the global_position uniform of the shader to make the shockwave emit from the object.

Shader code
shader_type canvas_item;

uniform vec2 global_position;
uniform vec2 screen_size;
uniform float force;
uniform float size;
uniform float thickness;

void fragment(){
	vec2 center = global_position;
	float ratio = SCREEN_PIXEL_SIZE.x / SCREEN_PIXEL_SIZE.y;
	center.x = center.x / screen_size.x;
	center.x = (center.x - 0.5) / ratio + 0.5;
	center.y = (screen_size.y - center.y) / screen_size.y;
	vec2 scaledUV = (SCREEN_UV - vec2(0.5, 0.0) ) / vec2(ratio, 1.0) + vec2(0.5, 0.0);
	float mask = (1.0 - smoothstep(size-0.1, size, length(scaledUV - center))) * smoothstep(size-thickness-0.1, size-thickness, length(scaledUV - center));
	vec2 disp = normalize(SCREEN_UV - center) * force * mask;
	COLOR = texture(SCREEN_TEXTURE, SCREEN_UV - disp);
}
Tags
explosion, shockwave
The shader code and all code snippets in this post are under MIT license and can be used freely. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

Related shaders

Distortion/Shockwave Shader

guest

10 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
snesmocha
4 years ago

um, we posted the same shader………

snesmocha
4 years ago
Reply to  pekopekorhino

huh didn’t realize that

Pandemic
3 years ago

Will this shader work in a 3D scene? I would like the shockwave appear to emanate from a 3D node.

eerbin13
eerbin13
1 year ago

This does not appear to work well in Godot 4.

nd123
nd123
1 year ago
Reply to  eerbin13

yes! cause it was made for godot 3

kotapi
kotapi
1 year ago

Anyone had luck using this for Godot 4?

falkri
falkri
1 year ago
Reply to  kotapi

I managed to get it working by calculating the scaled center position for the original shader script. Using the get_screen_center_position() will make sure the visible global position is taken even when the camera limits are hit and the camera zoom’s effect on the viewport.

var target = get_tree().get_first_node_in_group(‘Enemies’)
var viewport_size := get_viewport_rect().size
var zoomed_view := viewport_size / cam.zoom

var cam_relative_pos = (target.global_position – cam.get_screen_center_position()) \
+ zoomed_view / 2.0
var ratio = zoomed_view.x / zoomed_view.y

var x = cam_relative_pos.x / zoomed_view.x
var y = cam_relative_pos.y / zoomed_view.y
x = (x – 0.5) * ratio + 0.5 # reversing the effect of scaling in shader

shock_material.set_shader_parameter(‘center’, Vector2(x,y))

Last edited 1 year ago by falkri
The2AndOnly
5 days ago

I think there’s a better way to do this! Instead, make a Sprite2D and set it’s texture to a Gradient2D with the width and height the same as the project resolution. Then, attach the original shockwave shader to it (from the original video) and on the line where it says

vec2 scaledUV = (SCREEN_UV - vec2(0.5, 0.0) ) / vec2(ratio, 1.0) + vec2(0.5, 0.0);

just change SCREEN_UV to UV

and now you can place the shockwave wherever you want in the world, and it even works when the camera rotates

Problem: The shockwave doesn’t scale good when the camera zooms in and out but I’m not smart enough to find a solution to that yet

Another problem: Can’t have multiple shockwaves at once on the screen. But again, that’s a problem I’m not fit for solving right now

The2AndOnly
4 days ago
Reply to  The2AndOnly

Update: Here is how you can have multiple shockwaves on the screen at once:
There needs to be a “BackBufferCopy” node between each sprite2D that has the shockwave effect, and make sure it has “copy mode” set to “viewport.”

You can put it as a child of all the nodes that have the shockwave effect to ensure that there’s always a BackBufferCopy between them all.

	var bbc = BackBufferCopy.new()
	shaderNode.add_child(bbc)
	bbc.copy_mode = BackBufferCopy.COPY_MODE_VIEWPORT