Perspective Warp/Skew Shader

Credit to this guy’s blog because the code is basically entirely his, I just converted it to Godot.


Just add the shader code to a ColorRect (or any control node with a texture) and set its anchor to full rect. Like this:

- CanvasLayer
     - ColorRect (w/ shader)

Then, in the shader parameters, change the topright/topleft/bottomright/bottomleft parameters to change the skew/perspective. 

Shader code
shader_type canvas_item;

uniform vec2 topleft = vec2(0.01, 0.0);
uniform vec2 topright;
uniform vec2 bottomleft;
uniform vec2 bottomright;

float _cross( in vec2 a, in vec2 b ) { return a.x*b.y - a.y*b.x; }

vec2 invBilinear( in vec2 p, in vec2 a, in vec2 b, in vec2 c, in vec2 d ) {
	vec2 res = vec2(-1.0);

	vec2 e = b-a;
	vec2 f = d-a;
	vec2 g = a-b+c-d;
	vec2 h = p-a;

	float k2 = _cross( g, f );
	float k1 = _cross( e, f ) + _cross( h, g );
	float k0 = _cross( h, e );

	// if edges are parallel, use a linear equation.
	if( abs(k2)<0.001 ) {
		res = vec2( (h.x*k1+f.x*k0)/(e.x*k1-g.x*k0), -k0/k1 );
	// otherwise, it's a quadratic
	else {
		float w = k1*k1 - 4.0*k0*k2;
		if( w<0.0 ) return vec2(-1.0);
		w = sqrt( w );

		float ik2 = 0.5/k2;
		float v = (-k1 - w)*ik2;
		float u = (h.x - f.x*v)/(e.x + g.x*v);
		if( u<0.0 || u>1.0 || v<0.0 || v>1.0 ) {
		v = (-k1 + w)*ik2;
		   u = (h.x - f.x*v)/(e.x + g.x*v);
		res = vec2( u, 1.0 - v );
	return res;

void fragment(){
	vec2 topleftUV = topleft / vec2(textureSize(TEXTURE,0));  // compensates for screensize ratio
	vec2 toprightUV = vec2(1.0,0.0)+topright / vec2(textureSize(TEXTURE,0));
	vec2 bottomrightUV = vec2(1.0,1.0)+bottomright / vec2(textureSize(TEXTURE,0));
	vec2 bottomleftUV =vec2(0.0,1.0)+ bottomleft / vec2(textureSize(TEXTURE,0));

	vec2 newUV = invBilinear(UV, topleftUV, toprightUV, bottomrightUV, bottomleftUV);
	if (topleft.x == 0.0 || topright.x == 0.0) {
	else {
		if (newUV == vec2(-1.0)){
			COLOR = vec4(0.0);
		}else {
			COLOR = texture(SCREEN_TEXTURE, newUV);
perspective, screen, skew, warp
The shader code and all code snippets in this post are under MIT license and can be used freely. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from ACB_Gamez

2D Controlled Shine Highlight With Angle Adjustment

Related shaders

Image Warp Shader

Undertale Animation Skew

Fnaf / Clickteam perspective (displacement) – Godot 4.2

Notify of

Newest Most Voted
Inline Feedbacks
View all comments
3 years ago

oh my god, thank you so much

3 years ago

alright, after using the shader, the shader does not work and the shader itself isn’t being overlayed correctly

3 years ago

ok i figured out an easy fix to it, just change screen_space to texture 2d

2 years ago
Reply to  snesmocha

i can not use it as well

2 years ago

gles2 version if possible?