Godot Quick Tip #2 - Getting the mouse cursor position in your 2D fragment shader
Want to create a pixel effect based on the position of the mouse in Godot Engine? Let me show you how.
Note: this quick tip assume that you know what a fragment shader is and how to use one in Godot.
Getting the mouse position, or coordinates, in a fragment shader is not as straightforward as one might think. There is two issues:
- The fragment shader use normalized device coordinates, or NDC, where values are between 0 and 1, instead of pixels for the mouse.
- The NDC origin is bottom-left while mouse coordinates are top-left.
The GD script
onready var _material = get_material() # ... func _input(event): if event.type == InputEvent.MOUSE_MOTION: var norm_mouse = get_viewport().get_mouse_pos()/get_viewport_rect().size norm_mouse.y = 1.0 - norm_mouse.y _material.set_shader_param("mouse_pos", norm_mouse) update()
This is the code you want to put in the script of the node where the effect should apply. The calculation takes place on a mouse motion event. The first thing you want to do is normalize the mouse coordinates by dividing the mouse position by the viewport size, effectively giving you coordinates between 0 and 1. Then, in order to change from a top-left origin to a bottom-left origin, you just subtract the vertical normalized coordinate from 1. Sending the value to the fragment shader is quite easy with Godot, you call the set_shader_param function of the material. Finally, a call to update makes sure that the node will be redrawn, using the new mouse coordinates.
The fragment shader
uniform vec2 mouse_pos = vec2(0.0, 0.0); float dist = distance(SCREEN_UV, mouse_pos);
To be able to use the value in the fragment shader you have to declare a uniform with the type vec2, equivalent of a GD script Vector2. The name of the uniform should match exactly the name given to set_shader_param. After that you can use the mouse coordinates the way you want, in the example I calculate the distance between the mouse and the current fragment, or pixel, being drawn.
Written by Olivier on Friday March 3, 2017