Trampoline
This shader is very straightforward : It deforms the background using a bezier curve. It can be used alone, but with at least this script to set the uniforms screen_pos and screen_size (UV computed from the viewport). Apply this shader on a node such as ColorRect.
extends ColorRect
func _ready():
var viewport_size : Vector2 = get_viewport_rect().size
material.set_shader_param("screen_size", rect_size / viewport_size)
material.set_shader_param("screen_pos", rect_position / viewport_size)
Now, if you want to add a spring effect (so that the effect look like something is landing on the screen like on a trampoline, add a Tween node as a child (name it … well … Tween), and use the following script for your main ColorRect node:
class_name TrampolineEffect
extends ColorRect
signal finished()
export(float, -0.5, 1.0, 0.001) var height : float = 0.4
export(float) var stiffness = 5.0
export(float) var dampening = 3.0
export(float) var amplitude = 1.0
export(float) var start_delay = 1.4
const ACTIVITY_MARGIN : float = 0.01
onready var tween : Tween = $Tween
onready var velocity : float = 0
onready var release : bool = false
var current_height : float
func _ready():
set_process(false)
reset_uv()
material.set_shader_param("force", 0)
tween.connect("tween_all_completed", self, "_on_start_completed")
func reset_uv() -> void:
var viewport_size : Vector2 = get_viewport_rect().size
material.set_shader_param("screen_size", rect_size / viewport_size)
material.set_shader_param("screen_pos", rect_position / viewport_size)
func activate() -> void:
current_height = height
reset_uv()
set_process(false)
release = false
tween.remove_all()
tween.interpolate_property(
self,
"material:shader_param/force",
0,
height,
start_delay,
Tween.TRANS_QUART,
Tween.EASE_IN)
tween.seek(0.0)
tween.start()
func _on_start_completed() -> void:
release = true
set_process(true)
func _process(delta):
if release:
velocity -= ((current_height * stiffness) + (dampening * velocity)) * delta
current_height = clamp(velocity + current_height, -amplitude, amplitude)
material.set_shader_param("force", current_height)
if abs(current_height) < ACTIVITY_MARGIN and abs(velocity) < ACTIVITY_MARGIN:
current_height = 0
velocity = 0
material.set_shader_param("force", 0)
emit_signal("finished")
release = false
The exported variables are:
- height : The height/force to apply. Range between -0.5 (push) and 1.0 (pull).
- stiffness and dampening : Typical spring-mass system constants.
- amplitude : Height clamping value. Should remain to 1.0
- start_delay : Before doing the trampoline effect, the script will bring the deformation from 0 to the height value in start_delay seconds.
To activate the effect, just call the activate function. The effect can be reused, so the activate function can be re-called.
The signal finished is emitted when the spring-mass system reached a stable state (height is 0 and no movement).
Shader code
shader_type canvas_item;
uniform float force : hint_range(-0.5, 1.0, 0.001) = 0.4;
uniform vec2 screen_pos;
uniform vec2 screen_size;
void fragment() {
vec2 v = vec2(.5) - UV;
float d = min(1., length(v) * 2.);
vec2 target_id = screen_pos + ((UV + ((2.*v/d)
* clamp(
force * (d + 2.*sqrt(1. - d) - 1.),
(d - 1.) / 2.,
d / 2.) )) * screen_size);
target_id.y = 1. - target_id.y;
vec4 color = texture(SCREEN_TEXTURE, target_id);
COLOR = color;
}