Magnifier Shader
A Godot shader that magnifies what’s behind it. Written in Godot Engine v3.4.4.
This shader reads from screen texture. So if the image you want to zoom in isn’t rendered properly, you may end up with an unwanted result.
In order to get this shader working in Godot, you must attach this to a node with a texture. It might work with nodes without textures too, but it’s not tested yet.
For more information or to contribute: https://github.com/Orbbloff/Godot-Magnifier-Shader
Shader code
/*
This is a magnifier shader written in Godot Shading Language which is similar to GLSL ES 3.0.
In order to get this shader working, you must attach this to a node with a texture.
It might work with nodes without textures too, but isn't tested yet.
Author is Yavuz Burak Yalçın @orbbloff
MIT License
*/
shader_type canvas_item;
uniform bool is_object_centered; // Note that this needs to match with the sprite's centered property
uniform float magnification:hint_range(0.0, 400.0) = 2.0;
uniform bool filtering;
uniform bool is_round;
uniform float roundness:hint_range(0.0, 2.0) = 1.0;
uniform float circle_radius:hint_range(0.0, 0.71) = 0.5;
uniform float outline_thickness:hint_range(0.0, 0.1) = 0.01;
uniform vec4 outline_color:hint_color = vec4(0.4, 0.0, 0.0, 1.0);
varying flat vec2 center_pos;
void vertex(){
if(is_object_centered){
center_pos = vec2(0.0, 0.0);
}
else{
center_pos = (1.0 / TEXTURE_PIXEL_SIZE) / 2.0;
}
center_pos = (WORLD_MATRIX * vec4(center_pos, 0.0, 1.0)).xy; // From local space texel coordinates
// to screen space pixel coordinates
}
void fragment(){
vec2 screen_resolution = 1.0 / SCREEN_PIXEL_SIZE;
vec2 uv_distance = vec2(0.5) - UV; // UV distance between fragment and object center in local space
vec2 pixel_distance; // Pixel distance between fragment and object center
pixel_distance.x = center_pos.x - FRAGCOORD.x;
pixel_distance.y = center_pos.y - (screen_resolution.y - FRAGCOORD.y); // Since y component of FRAGCOORD built-in is
// inverted it is extracted from screen resolution
vec2 obj_size = pixel_distance / uv_distance; // Ratio of pixel distance to uv distance gives the objects dimensions
vec2 ratio = obj_size / screen_resolution; // This gives the ratio of object to screen
float magnify_value = (magnification - 1.0) / magnification; // Maps the magnification value to range[0.0, 1.0)
// while magnification is higher than 1.0
if(is_round){
magnify_value /= smoothstep(0.0, 1.0, length(UV - vec2(0.5))) * roundness + 1.0; // It slightly reduces the magnification
// of points that are far to the center
}
vec2 local_mapped_uv = mix(UV, vec2(0.5 /*center*/), magnify_value); // Calculates a local UV position towards
// the center, proportional to magnification
vec2 difference = local_mapped_uv - UV;
vec2 global_mapped_uv; // Calculates a global UV position to from screen texture
global_mapped_uv.x = SCREEN_UV.x + difference.x * ratio.x;
global_mapped_uv.y = SCREEN_UV.y - difference.y * ratio.y;
if(filtering){
// Applies filter while reading from screen texture
COLOR = texture(SCREEN_TEXTURE, global_mapped_uv);
}
else{
// Doesn't apply filter.
// Since texelFetch function uses screen space pixel coordinates, global_mapped_uv is transformed to pixel coordinates.
COLOR = texelFetch(SCREEN_TEXTURE, ivec2(int(global_mapped_uv.x * screen_resolution.x), int((global_mapped_uv.y) * screen_resolution.y)), 0);
}
// Creates outline
if(length(UV - vec2(0.5)) > circle_radius - outline_thickness){
COLOR = vec4(0.0); // Makes fragments transparent
if(length(UV - vec2(0.5)) < circle_radius){
COLOR = outline_color;
}
}
}
good work! however I could not handle to organize the project for that shader. is it possible to share scene? Emeğine sağlık! Şimdiden teşekkürler 🙂
Sure! Here’s the demo scene i just set up. Make sure the node’s Z index this shader is attached to be higher than the other nodes. Teşekkürler!
The link to the Godot project: https://easyupload.io/u6pcsj
Hi. I’m trying to use the asset in a world with light and it seems the shader does not take the light into account. The objects in the map have inverted and semitransparent colors. Is there some way to make the shader work with light? Cool shader by the way 🙂
I actually don’t know why it doesn’t work with lights. Actually I don’t know much about lights in Godot so can’t fix the problem with current knowledge I have. Sorry I couldn’t help :/ Thanks for likedand comment!
Hi, anyone has used this shader successfully on Godot 4? On Godot 4 the problem with the light is no more, but now the shader is magnifiyng the wrong part, when I move the camera, the texture the shader is zooming is offseted.
Hi! I haven’t tried the shader on Godot 4. I’ll check and inform you.