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


um, we posted the same shader………
hi! yours does not account for the position of the object and the camera
huh didn’t realize that
Will this shader work in a 3D scene? I would like the shockwave appear to emanate from a 3D node.
This does not appear to work well in Godot 4.
yes! cause it was made for godot 3
Anyone had luck using this for Godot 4?
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))
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
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
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.