2D Perspective wall shader

Looking for a 2D perspective view of a wall or a roof whithout a 3D object? You can try this!

rotation_angle:Adjust the angle of its rotation. In the cover image, there are 4 planes which are all 1.57(pi/2) rotated, which means they are straightly forwarded inside and the camera is at center.

isVertical:Tick it if it is a wall! Don’t tick it if it is a roof or floor.

isBottomOrLeftLonger:Tick it if it is a leftwall/floor, which has a wider edge on left/bottom side.

viewPosition:The offset of viewer from the center.eg. (-0.1,-0.2)means move the camera 0.1 left and 0.2 down

thickness:Control the depth of the wall or roof/floor

(3 Sep,2024 updated)

Shader code
#define pi 3.14159265358979323

shader_type canvas_item;

uniform float rotationAngle;
uniform bool isVertical;
uniform bool isLeftOrBottomLonger;
uniform vec2 viewPosition;
uniform float thickness=0.5;

struct ray{
    vec3 o,d;
};

ray GetRay(vec2 uv, vec3 camPos, vec3 lookAt, float zoom){
    ray a;
    a.o = camPos;
    
    vec3 f = normalize(lookAt-camPos);
    vec3 r = normalize(cross(vec3(0.0,1.0,0.0),f));
    vec3 u = cross(f,r);
    vec3 c = camPos + f * zoom;
	vec3 i;
	i = vec3(0.,0.,1.)+uv.x*vec3(0.,1.,0.)+uv.y*vec3(1.,0.,0.);
	//i = c + uv.x * u + uv.y * r;
    
    a.d = normalize(i-a.o);
    
    return a;
}

void vertex() {
	// Called for every vertex the material is visible on.
}

void fragment() {
	vec2 uv=2.*(UV-.5);
	vec3 camPos = vec3(viewPosition.y,viewPosition.x,0.0);
    vec3 lookAt = vec3(viewPosition.y,viewPosition.x,1.0);
    
    ray r = GetRay(uv, camPos, lookAt, 1.0);
    
    float rotat = rotationAngle;
    //describe the plane
    vec3 tar_point;
    vec3 tar_normal;
	if(isVertical){
		if(isLeftOrBottomLonger){
			tar_point=vec3(-1.0,-1.0,1.0);
			tar_normal=vec3(0.0,sin(rotat),-cos(rotat));
		}else{
			tar_point=vec3(1.0,1.0,1.0);
			tar_normal=vec3(0.0,-sin(rotat),-cos(rotat));
		}
	}else{
		if(isLeftOrBottomLonger){
			tar_point=vec3(-1.0,-1.0,1.0);
			tar_normal=vec3(sin(rotat),0.,-cos(rotat));
		}else{
			tar_point=vec3(1.0,1.0,1.0);
			tar_normal=vec3(-sin(rotat),0.,-cos(rotat));
		}
	}
	
    float dividend=dot(tar_normal,(tar_point-r.o));
    float divider=dot(tar_normal,r.d);
    float t=0.0;
    vec3 col=vec3(0.0);
    vec3 hitPoint;
	vec3 text_xy_10_point;
	vec3 text_xy_11_point;
	vec3 text_xy_01_point;
	vec3 text_xy_00_point;
	float text_x_bound=4.0;
	float text_y_bound=4.0;
    if (abs(divider)>=1e-6 && abs(dividend)>=1e-6)
	{
        t=dividend/divider;
        hitPoint=r.o+t*r.d;
		if(isVertical){
			if(isLeftOrBottomLonger){
				text_xy_10_point=vec3(-1.0,thickness*2.*cos(rotat)-1.0,1.0+thickness*2.*sin(rotat));
    			text_xy_11_point=vec3(1.0,thickness*2.*cos(rotat)-1.0,1.0+thickness*2.*sin(rotat));
    			text_xy_01_point=vec3(1.0,-1.0,1.0);
    			text_xy_00_point=vec3(-1.0,-1.0,1.0);
				text_x_bound*=thickness*thickness;
			}else{
				text_xy_10_point=vec3(-1.0,1.0,1.0);
    			text_xy_11_point=vec3(1.0,1.0,1.0);
    			text_xy_01_point=vec3(1.0,1.-thickness*2.*cos(rotat),1.0+thickness*2.*sin(rotat));
    			text_xy_00_point=vec3(-1.0,1.-thickness*2.*cos(rotat),1.0+thickness*2.*sin(rotat));
				text_x_bound*=thickness*thickness;
			}
		}else{
			if(isLeftOrBottomLonger){
				text_xy_10_point=vec3(-1.0,1.0,1.0);
    			text_xy_11_point=vec3(thickness*2.*cos(rotat)-1.,1.0,1.0+thickness*2.*sin(rotat));
    			text_xy_01_point=vec3(thickness*2.*cos(rotat)-1.,-1.0,1.0+thickness*2.*sin(rotat));
    			text_xy_00_point=vec3(-1.0,-1.0,1.0);
				text_y_bound*=thickness*thickness;
			}else{
				text_xy_10_point=vec3(1.-thickness*2.*cos(rotat),1.0,1.0+thickness*2.*sin(rotat));
    			text_xy_11_point=vec3(1.0,1.0,1.0);
    			text_xy_01_point=vec3(1.0,-1.0,1.0);
    			text_xy_00_point=vec3(1.-thickness*2.*cos(rotat),-1.0,1.0+thickness*2.*sin(rotat));
				text_y_bound*=thickness*thickness;
			}
		}
    	float text_x=dot((hitPoint-text_xy_00_point),(text_xy_10_point-text_xy_00_point));
    	float text_y=dot((hitPoint-text_xy_00_point),(text_xy_01_point-text_xy_00_point));
		if(text_x<text_x_bound && text_y<text_y_bound && text_x>0.0 && text_y>0.0)
    	{
    		vec2 tex_coord=vec2(text_x,text_y);
			tex_coord/=4.0;
			if(isVertical){
				tex_coord.x/=thickness*thickness;
			}else{
				tex_coord.y/=thickness*thickness;
			}
    		col=vec3(texture(TEXTURE,tex_coord).x);
    	}
		else{
			COLOR.a=0.0;
		}
	}
	else{
		COLOR.a=0.0;
	}
    // Output to screen
    COLOR.xyz = col;
	// Called for every pixel the material is visible on.
}

//void light() {
	// Called for every pixel for every light affecting the CanvasItem.
	// Uncomment to replace the default light processing function with this one.
//}
Tags
2d, perspective
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

Related shaders

Blast Wall

Brick/tiled wall

Wall of Glyphs

Subscribe
Notify of
guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments