Untie shader scene from full-screen

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By pferft

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?

:bust_in_silhouette: Reply From: Inces

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.

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?

pferft | 2021-12-28 17:28

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 SCREEN_UV and SCREEN_TEXTURE to apply color to sprite and distortion

Inces | 2021-12-28 17:48

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 SCREEN_UV and SCREEN_TEXTURE “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?

pferft | 2021-12-29 13:20

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 mouse_position 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_viewport_size)
    material.set_shader_param(“center”,realmousepos)
    2.In shader :
    uniform vec2 center ; //You already have it there in your shader

Inces | 2021-12-29 20:35

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

pferft | 2021-12-30 12:29

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 get_visible_rect 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 :slight_smile:

Inces | 2021-12-30 19:06