0 votes

Hi everyone,

following this tutorial (https://www.youtube.com/watch?v=SCHdglr35pk) I was able to instance that shader-scene on a button-release, so on release there's that nice "shockwave" happening right in the center of the screen.

shader_type canvas_item;

uniform vec2 center;
uniform float force;
uniform float size;
uniform float thickness;

void fragment() {
    float ratio = SCREEN_PIXEL_SIZE.x / SCREEN_PIXEL_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.04, size, length(scaledUV - center))) *
        smoothstep(size-thickness-0.08, size-thickness, length(scaledUV - center));
    vec2 disp = normalize(scaledUV - center) * force * mask;
    COLOR = texture(SCREEN_TEXTURE, SCREEN_UV - disp);
}

I instanced other scenes in other situations and I usually can position them like this:

var shockwave = preload("res://shader/shockwave.tscn").instance()
add_child(shockwave)
shockwave.position = Vector2(80, 800)

In this case, however, positioning like that won't work.

It would be nice to have such a shockwave-scene independent from "the whole screen", but as its "own little object" instead, like some invisible sprite which could be instanced and positioned (and scaled etc.) anywhere... just so I could position it on top of my button.
Any ideas how that could be done?

Godot version 3.3
in Engine by (492 points)

1 Answer

0 votes

take a note how uniform "center" was used in this shader. You can replace it with a coordinates of your mouse translated to screen size. This way You will be able to :

material.set_shader_param("mouse",xxxx)

So every click shockwave will expand form cursor. You just have to count the ratio of mouse vector/screen_size
There is also another way, to apply shader to Sprite, but use sprites center as shockwave center, while using screens color to mimic transparency.

by (7,925 points)

Thanks for your answer, and sorry for the late reply.

I think that in my case applying the shader to a sprite would be the better way. (It's a button which can occur in different screen-positions...)
So I guess I'd have to put the shader to the button-sprite and then have it run on button release. But how do place it sprite-centered and how do I call that shader then?

When You apply it to the button, it will only have a range of that button. It will start in the middle of Sprite, but will never reach beyond Sprite size. Still, if You want it like this, the center of the Sprite in shader is always vec2(0.5). UV is a built in to measure size of sprite form 0 to 1, so 0.5 is a center of each axis. So Use this UV to mark start of the shockwave, but use SCREENUV and SCREENTEXTURE to apply color to sprite and distortion

I see, the ripple-effect of this shader would of course look strange if it ends at the sprite's borders. So I would have to leave SCREENUV and SCREENTEXTURE "globally" as they are.

But I would need to get rid of all positioning within the shader itself and replace it with that of the sprite-center vec2(0.5). Can that be donedirectly in the shader-code or would I have to do this within the sprite's script?

If You choose global shader You have to apply it to whole screen texture, like a texture rect. You need to write a code to calculate mouseposition in regards to the viewport and pass it to the shader, where it will be handled by shader code. So in pseudocode :
1. On mouse click : var realmousepos = vector2(globalmouseposition/ get
viewportsize)
material.set
shader_param("center",realmousepos)
2.In shader :
uniform vec2 center ; //You already have it there in your shader

I understand in theory. But I reached the point when I start stumbling over practical hurdles. Right now the line var realmousepos = vector2(get_global_mouse_position() / get_viewport_rect()) throws the error Invalid operand types ("Vector2" and "Rect2") to operator "/".
That's the beginner in me struggling with these kind of things now... ; )

it was pseudocode :). Try to solve it too. You need to pass the proportion of where mouse cursor is in relation to the visible screen. So You need the size property of the viewport rect precisely. But there is also getvisiblerect methods and OS.screen_size method. Using them will have different outcomes depending on if project is played in window or fullscreen. Try them out and find out which is best :)

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.